diff options
Diffstat (limited to 'source/blender')
721 files changed, 11043 insertions, 5426 deletions
diff --git a/source/blender/blenfont/intern/blf.c b/source/blender/blenfont/intern/blf.c index a673f4a1bc7..d4f5be617fd 100644 --- a/source/blender/blenfont/intern/blf.c +++ b/source/blender/blenfont/intern/blf.c @@ -162,6 +162,14 @@ int BLF_load_unique(const char *name) } FontBLF *font = blf_font_new(name, filepath); + + /* XXX: Temporarily disable kerning in our main font. Kerning had been accidentally removed from + * our font in 3.1. In 3.4 we disable kerning here in the new version to keep spacing the same + * (T101506). Enable again later with change of font, placement, or rendering - Harley. */ + if (font && BLI_str_endswith(filepath, BLF_DEFAULT_PROPORTIONAL_FONT)) { + font->face_flags &= ~FT_FACE_FLAG_KERNING; + } + MEM_freeN(filepath); if (!font) { diff --git a/source/blender/blenfont/intern/blf_dir.c b/source/blender/blenfont/intern/blf_dir.c index 8534a8c583f..395d981cb0b 100644 --- a/source/blender/blenfont/intern/blf_dir.c +++ b/source/blender/blenfont/intern/blf_dir.c @@ -115,7 +115,7 @@ char *blf_dir_search(const char *file) char *s = NULL; for (dir = global_font_dir.first; dir; dir = dir->next) { - BLI_join_dirfile(full_path, sizeof(full_path), dir->path, file); + BLI_path_join(full_path, sizeof(full_path), dir->path, file); if (BLI_exists(full_path)) { s = BLI_strdup(full_path); break; diff --git a/source/blender/blenfont/intern/blf_font_default.c b/source/blender/blenfont/intern/blf_font_default.c index d35692f6eae..63b1cf34db5 100644 --- a/source/blender/blenfont/intern/blf_font_default.c +++ b/source/blender/blenfont/intern/blf_font_default.c @@ -32,7 +32,7 @@ static int blf_load_font_default(const char *filename, const bool unique) } char filepath[FILE_MAX]; - BLI_join_dirfile(filepath, sizeof(filepath), dir, filename); + BLI_path_join(filepath, sizeof(filepath), dir, filename); return (unique) ? BLF_load_unique(filepath) : BLF_load(filepath); } diff --git a/source/blender/blenkernel/BKE_armature.h b/source/blender/blenkernel/BKE_armature.h index ee0f41937e2..eff05e471aa 100644 --- a/source/blender/blenkernel/BKE_armature.h +++ b/source/blender/blenkernel/BKE_armature.h @@ -34,9 +34,9 @@ typedef struct EditBone { /** User-Defined Properties on this Bone */ struct IDProperty *prop; /** - * Editbones have a one-way link (i.e. children refer + * Edit-bones have a one-way link (i.e. children refer * to parents. This is converted to a two-way link for - * normal bones when leaving editmode. + * normal bones when leaving edit-mode. */ struct EditBone *parent; /** (64 == MAXBONENAME) */ diff --git a/source/blender/blenkernel/BKE_asset_catalog.hh b/source/blender/blenkernel/BKE_asset_catalog.hh index caed12d4fdf..73c2e00c4c4 100644 --- a/source/blender/blenkernel/BKE_asset_catalog.hh +++ b/source/blender/blenkernel/BKE_asset_catalog.hh @@ -307,7 +307,7 @@ class AssetCatalogTreeItem { /** Iterate over children calling \a callback for each of them, but do not recurse into their * children. */ - void foreach_child(const ItemIterFn callback); + void foreach_child(ItemIterFn callback); protected: /** Child tree items, ordered by their names. */ @@ -345,10 +345,15 @@ class AssetCatalogTree { /** Ensure an item representing \a path is in the tree, adding it if necessary. */ void insert_item(const AssetCatalog &catalog); - void foreach_item(const AssetCatalogTreeItem::ItemIterFn callback); + void foreach_item(ItemIterFn callback); /** Iterate over root items calling \a callback for each of them, but do not recurse into their * children. */ - void foreach_root_item(const ItemIterFn callback); + void foreach_root_item(ItemIterFn callback); + + bool is_empty() const; + + AssetCatalogTreeItem *find_item(const AssetCatalogPath &path); + AssetCatalogTreeItem *find_root_item(const AssetCatalogPath &path); protected: /** Child tree items, ordered by their names. */ diff --git a/source/blender/blenkernel/BKE_asset_catalog_path.hh b/source/blender/blenkernel/BKE_asset_catalog_path.hh index 135906dd064..93ab0389daf 100644 --- a/source/blender/blenkernel/BKE_asset_catalog_path.hh +++ b/source/blender/blenkernel/BKE_asset_catalog_path.hh @@ -49,7 +49,7 @@ class AssetCatalogPath { AssetCatalogPath() = default; AssetCatalogPath(StringRef path); - AssetCatalogPath(const std::string &path); + AssetCatalogPath(std::string path); AssetCatalogPath(const char *path); AssetCatalogPath(const AssetCatalogPath &other_path) = default; AssetCatalogPath(AssetCatalogPath &&other_path) noexcept; diff --git a/source/blender/blenkernel/BKE_asset_library.hh b/source/blender/blenkernel/BKE_asset_library.hh index e0a39e3aee8..2058df71f6a 100644 --- a/source/blender/blenkernel/BKE_asset_library.hh +++ b/source/blender/blenkernel/BKE_asset_library.hh @@ -10,6 +10,8 @@ # error This is a C++-only header file. Use BKE_asset_library.h instead. #endif +#include "DNA_asset_types.h" + #include "BKE_asset_library.h" #include "BKE_asset_catalog.hh" @@ -44,19 +46,24 @@ struct AssetLibrary { * No-op if the catalog cannot be found. This could be the kind of "the * catalog definition file is corrupt/lost" scenario that the simple name is * meant to help recover from. */ - void refresh_catalog_simplename(struct AssetMetaData *asset_data); + void refresh_catalog_simplename(AssetMetaData *asset_data); void on_blend_save_handler_register(); void on_blend_save_handler_unregister(); - void on_blend_save_post(struct Main *, struct PointerRNA **pointers, int num_pointers); + void on_blend_save_post(Main *bmain, PointerRNA **pointers, int num_pointers); private: bCallbackFuncStore on_save_callback_store_{}; }; +Vector<AssetLibraryReference> all_valid_asset_library_refs(); + } // namespace blender::bke +blender::bke::AssetLibrary *BKE_asset_library_load(const Main *bmain, + const AssetLibraryReference &library_reference); + blender::bke::AssetCatalogService *BKE_asset_library_get_catalog_service( const ::AssetLibrary *library); blender::bke::AssetCatalogTree *BKE_asset_library_get_catalog_tree(const ::AssetLibrary *library); diff --git a/source/blender/blenkernel/BKE_attribute.hh b/source/blender/blenkernel/BKE_attribute.hh index 7b13b8a2b09..a4f9d73c31e 100644 --- a/source/blender/blenkernel/BKE_attribute.hh +++ b/source/blender/blenkernel/BKE_attribute.hh @@ -793,7 +793,9 @@ class CustomDataAttributes { ~CustomDataAttributes(); CustomDataAttributes(const CustomDataAttributes &other); CustomDataAttributes(CustomDataAttributes &&other); + CustomDataAttributes &operator=(const CustomDataAttributes &other); + CustomDataAttributes &operator=(CustomDataAttributes &&other); void reallocate(int size); diff --git a/source/blender/blenkernel/BKE_blender_version.h b/source/blender/blenkernel/BKE_blender_version.h index 3c8f7d758b6..806fff2099e 100644 --- a/source/blender/blenkernel/BKE_blender_version.h +++ b/source/blender/blenkernel/BKE_blender_version.h @@ -25,7 +25,7 @@ extern "C" { /* Blender file format version. */ #define BLENDER_FILE_VERSION BLENDER_VERSION -#define BLENDER_FILE_SUBVERSION 3 +#define BLENDER_FILE_SUBVERSION 5 /* 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 diff --git a/source/blender/blenkernel/BKE_bpath.h b/source/blender/blenkernel/BKE_bpath.h index bc60b6f050e..5b1dea0833a 100644 --- a/source/blender/blenkernel/BKE_bpath.h +++ b/source/blender/blenkernel/BKE_bpath.h @@ -55,15 +55,18 @@ typedef enum eBPathForeachFlag { * This is needed for directory manipulation callbacks which might otherwise modify the same * directory multiple times. */ BKE_BPATH_FOREACH_PATH_SKIP_MULTIFILE = (1 << 8), - /** Reload data (when the path is edited). - * \note Only used by Image IDType currently. */ + /** + * Reload data (when the path is edited). + * \note Only used by Image #IDType currently. + */ BKE_BPATH_FOREACH_PATH_RELOAD_EDITED = (1 << 9), } eBPathForeachFlag; ENUM_OPERATORS(eBPathForeachFlag, BKE_BPATH_FOREACH_PATH_RELOAD_EDITED) struct BPathForeachPathData; -/** Callback used to iterate over an ID's file paths. +/** + * Callback used to iterate over an ID's file paths. * * \note `path`s parameters should be considered as having a maximal `FILE_MAX` string length. * @@ -145,8 +148,9 @@ bool BKE_bpath_foreach_path_allocated_process(struct BPathForeachPathData *bpath /** Check for missing files. */ void BKE_bpath_missing_files_check(struct Main *bmain, struct ReportList *reports); -/** Recursively search into given search directory, for all file paths of all IDs in given \a - * bmain, and replace existing paths as needed. +/** + * Recursively search into given search directory, for all file paths of all IDs in given + * \a bmain, and replace existing paths as needed. * * \note The search will happen into the whole search directory tree recursively (with a limit of * MAX_DIR_RECURSE), if several files are found matching a searched filename, the biggest one will @@ -156,7 +160,7 @@ void BKE_bpath_missing_files_check(struct Main *bmain, struct ReportList *report * \param searchpath: The root directory in which the new filepaths should be searched for. * \param find_all: If `true`, also search for files which current path is still valid, if `false` * skip those still valid paths. - * */ + */ void BKE_bpath_missing_files_find(struct Main *bmain, const char *searchpath, struct ReportList *reports, @@ -178,23 +182,28 @@ void BKE_bpath_absolute_convert(struct Main *bmain, const char *basedir, struct ReportList *reports); -/** Temp backup of paths from all IDs in given \a bmain. +/** + * Temp backup of paths from all IDs in given \a bmain. * - * \return An opaque handle to pass to #BKE_bpath_list_restore and #BKE_bpath_list_free. + * \return An opaque handle to pass to #BKE_bpath_list_restore and #BKE_bpath_list_free. */ void *BKE_bpath_list_backup(struct Main *bmain, eBPathForeachFlag flag); -/** Restore the temp backup of paths from \a path_list_handle into all IDs in given \a bmain. +/** + * Restore the temp backup of paths from \a path_list_handle into all IDs in given \a bmain. * * \note This function assumes that the data in given Main did not change (no * addition/deletion/re-ordering of IDs, or their file paths) since the call to - * #BKE_bpath_list_backup that generated the given \a path_list_handle. */ + * #BKE_bpath_list_backup that generated the given \a path_list_handle. + */ void BKE_bpath_list_restore(struct Main *bmain, eBPathForeachFlag flag, void *path_list_handle); -/** Free the temp backup of paths in \a path_list_handle. +/** + * Free the temp backup of paths in \a path_list_handle. * * \note This function assumes that the path list has already been restored with a call to - * #BKE_bpath_list_restore, and is therefore empty. */ + * #BKE_bpath_list_restore, and is therefore empty. + */ void BKE_bpath_list_free(void *path_list_handle); /** \} */ diff --git a/source/blender/blenkernel/BKE_brush.h b/source/blender/blenkernel/BKE_brush.h index 4d728002c87..a763b3d12c2 100644 --- a/source/blender/blenkernel/BKE_brush.h +++ b/source/blender/blenkernel/BKE_brush.h @@ -18,7 +18,9 @@ extern "C" { struct Brush; struct ImBuf; struct ImagePool; +struct Object; struct Main; +struct MTex; struct Scene; struct ToolSettings; struct UnifiedPaintSettings; @@ -109,6 +111,7 @@ float BKE_brush_curve_strength(const struct Brush *br, float p, float len); */ float BKE_brush_sample_tex_3d(const struct Scene *scene, const struct Brush *br, + const struct MTex *mtex, const float point[3], float rgba[4], int thread, @@ -120,6 +123,24 @@ float BKE_brush_sample_masktex(const struct Scene *scene, struct ImagePool *pool); /** + * Get the mask texture for this given object mode. + * + * This is preferred above using mtex/mask_mtex attributes directly as due to legacy these + * attributes got switched in sculpt mode. + */ +const struct MTex *BKE_brush_mask_texture_get(const struct Brush *brush, + const eObjectMode object_mode); + +/** + * Get the color texture for this given object mode. + * + * This is preferred above using mtex/mask_mtex attributes directly as due to legacy these + * attributes got switched in sculpt mode. + */ +const struct MTex *BKE_brush_color_texture_get(const struct Brush *brush, + const eObjectMode object_mode); + +/** * Radial control. */ struct ImBuf *BKE_brush_gen_radial_control_imbuf(struct Brush *br, diff --git a/source/blender/blenkernel/BKE_context.h b/source/blender/blenkernel/BKE_context.h index b7068720469..e1406e63ce1 100644 --- a/source/blender/blenkernel/BKE_context.h +++ b/source/blender/blenkernel/BKE_context.h @@ -285,7 +285,7 @@ bool CTX_data_dir(const char *member); CTX_DATA_BEGIN (C, Type, instance, member) \ Type_id instance_id = (Type_id)ctx_link->ptr.owner_id; -int ctx_data_list_count(const bContext *C, int (*func)(const bContext *, ListBase *)); +int ctx_data_list_count(const bContext *C, bool (*func)(const bContext *, ListBase *)); #define CTX_DATA_COUNT(C, member) ctx_data_list_count(C, CTX_data_##member) @@ -316,22 +316,22 @@ void CTX_data_main_set(bContext *C, struct Main *bmain); void CTX_data_scene_set(bContext *C, struct Scene *scene); /* Only Outliner currently! */ -int CTX_data_selected_ids(const bContext *C, ListBase *list); +bool CTX_data_selected_ids(const bContext *C, ListBase *list); -int CTX_data_selected_editable_objects(const bContext *C, ListBase *list); -int CTX_data_selected_editable_bases(const bContext *C, ListBase *list); +bool CTX_data_selected_editable_objects(const bContext *C, ListBase *list); +bool CTX_data_selected_editable_bases(const bContext *C, ListBase *list); -int CTX_data_editable_objects(const bContext *C, ListBase *list); -int CTX_data_editable_bases(const bContext *C, ListBase *list); +bool CTX_data_editable_objects(const bContext *C, ListBase *list); +bool CTX_data_editable_bases(const bContext *C, ListBase *list); -int CTX_data_selected_objects(const bContext *C, ListBase *list); -int CTX_data_selected_bases(const bContext *C, ListBase *list); +bool CTX_data_selected_objects(const bContext *C, ListBase *list); +bool CTX_data_selected_bases(const bContext *C, ListBase *list); -int CTX_data_visible_objects(const bContext *C, ListBase *list); -int CTX_data_visible_bases(const bContext *C, ListBase *list); +bool CTX_data_visible_objects(const bContext *C, ListBase *list); +bool CTX_data_visible_bases(const bContext *C, ListBase *list); -int CTX_data_selectable_objects(const bContext *C, ListBase *list); -int CTX_data_selectable_bases(const bContext *C, ListBase *list); +bool CTX_data_selectable_objects(const bContext *C, ListBase *list); +bool CTX_data_selectable_bases(const bContext *C, ListBase *list); struct Object *CTX_data_active_object(const bContext *C); struct Base *CTX_data_active_base(const bContext *C); @@ -345,25 +345,25 @@ struct Mask *CTX_data_edit_mask(const bContext *C); struct CacheFile *CTX_data_edit_cachefile(const bContext *C); -int CTX_data_selected_nodes(const bContext *C, ListBase *list); +bool CTX_data_selected_nodes(const bContext *C, ListBase *list); struct EditBone *CTX_data_active_bone(const bContext *C); -int CTX_data_selected_bones(const bContext *C, ListBase *list); -int CTX_data_selected_editable_bones(const bContext *C, ListBase *list); -int CTX_data_visible_bones(const bContext *C, ListBase *list); -int CTX_data_editable_bones(const bContext *C, ListBase *list); +bool CTX_data_selected_bones(const bContext *C, ListBase *list); +bool CTX_data_selected_editable_bones(const bContext *C, ListBase *list); +bool CTX_data_visible_bones(const bContext *C, ListBase *list); +bool CTX_data_editable_bones(const bContext *C, ListBase *list); struct bPoseChannel *CTX_data_active_pose_bone(const bContext *C); -int CTX_data_selected_pose_bones(const bContext *C, ListBase *list); -int CTX_data_selected_pose_bones_from_active_object(const bContext *C, ListBase *list); -int CTX_data_visible_pose_bones(const bContext *C, ListBase *list); +bool CTX_data_selected_pose_bones(const bContext *C, ListBase *list); +bool CTX_data_selected_pose_bones_from_active_object(const bContext *C, ListBase *list); +bool CTX_data_visible_pose_bones(const bContext *C, ListBase *list); struct bGPdata *CTX_data_gpencil_data(const bContext *C); struct bGPDlayer *CTX_data_active_gpencil_layer(const bContext *C); struct bGPDframe *CTX_data_active_gpencil_frame(const bContext *C); -int CTX_data_visible_gpencil_layers(const bContext *C, ListBase *list); -int CTX_data_editable_gpencil_layers(const bContext *C, ListBase *list); -int CTX_data_editable_gpencil_strokes(const bContext *C, ListBase *list); +bool CTX_data_visible_gpencil_layers(const bContext *C, ListBase *list); +bool CTX_data_editable_gpencil_layers(const bContext *C, ListBase *list); +bool CTX_data_editable_gpencil_strokes(const bContext *C, ListBase *list); const struct AssetLibraryReference *CTX_wm_asset_library_ref(const bContext *C); struct AssetHandle CTX_wm_asset_handle(const bContext *C, bool *r_is_valid); diff --git a/source/blender/blenkernel/BKE_duplilist.h b/source/blender/blenkernel/BKE_duplilist.h index 44c4df1fc2e..a0732bf39cf 100644 --- a/source/blender/blenkernel/BKE_duplilist.h +++ b/source/blender/blenkernel/BKE_duplilist.h @@ -76,16 +76,20 @@ typedef struct DupliObject { unsigned int random_id; } DupliObject; -/** Look up the RGBA value of a uniform shader attribute. - * \return true if the attribute was found; if not, r_value is also set to zero. */ +/** + * Look up the RGBA value of a uniform shader attribute. + * \return true if the attribute was found; if not, r_value is also set to zero. + */ bool BKE_object_dupli_find_rgba_attribute(struct Object *ob, struct DupliObject *dupli, struct Object *dupli_parent, const char *name, float r_value[4]); -/** Look up the RGBA value of a view layer/scene/world shader attribute. - * \return true if the attribute was found; if not, r_value is also set to zero. */ +/** + * Look up the RGBA value of a view layer/scene/world shader attribute. + * \return true if the attribute was found; if not, r_value is also set to zero. + */ bool BKE_view_layer_find_rgba_attribute(struct Scene *scene, struct ViewLayer *layer, const char *name, diff --git a/source/blender/blenkernel/BKE_geometry_fields.hh b/source/blender/blenkernel/BKE_geometry_fields.hh index 988e0017f04..2eef67dba98 100644 --- a/source/blender/blenkernel/BKE_geometry_fields.hh +++ b/source/blender/blenkernel/BKE_geometry_fields.hh @@ -75,14 +75,14 @@ class PointCloudFieldContext : public fn::FieldContext { class InstancesFieldContext : public fn::FieldContext { private: - const InstancesComponent &instances_; + const Instances &instances_; public: - InstancesFieldContext(const InstancesComponent &instances) : instances_(instances) + InstancesFieldContext(const Instances &instances) : instances_(instances) { } - const InstancesComponent &instances() const + const Instances &instances() const { return instances_; } @@ -128,13 +128,13 @@ class GeometryFieldContext : public fn::FieldContext { const Mesh *mesh() const; const CurvesGeometry *curves() const; const PointCloud *pointcloud() const; - const InstancesComponent *instances() const; + const Instances *instances() const; private: GeometryFieldContext(const Mesh &mesh, eAttrDomain domain); GeometryFieldContext(const CurvesGeometry &curves, eAttrDomain domain); GeometryFieldContext(const PointCloud &points); - GeometryFieldContext(const InstancesComponent &instances); + GeometryFieldContext(const Instances &instances); }; class GeometryFieldInput : public fn::FieldInput { @@ -187,8 +187,7 @@ class InstancesFieldInput : public fn::FieldInput { GVArray get_varray_for_context(const fn::FieldContext &context, IndexMask mask, ResourceScope &scope) const override; - virtual GVArray get_varray_for_context(const InstancesComponent &instances, - IndexMask mask) const = 0; + virtual GVArray get_varray_for_context(const Instances &instances, IndexMask mask) const = 0; }; class AttributeFieldInput : public GeometryFieldInput { diff --git a/source/blender/blenkernel/BKE_geometry_set.hh b/source/blender/blenkernel/BKE_geometry_set.hh index 2ef9556afc7..b488806c8e7 100644 --- a/source/blender/blenkernel/BKE_geometry_set.hh +++ b/source/blender/blenkernel/BKE_geometry_set.hh @@ -43,6 +43,7 @@ enum class GeometryOwnershipType { namespace blender::bke { class ComponentAttributeProviders; class CurvesEditHints; +class Instances; } // namespace blender::bke class GeometryComponent; @@ -246,6 +247,12 @@ struct GeometrySet { */ static GeometrySet create_with_curves( Curves *curves, GeometryOwnershipType ownership = GeometryOwnershipType::Owned); + /** + * Create a new geometry set that only contains the given instances. + */ + static GeometrySet create_with_instances( + blender::bke::Instances *instances, + GeometryOwnershipType ownership = GeometryOwnershipType::Owned); /* Utility methods for access. */ /** @@ -294,6 +301,10 @@ struct GeometrySet { */ const Curves *get_curves_for_read() const; /** + * Returns read-only instances or null. + */ + const blender::bke::Instances *get_instances_for_read() const; + /** * Returns read-only curve edit hints or null. */ const blender::bke::CurvesEditHints *get_curve_edit_hints_for_read() const; @@ -315,6 +326,10 @@ struct GeometrySet { */ Curves *get_curves_for_write(); /** + * Returns mutable instances or null. No ownership is transferred. + */ + blender::bke::Instances *get_instances_for_write(); + /** * Returns mutable curve edit hints or null. */ blender::bke::CurvesEditHints *get_curve_edit_hints_for_write(); @@ -339,6 +354,11 @@ struct GeometrySet { */ void replace_curves(Curves *curves, GeometryOwnershipType ownership = GeometryOwnershipType::Owned); + /** + * Clear the existing instances and replace them with the given one. + */ + void replace_instances(blender::bke::Instances *instances, + GeometryOwnershipType ownership = GeometryOwnershipType::Owned); private: /** @@ -515,244 +535,35 @@ class CurveComponent : public GeometryComponent { }; /** - * Holds a reference to conceptually unique geometry or a pointer to object/collection data - * that is instanced with a transform in #InstancesComponent. - */ -class InstanceReference { - public: - enum class Type { - /** - * An empty instance. This allows an `InstanceReference` to be default constructed without - * being in an invalid state. There might also be other use cases that we haven't explored much - * yet (such as changing the instance later on, and "disabling" some instances). - */ - None, - Object, - Collection, - GeometrySet, - }; - - private: - Type type_ = Type::None; - /** Depending on the type this is either null, an Object or Collection pointer. */ - void *data_ = nullptr; - std::unique_ptr<GeometrySet> geometry_set_; - - public: - InstanceReference() = default; - - InstanceReference(Object &object) : type_(Type::Object), data_(&object) - { - } - - InstanceReference(Collection &collection) : type_(Type::Collection), data_(&collection) - { - } - - InstanceReference(GeometrySet geometry_set) - : type_(Type::GeometrySet), - geometry_set_(std::make_unique<GeometrySet>(std::move(geometry_set))) - { - } - - InstanceReference(const InstanceReference &other) : type_(other.type_), data_(other.data_) - { - if (other.geometry_set_) { - geometry_set_ = std::make_unique<GeometrySet>(*other.geometry_set_); - } - } - - InstanceReference(InstanceReference &&other) - : type_(other.type_), data_(other.data_), geometry_set_(std::move(other.geometry_set_)) - { - other.type_ = Type::None; - other.data_ = nullptr; - } - - InstanceReference &operator=(const InstanceReference &other) - { - if (this == &other) { - return *this; - } - this->~InstanceReference(); - new (this) InstanceReference(other); - return *this; - } - - InstanceReference &operator=(InstanceReference &&other) - { - if (this == &other) { - return *this; - } - this->~InstanceReference(); - new (this) InstanceReference(std::move(other)); - return *this; - } - - Type type() const - { - return type_; - } - - Object &object() const - { - BLI_assert(type_ == Type::Object); - return *(Object *)data_; - } - - Collection &collection() const - { - BLI_assert(type_ == Type::Collection); - return *(Collection *)data_; - } - - const GeometrySet &geometry_set() const - { - BLI_assert(type_ == Type::GeometrySet); - return *geometry_set_; - } - - bool owns_direct_data() const - { - if (type_ != Type::GeometrySet) { - /* The object and collection instances are not direct data. */ - return true; - } - return geometry_set_->owns_direct_data(); - } - - void ensure_owns_direct_data() - { - if (type_ != Type::GeometrySet) { - return; - } - geometry_set_->ensure_owns_direct_data(); - } - - uint64_t hash() const - { - return blender::get_default_hash_2(data_, geometry_set_.get()); - } - - friend bool operator==(const InstanceReference &a, const InstanceReference &b) - { - return a.data_ == b.data_ && a.geometry_set_.get() == b.geometry_set_.get(); - } -}; - -/** - * A geometry component that stores instances. The instance data can be any type described by - * #InstanceReference. Geometry instances can even contain instances themselves, for nested - * instancing. Each instance has an index into an array of unique instance data, and a transform. - * The component can also store generic attributes for each instance. - * - * The component works differently from other geometry components in that it stores - * data about instancing directly, rather than owning a pointer to a separate data structure. - * - * This component is not responsible for handling the interface to a render engine, or other - * areas that work with all visible geometry, that is handled by the dependency graph iterator - * (see `DEG_depsgraph_query.h`). + * A geometry component that stores #Instances. */ class InstancesComponent : public GeometryComponent { private: - /** - * Indexed set containing information about the data that is instanced. - * Actual instances store an index ("handle") into this set. - */ - blender::VectorSet<InstanceReference> references_; - - /** Index into `references_`. Determines what data is instanced. */ - blender::Vector<int> instance_reference_handles_; - /** Transformation of the instances. */ - blender::Vector<blender::float4x4> instance_transforms_; - - /* These almost unique ids are generated based on the `id` attribute, which might not contain - * unique ids at all. They are *almost* unique, because under certain very unlikely - * circumstances, they are not unique. Code using these ids should not crash when they are not - * unique but can generally expect them to be unique. */ - mutable std::mutex almost_unique_ids_mutex_; - mutable blender::Array<int> almost_unique_ids_; - - blender::bke::CustomDataAttributes attributes_; + blender::bke::Instances *instances_ = nullptr; + GeometryOwnershipType ownership_ = GeometryOwnershipType::Owned; public: InstancesComponent(); - ~InstancesComponent() = default; + ~InstancesComponent(); GeometryComponent *copy() const override; void clear(); - void reserve(int min_capacity); - /** - * Resize the transform, handles, and attributes to the specified capacity. - * - * \note This function should be used carefully, only when it's guaranteed - * that the data will be filled. - */ - void resize(int capacity); + const blender::bke::Instances *get_for_read() const; + blender::bke::Instances *get_for_write(); - /** - * Returns a handle for the given reference. - * If the reference exists already, the handle of the existing reference is returned. - * Otherwise a new handle is added. - */ - int add_reference(const InstanceReference &reference); - /** - * Add a reference to the instance reference with an index specified by the #instance_handle - * argument. For adding many instances, using #resize and accessing the transform array directly - * is preferred. - */ - void add_instance(int instance_handle, const blender::float4x4 &transform); - - blender::Span<InstanceReference> references() const; - void remove_unused_references(); - - /** - * If references have a collection or object type, convert them into geometry instances - * recursively. After that, the geometry sets can be edited. There may still be instances of - * other types of they can't be converted to geometry sets. - */ - void ensure_geometry_instances(); - /** - * With write access to the instances component, the data in the instanced geometry sets can be - * changed. This is a function on the component rather than each reference to ensure `const` - * correctness for that reason. - */ - GeometrySet &geometry_set_from_reference(int reference_index); - - blender::Span<int> instance_reference_handles() const; - blender::MutableSpan<int> instance_reference_handles(); - blender::MutableSpan<blender::float4x4> instance_transforms(); - blender::Span<blender::float4x4> instance_transforms() const; - - int instances_num() const; - int references_num() const; - - /** - * Remove the indices that are not contained in the mask input, and remove unused instance - * references afterwards. - */ - void remove_instances(const blender::IndexMask mask); - - blender::Span<int> almost_unique_ids() const; - - blender::bke::CustomDataAttributes &instance_attributes(); - const blender::bke::CustomDataAttributes &instance_attributes() const; - - std::optional<blender::bke::AttributeAccessor> attributes() const final; - std::optional<blender::bke::MutableAttributeAccessor> attributes_for_write() final; - - void foreach_referenced_geometry( - blender::FunctionRef<void(const GeometrySet &geometry_set)> callback) const; + void replace(blender::bke::Instances *instances, + GeometryOwnershipType ownership = GeometryOwnershipType::Owned); bool is_empty() const final; bool owns_direct_data() const override; void ensure_owns_direct_data() override; - static constexpr inline GeometryComponentType static_type = GEO_COMPONENT_TYPE_INSTANCES; + std::optional<blender::bke::AttributeAccessor> attributes() const final; + std::optional<blender::bke::MutableAttributeAccessor> attributes_for_write() final; - private: + static constexpr inline GeometryComponentType static_type = GEO_COMPONENT_TYPE_INSTANCES; }; /** diff --git a/source/blender/blenkernel/BKE_gpencil_geom.h b/source/blender/blenkernel/BKE_gpencil_geom.h index b9219814c08..976961f27ae 100644 --- a/source/blender/blenkernel/BKE_gpencil_geom.h +++ b/source/blender/blenkernel/BKE_gpencil_geom.h @@ -332,8 +332,12 @@ bool BKE_gpencil_stroke_stretch(struct bGPDstroke *gps, * \param gps: Target stroke. * \param index_from: the index of the first point to be used in the trimmed result. * \param index_to: the index of the last point to be used in the trimmed result. + * \param keep_point: Keep strokes with one point. False remove the single points strokes */ -bool BKE_gpencil_stroke_trim_points(struct bGPDstroke *gps, int index_from, int index_to); +bool BKE_gpencil_stroke_trim_points(struct bGPDstroke *gps, + int index_from, + int index_to, + const bool keep_point); /** * Split the given stroke into several new strokes, partitioning * it based on whether the stroke points have a particular flag diff --git a/source/blender/blenkernel/BKE_instances.hh b/source/blender/blenkernel/BKE_instances.hh new file mode 100644 index 00000000000..f17ebba0dfa --- /dev/null +++ b/source/blender/blenkernel/BKE_instances.hh @@ -0,0 +1,270 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +#pragma once + +/** \file + * \ingroup bke + * + * #Instances is a container for geometry instances. It fulfills some key requirements: + * - Support nested instances. + * - Support instance attributes. + * - Support referencing different kinds of instances (objects, collections, geometry sets). + * - Support efficiently iterating over the instanced geometries, i.e. without have to iterate over + * all instances. + * + * #Instances has an ordered set of #InstanceReference. An #InstanceReference contains information + * about a particular instanced geometry. Each #InstanceReference has a handle (integer index) + * which is then stored per instance. Many instances can use the same #InstanceReference. + */ + +#include <mutex> + +#include "BLI_float4x4.hh" +#include "BLI_vector.hh" +#include "BLI_vector_set.hh" + +#include "BKE_attribute.hh" + +struct GeometrySet; +struct Object; +struct Collection; + +namespace blender::bke { + +/** + * Holds a reference to conceptually unique geometry or a pointer to object/collection data + * that is instanced with a transform in #Instances. + */ +class InstanceReference { + public: + enum class Type { + /** + * An empty instance. This allows an `InstanceReference` to be default constructed without + * being in an invalid state. There might also be other use cases that we haven't explored + * much yet (such as changing the instance later on, and "disabling" some instances). + */ + None, + Object, + Collection, + GeometrySet, + }; + + private: + Type type_ = Type::None; + /** Depending on the type this is either null, an Object or Collection pointer. */ + void *data_ = nullptr; + std::unique_ptr<GeometrySet> geometry_set_; + + public: + InstanceReference() = default; + InstanceReference(Object &object); + InstanceReference(Collection &collection); + InstanceReference(GeometrySet geometry_set); + + InstanceReference(const InstanceReference &other); + InstanceReference(InstanceReference &&other); + + InstanceReference &operator=(const InstanceReference &other); + InstanceReference &operator=(InstanceReference &&other); + + Type type() const; + Object &object() const; + Collection &collection() const; + const GeometrySet &geometry_set() const; + + bool owns_direct_data() const; + void ensure_owns_direct_data(); + + uint64_t hash() const; + friend bool operator==(const InstanceReference &a, const InstanceReference &b); +}; + +class Instances { + private: + /** + * Indexed set containing information about the data that is instanced. + * Actual instances store an index ("handle") into this set. + */ + blender::VectorSet<InstanceReference> references_; + + /** Indices into `references_`. Determines what data is instanced. */ + blender::Vector<int> reference_handles_; + /** Transformation of the instances. */ + blender::Vector<blender::float4x4> transforms_; + + /* These almost unique ids are generated based on the `id` attribute, which might not contain + * unique ids at all. They are *almost* unique, because under certain very unlikely + * circumstances, they are not unique. Code using these ids should not crash when they are not + * unique but can generally expect them to be unique. */ + mutable std::mutex almost_unique_ids_mutex_; + mutable blender::Array<int> almost_unique_ids_; + + CustomDataAttributes attributes_; + + public: + Instances() = default; + Instances(const Instances &other); + + void reserve(int min_capacity); + /** + * Resize the transform, handles, and attributes to the specified capacity. + * + * \note This function should be used carefully, only when it's guaranteed + * that the data will be filled. + */ + void resize(int capacity); + + /** + * Returns a handle for the given reference. + * If the reference exists already, the handle of the existing reference is returned. + * Otherwise a new handle is added. + */ + int add_reference(const InstanceReference &reference); + /** + * Add a reference to the instance reference with an index specified by the #instance_handle + * argument. For adding many instances, using #resize and accessing the transform array + * directly is preferred. + */ + void add_instance(int instance_handle, const blender::float4x4 &transform); + + blender::Span<InstanceReference> references() const; + void remove_unused_references(); + + /** + * If references have a collection or object type, convert them into geometry instances + * recursively. After that, the geometry sets can be edited. There may still be instances of + * other types of they can't be converted to geometry sets. + */ + void ensure_geometry_instances(); + /** + * With write access to the instances component, the data in the instanced geometry sets can be + * changed. This is a function on the component rather than each reference to ensure `const` + * correctness for that reason. + */ + GeometrySet &geometry_set_from_reference(int reference_index); + + blender::Span<int> reference_handles() const; + blender::MutableSpan<int> reference_handles(); + blender::MutableSpan<blender::float4x4> transforms(); + blender::Span<blender::float4x4> transforms() const; + + int instances_num() const; + int references_num() const; + + /** + * Remove the indices that are not contained in the mask input, and remove unused instance + * references afterwards. + */ + void remove(const blender::IndexMask mask); + /** + * Get an id for every instance. These can be used for e.g. motion blur. + */ + blender::Span<int> almost_unique_ids() const; + + blender::bke::AttributeAccessor attributes() const; + blender::bke::MutableAttributeAccessor attributes_for_write(); + + CustomDataAttributes &custom_data_attributes(); + const CustomDataAttributes &custom_data_attributes() const; + + void foreach_referenced_geometry( + blender::FunctionRef<void(const GeometrySet &geometry_set)> callback) const; + + bool owns_direct_data() const; + void ensure_owns_direct_data(); +}; + +/* -------------------------------------------------------------------- */ +/** \name #InstanceReference Inline Methods + * \{ */ + +inline InstanceReference::InstanceReference(Object &object) : type_(Type::Object), data_(&object) +{ +} + +inline InstanceReference::InstanceReference(Collection &collection) + : type_(Type::Collection), data_(&collection) +{ +} + +inline InstanceReference::InstanceReference(const InstanceReference &other) + : type_(other.type_), data_(other.data_) +{ + if (other.geometry_set_) { + geometry_set_ = std::make_unique<GeometrySet>(*other.geometry_set_); + } +} + +inline InstanceReference::InstanceReference(InstanceReference &&other) + : type_(other.type_), data_(other.data_), geometry_set_(std::move(other.geometry_set_)) +{ + other.type_ = Type::None; + other.data_ = nullptr; +} + +inline InstanceReference &InstanceReference::operator=(const InstanceReference &other) +{ + if (this == &other) { + return *this; + } + this->~InstanceReference(); + new (this) InstanceReference(other); + return *this; +} + +inline InstanceReference &InstanceReference::operator=(InstanceReference &&other) +{ + if (this == &other) { + return *this; + } + this->~InstanceReference(); + new (this) InstanceReference(std::move(other)); + return *this; +} + +inline InstanceReference::Type InstanceReference::type() const +{ + return type_; +} + +inline Object &InstanceReference::object() const +{ + BLI_assert(type_ == Type::Object); + return *(Object *)data_; +} + +inline Collection &InstanceReference::collection() const +{ + BLI_assert(type_ == Type::Collection); + return *(Collection *)data_; +} + +inline const GeometrySet &InstanceReference::geometry_set() const +{ + BLI_assert(type_ == Type::GeometrySet); + return *geometry_set_; +} + +inline CustomDataAttributes &Instances::custom_data_attributes() +{ + return attributes_; +} + +inline const CustomDataAttributes &Instances::custom_data_attributes() const +{ + return attributes_; +} + +inline uint64_t InstanceReference::hash() const +{ + return blender::get_default_hash_2(data_, geometry_set_.get()); +} + +inline bool operator==(const InstanceReference &a, const InstanceReference &b) +{ + return a.data_ == b.data_ && a.geometry_set_.get() == b.geometry_set_.get(); +} + +/** \} */ + +} // namespace blender::bke diff --git a/source/blender/blenkernel/BKE_key.h b/source/blender/blenkernel/BKE_key.h index 0fe351c0aa4..6cae56b775f 100644 --- a/source/blender/blenkernel/BKE_key.h +++ b/source/blender/blenkernel/BKE_key.h @@ -167,9 +167,9 @@ void BKE_keyblock_update_from_offset(const struct Object *ob, * Move shape key from org_index to new_index. Safe, clamps index to valid range, * updates reference keys, the object's active shape index, * the 'frame' value in case of absolute keys, etc. - * Note indices are expected in real values (not 'fake' shapenr +1 ones). + * Note indices are expected in real values (not *fake* `shapenr +1` ones). * - * \param org_index: if < 0, current object's active shape will be used as skey to move. + * \param org_index: if < 0, current object's active shape will be used as shape-key to move. * \return true if something was done, else false. */ bool BKE_keyblock_move(struct Object *ob, int org_index, int new_index); diff --git a/source/blender/blenkernel/BKE_mesh_types.h b/source/blender/blenkernel/BKE_mesh_types.h index dacc2188abb..80f61086052 100644 --- a/source/blender/blenkernel/BKE_mesh_types.h +++ b/source/blender/blenkernel/BKE_mesh_types.h @@ -99,7 +99,7 @@ struct MeshRuntime { /** Cache for BVH trees generated for the mesh. Defined in 'BKE_bvhutil.c' */ BVHCache *bvh_cache = nullptr; - /** Cache of non-manifold boundary data for Shrinkwrap Target Project. */ + /** Cache of non-manifold boundary data for Shrink-wrap Target Project. */ ShrinkwrapBoundaryData *shrinkwrap_data = nullptr; /** Needed in case we need to lazily initialize the mesh. */ @@ -136,8 +136,8 @@ struct MeshRuntime { /** * Caches for lazily computed vertex and polygon normals. These are stored here rather than in - * #CustomData because they can be calculated on a const mesh, and adding custom data layers on a - * const mesh is not thread-safe. + * #CustomData because they can be calculated on a `const` mesh, and adding custom data layers on + * a `const` mesh is not thread-safe. */ bool vert_normals_dirty = false; bool poly_normals_dirty = false; diff --git a/source/blender/blenkernel/BKE_nla.h b/source/blender/blenkernel/BKE_nla.h index efadd5c11d6..2913beee759 100644 --- a/source/blender/blenkernel/BKE_nla.h +++ b/source/blender/blenkernel/BKE_nla.h @@ -249,8 +249,8 @@ float BKE_nlastrip_compute_frame_to_next_strip(struct NlaStrip *strip); /** * Returns the next strip in this strip's NLA track, or a null pointer. * - * \param strip The strip to find the next trip from. - * \param check_transitions Whether or not to skip transitions. + * \param strip: The strip to find the next trip from. + * \param check_transitions: Whether or not to skip transitions. * \return The next strip in the track, or NULL if none are present. */ struct NlaStrip *BKE_nlastrip_next_in_track(struct NlaStrip *strip, bool skip_transitions); @@ -258,8 +258,8 @@ struct NlaStrip *BKE_nlastrip_next_in_track(struct NlaStrip *strip, bool skip_tr /** * Returns the previous strip in this strip's NLA track, or a null pointer. * - * \param strip The strip to find the previous trip from. - * \param check_transitions Whether or not to skip transitions. + * \param strip: The strip to find the previous trip from. + * \param check_transitions: Whether or not to skip transitions. * \return The previous strip in the track, or NULL if none are present. */ struct NlaStrip *BKE_nlastrip_prev_in_track(struct NlaStrip *strip, bool skip_transitions); diff --git a/source/blender/blenkernel/BKE_node.h b/source/blender/blenkernel/BKE_node.h index b1b4045370c..ecf7a556459 100644 --- a/source/blender/blenkernel/BKE_node.h +++ b/source/blender/blenkernel/BKE_node.h @@ -792,6 +792,12 @@ void nodeChainIterBackwards(const bNodeTree *ntree, */ void nodeParentsIter(bNode *node, bool (*callback)(bNode *, void *), void *userdata); +/** + * A dangling reroute node is a reroute node that does *not* have a "data source", i.e. no + * non-reroute node is connected to its input. + */ +bool nodeIsDanglingReroute(const struct bNodeTree *ntree, const struct bNode *node); + struct bNodeLink *nodeFindLink(struct bNodeTree *ntree, const struct bNodeSocket *from, const struct bNodeSocket *to); diff --git a/source/blender/blenkernel/BKE_object.h b/source/blender/blenkernel/BKE_object.h index 60dfc0af25f..5cbd7937f3f 100644 --- a/source/blender/blenkernel/BKE_object.h +++ b/source/blender/blenkernel/BKE_object.h @@ -323,7 +323,7 @@ struct Base **BKE_object_pose_base_array_get(const struct Scene *scene, void BKE_object_get_parent_matrix(struct Object *ob, struct Object *par, float r_parentmat[4][4]); /** - * Compute object world transform and store it in `ob->obmat`. + * Compute object world transform and store it in `ob->object_to_world`. */ void BKE_object_where_is_calc(struct Depsgraph *depsgraph, struct Scene *scene, struct Object *ob); void BKE_object_where_is_calc_ex(struct Depsgraph *depsgraph, diff --git a/source/blender/blenkernel/BKE_paint.h b/source/blender/blenkernel/BKE_paint.h index 5312292d431..9fc4aa5307d 100644 --- a/source/blender/blenkernel/BKE_paint.h +++ b/source/blender/blenkernel/BKE_paint.h @@ -860,7 +860,19 @@ int *BKE_sculpt_face_sets_ensure(struct Mesh *mesh); * (see #SCULPT_visibility_sync_all_from_faces). */ bool *BKE_sculpt_hide_poly_ensure(struct Mesh *mesh); -int BKE_sculpt_mask_layers_ensure(struct Object *ob, struct MultiresModifierData *mmd); + +/** + * Ensures a mask layer exists. If depsgraph and bmain are non-null, + * a mask doesn't exist and the object has a multi-resolution modifier + * then the scene depsgraph will be evaluated to update the runtime + * subdivision data. + * + * \note always call *before* #BKE_sculpt_update_object_for_edit. + */ +int BKE_sculpt_mask_layers_ensure(struct Depsgraph *depsgraph, + struct Main *bmain, + struct Object *ob, + struct MultiresModifierData *mmd); void BKE_sculpt_toolsettings_data_ensure(struct Scene *scene); struct PBVH *BKE_sculpt_object_pbvh_ensure(struct Depsgraph *depsgraph, struct Object *ob); @@ -874,7 +886,7 @@ void BKE_sculpt_sync_face_visibility_to_grids(struct Mesh *mesh, struct SubdivCC * Test if PBVH can be used directly for drawing, which is faster than * drawing the mesh and all updates that come with it. */ -bool BKE_sculptsession_use_pbvh_draw(const struct Object *ob, const struct View3D *v3d); +bool BKE_sculptsession_use_pbvh_draw(const struct Object *ob, const struct RegionView3D *rv3d); enum { SCULPT_MASK_LAYER_CALC_VERT = (1 << 0), diff --git a/source/blender/blenkernel/BKE_pbvh.h b/source/blender/blenkernel/BKE_pbvh.h index 89743f1d2b4..b375d69b61c 100644 --- a/source/blender/blenkernel/BKE_pbvh.h +++ b/source/blender/blenkernel/BKE_pbvh.h @@ -267,7 +267,8 @@ void BKE_pbvh_build_grids(PBVH *pbvh, void **gridfaces, struct DMFlagMat *flagmats, unsigned int **grid_hidden, - struct Mesh *me); + struct Mesh *me, + struct SubdivCCG *subdiv_ccg); /** * Build a PBVH from a BMesh. */ @@ -504,7 +505,8 @@ void BKE_pbvh_grids_update(PBVH *pbvh, struct CCGElem **grids, void **gridfaces, struct DMFlagMat *flagmats, - unsigned int **grid_hidden); + unsigned int **grid_hidden, + struct CCGKey *key); void BKE_pbvh_subdiv_cgg_set(PBVH *pbvh, struct SubdivCCG *subdiv_ccg); void BKE_pbvh_face_sets_set(PBVH *pbvh, int *face_sets); diff --git a/source/blender/blenkernel/BKE_pointcache.h b/source/blender/blenkernel/BKE_pointcache.h index efb8c2a9bb1..4331a25c112 100644 --- a/source/blender/blenkernel/BKE_pointcache.h +++ b/source/blender/blenkernel/BKE_pointcache.h @@ -293,6 +293,7 @@ void BKE_ptcache_ids_from_object(struct ListBase *lb, bool BKE_ptcache_object_has(struct Scene *scene, struct Object *ob, int duplis); /************ ID specific functions ************************/ + void BKE_ptcache_id_clear(PTCacheID *id, int mode, unsigned int cfra); bool BKE_ptcache_id_exist(PTCacheID *id, int cfra); int BKE_ptcache_id_reset(struct Scene *scene, PTCacheID *id, int mode); diff --git a/source/blender/blenkernel/BKE_screen.h b/source/blender/blenkernel/BKE_screen.h index 9a7d2bde810..a86953f35cc 100644 --- a/source/blender/blenkernel/BKE_screen.h +++ b/source/blender/blenkernel/BKE_screen.h @@ -385,6 +385,7 @@ typedef struct MenuType { bool (*poll)(const struct bContext *C, struct MenuType *mt); /* draw entirely, view changes should be handled here */ void (*draw)(const struct bContext *C, struct Menu *menu); + void (*listener)(const wmRegionListenerParams *params); /* RNA integration */ ExtensionRNA rna_ext; diff --git a/source/blender/blenkernel/BKE_undo_system.h b/source/blender/blenkernel/BKE_undo_system.h index f3a929dc5b9..5d1a27f8ba0 100644 --- a/source/blender/blenkernel/BKE_undo_system.h +++ b/source/blender/blenkernel/BKE_undo_system.h @@ -75,7 +75,7 @@ typedef struct UndoStep { /** Some situations require the global state to be stored, edge cases when exiting modes. */ bool use_memfile_step; /** When this is true, undo/memfile read code is allowed to re-use old data-blocks for unchanged - * IDs, and existing depsgraphes. This has to be forbidden in some cases (like renamed IDs). */ + * IDs, and existing depsgraphs. This has to be forbidden in some cases (like renamed IDs). */ bool use_old_bmain_data; /** For use by undo systems that accumulate changes (mesh-sculpt & image-painting). */ bool is_applied; diff --git a/source/blender/blenkernel/BKE_writeffmpeg.h b/source/blender/blenkernel/BKE_writeffmpeg.h index 736f7548bb4..cfe246eb470 100644 --- a/source/blender/blenkernel/BKE_writeffmpeg.h +++ b/source/blender/blenkernel/BKE_writeffmpeg.h @@ -27,6 +27,7 @@ enum { FFMPEG_OGG = 10, FFMPEG_INVALID = 11, FFMPEG_WEBM = 12, + FFMPEG_AV1 = 13, }; enum { @@ -38,6 +39,7 @@ enum { FFMPEG_PRESET_H264 = 5, FFMPEG_PRESET_THEORA = 6, FFMPEG_PRESET_XVID = 7, + FFMPEG_PRESET_AV1 = 8, }; struct RenderData; diff --git a/source/blender/blenkernel/CMakeLists.txt b/source/blender/blenkernel/CMakeLists.txt index 97bdff217d0..7d43fa7e6af 100644 --- a/source/blender/blenkernel/CMakeLists.txt +++ b/source/blender/blenkernel/CMakeLists.txt @@ -163,6 +163,7 @@ set(SRC intern/image_gpu.cc intern/image_partial_update.cc intern/image_save.cc + intern/instances.cc intern/ipo.c intern/kelvinlet.c intern/key.c @@ -398,6 +399,7 @@ set(SRC BKE_image_partial_update.hh BKE_image_save.h BKE_image_wrappers.hh + BKE_instances.hh BKE_ipo.h BKE_kelvinlet.h BKE_key.h diff --git a/source/blender/blenkernel/intern/action.c b/source/blender/blenkernel/intern/action.c index 10aa4ec7906..8f6bd812d8e 100644 --- a/source/blender/blenkernel/intern/action.c +++ b/source/blender/blenkernel/intern/action.c @@ -1738,7 +1738,7 @@ void what_does_obaction(Object *ob, BKE_object_workob_clear(workob); /* init workob */ - copy_m4_m4(workob->obmat, ob->obmat); + copy_m4_m4(workob->object_to_world, ob->object_to_world); copy_m4_m4(workob->parentinv, ob->parentinv); copy_m4_m4(workob->constinv, ob->constinv); workob->parent = ob->parent; diff --git a/source/blender/blenkernel/intern/appdir.c b/source/blender/blenkernel/intern/appdir.c index b2f1e75cd1d..b3990b2b7fc 100644 --- a/source/blender/blenkernel/intern/appdir.c +++ b/source/blender/blenkernel/intern/appdir.c @@ -191,7 +191,7 @@ bool BKE_appdir_folder_documents(char *dir) char try_documents_path[FILE_MAXDIR]; /* Own attempt at getting a valid Documents path. */ - BLI_path_join(try_documents_path, sizeof(try_documents_path), home_path, N_("Documents"), NULL); + BLI_path_join(try_documents_path, sizeof(try_documents_path), home_path, N_("Documents")); if (!BLI_is_dir(try_documents_path)) { return false; } @@ -214,11 +214,11 @@ bool BKE_appdir_folder_caches(char *r_path, const size_t path_len) #ifdef WIN32 BLI_path_join( - r_path, path_len, caches_root_path, "Blender Foundation", "Blender", "Cache", SEP_STR, NULL); + r_path, path_len, caches_root_path, "Blender Foundation", "Blender", "Cache", SEP_STR); #elif defined(__APPLE__) - BLI_path_join(r_path, path_len, caches_root_path, "Blender", SEP_STR, NULL); + BLI_path_join(r_path, path_len, caches_root_path, "Blender", SEP_STR); #else /* __linux__ */ - BLI_path_join(r_path, path_len, caches_root_path, "blender", SEP_STR, NULL); + BLI_path_join(r_path, path_len, caches_root_path, "blender", SEP_STR); #endif return true; @@ -237,7 +237,7 @@ bool BKE_appdir_font_folder_default(char *dir) } #elif defined(__APPLE__) STRNCPY(test_dir, BLI_expand_tilde("~/Library/Fonts/")); - BLI_path_slash_ensure(test_dir); + BLI_path_slash_ensure(test_dir, sizeof(test_dir)); #else STRNCPY(test_dir, "/usr/share/fonts"); #endif @@ -281,7 +281,9 @@ static bool test_path(char *targetpath, /* Only the last argument should be NULL. */ BLI_assert(!(folder_name == NULL && (subfolder_name != NULL))); - BLI_path_join(targetpath, targetpath_len, path_base, folder_name, subfolder_name, NULL); + const char *path_array[] = {path_base, folder_name, subfolder_name}; + const int path_array_num = (folder_name ? (subfolder_name ? 3 : 2) : 1); + BLI_path_join_array(targetpath, targetpath_len, path_array, path_array_num); if (check_is_dir == false) { CLOG_INFO(&LOG, 3, "using without test: '%s'", targetpath); return true; @@ -365,7 +367,9 @@ static bool get_path_local_ex(char *targetpath, STR_OR_FALLBACK(subfolder_name)); if (folder_name) { /* `subfolder_name` may be NULL. */ - BLI_path_join(relfolder, sizeof(relfolder), folder_name, subfolder_name, NULL); + const char *path_array[] = {folder_name, subfolder_name}; + const int path_array_num = subfolder_name ? 2 : 1; + BLI_path_join_array(relfolder, sizeof(relfolder), path_array, path_array_num); } else { relfolder[0] = '\0'; @@ -379,8 +383,7 @@ static bool get_path_local_ex(char *targetpath, * we must move the blender_version dir with contents to Resources. * Add 4 + 9 for the temporary `/../` path & `Resources`. */ char osx_resourses[FILE_MAX + 4 + 9]; - BLI_path_join( - osx_resourses, sizeof(osx_resourses), g_app.program_dirname, "..", "Resources", NULL); + BLI_path_join(osx_resourses, sizeof(osx_resourses), g_app.program_dirname, "..", "Resources"); /* Remove the '/../' added above. */ BLI_path_normalize(NULL, osx_resourses); path_base = osx_resourses; @@ -525,7 +528,9 @@ static bool get_path_system_ex(char *targetpath, char relfolder[FILE_MAX]; if (folder_name) { /* `subfolder_name` may be NULL. */ - BLI_path_join(relfolder, sizeof(relfolder), folder_name, subfolder_name, NULL); + const char *path_array[] = {folder_name, subfolder_name}; + const int path_array_num = subfolder_name ? 2 : 1; + BLI_path_join_array(relfolder, sizeof(relfolder), path_array, path_array_num); } else { relfolder[0] = '\0'; @@ -949,7 +954,7 @@ bool BKE_appdir_program_python_search(char *fullpath, if (python_bin_dir) { for (int i = 0; i < ARRAY_SIZE(python_names); i++) { - BLI_join_dirfile(fullpath, fullpath_len, python_bin_dir, python_names[i]); + BLI_path_join(fullpath, fullpath_len, python_bin_dir, python_names[i]); if ( #ifdef _WIN32 @@ -1018,7 +1023,7 @@ bool BKE_appdir_app_template_id_search(const char *app_template, char *path, siz { for (int i = 0; i < ARRAY_SIZE(app_template_directory_id); i++) { char subdir[FILE_MAX]; - BLI_join_dirfile(subdir, sizeof(subdir), app_template_directory_search[i], app_template); + BLI_path_join(subdir, sizeof(subdir), app_template_directory_search[i], app_template); if (BKE_appdir_folder_id_ex(app_template_directory_id[i], subdir, path, path_len)) { return true; } @@ -1041,8 +1046,7 @@ bool BKE_appdir_app_template_has_userpref(const char *app_template) } char userpref_path[FILE_MAX]; - BLI_path_join( - userpref_path, sizeof(userpref_path), app_template_path, BLENDER_USERPREF_FILE, NULL); + BLI_path_join(userpref_path, sizeof(userpref_path), app_template_path, BLENDER_USERPREF_FILE); return BLI_exists(userpref_path); } @@ -1089,13 +1093,13 @@ void BKE_appdir_app_templates(ListBase *templates) * \param userdir: Directory specified in user preferences (may be NULL). * note that by default this is an empty string, only use when non-empty. */ -static void where_is_temp(char *tempdir, const size_t tempdir_len, const char *userdir) +static void where_is_temp(char *tempdir, const size_t tempdir_maxlen, const char *userdir) { tempdir[0] = '\0'; if (userdir && BLI_is_dir(userdir)) { - BLI_strncpy(tempdir, userdir, tempdir_len); + BLI_strncpy(tempdir, userdir, tempdir_maxlen); } if (tempdir[0] == '\0') { @@ -1112,23 +1116,23 @@ static void where_is_temp(char *tempdir, const size_t tempdir_len, const char *u for (int i = 0; i < ARRAY_SIZE(env_vars); i++) { const char *tmp = BLI_getenv(env_vars[i]); if (tmp && (tmp[0] != '\0') && BLI_is_dir(tmp)) { - BLI_strncpy(tempdir, tmp, tempdir_len); + BLI_strncpy(tempdir, tmp, tempdir_maxlen); break; } } } if (tempdir[0] == '\0') { - BLI_strncpy(tempdir, "/tmp/", tempdir_len); + BLI_strncpy(tempdir, "/tmp/", tempdir_maxlen); } else { /* add a trailing slash if needed */ - BLI_path_slash_ensure(tempdir); + BLI_path_slash_ensure(tempdir, tempdir_maxlen); } } static void tempdir_session_create(char *tempdir_session, - const size_t tempdir_session_len, + const size_t tempdir_session_maxlen, const char *tempdir) { tempdir_session[0] = '\0'; @@ -1142,9 +1146,9 @@ static void tempdir_session_create(char *tempdir_session, * #_mktemp_s also requires the last null character is included. */ const int tempdir_session_len_required = tempdir_len + session_name_len + 1; - if (tempdir_session_len_required <= tempdir_session_len) { + if (tempdir_session_len_required <= tempdir_session_maxlen) { /* No need to use path joining utility as we know the last character of #tempdir is a slash. */ - BLI_string_join(tempdir_session, tempdir_session_len, tempdir, session_name); + BLI_string_join(tempdir_session, tempdir_session_maxlen, tempdir, session_name); #ifdef WIN32 const bool needs_create = (_mktemp_s(tempdir_session, tempdir_session_len_required) == 0); #else @@ -1154,7 +1158,7 @@ static void tempdir_session_create(char *tempdir_session, BLI_dir_create_recursive(tempdir_session); } if (BLI_is_dir(tempdir_session)) { - BLI_path_slash_ensure(tempdir_session); + BLI_path_slash_ensure(tempdir_session, tempdir_session_maxlen); /* Success. */ return; } @@ -1164,7 +1168,7 @@ static void tempdir_session_create(char *tempdir_session, "Could not generate a temp file name for '%s', falling back to '%s'", tempdir_session, tempdir); - BLI_strncpy(tempdir_session, tempdir, tempdir_session_len); + BLI_strncpy(tempdir_session, tempdir, tempdir_session_maxlen); } void BKE_tempdir_init(const char *userdir) diff --git a/source/blender/blenkernel/intern/armature.c b/source/blender/blenkernel/intern/armature.c index 2e73cac99b5..0f8bf0e9928 100644 --- a/source/blender/blenkernel/intern/armature.c +++ b/source/blender/blenkernel/intern/armature.c @@ -1596,7 +1596,7 @@ void BKE_armature_mat_world_to_pose(Object *ob, const float inmat[4][4], float o } /* Get inverse of (armature) object's matrix. */ - invert_m4_m4(obmat, ob->obmat); + invert_m4_m4(obmat, ob->object_to_world); /* multiply given matrix by object's-inverse to find pose-space matrix */ mul_m4_m4m4(outmat, inmat, obmat); @@ -2569,7 +2569,7 @@ void BKE_pose_where_is(struct Depsgraph *depsgraph, Scene *scene, Object *ob) } } else { - invert_m4_m4(ob->imat, ob->obmat); /* imat is needed */ + invert_m4_m4(ob->imat, ob->object_to_world); /* imat is needed */ /* 1. clear flags */ for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) { @@ -2696,14 +2696,14 @@ void BKE_pchan_minmax(const Object *ob, pchan->custom_translation[0], pchan->custom_translation[1], pchan->custom_translation[2]); - mul_m4_series(mat, ob->obmat, tmp, rmat, smat); + mul_m4_series(mat, ob->object_to_world, tmp, rmat, smat); BKE_boundbox_minmax(bb_custom, mat, r_min, r_max); } else { float vec[3]; - mul_v3_m4v3(vec, ob->obmat, pchan_tx->pose_head); + mul_v3_m4v3(vec, ob->object_to_world, pchan_tx->pose_head); minmax_v3v3_v3(r_min, r_max, vec); - mul_v3_m4v3(vec, ob->obmat, pchan_tx->pose_tail); + mul_v3_m4v3(vec, ob->object_to_world, pchan_tx->pose_tail); minmax_v3v3_v3(r_min, r_max, vec); } } diff --git a/source/blender/blenkernel/intern/armature_deform.c b/source/blender/blenkernel/intern/armature_deform.c index 89afb886fc2..64a3937c191 100644 --- a/source/blender/blenkernel/intern/armature_deform.c +++ b/source/blender/blenkernel/intern/armature_deform.c @@ -582,9 +582,9 @@ static void armature_deform_coords_impl(const Object *ob_arm, }; float obinv[4][4]; - invert_m4_m4(obinv, ob_target->obmat); + invert_m4_m4(obinv, ob_target->object_to_world); - mul_m4_m4m4(data.postmat, obinv, ob_arm->obmat); + mul_m4_m4m4(data.postmat, obinv, ob_arm->object_to_world); invert_m4_m4(data.premat, data.postmat); if (em_target != NULL) { diff --git a/source/blender/blenkernel/intern/armature_update.c b/source/blender/blenkernel/intern/armature_update.c index 6d7aed239e7..b9f46118c0d 100644 --- a/source/blender/blenkernel/intern/armature_update.c +++ b/source/blender/blenkernel/intern/armature_update.c @@ -249,7 +249,7 @@ static void apply_curve_transform( * unless the option to allow curve to be positioned elsewhere is activated (i.e. no root). */ if ((ik_data->flag & CONSTRAINT_SPLINEIK_NO_ROOT) == 0) { - mul_m4_v3(ik_data->tar->obmat, r_vec); + mul_m4_v3(ik_data->tar->object_to_world, r_vec); } /* Convert the position to pose-space. */ @@ -819,7 +819,7 @@ void BKE_pose_eval_init(struct Depsgraph *depsgraph, Scene *UNUSED(scene), Objec BLI_assert((object->pose->flag & POSE_RECALC) == 0); /* imat is needed for solvers. */ - invert_m4_m4(object->imat, object->obmat); + invert_m4_m4(object->imat, object->object_to_world); /* clear flags */ for (bPoseChannel *pchan = pose->chanbase.first; pchan != NULL; pchan = pchan->next) { diff --git a/source/blender/blenkernel/intern/asset_catalog.cc b/source/blender/blenkernel/intern/asset_catalog.cc index f7b14cc3479..62d03b2d79b 100644 --- a/source/blender/blenkernel/intern/asset_catalog.cc +++ b/source/blender/blenkernel/intern/asset_catalog.cc @@ -9,6 +9,7 @@ #include "BKE_asset_catalog.hh" #include "BKE_asset_library.h" +#include "BKE_asset_library.hh" #include "BLI_fileops.hh" #include "BLI_path_util.h" @@ -284,10 +285,10 @@ AssetCatalog *AssetCatalogService::create_catalog(const AssetCatalogPath &catalo static std::string asset_definition_default_file_path_from_dir(StringRef asset_library_root) { char file_path[PATH_MAX]; - BLI_join_dirfile(file_path, - sizeof(file_path), - asset_library_root.data(), - AssetCatalogService::DEFAULT_CATALOG_FILENAME.data()); + BLI_path_join(file_path, + sizeof(file_path), + asset_library_root.data(), + AssetCatalogService::DEFAULT_CATALOG_FILENAME.data()); return file_path; } @@ -515,8 +516,7 @@ CatalogFilePath AssetCatalogService::find_suitable_cdf_path_for_writing( BLI_path_join(asset_lib_cdf_path, sizeof(asset_lib_cdf_path), suitable_root_path, - DEFAULT_CATALOG_FILENAME.c_str(), - nullptr); + DEFAULT_CATALOG_FILENAME.c_str()); return asset_lib_cdf_path; } @@ -788,6 +788,41 @@ void AssetCatalogTree::foreach_root_item(const ItemIterFn callback) } } +bool AssetCatalogTree::is_empty() const +{ + return root_items_.empty(); +} + +AssetCatalogTreeItem *AssetCatalogTree::find_item(const AssetCatalogPath &path) +{ + AssetCatalogTreeItem *result = nullptr; + this->foreach_item([&](AssetCatalogTreeItem &item) { + if (result) { + /* There is no way to stop iteration. */ + return; + } + if (item.catalog_path() == path) { + result = &item; + } + }); + return result; +} + +AssetCatalogTreeItem *AssetCatalogTree::find_root_item(const AssetCatalogPath &path) +{ + AssetCatalogTreeItem *result = nullptr; + this->foreach_root_item([&](AssetCatalogTreeItem &item) { + if (result) { + /* There is no way to stop iteration. */ + return; + } + if (item.catalog_path() == path) { + result = &item; + } + }); + return result; +} + /* ---------------------------------------------------------------------- */ /* ---------------------------------------------------------------------- */ diff --git a/source/blender/blenkernel/intern/asset_catalog_path.cc b/source/blender/blenkernel/intern/asset_catalog_path.cc index 669adb7adf4..9c653c1a137 100644 --- a/source/blender/blenkernel/intern/asset_catalog_path.cc +++ b/source/blender/blenkernel/intern/asset_catalog_path.cc @@ -12,7 +12,7 @@ namespace blender::bke { const char AssetCatalogPath::SEPARATOR = '/'; -AssetCatalogPath::AssetCatalogPath(const std::string &path) : path_(path) +AssetCatalogPath::AssetCatalogPath(std::string path) : path_(std::move(path)) { } diff --git a/source/blender/blenkernel/intern/asset_catalog_test.cc b/source/blender/blenkernel/intern/asset_catalog_test.cc index 81eb1786322..ee2dd652b61 100644 --- a/source/blender/blenkernel/intern/asset_catalog_test.cc +++ b/source/blender/blenkernel/intern/asset_catalog_test.cc @@ -98,7 +98,7 @@ class AssetCatalogTest : public testing::Test { FAIL(); } - asset_library_root_ = test_files_dir + "/" + "asset_library"; + asset_library_root_ = test_files_dir + SEP_STR + "asset_library"; temp_library_path_ = ""; } @@ -116,7 +116,7 @@ class AssetCatalogTest : public testing::Test { { BKE_tempdir_init(""); const CatalogFilePath tempdir = BKE_tempdir_session(); - temp_library_path_ = tempdir + "test-temporary-path/"; + temp_library_path_ = tempdir + "test-temporary-path" + SEP_STR; return temp_library_path_; } @@ -202,9 +202,10 @@ class AssetCatalogTest : public testing::Test { void save_from_memory_into_existing_asset_lib(const bool should_top_level_cdf_exist) { const CatalogFilePath target_dir = create_temp_path(); /* Has trailing slash. */ - const CatalogFilePath original_cdf_file = asset_library_root_ + "/blender_assets.cats.txt"; - const CatalogFilePath registered_asset_lib = target_dir + "my_asset_library/"; - const CatalogFilePath asset_lib_subdir = registered_asset_lib + "subdir/"; + const CatalogFilePath original_cdf_file = asset_library_root_ + SEP_STR + + "blender_assets.cats.txt"; + const CatalogFilePath registered_asset_lib = target_dir + "my_asset_library" + SEP_STR; + const CatalogFilePath asset_lib_subdir = registered_asset_lib + "subdir" + SEP_STR; CatalogFilePath cdf_toplevel = registered_asset_lib + AssetCatalogService::DEFAULT_CATALOG_FILENAME; CatalogFilePath cdf_in_subdir = asset_lib_subdir + @@ -272,7 +273,7 @@ class AssetCatalogTest : public testing::Test { TEST_F(AssetCatalogTest, load_single_file) { AssetCatalogService service(asset_library_root_); - service.load_from_disk(asset_library_root_ + "/" + "blender_assets.cats.txt"); + service.load_from_disk(asset_library_root_ + SEP_STR + "blender_assets.cats.txt"); /* Test getting a non-existent catalog ID. */ EXPECT_EQ(nullptr, service.find_catalog(BLI_uuid_generate_random())); @@ -313,7 +314,7 @@ TEST_F(AssetCatalogTest, load_single_file) TEST_F(AssetCatalogTest, load_catalog_path_backslashes) { AssetCatalogService service(asset_library_root_); - service.load_from_disk(asset_library_root_ + "/" + "blender_assets.cats.txt"); + service.load_from_disk(asset_library_root_ + SEP_STR + "blender_assets.cats.txt"); const AssetCatalog *found_by_id = service.find_catalog(UUID_POSES_ELLIE_BACKSLASHES); ASSERT_NE(nullptr, found_by_id); @@ -332,7 +333,7 @@ TEST_F(AssetCatalogTest, load_catalog_path_backslashes) TEST_F(AssetCatalogTest, is_first_loaded_flag) { AssetCatalogService service(asset_library_root_); - service.load_from_disk(asset_library_root_ + "/" + "blender_assets.cats.txt"); + service.load_from_disk(asset_library_root_ + SEP_STR + "blender_assets.cats.txt"); AssetCatalog *new_cat = service.create_catalog("never/before/seen/path"); EXPECT_FALSE(new_cat->flags.is_first_loaded) @@ -435,7 +436,7 @@ TEST_F(AssetCatalogTest, insert_item_into_tree) TEST_F(AssetCatalogTest, load_single_file_into_tree) { AssetCatalogService service(asset_library_root_); - service.load_from_disk(asset_library_root_ + "/" + "blender_assets.cats.txt"); + service.load_from_disk(asset_library_root_ + SEP_STR + "blender_assets.cats.txt"); /* Contains not only paths from the CDF but also the missing parents (implicitly defined * catalogs). */ @@ -476,7 +477,7 @@ TEST_F(AssetCatalogTest, foreach_in_tree) } AssetCatalogService service(asset_library_root_); - service.load_from_disk(asset_library_root_ + "/" + "blender_assets.cats.txt"); + service.load_from_disk(asset_library_root_ + SEP_STR + "blender_assets.cats.txt"); std::vector<AssetCatalogPath> expected_root_items{{"character", "path"}}; AssetCatalogTree *tree = service.get_catalog_tree(); @@ -499,7 +500,7 @@ TEST_F(AssetCatalogTest, foreach_in_tree) TEST_F(AssetCatalogTest, find_catalog_by_path) { TestableAssetCatalogService service(asset_library_root_); - service.load_from_disk(asset_library_root_ + "/" + + service.load_from_disk(asset_library_root_ + SEP_STR + AssetCatalogService::DEFAULT_CATALOG_FILENAME); AssetCatalog *catalog; @@ -522,7 +523,7 @@ TEST_F(AssetCatalogTest, find_catalog_by_path) TEST_F(AssetCatalogTest, write_single_file) { TestableAssetCatalogService service(asset_library_root_); - service.load_from_disk(asset_library_root_ + "/" + + service.load_from_disk(asset_library_root_ + SEP_STR + AssetCatalogService::DEFAULT_CATALOG_FILENAME); const CatalogFilePath save_to_path = use_temp_path() + @@ -550,7 +551,7 @@ TEST_F(AssetCatalogTest, write_single_file) TEST_F(AssetCatalogTest, read_write_unicode_filepath) { TestableAssetCatalogService service(asset_library_root_); - const CatalogFilePath load_from_path = asset_library_root_ + "/новый/" + + const CatalogFilePath load_from_path = asset_library_root_ + SEP_STR + "новый" + SEP_STR + AssetCatalogService::DEFAULT_CATALOG_FILENAME; service.load_from_disk(load_from_path); @@ -588,8 +589,9 @@ TEST_F(AssetCatalogTest, on_blendfile_save__with_existing_cdf) const CatalogFilePath top_level_dir = create_temp_path(); /* Has trailing slash. */ /* Create a copy of the CDF in SVN, so we can safely write to it. */ - const CatalogFilePath original_cdf_file = asset_library_root_ + "/blender_assets.cats.txt"; - const CatalogFilePath cdf_dirname = top_level_dir + "other_dir/"; + const CatalogFilePath original_cdf_file = asset_library_root_ + SEP_STR + + "blender_assets.cats.txt"; + const CatalogFilePath cdf_dirname = top_level_dir + "other_dir" + SEP_STR; const CatalogFilePath cdf_filename = cdf_dirname + AssetCatalogService::DEFAULT_CATALOG_FILENAME; ASSERT_TRUE(BLI_dir_create_recursive(cdf_dirname.c_str())); ASSERT_EQ(0, BLI_copy(original_cdf_file.c_str(), cdf_filename.c_str())) @@ -600,7 +602,7 @@ TEST_F(AssetCatalogTest, on_blendfile_save__with_existing_cdf) service.load_from_disk(); const AssetCatalog *cat = service.create_catalog("some/catalog/path"); - const CatalogFilePath blendfilename = top_level_dir + "subdir/some_file.blend"; + const CatalogFilePath blendfilename = top_level_dir + "subdir" + SEP_STR + "some_file.blend"; ASSERT_TRUE(service.write_to_disk(blendfilename)); EXPECT_EQ(cdf_filename, service.get_catalog_definition_file()->file_path); @@ -650,7 +652,8 @@ TEST_F(AssetCatalogTest, on_blendfile_save__from_memory_into_empty_directory) TEST_F(AssetCatalogTest, on_blendfile_save__from_memory_into_existing_cdf_and_merge) { const CatalogFilePath target_dir = create_temp_path(); /* Has trailing slash. */ - const CatalogFilePath original_cdf_file = asset_library_root_ + "/blender_assets.cats.txt"; + const CatalogFilePath original_cdf_file = asset_library_root_ + SEP_STR + + "blender_assets.cats.txt"; CatalogFilePath writable_cdf_file = target_dir + AssetCatalogService::DEFAULT_CATALOG_FILENAME; BLI_path_slash_native(writable_cdf_file.data()); ASSERT_EQ(0, BLI_copy(original_cdf_file.c_str(), writable_cdf_file.c_str())); @@ -719,7 +722,7 @@ TEST_F(AssetCatalogTest, create_first_catalog_from_scratch) service.write_to_disk(temp_lib_root + "phony.blend"); EXPECT_TRUE(BLI_is_dir(temp_lib_root.c_str())); - const CatalogFilePath definition_file_path = temp_lib_root + "/" + + const CatalogFilePath definition_file_path = temp_lib_root + SEP_STR + AssetCatalogService::DEFAULT_CATALOG_FILENAME; EXPECT_TRUE(BLI_is_file(definition_file_path.c_str())); @@ -739,7 +742,7 @@ TEST_F(AssetCatalogTest, create_catalog_after_loading_file) /* Copy the asset catalog definition files to a separate location, so that we can test without * overwriting the test file in SVN. */ - const CatalogFilePath default_catalog_path = asset_library_root_ + "/" + + const CatalogFilePath default_catalog_path = asset_library_root_ + SEP_STR + AssetCatalogService::DEFAULT_CATALOG_FILENAME; const CatalogFilePath writable_catalog_path = temp_lib_root + AssetCatalogService::DEFAULT_CATALOG_FILENAME; @@ -801,7 +804,7 @@ TEST_F(AssetCatalogTest, create_catalog_simple_name) TEST_F(AssetCatalogTest, delete_catalog_leaf) { AssetCatalogService service(asset_library_root_); - service.load_from_disk(asset_library_root_ + "/" + "blender_assets.cats.txt"); + service.load_from_disk(asset_library_root_ + SEP_STR + "blender_assets.cats.txt"); /* Delete a leaf catalog, i.e. one that is not a parent of another catalog. * This keeps this particular test easy. */ @@ -833,7 +836,7 @@ TEST_F(AssetCatalogTest, delete_catalog_leaf) TEST_F(AssetCatalogTest, delete_catalog_parent_by_id) { TestableAssetCatalogService service(asset_library_root_); - service.load_from_disk(asset_library_root_ + "/" + "blender_assets.cats.txt"); + service.load_from_disk(asset_library_root_ + SEP_STR + "blender_assets.cats.txt"); /* Delete a parent catalog. */ service.delete_catalog_by_id_soft(UUID_POSES_RUZENA); @@ -847,7 +850,7 @@ TEST_F(AssetCatalogTest, delete_catalog_parent_by_id) TEST_F(AssetCatalogTest, delete_catalog_parent_by_path) { AssetCatalogService service(asset_library_root_); - service.load_from_disk(asset_library_root_ + "/" + "blender_assets.cats.txt"); + service.load_from_disk(asset_library_root_ + SEP_STR + "blender_assets.cats.txt"); /* Create an extra catalog with the to-be-deleted path, and one with a child of that. * This creates some duplicates that are bound to occur in production asset libraries as well. @@ -887,14 +890,14 @@ TEST_F(AssetCatalogTest, delete_catalog_parent_by_path) TEST_F(AssetCatalogTest, delete_catalog_write_to_disk) { TestableAssetCatalogService service(asset_library_root_); - service.load_from_disk(asset_library_root_ + "/" + + service.load_from_disk(asset_library_root_ + SEP_STR + AssetCatalogService::DEFAULT_CATALOG_FILENAME); service.delete_catalog_by_id_soft(UUID_POSES_ELLIE); const CatalogFilePath save_to_path = use_temp_path(); AssetCatalogDefinitionFile *cdf = service.get_catalog_definition_file(); - cdf->write_to_disk(save_to_path + "/" + AssetCatalogService::DEFAULT_CATALOG_FILENAME); + cdf->write_to_disk(save_to_path + SEP_STR + AssetCatalogService::DEFAULT_CATALOG_FILENAME); AssetCatalogService loaded_service(save_to_path); loaded_service.load_from_disk(); @@ -911,7 +914,7 @@ TEST_F(AssetCatalogTest, delete_catalog_write_to_disk) TEST_F(AssetCatalogTest, update_catalog_path) { AssetCatalogService service(asset_library_root_); - service.load_from_disk(asset_library_root_ + "/" + + service.load_from_disk(asset_library_root_ + SEP_STR + AssetCatalogService::DEFAULT_CATALOG_FILENAME); const AssetCatalog *orig_cat = service.find_catalog(UUID_POSES_RUZENA); @@ -940,7 +943,7 @@ TEST_F(AssetCatalogTest, update_catalog_path) TEST_F(AssetCatalogTest, update_catalog_path_simple_name) { AssetCatalogService service(asset_library_root_); - service.load_from_disk(asset_library_root_ + "/" + + service.load_from_disk(asset_library_root_ + SEP_STR + AssetCatalogService::DEFAULT_CATALOG_FILENAME); service.update_catalog_path(UUID_POSES_RUZENA, "charlib/Ružena"); @@ -956,7 +959,7 @@ TEST_F(AssetCatalogTest, update_catalog_path_simple_name) TEST_F(AssetCatalogTest, update_catalog_path_longer_than_simplename) { AssetCatalogService service(asset_library_root_); - service.load_from_disk(asset_library_root_ + "/" + + service.load_from_disk(asset_library_root_ + SEP_STR + AssetCatalogService::DEFAULT_CATALOG_FILENAME); const std::string new_path = "this/is/a/very/long/path/that/exceeds/the/simple-name/length/of/assets"; @@ -978,7 +981,7 @@ TEST_F(AssetCatalogTest, update_catalog_path_longer_than_simplename) TEST_F(AssetCatalogTest, update_catalog_path_add_slashes) { AssetCatalogService service(asset_library_root_); - service.load_from_disk(asset_library_root_ + "/" + + service.load_from_disk(asset_library_root_ + SEP_STR + AssetCatalogService::DEFAULT_CATALOG_FILENAME); const AssetCatalog *orig_cat = service.find_catalog(UUID_POSES_RUZENA); @@ -1019,8 +1022,10 @@ TEST_F(AssetCatalogTest, update_catalog_path_add_slashes) TEST_F(AssetCatalogTest, merge_catalog_files) { const CatalogFilePath cdf_dir = create_temp_path(); - const CatalogFilePath original_cdf_file = asset_library_root_ + "/blender_assets.cats.txt"; - const CatalogFilePath modified_cdf_file = asset_library_root_ + "/modified_assets.cats.txt"; + const CatalogFilePath original_cdf_file = asset_library_root_ + SEP_STR + + "blender_assets.cats.txt"; + const CatalogFilePath modified_cdf_file = asset_library_root_ + SEP_STR + + "modified_assets.cats.txt"; const CatalogFilePath temp_cdf_file = cdf_dir + "blender_assets.cats.txt"; ASSERT_EQ(0, BLI_copy(original_cdf_file.c_str(), temp_cdf_file.c_str())); @@ -1059,8 +1064,10 @@ TEST_F(AssetCatalogTest, merge_catalog_files) TEST_F(AssetCatalogTest, refresh_catalogs_with_modification) { const CatalogFilePath cdf_dir = create_temp_path(); - const CatalogFilePath original_cdf_file = asset_library_root_ + "/blender_assets.cats.txt"; - const CatalogFilePath modified_cdf_file = asset_library_root_ + "/catalog_reload_test.cats.txt"; + const CatalogFilePath original_cdf_file = asset_library_root_ + SEP_STR + + "blender_assets.cats.txt"; + const CatalogFilePath modified_cdf_file = asset_library_root_ + SEP_STR + + "catalog_reload_test.cats.txt"; const CatalogFilePath temp_cdf_file = cdf_dir + "blender_assets.cats.txt"; ASSERT_EQ(0, BLI_copy(original_cdf_file.c_str(), temp_cdf_file.c_str())); @@ -1131,8 +1138,9 @@ TEST_F(AssetCatalogTest, refresh_catalogs_with_modification) TEST_F(AssetCatalogTest, backups) { const CatalogFilePath cdf_dir = create_temp_path(); - const CatalogFilePath original_cdf_file = asset_library_root_ + "/blender_assets.cats.txt"; - const CatalogFilePath writable_cdf_file = cdf_dir + "/blender_assets.cats.txt"; + const CatalogFilePath original_cdf_file = asset_library_root_ + SEP_STR + + "blender_assets.cats.txt"; + const CatalogFilePath writable_cdf_file = cdf_dir + SEP_STR + "blender_assets.cats.txt"; ASSERT_EQ(0, BLI_copy(original_cdf_file.c_str(), writable_cdf_file.c_str())); /* Read a CDF, modify, and write it. */ diff --git a/source/blender/blenkernel/intern/asset_library.cc b/source/blender/blenkernel/intern/asset_library.cc index 968873cbcbe..b8420af1168 100644 --- a/source/blender/blenkernel/intern/asset_library.cc +++ b/source/blender/blenkernel/intern/asset_library.cc @@ -10,6 +10,7 @@ #include "BKE_main.h" #include "BKE_preferences.h" +#include "BLI_fileops.h" #include "BLI_path_util.h" #include "DNA_asset_types.h" @@ -19,6 +20,13 @@ bool blender::bke::AssetLibrary::save_catalogs_when_file_is_saved = true; +blender::bke::AssetLibrary *BKE_asset_library_load(const Main *bmain, + const AssetLibraryReference &library_reference) +{ + blender::bke::AssetLibraryService *service = blender::bke::AssetLibraryService::get(); + return service->get_asset_library(bmain, library_reference); +} + /** * Loading an asset library at this point only means loading the catalogs. Later on this should * invoke reading of asset representations too. @@ -172,4 +180,26 @@ void AssetLibrary::refresh_catalog_simplename(struct AssetMetaData *asset_data) } STRNCPY(asset_data->catalog_simple_name, catalog->simple_name.c_str()); } + +Vector<AssetLibraryReference> all_valid_asset_library_refs() +{ + Vector<AssetLibraryReference> result; + int i; + LISTBASE_FOREACH_INDEX (const bUserAssetLibrary *, asset_library, &U.asset_libraries, i) { + if (!BLI_is_dir(asset_library->path)) { + continue; + } + AssetLibraryReference library_ref{}; + library_ref.custom_library_index = i; + library_ref.type = ASSET_LIBRARY_CUSTOM; + result.append(library_ref); + } + + AssetLibraryReference library_ref{}; + library_ref.custom_library_index = -1; + library_ref.type = ASSET_LIBRARY_LOCAL; + result.append(library_ref); + return result; +} + } // namespace blender::bke diff --git a/source/blender/blenkernel/intern/asset_library_service.cc b/source/blender/blenkernel/intern/asset_library_service.cc index a6b2b7548a2..cd8de7908bf 100644 --- a/source/blender/blenkernel/intern/asset_library_service.cc +++ b/source/blender/blenkernel/intern/asset_library_service.cc @@ -7,11 +7,15 @@ #include "asset_library_service.hh" #include "BKE_blender.h" +#include "BKE_preferences.h" #include "BLI_fileops.h" /* For PATH_MAX (at least on Windows). */ #include "BLI_path_util.h" #include "BLI_string_ref.hh" +#include "DNA_asset_types.h" +#include "DNA_userdef_types.h" + #include "CLG_log.h" static CLG_LogRef LOG = {"bke.asset_service"}; @@ -38,13 +42,45 @@ void AssetLibraryService::destroy() instance_.reset(); } +AssetLibrary *AssetLibraryService::get_asset_library( + const Main *bmain, const AssetLibraryReference &library_reference) +{ + if (library_reference.type == ASSET_LIBRARY_LOCAL) { + /* For the "Current File" library we get the asset library root path based on main. */ + char root_path[FILE_MAX]; + if (bmain) { + BKE_asset_library_find_suitable_root_path_from_main(bmain, root_path); + } + else { + root_path[0] = '\0'; + } + + if (root_path[0] == '\0') { + /* File wasn't saved yet. */ + return get_asset_library_current_file(); + } + + return get_asset_library_on_disk(root_path); + } + if (library_reference.type == ASSET_LIBRARY_CUSTOM) { + bUserAssetLibrary *user_library = BKE_preferences_asset_library_find_from_index( + &U, library_reference.custom_library_index); + + if (user_library) { + return get_asset_library_on_disk(user_library->path); + } + } + + return nullptr; +} + namespace { std::string normalize_directory_path(StringRefNull directory) { char dir_normalized[PATH_MAX]; STRNCPY(dir_normalized, directory.c_str()); - BLI_path_normalize_dir(nullptr, dir_normalized); + BLI_path_normalize_dir(nullptr, dir_normalized, sizeof(dir_normalized)); return std::string(dir_normalized); } } // namespace diff --git a/source/blender/blenkernel/intern/asset_library_service.hh b/source/blender/blenkernel/intern/asset_library_service.hh index 277fb9db6cc..c22c6b182ce 100644 --- a/source/blender/blenkernel/intern/asset_library_service.hh +++ b/source/blender/blenkernel/intern/asset_library_service.hh @@ -44,6 +44,9 @@ class AssetLibraryService { /** Destroy the AssetLibraryService singleton. It will be reallocated by #get() if necessary. */ static void destroy(); + AssetLibrary *get_asset_library(const Main *bmain, + const AssetLibraryReference &library_reference); + /** * Get the given asset library. Opens it (i.e. creates a new AssetLibrary instance) if necessary. */ diff --git a/source/blender/blenkernel/intern/asset_library_service_test.cc b/source/blender/blenkernel/intern/asset_library_service_test.cc index de6180cb684..7952e7ea3b0 100644 --- a/source/blender/blenkernel/intern/asset_library_service_test.cc +++ b/source/blender/blenkernel/intern/asset_library_service_test.cc @@ -39,7 +39,7 @@ class AssetLibraryServiceTest : public testing::Test { if (test_files_dir.empty()) { FAIL(); } - asset_library_root_ = test_files_dir + "/" + "asset_library"; + asset_library_root_ = test_files_dir + SEP_STR + "asset_library"; temp_library_path_ = ""; } @@ -59,7 +59,7 @@ class AssetLibraryServiceTest : public testing::Test { { BKE_tempdir_init(""); const CatalogFilePath tempdir = BKE_tempdir_session(); - temp_library_path_ = tempdir + "test-temporary-path/"; + temp_library_path_ = tempdir + "test-temporary-path" + SEP_STR; return temp_library_path_; } @@ -118,7 +118,7 @@ TEST_F(AssetLibraryServiceTest, library_path_trailing_slashes) asset_lib_no_slash[strlen(asset_lib_no_slash) - 1] = '\0'; } - BLI_path_slash_ensure(asset_lib_with_slash); + BLI_path_slash_ensure(asset_lib_with_slash, PATH_MAX); AssetLibrary *const lib_no_slash = service->get_asset_library_on_disk(asset_lib_no_slash); @@ -168,7 +168,8 @@ TEST_F(AssetLibraryServiceTest, has_any_unsaved_catalogs) TEST_F(AssetLibraryServiceTest, has_any_unsaved_catalogs_after_write) { const CatalogFilePath writable_dir = create_temp_path(); /* Has trailing slash. */ - const CatalogFilePath original_cdf_file = asset_library_root_ + "/blender_assets.cats.txt"; + const CatalogFilePath original_cdf_file = asset_library_root_ + SEP_STR + + "blender_assets.cats.txt"; CatalogFilePath writable_cdf_file = writable_dir + AssetCatalogService::DEFAULT_CATALOG_FILENAME; BLI_path_slash_native(writable_cdf_file.data()); ASSERT_EQ(0, BLI_copy(original_cdf_file.c_str(), writable_cdf_file.c_str())); diff --git a/source/blender/blenkernel/intern/attribute_access.cc b/source/blender/blenkernel/intern/attribute_access.cc index b86353bdb74..544427cfdd3 100644 --- a/source/blender/blenkernel/intern/attribute_access.cc +++ b/source/blender/blenkernel/intern/attribute_access.cc @@ -642,15 +642,26 @@ CustomDataAttributes::CustomDataAttributes(CustomDataAttributes &&other) size_ = other.size_; data = other.data; CustomData_reset(&other.data); + other.size_ = 0; } CustomDataAttributes &CustomDataAttributes::operator=(const CustomDataAttributes &other) { - if (this != &other) { - CustomData_copy(&other.data, &data, CD_MASK_ALL, CD_DUPLICATE, other.size_); - size_ = other.size_; + if (this == &other) { + return *this; } + this->~CustomDataAttributes(); + new (this) CustomDataAttributes(other); + return *this; +} +CustomDataAttributes &CustomDataAttributes::operator=(CustomDataAttributes &&other) +{ + if (this == &other) { + return *this; + } + this->~CustomDataAttributes(); + new (this) CustomDataAttributes(std::move(other)); return *this; } diff --git a/source/blender/blenkernel/intern/blender.c b/source/blender/blenkernel/intern/blender.c index 23cf368af01..3598201d906 100644 --- a/source/blender/blenkernel/intern/blender.c +++ b/source/blender/blenkernel/intern/blender.c @@ -59,7 +59,7 @@ void BKE_blender_free(void) { /* samples are in a global list..., also sets G_MAIN->sound->sample NULL */ - /* Needs to run before main free as wm is still referenced for icons preview jobs. */ + /* Needs to run before main free as window-manager is still referenced for icons preview jobs. */ BKE_studiolight_free(); BKE_blender_globals_clear(); diff --git a/source/blender/blenkernel/intern/blender_undo.c b/source/blender/blenkernel/intern/blender_undo.c index a5096b4f9eb..f22dfc6054a 100644 --- a/source/blender/blenkernel/intern/blender_undo.c +++ b/source/blender/blenkernel/intern/blender_undo.c @@ -116,7 +116,7 @@ MemFileUndoData *BKE_memfile_undo_encode(Main *bmain, MemFileUndoData *mfu_prev) counter = counter % U.undosteps; BLI_snprintf(numstr, sizeof(numstr), "%d.blend", counter); - BLI_join_dirfile(filepath, sizeof(filepath), BKE_tempdir_session(), numstr); + BLI_path_join(filepath, sizeof(filepath), BKE_tempdir_session(), numstr); /* success = */ /* UNUSED */ BLO_write_file( bmain, filepath, fileflags, &(const struct BlendFileWriteParams){0}, NULL); diff --git a/source/blender/blenkernel/intern/blendfile.c b/source/blender/blenkernel/intern/blendfile.c index 6546659f6cd..8b0d3f2e92e 100644 --- a/source/blender/blenkernel/intern/blendfile.c +++ b/source/blender/blenkernel/intern/blendfile.c @@ -186,7 +186,7 @@ static void setup_app_data(bContext *C, clean_paths(bfd->main); } - /* XXX here the complex windowmanager matching */ + /* The following code blocks performs complex window-manager matching. */ /* no load screens? */ if (mode != LOAD_UI) { @@ -737,7 +737,7 @@ bool BKE_blendfile_userdef_write_all(ReportList *reports) if ((cfgdir = BKE_appdir_folder_id_create(BLENDER_USER_CONFIG, NULL))) { bool ok_write; - BLI_path_join(filepath, sizeof(filepath), cfgdir, BLENDER_USERPREF_FILE, NULL); + BLI_path_join(filepath, sizeof(filepath), cfgdir, BLENDER_USERPREF_FILE); printf("Writing userprefs: '%s' ", filepath); if (use_template_userpref) { @@ -764,7 +764,7 @@ bool BKE_blendfile_userdef_write_all(ReportList *reports) if (use_template_userpref) { if ((cfgdir = BKE_appdir_folder_id_create(BLENDER_USER_CONFIG, U.app_template))) { /* Also save app-template prefs */ - BLI_path_join(filepath, sizeof(filepath), cfgdir, BLENDER_USERPREF_FILE, NULL); + BLI_path_join(filepath, sizeof(filepath), cfgdir, BLENDER_USERPREF_FILE); printf("Writing userprefs app-template: '%s' ", filepath); if (BKE_blendfile_userdef_write(filepath, reports) != 0) { diff --git a/source/blender/blenkernel/intern/blendfile_link_append.c b/source/blender/blenkernel/intern/blendfile_link_append.c index 394469e19a4..4dd225c09ec 100644 --- a/source/blender/blenkernel/intern/blendfile_link_append.c +++ b/source/blender/blenkernel/intern/blendfile_link_append.c @@ -1494,6 +1494,7 @@ void BKE_blendfile_library_relocate(BlendfileLinkAppendContext *lapp_context, * code is wrong, we need to redo it here after adding them back to main. */ BKE_main_id_refcount_recompute(bmain, false); + BKE_layer_collection_resync_forbid(); /* Note that in reload case, we also want to replace indirect usages. */ const short remap_flags = ID_REMAP_SKIP_NEVER_NULL_USAGE | (do_reload ? 0 : ID_REMAP_SKIP_INDIRECT_USAGE); @@ -1523,6 +1524,8 @@ void BKE_blendfile_library_relocate(BlendfileLinkAppendContext *lapp_context, id_us_plus_no_lib(&old_key->id); } } + BKE_layer_collection_resync_allow(); + BKE_main_collection_sync_remap(bmain); BKE_main_unlock(bmain); @@ -1614,6 +1617,9 @@ void BKE_blendfile_library_relocate(BlendfileLinkAppendContext *lapp_context, (id->tag & LIB_TAG_PRE_EXISTING) == 0) { continue; } + if ((id->override_library->reference->tag & LIB_TAG_MISSING) == 0) { + id->tag &= ~LIB_TAG_MISSING; + } if ((id->override_library->reference->tag & LIB_TAG_PRE_EXISTING) == 0) { BKE_lib_override_library_update(bmain, id); } diff --git a/source/blender/blenkernel/intern/boids.c b/source/blender/blenkernel/intern/boids.c index 2e07b52c7bf..a0458f0f8d8 100644 --- a/source/blender/blenkernel/intern/boids.c +++ b/source/blender/blenkernel/intern/boids.c @@ -959,7 +959,7 @@ void boids_precalc_rules(ParticleSettings *part, float cfra) if (flbr->ob && flbr->cfra != cfra) { /* save object locations for velocity calculations */ copy_v3_v3(flbr->oloc, flbr->loc); - copy_v3_v3(flbr->loc, flbr->ob->obmat[3]); + copy_v3_v3(flbr->loc, flbr->ob->object_to_world[3]); flbr->cfra = cfra; } } diff --git a/source/blender/blenkernel/intern/bpath.c b/source/blender/blenkernel/intern/bpath.c index f639d03ae0f..6bf121675bc 100644 --- a/source/blender/blenkernel/intern/bpath.c +++ b/source/blender/blenkernel/intern/bpath.c @@ -155,7 +155,7 @@ bool BKE_bpath_foreach_path_dirfile_fixed_process(BPathForeachPathData *bpath_da char path_src[FILE_MAX]; char path_dst[FILE_MAX]; - BLI_join_dirfile(path_src, sizeof(path_src), path_dir, path_file); + BLI_path_join(path_src, sizeof(path_src), path_dir, path_file); /* So that functions can access the old value. */ BLI_strncpy(path_dst, path_src, FILE_MAX); @@ -279,7 +279,7 @@ static bool missing_files_find__recursive(const char *search_directory, continue; } - BLI_join_dirfile(path, sizeof(path), search_directory, de->d_name); + BLI_path_join(path, sizeof(path), search_directory, de->d_name); if (BLI_stat(path, &status) == -1) { CLOG_WARN(&LOG, "Cannot get file status (`stat()`) of '%s'", path); diff --git a/source/blender/blenkernel/intern/brush.cc b/source/blender/blenkernel/intern/brush.cc index 20d86ea5a2d..6f1435e90b8 100644 --- a/source/blender/blenkernel/intern/brush.cc +++ b/source/blender/blenkernel/intern/brush.cc @@ -1974,19 +1974,37 @@ void BKE_brush_curve_preset(Brush *b, eCurveMappingPreset preset) BKE_curvemapping_changed(cumap, false); } +const struct MTex *BKE_brush_mask_texture_get(const struct Brush *brush, + const eObjectMode object_mode) +{ + if (object_mode == OB_MODE_SCULPT) { + return &brush->mtex; + } + return &brush->mask_mtex; +} + +const struct MTex *BKE_brush_color_texture_get(const struct Brush *brush, + const eObjectMode object_mode) +{ + if (object_mode == OB_MODE_SCULPT) { + return &brush->mask_mtex; + } + return &brush->mtex; +} + float BKE_brush_sample_tex_3d(const Scene *scene, const Brush *br, + const MTex *mtex, const float point[3], float rgba[4], const int thread, struct ImagePool *pool) { UnifiedPaintSettings *ups = &scene->toolsettings->unified_paint_settings; - const MTex *mtex = &br->mtex; float intensity = 1.0; bool hasrgb = false; - if (!mtex->tex) { + if (mtex == nullptr || mtex->tex == nullptr) { intensity = 1; } else if (mtex->brush_map_mode == MTEX_MAP_MODE_3D) { diff --git a/source/blender/blenkernel/intern/camera.c b/source/blender/blenkernel/intern/camera.c index 8608ce97397..7c1193d80ab 100644 --- a/source/blender/blenkernel/intern/camera.c +++ b/source/blender/blenkernel/intern/camera.c @@ -221,16 +221,16 @@ float BKE_camera_object_dof_distance(const Object *ob) } if (cam->dof.focus_object) { float view_dir[3], dof_dir[3]; - normalize_v3_v3(view_dir, ob->obmat[2]); + normalize_v3_v3(view_dir, ob->object_to_world[2]); bPoseChannel *pchan = BKE_pose_channel_find_name(cam->dof.focus_object->pose, cam->dof.focus_subtarget); if (pchan) { float posemat[4][4]; - mul_m4_m4m4(posemat, cam->dof.focus_object->obmat, pchan->pose_mat); - sub_v3_v3v3(dof_dir, ob->obmat[3], posemat[3]); + mul_m4_m4m4(posemat, cam->dof.focus_object->object_to_world, pchan->pose_mat); + sub_v3_v3v3(dof_dir, ob->object_to_world[3], posemat[3]); } else { - sub_v3_v3v3(dof_dir, ob->obmat[3], cam->dof.focus_object->obmat[3]); + sub_v3_v3v3(dof_dir, ob->object_to_world[3], cam->dof.focus_object->object_to_world[3]); } return fabsf(dot_v3v3(view_dir, dof_dir)); } @@ -628,7 +628,7 @@ static void camera_frame_fit_data_init(const Scene *scene, BKE_camera_params_compute_matrix(params); /* initialize callback data */ - copy_m3_m4(data->camera_rotmat, (float(*)[4])ob->obmat); + copy_m3_m4(data->camera_rotmat, (float(*)[4])ob->object_to_world); normalize_m3(data->camera_rotmat); /* To transform a plane which is in its homogeneous representation (4d vector), * we need the inverse of the transpose of the transform matrix... */ @@ -828,7 +828,7 @@ bool BKE_camera_view_frame_fit_to_coords(const Depsgraph *depsgraph, static void camera_model_matrix(const Object *camera, float r_modelmat[4][4]) { - copy_m4_m4(r_modelmat, camera->obmat); + copy_m4_m4(r_modelmat, camera->object_to_world); } static void camera_stereo3d_model_matrix(const Object *camera, @@ -854,7 +854,7 @@ static void camera_stereo3d_model_matrix(const Object *camera, } float size[3]; - mat4_to_size(size, camera->obmat); + mat4_to_size(size, camera->object_to_world); size_to_mat4(sizemat, size); if (pivot == CAM_S3D_PIVOT_CENTER) { @@ -894,7 +894,7 @@ static void camera_stereo3d_model_matrix(const Object *camera, toeinmat[3][0] = interocular_distance * fac_signed; /* transform */ - normalize_m4_m4(r_modelmat, camera->obmat); + normalize_m4_m4(r_modelmat, camera->object_to_world); mul_m4_m4m4(r_modelmat, r_modelmat, toeinmat); /* scale back to the original size */ @@ -902,7 +902,7 @@ static void camera_stereo3d_model_matrix(const Object *camera, } else { /* CAM_S3D_PIVOT_LEFT, CAM_S3D_PIVOT_RIGHT */ /* rotate perpendicular to the interocular line */ - normalize_m4_m4(r_modelmat, camera->obmat); + normalize_m4_m4(r_modelmat, camera->object_to_world); mul_m4_m4m4(r_modelmat, r_modelmat, rotmat); /* translate along the interocular line */ @@ -918,7 +918,7 @@ static void camera_stereo3d_model_matrix(const Object *camera, } } else { - normalize_m4_m4(r_modelmat, camera->obmat); + normalize_m4_m4(r_modelmat, camera->object_to_world); /* translate - no rotation in CAM_S3D_OFFAXIS, CAM_S3D_PARALLEL */ translate_m4(r_modelmat, -interocular_distance * fac_signed, 0.0f, 0.0f); diff --git a/source/blender/blenkernel/intern/cloth.c b/source/blender/blenkernel/intern/cloth.c index 89983eb8f62..910869bbc72 100644 --- a/source/blender/blenkernel/intern/cloth.c +++ b/source/blender/blenkernel/intern/cloth.c @@ -269,7 +269,7 @@ static int do_step_cloth( /* Get the current position. */ copy_v3_v3(verts->xconst, mvert[i].co); - mul_m4_v3(ob->obmat, verts->xconst); + mul_m4_v3(ob->object_to_world, verts->xconst); if (vert_mass_changed) { verts->mass = clmd->sim_parms->mass; @@ -581,7 +581,7 @@ static void cloth_to_object(Object *ob, ClothModifierData *clmd, float (*vertexC if (clmd->clothObject) { /* Inverse matrix is not up to date. */ - invert_m4_m4(ob->imat, ob->obmat); + invert_m4_m4(ob->imat, ob->object_to_world); for (i = 0; i < cloth->mvert_num; i++) { copy_v3_v3(vertexCos[i], cloth->verts[i].x); @@ -763,11 +763,11 @@ static bool cloth_from_object( if (first) { copy_v3_v3(verts->x, mvert[i].co); - mul_m4_v3(ob->obmat, verts->x); + mul_m4_v3(ob->object_to_world, verts->x); if (shapekey_rest) { copy_v3_v3(verts->xrest, shapekey_rest[i]); - mul_m4_v3(ob->obmat, verts->xrest); + mul_m4_v3(ob->object_to_world, verts->xrest); } else { copy_v3_v3(verts->xrest, verts->x); @@ -1155,7 +1155,7 @@ static void cloth_update_verts(Object *ob, ClothModifierData *clmd, Mesh *mesh) /* vertex count is already ensured to match */ for (i = 0; i < mesh->totvert; i++, verts++) { copy_v3_v3(verts->xrest, mvert[i].co); - mul_m4_v3(ob->obmat, verts->xrest); + mul_m4_v3(ob->object_to_world, verts->xrest); } } diff --git a/source/blender/blenkernel/intern/constraint.c b/source/blender/blenkernel/intern/constraint.c index a6a6a1ca28f..1f288aef5ad 100644 --- a/source/blender/blenkernel/intern/constraint.c +++ b/source/blender/blenkernel/intern/constraint.c @@ -149,7 +149,7 @@ bConstraintOb *BKE_constraints_make_evalob( /* Quats/Axis-Angle, so Eulers should just use default order */ cob->rotOrder = EULER_ORDER_DEFAULT; } - copy_m4_m4(cob->matrix, ob->obmat); + copy_m4_m4(cob->matrix, ob->object_to_world); } else { unit_m4(cob->matrix); @@ -175,7 +175,7 @@ bConstraintOb *BKE_constraints_make_evalob( } /* matrix in world-space */ - mul_m4_m4m4(cob->matrix, ob->obmat, cob->pchan->pose_mat); + mul_m4_m4m4(cob->matrix, ob->object_to_world, cob->pchan->pose_mat); } else { unit_m4(cob->matrix); @@ -216,7 +216,7 @@ void BKE_constraints_clear_evalob(bConstraintOb *cob) /* cob->ob might not exist! */ if (cob->ob) { /* copy new ob-matrix back to owner */ - copy_m4_m4(cob->ob->obmat, cob->matrix); + copy_m4_m4(cob->ob->object_to_world, cob->matrix); /* copy inverse of delta back to owner */ invert_m4_m4(cob->ob->constinv, delta); @@ -276,7 +276,7 @@ void BKE_constraint_mat_convertspace(Object *ob, } else { /* World to pose. */ - invert_m4_m4(imat, ob->obmat); + invert_m4_m4(imat, ob->object_to_world); mul_m4_m4m4(mat, imat, mat); /* Use pose-space as stepping stone for other spaces. */ @@ -319,7 +319,7 @@ void BKE_constraint_mat_convertspace(Object *ob, } else { /* Pose to world. */ - mul_m4_m4m4(mat, ob->obmat, mat); + mul_m4_m4m4(mat, ob->object_to_world, mat); /* Use world-space as stepping stone for other spaces. */ if (to != CONSTRAINT_SPACE_WORLD) { /* Call self with slightly different values. */ @@ -429,7 +429,7 @@ void BKE_constraint_mat_convertspace(Object *ob, /* Check if object has a parent. */ if (ob->parent) { /* 'subtract' parent's effects from owner. */ - mul_m4_m4m4(diff_mat, ob->parent->obmat, ob->parentinv); + mul_m4_m4m4(diff_mat, ob->parent->object_to_world, ob->parentinv); invert_m4_m4_safe(imat, diff_mat); mul_m4_m4m4(mat, imat, mat); } @@ -465,7 +465,7 @@ void BKE_constraint_mat_convertspace(Object *ob, /* check that object has a parent - otherwise this won't work */ if (ob->parent) { /* 'add' parent's effect back to owner */ - mul_m4_m4m4(diff_mat, ob->parent->obmat, ob->parentinv); + mul_m4_m4m4(diff_mat, ob->parent->object_to_world, ob->parentinv); mul_m4_m4m4(mat, diff_mat, mat); } else { @@ -518,7 +518,7 @@ static void contarget_get_mesh_mat(Object *ob, const char *substring, float mat[ const int defgroup = BKE_object_defgroup_name_index(ob, substring); /* initialize target matrix using target matrix */ - copy_m4_m4(mat, ob->obmat); + copy_m4_m4(mat, ob->object_to_world); /* get index of vertex group */ if (defgroup == -1) { @@ -584,7 +584,7 @@ static void contarget_get_mesh_mat(Object *ob, const char *substring, float mat[ * calc_gizmo_stats, V3D_ORIENT_NORMAL case */ /* We need the transpose of the inverse for a normal. */ - copy_m3_m4(imat, ob->obmat); + copy_m3_m4(imat, ob->object_to_world); invert_m3_m3(tmat, imat); transpose_m3(tmat); @@ -605,7 +605,7 @@ static void contarget_get_mesh_mat(Object *ob, const char *substring, float mat[ normalize_m4(mat); /* apply the average coordinate as the new location */ - mul_v3_m4v3(mat[3], ob->obmat, vec); + mul_v3_m4v3(mat[3], ob->object_to_world, vec); } /* function that sets the given matrix based on given vertex group in lattice */ @@ -627,7 +627,7 @@ static void contarget_get_lattice_mat(Object *ob, const char *substring, float m const int defgroup = BKE_object_defgroup_name_index(ob, substring); /* initialize target matrix using target matrix */ - copy_m4_m4(mat, ob->obmat); + copy_m4_m4(mat, ob->object_to_world); /* get index of vertex group */ if (defgroup == -1) { @@ -661,11 +661,11 @@ static void contarget_get_lattice_mat(Object *ob, const char *substring, float m } } - /* find average location, then multiply by ob->obmat to find world-space location */ + /* find average location, then multiply by ob->object_to_world to find world-space location */ if (grouped) { mul_v3_fl(vec, 1.0f / grouped); } - mul_v3_m4v3(tvec, ob->obmat, vec); + mul_v3_m4v3(tvec, ob->object_to_world, vec); /* copy new location to matrix */ copy_v3_v3(mat[3], tvec); @@ -684,7 +684,7 @@ static void constraint_target_to_mat4(Object *ob, { /* Case OBJECT */ if (substring[0] == '\0') { - copy_m4_m4(mat, ob->obmat); + copy_m4_m4(mat, ob->object_to_world); BKE_constraint_mat_convertspace(ob, NULL, cob, mat, from, to, false); } /* Case VERTEXGROUP */ @@ -719,7 +719,7 @@ static void constraint_target_to_mat4(Object *ob, if (headtail < 0.000001f && !(is_bbone && full_bbone)) { /* skip length interpolation if set to head */ - mul_m4_m4m4(mat, ob->obmat, pchan->pose_mat); + mul_m4_m4m4(mat, ob->object_to_world, pchan->pose_mat); } else if (is_bbone && pchan->bone->segments == pchan->runtime.bbone_segments) { /* use point along bbone */ @@ -745,7 +745,7 @@ static void constraint_target_to_mat4(Object *ob, mul_v3_m4v3(tempmat[3], pchan->pose_mat, loc); } - mul_m4_m4m4(mat, ob->obmat, tempmat); + mul_m4_m4m4(mat, ob->object_to_world, tempmat); } else { float tempmat[4][4], loc[3]; @@ -757,11 +757,11 @@ static void constraint_target_to_mat4(Object *ob, copy_m4_m4(tempmat, pchan->pose_mat); copy_v3_v3(tempmat[3], loc); - mul_m4_m4m4(mat, ob->obmat, tempmat); + mul_m4_m4m4(mat, ob->object_to_world, tempmat); } } else { - copy_m4_m4(mat, ob->obmat); + copy_m4_m4(mat, ob->object_to_world); } /* convert matrix space as required */ @@ -1069,7 +1069,7 @@ static void childof_evaluate(bConstraint *con, bConstraintOb *cob, ListBase *tar if (data->flag & CHILDOF_SET_INVERSE) { invert_m4_m4(data->invmat, parmat); if (cob->pchan != NULL) { - mul_m4_series(data->invmat, data->invmat, cob->ob->obmat); + mul_m4_series(data->invmat, data->invmat, cob->ob->object_to_world); } copy_m4_m4(inverse_matrix, data->invmat); @@ -1388,8 +1388,8 @@ static void kinematic_get_tarmat(struct Depsgraph *UNUSED(depsgraph), else { float vec[3]; /* move grabtarget into world space */ - mul_v3_m4v3(vec, ob->obmat, data->grabtarget); - copy_m4_m4(ct->matrix, ob->obmat); + mul_v3_m4v3(vec, ob->object_to_world, data->grabtarget); + copy_m4_m4(ct->matrix, ob->object_to_world); copy_v3_v3(ct->matrix[3], vec); } } @@ -1528,7 +1528,7 @@ static void followpath_get_tarmat(struct Depsgraph *UNUSED(depsgraph), copy_v3_v3(totmat[3], vec); - mul_m4_m4m4(ct->matrix, ct->tar->obmat, totmat); + mul_m4_m4m4(ct->matrix, ct->tar->object_to_world, totmat); } } } @@ -2557,7 +2557,7 @@ static void armdef_get_tarmat(struct Depsgraph *UNUSED(depsgraph), bPoseChannel *pchan = BKE_pose_channel_find_name(ct->tar->pose, ct->subtarget); if (pchan != NULL) { - mul_m4_m4m4(ct->matrix, ct->tar->obmat, pchan->pose_mat); + mul_m4_m4m4(ct->matrix, ct->tar->object_to_world, pchan->pose_mat); return; } } @@ -2613,7 +2613,7 @@ static void armdef_accumulate_bone(bConstraintTarget *ct, float weight = ct->weight; /* Our object's location in target pose space. */ - invert_m4_m4(iobmat, ct->tar->obmat); + invert_m4_m4(iobmat, ct->tar->object_to_world); mul_v3_m4v3(co, iobmat, wco); /* Multiply by the envelope weight when appropriate. */ @@ -2644,7 +2644,7 @@ static void armdef_accumulate_bone(bConstraintTarget *ct, mul_m4_m4m4(basemat, bone->arm_mat, b_bone_rest_mats[index].mat); } - armdef_accumulate_matrix(ct->tar->obmat, + armdef_accumulate_matrix(ct->tar->object_to_world, iobmat, basemat, b_bone_mats[index + 1].mat, @@ -2657,7 +2657,7 @@ static void armdef_accumulate_bone(bConstraintTarget *ct, mul_m4_m4m4(basemat, bone->arm_mat, b_bone_rest_mats[index + 1].mat); } - armdef_accumulate_matrix(ct->tar->obmat, + armdef_accumulate_matrix(ct->tar->object_to_world, iobmat, basemat, b_bone_mats[index + 2].mat, @@ -2667,8 +2667,13 @@ static void armdef_accumulate_bone(bConstraintTarget *ct, } else { /* Simple bone. This requires DEG_OPCODE_BONE_DONE dependency due to chan_mat. */ - armdef_accumulate_matrix( - ct->tar->obmat, iobmat, bone->arm_mat, pchan->chan_mat, weight, r_sum_mat, r_sum_dq); + armdef_accumulate_matrix(ct->tar->object_to_world, + iobmat, + bone->arm_mat, + pchan->chan_mat, + weight, + r_sum_mat, + r_sum_dq); } /* Accumulate the weight. */ @@ -2694,7 +2699,7 @@ static void armdef_evaluate(bConstraint *con, bConstraintOb *cob, ListBase *targ /* For constraints on bones, use the rest position to bind b-bone segments * and envelopes, to allow safely changing the bone location as if parented. */ copy_v3_v3(input_co, cob->pchan->bone->arm_head); - mul_m4_v3(cob->ob->obmat, input_co); + mul_m4_v3(cob->ob->object_to_world, input_co); } else { copy_v3_v3(input_co, cob->matrix[3]); @@ -3927,7 +3932,7 @@ static void clampto_evaluate(bConstraint *con, bConstraintOb *cob, ListBase *tar unit_m4(totmat); copy_v3_v3(totmat[3], vec); - mul_m4_m4m4(targetMatrix, ct->tar->obmat, totmat); + mul_m4_m4m4(targetMatrix, ct->tar->object_to_world, totmat); } } @@ -4227,7 +4232,7 @@ static void shrinkwrap_get_tarmat(struct Depsgraph *UNUSED(depsgraph), if (BKE_shrinkwrap_init_tree( &tree, target_eval, scon->shrinkType, scon->shrinkMode, do_track_normal)) { - BLI_space_transform_from_matrices(&transform, cob->matrix, ct->tar->obmat); + BLI_space_transform_from_matrices(&transform, cob->matrix, ct->tar->object_to_world); switch (scon->shrinkType) { case MOD_SHRINKWRAP_NEAREST_SURFACE: @@ -4902,7 +4907,7 @@ static void followtrack_evaluate_using_3d_position_object(FollowTrackContext *co /* Object matrix of the camera. */ float camera_obmat[4][4]; - copy_m4_m4(camera_obmat, camera_object->obmat); + copy_m4_m4(camera_obmat, camera_object->object_to_world); /* Calculate inverted matrix of the solved camera at the current time. */ float reconstructed_camera_mat[4][4]; @@ -5054,10 +5059,10 @@ static void followtrack_project_to_depth_object_if_needed(FollowTrackContext *co } float depth_object_mat_inv[4][4]; - invert_m4_m4(depth_object_mat_inv, depth_object->obmat); + invert_m4_m4(depth_object_mat_inv, depth_object->object_to_world); float ray_start[3], ray_end[3]; - mul_v3_m4v3(ray_start, depth_object_mat_inv, context->camera_object->obmat[3]); + mul_v3_m4v3(ray_start, depth_object_mat_inv, context->camera_object->object_to_world[3]); mul_v3_m4v3(ray_end, depth_object_mat_inv, cob->matrix[3]); float ray_direction[3]; @@ -5080,7 +5085,7 @@ static void followtrack_project_to_depth_object_if_needed(FollowTrackContext *co &tree_data); if (result != -1) { - mul_v3_m4v3(cob->matrix[3], depth_object->obmat, hit.co); + mul_v3_m4v3(cob->matrix[3], depth_object->object_to_world, hit.co); } free_bvhtree_from_mesh(&tree_data); @@ -5128,9 +5133,9 @@ static void followtrack_evaluate_using_2d_position(FollowTrackContext *context, } float disp[3]; - mul_v3_m4v3(disp, camera_object->obmat, vec); + mul_v3_m4v3(disp, camera_object->object_to_world, vec); - copy_m4_m4(rmat, camera_object->obmat); + copy_m4_m4(rmat, camera_object->object_to_world); zero_v3(rmat[3]); mul_m4_m4m4(cob->matrix, cob->matrix, rmat); @@ -5152,10 +5157,10 @@ static void followtrack_evaluate_using_2d_position(FollowTrackContext *context, } float disp[3]; - mul_v3_m4v3(disp, camera_object->obmat, vec); + mul_v3_m4v3(disp, camera_object->object_to_world, vec); /* apply camera rotation so Z-axis would be co-linear */ - copy_m4_m4(rmat, camera_object->obmat); + copy_m4_m4(rmat, camera_object->object_to_world); zero_v3(rmat[3]); mul_m4_m4m4(cob->matrix, cob->matrix, rmat); @@ -5303,7 +5308,7 @@ static void objectsolver_evaluate(bConstraint *con, bConstraintOb *cob, ListBase BKE_tracking_camera_get_reconstructed_interpolate(tracking, object, framenr, mat); invert_m4_m4(imat, mat); - mul_m4_m4m4(parmat, camob->obmat, imat); + mul_m4_m4m4(parmat, camob->object_to_world, imat); copy_m4_m4(obmat, cob->matrix); @@ -5650,7 +5655,7 @@ bool BKE_constraint_apply_for_object(Depsgraph *depsgraph, BLI_freelinkN(&single_con, new_con); /* Apply transform from matrix. */ - BKE_object_apply_mat4(ob, ob_eval->obmat, true, true); + BKE_object_apply_mat4(ob, ob_eval->object_to_world, true, true); return true; } @@ -6237,7 +6242,7 @@ void BKE_constraint_target_matrix_get(struct Depsgraph *depsgraph, cob->ob = (Object *)ownerdata; cob->pchan = NULL; if (cob->ob) { - copy_m4_m4(cob->matrix, cob->ob->obmat); + copy_m4_m4(cob->matrix, cob->ob->object_to_world); copy_m4_m4(cob->startmat, cob->matrix); } else { diff --git a/source/blender/blenkernel/intern/context.c b/source/blender/blenkernel/intern/context.c index d7bd0038d3c..1d6092849cc 100644 --- a/source/blender/blenkernel/intern/context.c +++ b/source/blender/blenkernel/intern/context.c @@ -393,37 +393,37 @@ static void *ctx_data_pointer_get(const bContext *C, const char *member) return NULL; } -static int ctx_data_pointer_verify(const bContext *C, const char *member, void **pointer) +static bool ctx_data_pointer_verify(const bContext *C, const char *member, void **pointer) { /* if context is NULL, pointer must be NULL too and that is a valid return */ if (C == NULL) { *pointer = NULL; - return 1; + return true; } bContextDataResult result; if (ctx_data_get((bContext *)C, member, &result) == CTX_RESULT_OK) { BLI_assert(result.type == CTX_DATA_TYPE_POINTER); *pointer = result.ptr.data; - return 1; + return true; } *pointer = NULL; - return 0; + return false; } -static int ctx_data_collection_get(const bContext *C, const char *member, ListBase *list) +static bool ctx_data_collection_get(const bContext *C, const char *member, ListBase *list) { bContextDataResult result; if (ctx_data_get((bContext *)C, member, &result) == CTX_RESULT_OK) { BLI_assert(result.type == CTX_DATA_TYPE_COLLECTION); *list = result.list; - return 1; + return true; } BLI_listbase_clear(list); - return 0; + return false; } static int ctx_data_base_collection_get(const bContext *C, const char *member, ListBase *list) @@ -681,7 +681,7 @@ void CTX_data_list_add_ptr(bContextDataResult *result, const PointerRNA *ptr) BLI_addtail(&result->list, link); } -int ctx_data_list_count(const bContext *C, int (*func)(const bContext *, ListBase *)) +int ctx_data_list_count(const bContext *C, bool (*func)(const bContext *, ListBase *)) { ListBase list; @@ -1291,62 +1291,62 @@ ToolSettings *CTX_data_tool_settings(const bContext *C) return NULL; } -int CTX_data_selected_ids(const bContext *C, ListBase *list) +bool CTX_data_selected_ids(const bContext *C, ListBase *list) { return ctx_data_collection_get(C, "selected_ids", list); } -int CTX_data_selected_nodes(const bContext *C, ListBase *list) +bool CTX_data_selected_nodes(const bContext *C, ListBase *list) { return ctx_data_collection_get(C, "selected_nodes", list); } -int CTX_data_selected_editable_objects(const bContext *C, ListBase *list) +bool CTX_data_selected_editable_objects(const bContext *C, ListBase *list) { return ctx_data_collection_get(C, "selected_editable_objects", list); } -int CTX_data_selected_editable_bases(const bContext *C, ListBase *list) +bool CTX_data_selected_editable_bases(const bContext *C, ListBase *list) { return ctx_data_base_collection_get(C, "selected_editable_objects", list); } -int CTX_data_editable_objects(const bContext *C, ListBase *list) +bool CTX_data_editable_objects(const bContext *C, ListBase *list) { return ctx_data_collection_get(C, "editable_objects", list); } -int CTX_data_editable_bases(const bContext *C, ListBase *list) +bool CTX_data_editable_bases(const bContext *C, ListBase *list) { return ctx_data_base_collection_get(C, "editable_objects", list); } -int CTX_data_selected_objects(const bContext *C, ListBase *list) +bool CTX_data_selected_objects(const bContext *C, ListBase *list) { return ctx_data_collection_get(C, "selected_objects", list); } -int CTX_data_selected_bases(const bContext *C, ListBase *list) +bool CTX_data_selected_bases(const bContext *C, ListBase *list) { return ctx_data_base_collection_get(C, "selected_objects", list); } -int CTX_data_visible_objects(const bContext *C, ListBase *list) +bool CTX_data_visible_objects(const bContext *C, ListBase *list) { return ctx_data_collection_get(C, "visible_objects", list); } -int CTX_data_visible_bases(const bContext *C, ListBase *list) +bool CTX_data_visible_bases(const bContext *C, ListBase *list) { return ctx_data_base_collection_get(C, "visible_objects", list); } -int CTX_data_selectable_objects(const bContext *C, ListBase *list) +bool CTX_data_selectable_objects(const bContext *C, ListBase *list) { return ctx_data_collection_get(C, "selectable_objects", list); } -int CTX_data_selectable_bases(const bContext *C, ListBase *list) +bool CTX_data_selectable_bases(const bContext *C, ListBase *list) { return ctx_data_base_collection_get(C, "selectable_objects", list); } @@ -1404,22 +1404,22 @@ struct CacheFile *CTX_data_edit_cachefile(const bContext *C) return ctx_data_pointer_get(C, "edit_cachefile"); } -int CTX_data_selected_bones(const bContext *C, ListBase *list) +bool CTX_data_selected_bones(const bContext *C, ListBase *list) { return ctx_data_collection_get(C, "selected_bones", list); } -int CTX_data_selected_editable_bones(const bContext *C, ListBase *list) +bool CTX_data_selected_editable_bones(const bContext *C, ListBase *list) { return ctx_data_collection_get(C, "selected_editable_bones", list); } -int CTX_data_visible_bones(const bContext *C, ListBase *list) +bool CTX_data_visible_bones(const bContext *C, ListBase *list) { return ctx_data_collection_get(C, "visible_bones", list); } -int CTX_data_editable_bones(const bContext *C, ListBase *list) +bool CTX_data_editable_bones(const bContext *C, ListBase *list) { return ctx_data_collection_get(C, "editable_bones", list); } @@ -1429,17 +1429,17 @@ struct bPoseChannel *CTX_data_active_pose_bone(const bContext *C) return ctx_data_pointer_get(C, "active_pose_bone"); } -int CTX_data_selected_pose_bones(const bContext *C, ListBase *list) +bool CTX_data_selected_pose_bones(const bContext *C, ListBase *list) { return ctx_data_collection_get(C, "selected_pose_bones", list); } -int CTX_data_selected_pose_bones_from_active_object(const bContext *C, ListBase *list) +bool CTX_data_selected_pose_bones_from_active_object(const bContext *C, ListBase *list) { return ctx_data_collection_get(C, "selected_pose_bones_from_active_object", list); } -int CTX_data_visible_pose_bones(const bContext *C, ListBase *list) +bool CTX_data_visible_pose_bones(const bContext *C, ListBase *list) { return ctx_data_collection_get(C, "visible_pose_bones", list); } @@ -1459,17 +1459,17 @@ bGPDframe *CTX_data_active_gpencil_frame(const bContext *C) return ctx_data_pointer_get(C, "active_gpencil_frame"); } -int CTX_data_visible_gpencil_layers(const bContext *C, ListBase *list) +bool CTX_data_visible_gpencil_layers(const bContext *C, ListBase *list) { return ctx_data_collection_get(C, "visible_gpencil_layers", list); } -int CTX_data_editable_gpencil_layers(const bContext *C, ListBase *list) +bool CTX_data_editable_gpencil_layers(const bContext *C, ListBase *list) { return ctx_data_collection_get(C, "editable_gpencil_layers", list); } -int CTX_data_editable_gpencil_strokes(const bContext *C, ListBase *list) +bool CTX_data_editable_gpencil_strokes(const bContext *C, ListBase *list) { return ctx_data_collection_get(C, "editable_gpencil_strokes", list); } diff --git a/source/blender/blenkernel/intern/crazyspace.cc b/source/blender/blenkernel/intern/crazyspace.cc index 190e2d3bb7e..f83c321c4ae 100644 --- a/source/blender/blenkernel/intern/crazyspace.cc +++ b/source/blender/blenkernel/intern/crazyspace.cc @@ -70,47 +70,48 @@ static void set_crazy_vertex_quat(float r_quat[4], sub_qt_qtqt(r_quat, q2, q1); } -static bool modifiers_disable_subsurf_temporary(struct Scene *scene, Object *ob) +static bool modifiers_disable_subsurf_temporary(Object *ob, const int cageIndex) { - bool disabled = false; - int cageIndex = BKE_modifiers_get_cage_index(scene, ob, nullptr, true); + bool changed = false; ModifierData *md = static_cast<ModifierData *>(ob->modifiers.first); for (int i = 0; md && i <= cageIndex; i++, md = md->next) { if (md->type == eModifierType_Subsurf) { md->mode ^= eModifierMode_DisableTemporary; - disabled = true; + changed = true; } } - return disabled; + return changed; } float (*BKE_crazyspace_get_mapped_editverts(struct Depsgraph *depsgraph, Object *obedit))[3] { - Scene *scene = DEG_get_input_scene(depsgraph); Scene *scene_eval = DEG_get_evaluated_scene(depsgraph); Object *obedit_eval = DEG_get_evaluated_object(depsgraph, obedit); - Mesh *mesh_eval = static_cast<Mesh *>(obedit_eval->data); - BMEditMesh *editmesh_eval = mesh_eval->edit_mesh; + const int cageIndex = BKE_modifiers_get_cage_index(scene_eval, obedit_eval, nullptr, true); - /* disable subsurf temporal, get mapped cos, and enable it */ - if (modifiers_disable_subsurf_temporary(scene_eval, obedit_eval)) { - /* Need to make new derived-mesh. */ + /* Disable subsurf temporal, get mapped cos, and enable it. */ + if (modifiers_disable_subsurf_temporary(obedit_eval, cageIndex)) { + /* Need to make new cage. + * TODO: Avoid losing original evaluated geometry. */ makeDerivedMesh(depsgraph, scene_eval, obedit_eval, &CD_MASK_BAREMESH); } - /* now get the cage */ - Mesh *mesh_eval_cage = editbmesh_get_eval_cage_from_orig( - depsgraph, scene, obedit, &CD_MASK_BAREMESH); + /* Now get the cage. */ + BMEditMesh *em_eval = BKE_editmesh_from_object(obedit_eval); + Mesh *mesh_eval_cage = editbmesh_get_eval_cage( + depsgraph, scene_eval, obedit_eval, em_eval, &CD_MASK_BAREMESH); - const int nverts = editmesh_eval->bm->totvert; + const int nverts = em_eval->bm->totvert; float(*vertexcos)[3] = static_cast<float(*)[3]>( MEM_mallocN(sizeof(*vertexcos) * nverts, "vertexcos map")); mesh_get_mapped_verts_coords(mesh_eval_cage, vertexcos, nverts); - /* set back the flag, no new cage needs to be built, transform does it */ - modifiers_disable_subsurf_temporary(scene_eval, obedit_eval); + /* Set back the flag, and ensure new cage needs to be built. */ + if (modifiers_disable_subsurf_temporary(obedit_eval, cageIndex)) { + DEG_id_tag_update(&obedit->id, ID_RECALC_GEOMETRY); + } return vertexcos; } diff --git a/source/blender/blenkernel/intern/curve_deform.c b/source/blender/blenkernel/intern/curve_deform.c index 9a27ba91c2f..066d8494451 100644 --- a/source/blender/blenkernel/intern/curve_deform.c +++ b/source/blender/blenkernel/intern/curve_deform.c @@ -44,8 +44,8 @@ typedef struct { static void init_curve_deform(const Object *ob_curve, const Object *ob_target, CurveDeform *cd) { float imat[4][4]; - invert_m4_m4(imat, ob_target->obmat); - mul_m4_m4m4(cd->objectspace, imat, ob_curve->obmat); + invert_m4_m4(imat, ob_target->object_to_world); + mul_m4_m4m4(cd->objectspace, imat, ob_curve->object_to_world); invert_m4_m4(cd->curvespace, cd->objectspace); copy_m3_m4(cd->objectspace3, cd->objectspace); cd->no_rot_axis = 0; diff --git a/source/blender/blenkernel/intern/curve_to_mesh_convert.cc b/source/blender/blenkernel/intern/curve_to_mesh_convert.cc index b9fea2a27b8..ecf3be9bd81 100644 --- a/source/blender/blenkernel/intern/curve_to_mesh_convert.cc +++ b/source/blender/blenkernel/intern/curve_to_mesh_convert.cc @@ -332,7 +332,8 @@ static eAttrDomain get_attribute_domain_for_mesh(const AttributeAccessor &mesh_a static bool should_add_attribute_to_mesh(const AttributeAccessor &curve_attributes, const AttributeAccessor &mesh_attributes, - const AttributeIDRef &id) + const AttributeIDRef &id, + const AttributeMetaData &meta_data) { /* The position attribute has special non-generic evaluation. */ @@ -346,6 +347,9 @@ static bool should_add_attribute_to_mesh(const AttributeAccessor &curve_attribut if (!id.should_be_kept()) { return false; } + if (meta_data.data_type == CD_PROP_STRING) { + return false; + } return true; } @@ -714,7 +718,7 @@ Mesh *curve_to_mesh_sweep(const CurvesGeometry &main, MutableAttributeAccessor mesh_attributes = mesh->attributes_for_write(); main_attributes.for_all([&](const AttributeIDRef &id, const AttributeMetaData meta_data) { - if (!should_add_attribute_to_mesh(main_attributes, mesh_attributes, id)) { + if (!should_add_attribute_to_mesh(main_attributes, mesh_attributes, id, meta_data)) { return true; } main_attributes_set.add_new(id); @@ -751,7 +755,7 @@ Mesh *curve_to_mesh_sweep(const CurvesGeometry &main, if (main_attributes.contains(id)) { return true; } - if (!should_add_attribute_to_mesh(profile_attributes, mesh_attributes, id)) { + if (!should_add_attribute_to_mesh(profile_attributes, mesh_attributes, id, meta_data)) { return true; } const eAttrDomain src_domain = meta_data.domain; diff --git a/source/blender/blenkernel/intern/curves.cc b/source/blender/blenkernel/intern/curves.cc index 01be22a57b0..61755a5be9b 100644 --- a/source/blender/blenkernel/intern/curves.cc +++ b/source/blender/blenkernel/intern/curves.cc @@ -287,7 +287,10 @@ static void curves_evaluate_modifiers(struct Depsgraph *depsgraph, { /* Modifier evaluation modes. */ const bool use_render = (DEG_get_mode(depsgraph) == DAG_EVAL_RENDER); - const int required_mode = use_render ? eModifierMode_Render : eModifierMode_Realtime; + int required_mode = use_render ? eModifierMode_Render : eModifierMode_Realtime; + if (BKE_object_is_in_editmode(object)) { + required_mode = (ModifierMode)(int(required_mode) | eModifierMode_Editmode); + } ModifierApplyFlag apply_flag = use_render ? MOD_APPLY_RENDER : MOD_APPLY_USECACHE; const ModifierEvalContext mectx = {depsgraph, object, apply_flag}; @@ -409,11 +412,11 @@ void curves_copy_parameters(const Curves &src, Curves &dst) CurvesSurfaceTransforms::CurvesSurfaceTransforms(const Object &curves_ob, const Object *surface_ob) { - this->curves_to_world = curves_ob.obmat; + this->curves_to_world = curves_ob.object_to_world; this->world_to_curves = this->curves_to_world.inverted(); if (surface_ob != nullptr) { - this->surface_to_world = surface_ob->obmat; + this->surface_to_world = surface_ob->object_to_world; this->world_to_surface = this->surface_to_world.inverted(); this->surface_to_curves = this->world_to_curves * this->surface_to_world; this->curves_to_surface = this->world_to_surface * this->curves_to_world; diff --git a/source/blender/blenkernel/intern/curves_geometry.cc b/source/blender/blenkernel/intern/curves_geometry.cc index f5c845443f1..7c338480c71 100644 --- a/source/blender/blenkernel/intern/curves_geometry.cc +++ b/source/blender/blenkernel/intern/curves_geometry.cc @@ -9,6 +9,7 @@ #include "MEM_guardedalloc.h" +#include "BLI_array_utils.hh" #include "BLI_bounds.hh" #include "BLI_index_mask_ops.hh" #include "BLI_length_parameterize.hh" @@ -1111,21 +1112,11 @@ static void copy_between_buffers(const CPPType &type, src_range.size()); } -template<typename T> -static void copy_with_map(const Span<T> src, const Span<int> map, MutableSpan<T> dst) -{ - threading::parallel_for(map.index_range(), 1024, [&](const IndexRange range) { - for (const int i : range) { - dst[i] = src[map[i]]; - } - }); -} - static void copy_with_map(const GSpan src, const Span<int> map, GMutableSpan dst) { attribute_math::convert_to_static_type(src.type(), [&](auto dummy) { using T = decltype(dummy); - copy_with_map(src.typed<T>(), map, dst.typed<T>()); + array_utils::gather(src.typed<T>(), map, dst.typed<T>()); }); } @@ -1233,6 +1224,10 @@ static CurvesGeometry copy_with_removed_points(const CurvesGeometry &curves, attribute.dst.finish(); } + if (new_curves.curves_num() != curves.curves_num()) { + new_curves.remove_attributes_based_on_types(); + } + return new_curves; } @@ -1338,6 +1333,8 @@ static CurvesGeometry copy_with_removed_curves(const CurvesGeometry &curves, attribute.dst.finish(); } + new_curves.remove_attributes_based_on_types(); + return new_curves; } @@ -1402,6 +1399,9 @@ void CurvesGeometry::reverse_curves(const IndexMask curves_to_reverse) if (meta_data.domain != ATTR_DOMAIN_POINT) { return true; } + if (meta_data.data_type == CD_PROP_STRING) { + return true; + } if (id.is_named() && bezier_handle_names.contains(id.name())) { return true; } diff --git a/source/blender/blenkernel/intern/customdata.cc b/source/blender/blenkernel/intern/customdata.cc index 6f2390fc28f..03a0f17a4bb 100644 --- a/source/blender/blenkernel/intern/customdata.cc +++ b/source/blender/blenkernel/intern/customdata.cc @@ -19,6 +19,7 @@ #include "BLI_bitmap.h" #include "BLI_color.hh" +#include "BLI_cpp_type_make.hh" #include "BLI_endian_switch.h" #include "BLI_index_range.hh" #include "BLI_math.h" @@ -5387,6 +5388,8 @@ const blender::CPPType *custom_data_type_to_cpp_type(const eCustomDataType type) return &CPPType::get<int8_t>(); case CD_PROP_BYTE_COLOR: return &CPPType::get<ColorGeometry4b>(); + case CD_PROP_STRING: + return &CPPType::get<MStringProperty>(); default: return nullptr; } @@ -5419,6 +5422,9 @@ eCustomDataType cpp_type_to_custom_data_type(const blender::CPPType &type) if (type.is<ColorGeometry4b>()) { return CD_PROP_BYTE_COLOR; } + if (type.is<MStringProperty>()) { + return CD_PROP_STRING; + } return static_cast<eCustomDataType>(-1); } @@ -5430,3 +5436,5 @@ size_t CustomData_get_elem_size(CustomDataLayer *layer) { return LAYERTYPEINFO[layer->type].size; } + +BLI_CPP_TYPE_MAKE(MStringProperty, MStringProperty, CPPTypeFlags::None); diff --git a/source/blender/blenkernel/intern/dynamicpaint.c b/source/blender/blenkernel/intern/dynamicpaint.c index e177250ae5a..b9cec17b6e0 100644 --- a/source/blender/blenkernel/intern/dynamicpaint.c +++ b/source/blender/blenkernel/intern/dynamicpaint.c @@ -3783,7 +3783,7 @@ static void dynamicPaint_brushMeshCalculateVelocity(Depsgraph *depsgraph, numOfVerts_p = mesh_p->totvert; mvert_p = BKE_mesh_verts_for_write(mesh_p); - copy_m4_m4(prev_obmat, ob->obmat); + copy_m4_m4(prev_obmat, ob->object_to_world); /* current frame mesh */ scene->r.cfra = cur_fra; @@ -3816,7 +3816,7 @@ static void dynamicPaint_brushMeshCalculateVelocity(Depsgraph *depsgraph, .brush_vel = *brushVel, .mvert_p = mvert_p, .mvert_c = mvert_c, - .obmat = ob->obmat, + .obmat = ob->object_to_world, .prev_obmat = prev_obmat, .timescale = timescale, }; @@ -3856,7 +3856,7 @@ static void dynamicPaint_brushObjectCalculateVelocity( SUBFRAME_RECURSION, BKE_scene_ctime_get(scene), eModifierType_DynamicPaint); - copy_m4_m4(prev_obmat, ob->obmat); + copy_m4_m4(prev_obmat, ob->object_to_world); /* current frame mesh */ scene->r.cfra = cur_fra; @@ -3871,7 +3871,7 @@ static void dynamicPaint_brushObjectCalculateVelocity( /* calculate speed */ mul_m4_v3(prev_obmat, prev_loc); - mul_m4_v3(ob->obmat, cur_loc); + mul_m4_v3(ob->object_to_world, cur_loc); sub_v3_v3v3(brushVel->v, cur_loc, prev_loc); mul_v3_fl(brushVel->v, 1.0f / timescale); @@ -4279,14 +4279,14 @@ static bool dynamicPaint_paintMesh(Depsgraph *depsgraph, * (Faster than transforming per surface point * coordinates and normals to object space) */ for (ii = 0; ii < numOfVerts; ii++) { - mul_m4_v3(brushOb->obmat, mvert[ii].co); + mul_m4_v3(brushOb->object_to_world, mvert[ii].co); boundInsert(&mesh_bb, mvert[ii].co); /* for proximity project calculate average normal */ if (brush->flags & MOD_DPAINT_PROX_PROJECT && brush->collision != MOD_DPAINT_COL_VOLUME) { float nor[3]; copy_v3_v3(nor, vert_normals[ii]); - mul_mat3_m4_v3(brushOb->obmat, nor); + mul_mat3_m4_v3(brushOb->object_to_world, nor); normalize_v3(nor); add_v3_v3(avg_brushNor, nor); @@ -5870,7 +5870,7 @@ static bool dynamicPaint_surfaceHasMoved(DynamicPaintSurface *surface, Object *o } /* matrix comparison */ - if (!equals_m4m4(bData->prev_obmat, ob->obmat)) { + if (!equals_m4m4(bData->prev_obmat, ob->object_to_world)) { return true; } @@ -5957,7 +5957,7 @@ static void dynamic_paint_generate_bake_data_cb(void *__restrict userdata, mul_v3_v3v3(scaled_nor, temp_nor, ob->scale); bData->bNormal[index].normal_scale = len_v3(scaled_nor); } - mul_mat3_m4_v3(ob->obmat, temp_nor); + mul_mat3_m4_v3(ob->object_to_world, temp_nor); normalize_v3(temp_nor); negate_v3_v3(bData->bNormal[index].invNorm, temp_nor); } @@ -5995,7 +5995,7 @@ static void dynamic_paint_generate_bake_data_cb(void *__restrict userdata, mul_v3_v3v3(scaled_nor, temp_nor, ob->scale); bData->bNormal[index].normal_scale = len_v3(scaled_nor); } - mul_mat3_m4_v3(ob->obmat, temp_nor); + mul_mat3_m4_v3(ob->object_to_world, temp_nor); normalize_v3(temp_nor); negate_v3_v3(bData->bNormal[index].invNorm, temp_nor); } @@ -6113,7 +6113,7 @@ static bool dynamicPaint_generateBakeData(DynamicPaintSurface *surface, bData->mesh_bounds.valid = false; for (index = 0; index < canvasNumOfVerts; index++) { copy_v3_v3(canvas_verts[index].v, mvert[index].co); - mul_m4_v3(ob->obmat, canvas_verts[index].v); + mul_m4_v3(ob->object_to_world, canvas_verts[index].v); boundInsert(&bData->mesh_bounds, canvas_verts[index].v); } @@ -6143,7 +6143,7 @@ static bool dynamicPaint_generateBakeData(DynamicPaintSurface *surface, dynamicPaint_prepareAdjacencyData(surface, false); /* Copy current frame vertices to check against in next frame */ - copy_m4_m4(bData->prev_obmat, ob->obmat); + copy_m4_m4(bData->prev_obmat, ob->object_to_world); memcpy(bData->prev_verts, mvert, canvasNumOfVerts * sizeof(MVert)); bData->clear = 0; diff --git a/source/blender/blenkernel/intern/effect.c b/source/blender/blenkernel/intern/effect.c index 42b38854248..983e4b3c6e6 100644 --- a/source/blender/blenkernel/intern/effect.c +++ b/source/blender/blenkernel/intern/effect.c @@ -154,8 +154,8 @@ static void precalculate_effector(struct Depsgraph *depsgraph, EffectorCache *ef if (eff->ob->runtime.curve_cache->anim_path_accum_length) { BKE_where_on_path( eff->ob, 0.0, eff->guide_loc, eff->guide_dir, NULL, &eff->guide_radius, NULL); - mul_m4_v3(eff->ob->obmat, eff->guide_loc); - mul_mat3_m4_v3(eff->ob->obmat, eff->guide_dir); + mul_m4_v3(eff->ob->object_to_world, eff->guide_loc); + mul_mat3_m4_v3(eff->ob->object_to_world, eff->guide_dir); } } } @@ -707,8 +707,8 @@ bool get_effector_data(EffectorCache *eff, copy_v3_v3(efd->loc, verts[*efd->index].co); copy_v3_v3(efd->nor, vert_normals[*efd->index]); - mul_m4_v3(eff->ob->obmat, efd->loc); - mul_mat3_m4_v3(eff->ob->obmat, efd->nor); + mul_m4_v3(eff->ob->object_to_world, efd->loc); + mul_mat3_m4_v3(eff->ob->object_to_world, efd->nor); normalize_v3(efd->nor); @@ -760,23 +760,23 @@ bool get_effector_data(EffectorCache *eff, const Object *ob = eff->ob; /* Use z-axis as normal. */ - normalize_v3_v3(efd->nor, ob->obmat[2]); + normalize_v3_v3(efd->nor, ob->object_to_world[2]); if (eff->pd && ELEM(eff->pd->shape, PFIELD_SHAPE_PLANE, PFIELD_SHAPE_LINE)) { float temp[3], translate[3]; - sub_v3_v3v3(temp, point->loc, ob->obmat[3]); + sub_v3_v3v3(temp, point->loc, ob->object_to_world[3]); project_v3_v3v3(translate, temp, efd->nor); /* for vortex the shape chooses between old / new force */ if (eff->pd->forcefield == PFIELD_VORTEX || eff->pd->shape == PFIELD_SHAPE_LINE) { - add_v3_v3v3(efd->loc, ob->obmat[3], translate); + add_v3_v3v3(efd->loc, ob->object_to_world[3], translate); } else { /* normally efd->loc is closest point on effector xy-plane */ sub_v3_v3v3(efd->loc, point->loc, translate); } } else { - copy_v3_v3(efd->loc, ob->obmat[3]); + copy_v3_v3(efd->loc, ob->object_to_world[3]); } zero_v3(efd->vel); @@ -801,8 +801,8 @@ bool get_effector_data(EffectorCache *eff, } else { /* for some effectors we need the object center every time */ - sub_v3_v3v3(efd->vec_to_point2, point->loc, eff->ob->obmat[3]); - normalize_v3_v3(efd->nor2, eff->ob->obmat[2]); + sub_v3_v3v3(efd->vec_to_point2, point->loc, eff->ob->object_to_world[3]); + normalize_v3_v3(efd->nor2, eff->ob->object_to_world[2]); } } diff --git a/source/blender/blenkernel/intern/fcurve_driver.c b/source/blender/blenkernel/intern/fcurve_driver.c index 9f63e2d3743..3d1439b5530 100644 --- a/source/blender/blenkernel/intern/fcurve_driver.c +++ b/source/blender/blenkernel/intern/fcurve_driver.c @@ -321,7 +321,7 @@ static float dvar_eval_rotDiff(ChannelDriver *driver, DriverVar *dvar) } else { /* Object. */ - mat[i] = ob->obmat; + mat[i] = ob->object_to_world; } } @@ -399,7 +399,7 @@ static float dvar_eval_locDiff(ChannelDriver *driver, DriverVar *dvar) else { /* Convert to world-space. */ copy_v3_v3(tmp_loc, pchan->pose_head); - mul_m4_v3(ob->obmat, tmp_loc); + mul_m4_v3(ob->object_to_world, tmp_loc); } } else { @@ -410,7 +410,7 @@ static float dvar_eval_locDiff(ChannelDriver *driver, DriverVar *dvar) float mat[4][4]; /* Extract transform just like how the constraints do it! */ - copy_m4_m4(mat, ob->obmat); + copy_m4_m4(mat, ob->object_to_world); BKE_constraint_mat_convertspace( ob, NULL, NULL, mat, CONSTRAINT_SPACE_WORLD, CONSTRAINT_SPACE_LOCAL, false); @@ -424,7 +424,7 @@ static float dvar_eval_locDiff(ChannelDriver *driver, DriverVar *dvar) } else { /* World-space. */ - copy_v3_v3(tmp_loc, ob->obmat[3]); + copy_v3_v3(tmp_loc, ob->object_to_world[3]); } } @@ -500,7 +500,7 @@ static float dvar_eval_transChan(ChannelDriver *driver, DriverVar *dvar) } else { /* World-space matrix. */ - mul_m4_m4m4(mat, ob->obmat, pchan->pose_mat); + mul_m4_m4m4(mat, ob->object_to_world, pchan->pose_mat); } } else { @@ -514,7 +514,7 @@ static float dvar_eval_transChan(ChannelDriver *driver, DriverVar *dvar) if (dtar->flag & DTAR_FLAG_LOCALSPACE) { if (dtar->flag & DTAR_FLAG_LOCAL_CONSTS) { /* Just like how the constraints do it! */ - copy_m4_m4(mat, ob->obmat); + copy_m4_m4(mat, ob->object_to_world); BKE_constraint_mat_convertspace( ob, NULL, NULL, mat, CONSTRAINT_SPACE_WORLD, CONSTRAINT_SPACE_LOCAL, false); } @@ -525,7 +525,7 @@ static float dvar_eval_transChan(ChannelDriver *driver, DriverVar *dvar) } else { /* World-space matrix - just the good-old one. */ - copy_m4_m4(mat, ob->obmat); + copy_m4_m4(mat, ob->object_to_world); } } diff --git a/source/blender/blenkernel/intern/fluid.c b/source/blender/blenkernel/intern/fluid.c index 0a39207184a..b0e99e10acc 100644 --- a/source/blender/blenkernel/intern/fluid.c +++ b/source/blender/blenkernel/intern/fluid.c @@ -327,17 +327,17 @@ void BKE_fluid_cache_free(FluidDomainSettings *fds, Object *ob, int cache_map) if (cache_map & FLUID_DOMAIN_OUTDATED_DATA) { flags &= ~(FLUID_DOMAIN_BAKING_DATA | FLUID_DOMAIN_BAKED_DATA | FLUID_DOMAIN_OUTDATED_DATA); - BLI_path_join(temp_dir, sizeof(temp_dir), fds->cache_directory, FLUID_DOMAIN_DIR_CONFIG, NULL); + BLI_path_join(temp_dir, sizeof(temp_dir), fds->cache_directory, FLUID_DOMAIN_DIR_CONFIG); BLI_path_abs(temp_dir, relbase); if (BLI_exists(temp_dir)) { BLI_delete(temp_dir, true, true); } - BLI_path_join(temp_dir, sizeof(temp_dir), fds->cache_directory, FLUID_DOMAIN_DIR_DATA, NULL); + BLI_path_join(temp_dir, sizeof(temp_dir), fds->cache_directory, FLUID_DOMAIN_DIR_DATA); BLI_path_abs(temp_dir, relbase); if (BLI_exists(temp_dir)) { BLI_delete(temp_dir, true, true); } - BLI_path_join(temp_dir, sizeof(temp_dir), fds->cache_directory, FLUID_DOMAIN_DIR_SCRIPT, NULL); + BLI_path_join(temp_dir, sizeof(temp_dir), fds->cache_directory, FLUID_DOMAIN_DIR_SCRIPT); BLI_path_abs(temp_dir, relbase); if (BLI_exists(temp_dir)) { BLI_delete(temp_dir, true, true); @@ -346,7 +346,7 @@ void BKE_fluid_cache_free(FluidDomainSettings *fds, Object *ob, int cache_map) } if (cache_map & FLUID_DOMAIN_OUTDATED_NOISE) { flags &= ~(FLUID_DOMAIN_BAKING_NOISE | FLUID_DOMAIN_BAKED_NOISE | FLUID_DOMAIN_OUTDATED_NOISE); - BLI_path_join(temp_dir, sizeof(temp_dir), fds->cache_directory, FLUID_DOMAIN_DIR_NOISE, NULL); + BLI_path_join(temp_dir, sizeof(temp_dir), fds->cache_directory, FLUID_DOMAIN_DIR_NOISE); BLI_path_abs(temp_dir, relbase); if (BLI_exists(temp_dir)) { BLI_delete(temp_dir, true, true); @@ -355,7 +355,7 @@ void BKE_fluid_cache_free(FluidDomainSettings *fds, Object *ob, int cache_map) } if (cache_map & FLUID_DOMAIN_OUTDATED_MESH) { flags &= ~(FLUID_DOMAIN_BAKING_MESH | FLUID_DOMAIN_BAKED_MESH | FLUID_DOMAIN_OUTDATED_MESH); - BLI_path_join(temp_dir, sizeof(temp_dir), fds->cache_directory, FLUID_DOMAIN_DIR_MESH, NULL); + BLI_path_join(temp_dir, sizeof(temp_dir), fds->cache_directory, FLUID_DOMAIN_DIR_MESH); BLI_path_abs(temp_dir, relbase); if (BLI_exists(temp_dir)) { BLI_delete(temp_dir, true, true); @@ -365,8 +365,7 @@ void BKE_fluid_cache_free(FluidDomainSettings *fds, Object *ob, int cache_map) if (cache_map & FLUID_DOMAIN_OUTDATED_PARTICLES) { flags &= ~(FLUID_DOMAIN_BAKING_PARTICLES | FLUID_DOMAIN_BAKED_PARTICLES | FLUID_DOMAIN_OUTDATED_PARTICLES); - BLI_path_join( - temp_dir, sizeof(temp_dir), fds->cache_directory, FLUID_DOMAIN_DIR_PARTICLES, NULL); + BLI_path_join(temp_dir, sizeof(temp_dir), fds->cache_directory, FLUID_DOMAIN_DIR_PARTICLES); BLI_path_abs(temp_dir, relbase); if (BLI_exists(temp_dir)) { BLI_delete(temp_dir, true, true); @@ -375,7 +374,7 @@ void BKE_fluid_cache_free(FluidDomainSettings *fds, Object *ob, int cache_map) } if (cache_map & FLUID_DOMAIN_OUTDATED_GUIDE) { flags &= ~(FLUID_DOMAIN_BAKING_GUIDE | FLUID_DOMAIN_BAKED_GUIDE | FLUID_DOMAIN_OUTDATED_GUIDE); - BLI_path_join(temp_dir, sizeof(temp_dir), fds->cache_directory, FLUID_DOMAIN_DIR_GUIDE, NULL); + BLI_path_join(temp_dir, sizeof(temp_dir), fds->cache_directory, FLUID_DOMAIN_DIR_GUIDE); BLI_path_abs(temp_dir, relbase); if (BLI_exists(temp_dir)) { BLI_delete(temp_dir, true, true); @@ -434,7 +433,7 @@ static void manta_set_domain_from_mesh(FluidDomainSettings *fds, copy_v3_v3(fds->global_size, size); copy_v3_v3(fds->dp0, min); - invert_m4_m4(fds->imat, ob->obmat); + invert_m4_m4(fds->imat, ob->object_to_world); /* Prevent crash when initializing a plane as domain. */ if (!init_resolution || (size[0] < FLT_EPSILON) || (size[1] < FLT_EPSILON) || @@ -499,8 +498,8 @@ static bool fluid_modifier_init( zero_v3(fds->shift_f); add_v3_fl(fds->shift_f, 0.5f); zero_v3(fds->prev_loc); - mul_m4_v3(ob->obmat, fds->prev_loc); - copy_m4_m4(fds->obmat, ob->obmat); + mul_m4_v3(ob->object_to_world, fds->prev_loc); + copy_m4_m4(fds->obmat, ob->object_to_world); /* Set resolutions. */ if (fmd->domain->type == FLUID_DOMAIN_TYPE_GAS && @@ -567,11 +566,11 @@ static int get_light(Scene *scene, ViewLayer *view_layer, float *light) Light *la = base_tmp->object->data; if (la->type == LA_LOCAL) { - copy_v3_v3(light, base_tmp->object->obmat[3]); + copy_v3_v3(light, base_tmp->object->object_to_world[3]); return 1; } if (!found_light) { - copy_v3_v3(light, base_tmp->object->obmat[3]); + copy_v3_v3(light, base_tmp->object->object_to_world[3]); found_light = 1; } } @@ -1037,7 +1036,7 @@ static void obstacles_from_mesh(Object *coll_ob, float co[3]; /* Vertex position. */ - mul_m4_v3(coll_ob->obmat, verts[i].co); + mul_m4_v3(coll_ob->object_to_world, verts[i].co); manta_pos_to_cell(fds, verts[i].co); /* Vertex velocity. */ @@ -2100,11 +2099,11 @@ static void emit_from_mesh( float(*vert_normals)[3] = BKE_mesh_vertex_normals_for_write(me); for (i = 0; i < numverts; i++) { /* Vertex position. */ - mul_m4_v3(flow_ob->obmat, verts[i].co); + mul_m4_v3(flow_ob->object_to_world, verts[i].co); manta_pos_to_cell(fds, verts[i].co); /* Vertex normal. */ - mul_mat3_m4_v3(flow_ob->obmat, vert_normals[i]); + mul_mat3_m4_v3(flow_ob->object_to_world, vert_normals[i]); mul_mat3_m4_v3(fds->imat, vert_normals[i]); normalize_v3(vert_normals[i]); @@ -2122,7 +2121,7 @@ static void emit_from_mesh( /* Calculate emission map bounds. */ bb_boundInsert(bb, verts[i].co); } - mul_m4_v3(flow_ob->obmat, flow_center); + mul_m4_v3(flow_ob->object_to_world, flow_center); manta_pos_to_cell(fds, flow_center); /* Set emission map. @@ -2192,7 +2191,7 @@ static void adaptive_domain_adjust( float frame_shift_f[3]; float ob_loc[3] = {0}; - mul_m4_v3(ob->obmat, ob_loc); + mul_m4_v3(ob->object_to_world, ob_loc); sub_v3_v3v3(frame_shift_f, ob_loc, fds->prev_loc); copy_v3_v3(fds->prev_loc, ob_loc); @@ -3496,8 +3495,8 @@ static Mesh *create_smoke_geometry(FluidDomainSettings *fds, Mesh *orgmesh, Obje /* Calculate required shift to match domain's global position * it was originally simulated at (if object moves without manta step). */ - invert_m4_m4(ob->imat, ob->obmat); - mul_m4_v3(ob->obmat, ob_loc); + invert_m4_m4(ob->imat, ob->object_to_world); + mul_m4_v3(ob->object_to_world, ob_loc); mul_m4_v3(fds->obmat, ob_cache_loc); sub_v3_v3v3(fds->obj_shift_f, ob_cache_loc, ob_loc); /* Convert shift to local space and apply to vertices. */ @@ -3526,8 +3525,8 @@ static int manta_step( bool mode_replay = (mode == FLUID_DOMAIN_CACHE_REPLAY); /* Update object state. */ - invert_m4_m4(fds->imat, ob->obmat); - copy_m4_m4(fds->obmat, ob->obmat); + invert_m4_m4(fds->imat, ob->object_to_world); + copy_m4_m4(fds->obmat, ob->object_to_world); /* Gas domain might use adaptive domain. */ if (fds->type == FLUID_DOMAIN_TYPE_GAS) { diff --git a/source/blender/blenkernel/intern/geometry_component_instances.cc b/source/blender/blenkernel/intern/geometry_component_instances.cc index 0b5f7cbf902..be1d9524509 100644 --- a/source/blender/blenkernel/intern/geometry_component_instances.cc +++ b/source/blender/blenkernel/intern/geometry_component_instances.cc @@ -16,6 +16,7 @@ #include "BKE_attribute_math.hh" #include "BKE_geometry_set.hh" #include "BKE_geometry_set_instances.hh" +#include "BKE_instances.hh" #include "attribute_access_intern.hh" @@ -29,8 +30,8 @@ using blender::MutableSpan; using blender::Set; using blender::Span; using blender::VectorSet; - -BLI_CPP_TYPE_MAKE(InstanceReference, InstanceReference, CPPTypeFlags::None) +using blender::bke::InstanceReference; +using blender::bke::Instances; /* -------------------------------------------------------------------- */ /** \name Geometry Component Implementation @@ -40,339 +41,76 @@ InstancesComponent::InstancesComponent() : GeometryComponent(GEO_COMPONENT_TYPE_ { } -GeometryComponent *InstancesComponent::copy() const -{ - InstancesComponent *new_component = new InstancesComponent(); - new_component->instance_reference_handles_ = instance_reference_handles_; - new_component->instance_transforms_ = instance_transforms_; - new_component->references_ = references_; - new_component->attributes_ = attributes_; - return new_component; -} - -void InstancesComponent::reserve(int min_capacity) +InstancesComponent::~InstancesComponent() { - instance_reference_handles_.reserve(min_capacity); - instance_transforms_.reserve(min_capacity); - attributes_.reallocate(min_capacity); + this->clear(); } -void InstancesComponent::resize(int capacity) +GeometryComponent *InstancesComponent::copy() const { - instance_reference_handles_.resize(capacity); - instance_transforms_.resize(capacity); - attributes_.reallocate(capacity); + InstancesComponent *new_component = new InstancesComponent(); + if (instances_ != nullptr) { + new_component->instances_ = new Instances(*instances_); + new_component->ownership_ = GeometryOwnershipType::Owned; + } + return new_component; } void InstancesComponent::clear() { - instance_reference_handles_.clear(); - instance_transforms_.clear(); - attributes_.clear(); - references_.clear(); -} - -void InstancesComponent::add_instance(const int instance_handle, const float4x4 &transform) -{ - BLI_assert(instance_handle >= 0); - BLI_assert(instance_handle < references_.size()); - instance_reference_handles_.append(instance_handle); - instance_transforms_.append(transform); - attributes_.reallocate(this->instances_num()); -} - -blender::Span<int> InstancesComponent::instance_reference_handles() const -{ - return instance_reference_handles_; -} - -blender::MutableSpan<int> InstancesComponent::instance_reference_handles() -{ - return instance_reference_handles_; -} - -blender::MutableSpan<blender::float4x4> InstancesComponent::instance_transforms() -{ - return instance_transforms_; -} -blender::Span<blender::float4x4> InstancesComponent::instance_transforms() const -{ - return instance_transforms_; -} - -GeometrySet &InstancesComponent::geometry_set_from_reference(const int reference_index) -{ - /* If this assert fails, it means #ensure_geometry_instances must be called first or that the - * reference can't be converted to a geometry set. */ - BLI_assert(references_[reference_index].type() == InstanceReference::Type::GeometrySet); - - /* The const cast is okay because the instance's hash in the set - * is not changed by adjusting the data inside the geometry set. */ - return const_cast<GeometrySet &>(references_[reference_index].geometry_set()); -} - -int InstancesComponent::add_reference(const InstanceReference &reference) -{ - return references_.index_of_or_add_as(reference); -} - -blender::Span<InstanceReference> InstancesComponent::references() const -{ - return references_; -} - -template<typename T> -static void copy_data_based_on_mask(Span<T> src, MutableSpan<T> dst, IndexMask mask) -{ - BLI_assert(src.data() != dst.data()); - using namespace blender; - threading::parallel_for(mask.index_range(), 1024, [&](IndexRange range) { - for (const int i : range) { - dst[i] = src[mask[i]]; - } - }); -} - -void InstancesComponent::remove_instances(const IndexMask mask) -{ - using namespace blender; - if (mask.is_range() && mask.as_range().start() == 0) { - /* Deleting from the end of the array can be much faster since no data has to be shifted. */ - this->resize(mask.size()); - this->remove_unused_references(); - return; + BLI_assert(this->is_mutable()); + if (ownership_ == GeometryOwnershipType::Owned) { + delete instances_; } - - Vector<int> new_handles(mask.size()); - copy_data_based_on_mask<int>(this->instance_reference_handles(), new_handles, mask); - instance_reference_handles_ = std::move(new_handles); - Vector<float4x4> new_transforms(mask.size()); - copy_data_based_on_mask<float4x4>(this->instance_transforms(), new_transforms, mask); - instance_transforms_ = std::move(new_transforms); - - const bke::CustomDataAttributes &src_attributes = attributes_; - - bke::CustomDataAttributes dst_attributes; - dst_attributes.reallocate(mask.size()); - - src_attributes.foreach_attribute( - [&](const bke::AttributeIDRef &id, const bke::AttributeMetaData &meta_data) { - if (!id.should_be_kept()) { - return true; - } - - GSpan src = *src_attributes.get_for_read(id); - dst_attributes.create(id, meta_data.data_type); - GMutableSpan dst = *dst_attributes.get_for_write(id); - - attribute_math::convert_to_static_type(src.type(), [&](auto dummy) { - using T = decltype(dummy); - copy_data_based_on_mask<T>(src.typed<T>(), dst.typed<T>(), mask); - }); - return true; - }, - ATTR_DOMAIN_INSTANCE); - - attributes_ = std::move(dst_attributes); - this->remove_unused_references(); + instances_ = nullptr; } -void InstancesComponent::remove_unused_references() +bool InstancesComponent::is_empty() const { - using namespace blender; - using namespace blender::bke; - - const int tot_instances = this->instances_num(); - const int tot_references_before = references_.size(); - - if (tot_instances == 0) { - /* If there are no instances, no reference is needed. */ - references_.clear(); - return; - } - if (tot_references_before == 1) { - /* There is only one reference and at least one instance. So the only existing reference is - * used. Nothing to do here. */ - return; - } - - Array<bool> usage_by_handle(tot_references_before, false); - std::mutex mutex; - - /* Loop over all instances to see which references are used. */ - threading::parallel_for(IndexRange(tot_instances), 1000, [&](IndexRange range) { - /* Use local counter to avoid lock contention. */ - Array<bool> local_usage_by_handle(tot_references_before, false); - - for (const int i : range) { - const int handle = instance_reference_handles_[i]; - BLI_assert(handle >= 0 && handle < tot_references_before); - local_usage_by_handle[handle] = true; - } - - std::lock_guard lock{mutex}; - for (const int i : IndexRange(tot_references_before)) { - usage_by_handle[i] |= local_usage_by_handle[i]; - } - }); - - if (!usage_by_handle.as_span().contains(false)) { - /* All references are used. */ - return; - } - - /* Create new references and a mapping for the handles. */ - Vector<int> handle_mapping; - VectorSet<InstanceReference> new_references; - int next_new_handle = 0; - bool handles_have_to_be_updated = false; - for (const int old_handle : IndexRange(tot_references_before)) { - if (!usage_by_handle[old_handle]) { - /* Add some dummy value. It won't be read again. */ - handle_mapping.append(-1); - } - else { - const InstanceReference &reference = references_[old_handle]; - handle_mapping.append(next_new_handle); - new_references.add_new(reference); - if (old_handle != next_new_handle) { - handles_have_to_be_updated = true; - } - next_new_handle++; + if (instances_ != nullptr) { + if (instances_->instances_num() > 0) { + return false; } } - references_ = new_references; - - if (!handles_have_to_be_updated) { - /* All remaining handles are the same as before, so they don't have to be updated. This happens - * when unused handles are only at the end. */ - return; - } - - /* Update handles of instances. */ - threading::parallel_for(IndexRange(tot_instances), 1000, [&](IndexRange range) { - for (const int i : range) { - instance_reference_handles_[i] = handle_mapping[instance_reference_handles_[i]]; - } - }); -} - -int InstancesComponent::instances_num() const -{ - return instance_transforms_.size(); -} - -int InstancesComponent::references_num() const -{ - return references_.size(); -} - -bool InstancesComponent::is_empty() const -{ - return this->instance_reference_handles_.size() == 0; + return true; } bool InstancesComponent::owns_direct_data() const { - for (const InstanceReference &reference : references_) { - if (!reference.owns_direct_data()) { - return false; - } + if (instances_ != nullptr) { + return instances_->owns_direct_data(); } return true; } void InstancesComponent::ensure_owns_direct_data() { - BLI_assert(this->is_mutable()); - for (const InstanceReference &const_reference : references_) { - /* Const cast is fine because we are not changing anything that would change the hash of the - * reference. */ - InstanceReference &reference = const_cast<InstanceReference &>(const_reference); - reference.ensure_owns_direct_data(); + if (instances_ != nullptr) { + instances_->ensure_owns_direct_data(); } } -static blender::Array<int> generate_unique_instance_ids(Span<int> original_ids) +const blender::bke::Instances *InstancesComponent::get_for_read() const { - using namespace blender; - Array<int> unique_ids(original_ids.size()); - - Set<int> used_unique_ids; - used_unique_ids.reserve(original_ids.size()); - Vector<int> instances_with_id_collision; - for (const int instance_index : original_ids.index_range()) { - const int original_id = original_ids[instance_index]; - if (used_unique_ids.add(original_id)) { - /* The original id has not been used by another instance yet. */ - unique_ids[instance_index] = original_id; - } - else { - /* The original id of this instance collided with a previous instance, it needs to be looked - * at again in a second pass. Don't generate a new random id here, because this might collide - * with other existing ids. */ - instances_with_id_collision.append(instance_index); - } - } - - Map<int, RandomNumberGenerator> generator_by_original_id; - for (const int instance_index : instances_with_id_collision) { - const int original_id = original_ids[instance_index]; - RandomNumberGenerator &rng = generator_by_original_id.lookup_or_add_cb(original_id, [&]() { - RandomNumberGenerator rng; - rng.seed_random(original_id); - return rng; - }); - - const int max_iteration = 100; - for (int iteration = 0;; iteration++) { - /* Try generating random numbers until an unused one has been found. */ - const int random_id = rng.get_int32(); - if (used_unique_ids.add(random_id)) { - /* This random id is not used by another instance. */ - unique_ids[instance_index] = random_id; - break; - } - if (iteration == max_iteration) { - /* It seems to be very unlikely that we ever run into this case (assuming there are less - * than 2^30 instances). However, if that happens, it's better to use an id that is not - * unique than to be stuck in an infinite loop. */ - unique_ids[instance_index] = original_id; - break; - } - } - } - - return unique_ids; + return instances_; } -blender::Span<int> InstancesComponent::almost_unique_ids() const +blender::bke::Instances *InstancesComponent::get_for_write() { - std::lock_guard lock(almost_unique_ids_mutex_); - std::optional<GSpan> instance_ids_gspan = attributes_.get_for_read("id"); - if (instance_ids_gspan) { - Span<int> instance_ids = instance_ids_gspan->typed<int>(); - if (almost_unique_ids_.size() != instance_ids.size()) { - almost_unique_ids_ = generate_unique_instance_ids(instance_ids); - } - } - else { - almost_unique_ids_.reinitialize(this->instances_num()); - for (const int i : almost_unique_ids_.index_range()) { - almost_unique_ids_[i] = i; - } + BLI_assert(this->is_mutable()); + if (ownership_ == GeometryOwnershipType::ReadOnly) { + instances_ = new Instances(*instances_); + ownership_ = GeometryOwnershipType::Owned; } - return almost_unique_ids_; + return instances_; } -blender::bke::CustomDataAttributes &InstancesComponent::instance_attributes() +void InstancesComponent::replace(Instances *instances, GeometryOwnershipType ownership) { - return this->attributes_; -} - -const blender::bke::CustomDataAttributes &InstancesComponent::instance_attributes() const -{ - return this->attributes_; + BLI_assert(this->is_mutable()); + this->clear(); + instances_ = instances; + ownership_ = ownership; } namespace blender::bke { @@ -397,16 +135,21 @@ class InstancePositionAttributeProvider final : public BuiltinAttributeProvider GVArray try_get_for_read(const void *owner) const final { - const InstancesComponent &instances_component = *static_cast<const InstancesComponent *>( - owner); - Span<float4x4> transforms = instances_component.instance_transforms(); + const Instances *instances = static_cast<const Instances *>(owner); + if (instances == nullptr) { + return {}; + } + Span<float4x4> transforms = instances->transforms(); return VArray<float3>::ForDerivedSpan<float4x4, get_transform_position>(transforms); } GAttributeWriter try_get_for_write(void *owner) const final { - InstancesComponent &instances_component = *static_cast<InstancesComponent *>(owner); - MutableSpan<float4x4> transforms = instances_component.instance_transforms(); + Instances *instances = static_cast<Instances *>(owner); + if (instances == nullptr) { + return {}; + } + MutableSpan<float4x4> transforms = instances->transforms(); return {VMutableArray<float3>::ForDerivedSpan<float4x4, get_transform_position, set_transform_position>(transforms), @@ -434,16 +177,16 @@ static ComponentAttributeProviders create_attribute_providers_for_instances() static InstancePositionAttributeProvider position; static CustomDataAccessInfo instance_custom_data_access = { [](void *owner) -> CustomData * { - InstancesComponent &inst = *static_cast<InstancesComponent *>(owner); - return &inst.instance_attributes().data; + Instances *instances = static_cast<Instances *>(owner); + return &instances->custom_data_attributes().data; }, [](const void *owner) -> const CustomData * { - const InstancesComponent &inst = *static_cast<const InstancesComponent *>(owner); - return &inst.instance_attributes().data; + const Instances *instances = static_cast<const Instances *>(owner); + return &instances->custom_data_attributes().data; }, [](const void *owner) -> int { - const InstancesComponent &inst = *static_cast<const InstancesComponent *>(owner); - return inst.instances_num(); + const Instances *instances = static_cast<const Instances *>(owner); + return instances->instances_num(); }}; /** @@ -479,10 +222,10 @@ static AttributeAccessorFunctions get_instances_accessor_functions() if (owner == nullptr) { return 0; } - const InstancesComponent &instances = *static_cast<const InstancesComponent *>(owner); + const Instances *instances = static_cast<const Instances *>(owner); switch (domain) { case ATTR_DOMAIN_INSTANCE: - return instances.instances_num(); + return instances->instances_num(); default: return 0; } @@ -508,18 +251,30 @@ static const AttributeAccessorFunctions &get_instances_accessor_functions_ref() return fn; } +blender::bke::AttributeAccessor Instances::attributes() const +{ + return blender::bke::AttributeAccessor(this, + blender::bke::get_instances_accessor_functions_ref()); +} + +blender::bke::MutableAttributeAccessor Instances::attributes_for_write() +{ + return blender::bke::MutableAttributeAccessor( + this, blender::bke::get_instances_accessor_functions_ref()); +} + } // namespace blender::bke std::optional<blender::bke::AttributeAccessor> InstancesComponent::attributes() const { - return blender::bke::AttributeAccessor(this, + return blender::bke::AttributeAccessor(instances_, blender::bke::get_instances_accessor_functions_ref()); } std::optional<blender::bke::MutableAttributeAccessor> InstancesComponent::attributes_for_write() { return blender::bke::MutableAttributeAccessor( - this, blender::bke::get_instances_accessor_functions_ref()); + instances_, blender::bke::get_instances_accessor_functions_ref()); } /** \} */ diff --git a/source/blender/blenkernel/intern/geometry_fields.cc b/source/blender/blenkernel/intern/geometry_fields.cc index b492af4af77..82ffda57398 100644 --- a/source/blender/blenkernel/intern/geometry_fields.cc +++ b/source/blender/blenkernel/intern/geometry_fields.cc @@ -4,6 +4,7 @@ #include "BKE_curves.hh" #include "BKE_geometry_fields.hh" #include "BKE_geometry_set.hh" +#include "BKE_instances.hh" #include "BKE_mesh.h" #include "BKE_pointcloud.h" #include "BKE_type_conversions.hh" @@ -64,7 +65,7 @@ GeometryFieldContext::GeometryFieldContext(const GeometryComponent &component, case GEO_COMPONENT_TYPE_INSTANCES: { const InstancesComponent &instances_component = static_cast<const InstancesComponent &>( component); - geometry_ = &instances_component; + geometry_ = instances_component.get_for_read(); break; } case GEO_COMPONENT_TYPE_VOLUME: @@ -86,7 +87,7 @@ GeometryFieldContext::GeometryFieldContext(const PointCloud &points) : geometry_(&points), type_(GEO_COMPONENT_TYPE_POINT_CLOUD), domain_(ATTR_DOMAIN_POINT) { } -GeometryFieldContext::GeometryFieldContext(const InstancesComponent &instances) +GeometryFieldContext::GeometryFieldContext(const Instances &instances) : geometry_(&instances), type_(GEO_COMPONENT_TYPE_INSTANCES), domain_(ATTR_DOMAIN_INSTANCE) { } @@ -102,7 +103,7 @@ std::optional<AttributeAccessor> GeometryFieldContext::attributes() const if (const PointCloud *pointcloud = this->pointcloud()) { return pointcloud->attributes(); } - if (const InstancesComponent *instances = this->instances()) { + if (const Instances *instances = this->instances()) { return instances->attributes(); } return {}; @@ -124,11 +125,10 @@ const PointCloud *GeometryFieldContext::pointcloud() const static_cast<const PointCloud *>(geometry_) : nullptr; } -const InstancesComponent *GeometryFieldContext::instances() const +const Instances *GeometryFieldContext::instances() const { - return this->type() == GEO_COMPONENT_TYPE_INSTANCES ? - static_cast<const InstancesComponent *>(geometry_) : - nullptr; + return this->type() == GEO_COMPONENT_TYPE_INSTANCES ? static_cast<const Instances *>(geometry_) : + nullptr; } GVArray GeometryFieldInput::get_varray_for_context(const fn::FieldContext &context, @@ -230,7 +230,7 @@ GVArray InstancesFieldInput::get_varray_for_context(const fn::FieldContext &cont { if (const GeometryFieldContext *geometry_context = dynamic_cast<const GeometryFieldContext *>( &context)) { - if (const InstancesComponent *instances = geometry_context->instances()) { + if (const Instances *instances = geometry_context->instances()) { return this->get_varray_for_context(*instances, mask); } } diff --git a/source/blender/blenkernel/intern/geometry_set.cc b/source/blender/blenkernel/intern/geometry_set.cc index 46ff8141504..ee4c398c3d6 100644 --- a/source/blender/blenkernel/intern/geometry_set.cc +++ b/source/blender/blenkernel/intern/geometry_set.cc @@ -9,6 +9,7 @@ #include "BKE_attribute.h" #include "BKE_curves.hh" #include "BKE_geometry_set.hh" +#include "BKE_instances.hh" #include "BKE_lib_id.h" #include "BKE_mesh.h" #include "BKE_mesh_wrapper.h" @@ -31,6 +32,8 @@ using blender::MutableSpan; using blender::Span; using blender::StringRef; using blender::Vector; +using blender::bke::InstanceReference; +using blender::bke::Instances; /* -------------------------------------------------------------------- */ /** \name Geometry Component @@ -256,8 +259,7 @@ std::ostream &operator<<(std::ostream &stream, const GeometrySet &geometry_set) parts.append(std::to_string(BKE_volume_num_grids(volume)) + " volume grids"); } if (geometry_set.has_instances()) { - parts.append(std::to_string( - geometry_set.get_component_for_read<InstancesComponent>()->instances_num()) + + parts.append(std::to_string(geometry_set.get_instances_for_read()->instances_num()) + " instances"); } if (geometry_set.get_curve_edit_hints_for_read()) { @@ -338,6 +340,12 @@ const Curves *GeometrySet::get_curves_for_read() const return (component == nullptr) ? nullptr : component->get_for_read(); } +const Instances *GeometrySet::get_instances_for_read() const +{ + const InstancesComponent *component = this->get_component_for_read<InstancesComponent>(); + return (component == nullptr) ? nullptr : component->get_for_read(); +} + const blender::bke::CurvesEditHints *GeometrySet::get_curve_edit_hints_for_read() const { const GeometryComponentEditData *component = @@ -354,7 +362,8 @@ bool GeometrySet::has_pointcloud() const bool GeometrySet::has_instances() const { const InstancesComponent *component = this->get_component_for_read<InstancesComponent>(); - return component != nullptr && component->instances_num() >= 1; + return component != nullptr && component->get_for_read() != nullptr && + component->get_for_read()->instances_num() >= 1; } bool GeometrySet::has_volume() const @@ -428,6 +437,14 @@ GeometrySet GeometrySet::create_with_curves(Curves *curves, GeometryOwnershipTyp return geometry_set; } +GeometrySet GeometrySet::create_with_instances(Instances *instances, + GeometryOwnershipType ownership) +{ + GeometrySet geometry_set; + geometry_set.replace_instances(instances, ownership); + return geometry_set; +} + void GeometrySet::replace_mesh(Mesh *mesh, GeometryOwnershipType ownership) { if (mesh == nullptr) { @@ -456,6 +473,20 @@ void GeometrySet::replace_curves(Curves *curves, GeometryOwnershipType ownership component.replace(curves, ownership); } +void GeometrySet::replace_instances(Instances *instances, GeometryOwnershipType ownership) +{ + if (instances == nullptr) { + this->remove<InstancesComponent>(); + return; + } + if (instances == this->get_instances_for_read()) { + return; + } + this->remove<InstancesComponent>(); + InstancesComponent &component = this->get_component_for_write<InstancesComponent>(); + component.replace(instances, ownership); +} + void GeometrySet::replace_pointcloud(PointCloud *pointcloud, GeometryOwnershipType ownership) { if (pointcloud == nullptr) { @@ -508,6 +539,12 @@ Curves *GeometrySet::get_curves_for_write() return component == nullptr ? nullptr : component->get_for_write(); } +Instances *GeometrySet::get_instances_for_write() +{ + InstancesComponent *component = this->get_component_ptr<InstancesComponent>(); + return component == nullptr ? nullptr : component->get_for_write(); +} + blender::bke::CurvesEditHints *GeometrySet::get_curve_edit_hints_for_write() { if (!this->has<GeometryComponentEditData>()) { @@ -539,7 +576,7 @@ void GeometrySet::attribute_foreach(const Span<GeometryComponentType> component_ } } if (include_instances && this->has_instances()) { - const InstancesComponent &instances = *this->get_component_for_read<InstancesComponent>(); + const Instances &instances = *this->get_instances_for_read(); instances.foreach_referenced_geometry([&](const GeometrySet &instance_geometry_set) { instance_geometry_set.attribute_foreach(component_types, include_instances, callback); }); @@ -570,7 +607,10 @@ void GeometrySet::gather_attributes_for_propagation( return; } } - + if (meta_data.data_type == CD_PROP_STRING) { + /* Propagating string attributes is not supported yet. */ + return; + } if (!attribute_id.should_be_kept()) { return; } @@ -611,7 +651,7 @@ static void gather_component_types_recursive(const GeometrySet &geometry_set, if (!include_instances) { return; } - const InstancesComponent *instances = geometry_set.get_component_for_read<InstancesComponent>(); + const blender::bke::Instances *instances = geometry_set.get_instances_for_read(); if (instances == nullptr) { return; } @@ -638,12 +678,11 @@ static void gather_mutable_geometry_sets(GeometrySet &geometry_set, } /* In the future this can be improved by deduplicating instance references across different * instances. */ - InstancesComponent &instances_component = - geometry_set.get_component_for_write<InstancesComponent>(); - instances_component.ensure_geometry_instances(); - for (const int handle : instances_component.references().index_range()) { - if (instances_component.references()[handle].type() == InstanceReference::Type::GeometrySet) { - GeometrySet &instance_geometry = instances_component.geometry_set_from_reference(handle); + Instances &instances = *geometry_set.get_instances_for_write(); + instances.ensure_geometry_instances(); + for (const int handle : instances.references().index_range()) { + if (instances.references()[handle].type() == InstanceReference::Type::GeometrySet) { + GeometrySet &instance_geometry = instances.geometry_set_from_reference(handle); gather_mutable_geometry_sets(instance_geometry, r_geometry_sets); } } diff --git a/source/blender/blenkernel/intern/geometry_set_instances.cc b/source/blender/blenkernel/intern/geometry_set_instances.cc index 0ae49a586f1..2b36020b4e7 100644 --- a/source/blender/blenkernel/intern/geometry_set_instances.cc +++ b/source/blender/blenkernel/intern/geometry_set_instances.cc @@ -2,6 +2,7 @@ #include "BKE_collection.h" #include "BKE_geometry_set_instances.hh" +#include "BKE_instances.hh" #include "BKE_material.h" #include "BKE_mesh.h" #include "BKE_mesh_wrapper.h" @@ -62,12 +63,11 @@ GeometrySet object_get_evaluated_geometry_set(const Object &object) return geometry_set; } if (object.type == OB_EMPTY && object.instance_collection != nullptr) { - GeometrySet geometry_set; Collection &collection = *object.instance_collection; - InstancesComponent &instances = geometry_set.get_component_for_write<InstancesComponent>(); - const int handle = instances.add_reference(collection); - instances.add_instance(handle, float4x4::identity()); - return geometry_set; + std::unique_ptr<Instances> instances = std::make_unique<Instances>(); + const int handle = instances->add_reference(collection); + instances->add_instance(handle, float4x4::identity()); + return GeometrySet::create_with_instances(instances.release()); } /* Return by value since there is not always an existing geometry set owned elsewhere to use. */ @@ -98,7 +98,7 @@ static void geometry_set_collect_recursive_collection(const Collection &collecti LISTBASE_FOREACH (const CollectionObject *, collection_object, &collection.gobject) { BLI_assert(collection_object->ob != nullptr); const Object &object = *collection_object->ob; - const float4x4 object_transform = transform * object.obmat; + const float4x4 object_transform = transform * object.object_to_world; geometry_set_collect_recursive_object(object, object_transform, r_sets); } LISTBASE_FOREACH (const CollectionChild *, collection_child, &collection.children) { @@ -115,12 +115,11 @@ static void geometry_set_collect_recursive(const GeometrySet &geometry_set, r_sets.append({geometry_set, {transform}}); if (geometry_set.has_instances()) { - const InstancesComponent &instances_component = - *geometry_set.get_component_for_read<InstancesComponent>(); + const Instances &instances = *geometry_set.get_instances_for_read(); - Span<float4x4> transforms = instances_component.instance_transforms(); - Span<int> handles = instances_component.instance_reference_handles(); - Span<InstanceReference> references = instances_component.references(); + Span<float4x4> transforms = instances.transforms(); + Span<int> handles = instances.reference_handles(); + Span<InstanceReference> references = instances.references(); for (const int i : transforms.index_range()) { const InstanceReference &reference = references[handles[i]]; const float4x4 instance_transform = transform * transforms[i]; @@ -156,9 +155,7 @@ void geometry_set_gather_instances(const GeometrySet &geometry_set, geometry_set_collect_recursive(geometry_set, float4x4::identity(), r_instance_groups); } -} // namespace blender::bke - -void InstancesComponent::foreach_referenced_geometry( +void Instances::foreach_referenced_geometry( blender::FunctionRef<void(const GeometrySet &geometry_set)> callback) const { using namespace blender::bke; @@ -191,7 +188,7 @@ void InstancesComponent::foreach_referenced_geometry( } } -void InstancesComponent::ensure_geometry_instances() +void Instances::ensure_geometry_instances() { using namespace blender; using namespace blender::bke; @@ -211,9 +208,7 @@ void InstancesComponent::ensure_geometry_instances() const Object &object = reference.object(); GeometrySet object_geometry_set = object_get_evaluated_geometry_set(object); if (object_geometry_set.has_instances()) { - InstancesComponent &component = - object_geometry_set.get_component_for_write<InstancesComponent>(); - component.ensure_geometry_instances(); + object_geometry_set.get_instances_for_write()->ensure_geometry_instances(); } new_references.add_new(std::move(object_geometry_set)); break; @@ -221,22 +216,22 @@ void InstancesComponent::ensure_geometry_instances() case InstanceReference::Type::Collection: { /* Create a new reference that contains a geometry set that contains all objects from the * collection as instances. */ - GeometrySet collection_geometry_set; - InstancesComponent &component = - collection_geometry_set.get_component_for_write<InstancesComponent>(); + std::unique_ptr<Instances> instances = std::make_unique<Instances>(); Collection &collection = reference.collection(); FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN (&collection, object) { - const int handle = component.add_reference(*object); - component.add_instance(handle, object->obmat); - float4x4 &transform = component.instance_transforms().last(); + const int handle = instances->add_reference(*object); + instances->add_instance(handle, object->object_to_world); + float4x4 &transform = instances->transforms().last(); sub_v3_v3(transform.values[3], collection.instance_offset); } FOREACH_COLLECTION_OBJECT_RECURSIVE_END; - component.ensure_geometry_instances(); - new_references.add_new(std::move(collection_geometry_set)); + instances->ensure_geometry_instances(); + new_references.add_new(GeometrySet::create_with_instances(instances.release())); break; } } } references_ = std::move(new_references); } + +} // namespace blender::bke diff --git a/source/blender/blenkernel/intern/gpencil.c b/source/blender/blenkernel/intern/gpencil.c index 45e56717d6a..666142e3a54 100644 --- a/source/blender/blenkernel/intern/gpencil.c +++ b/source/blender/blenkernel/intern/gpencil.c @@ -2691,7 +2691,7 @@ void BKE_gpencil_layer_transform_matrix_get(const Depsgraph *depsgraph, /* if not layer parented, try with object parented */ if (obparent_eval == NULL) { if ((ob_eval != NULL) && (ob_eval->type == OB_GPENCIL)) { - copy_m4_m4(diff_mat, ob_eval->obmat); + copy_m4_m4(diff_mat, ob_eval->object_to_world); mul_m4_m4m4(diff_mat, diff_mat, gpl->layer_mat); return; } @@ -2701,8 +2701,8 @@ void BKE_gpencil_layer_transform_matrix_get(const Depsgraph *depsgraph, } if (ELEM(gpl->partype, PAROBJECT, PARSKEL)) { - mul_m4_m4m4(diff_mat, obparent_eval->obmat, gpl->inverse); - add_v3_v3(diff_mat[3], ob_eval->obmat[3]); + mul_m4_m4m4(diff_mat, obparent_eval->object_to_world, gpl->inverse); + add_v3_v3(diff_mat[3], ob_eval->object_to_world[3]); mul_m4_m4m4(diff_mat, diff_mat, gpl->layer_mat); return; } @@ -2710,14 +2710,14 @@ void BKE_gpencil_layer_transform_matrix_get(const Depsgraph *depsgraph, bPoseChannel *pchan = BKE_pose_channel_find_name(obparent_eval->pose, gpl->parsubstr); if (pchan) { float tmp_mat[4][4]; - mul_m4_m4m4(tmp_mat, obparent_eval->obmat, pchan->pose_mat); + mul_m4_m4m4(tmp_mat, obparent_eval->object_to_world, pchan->pose_mat); mul_m4_m4m4(diff_mat, tmp_mat, gpl->inverse); - add_v3_v3(diff_mat[3], ob_eval->obmat[3]); + add_v3_v3(diff_mat[3], ob_eval->object_to_world[3]); } else { /* if bone not found use object (armature) */ - mul_m4_m4m4(diff_mat, obparent_eval->obmat, gpl->inverse); - add_v3_v3(diff_mat[3], ob_eval->obmat[3]); + mul_m4_m4m4(diff_mat, obparent_eval->object_to_world, gpl->inverse); + add_v3_v3(diff_mat[3], ob_eval->object_to_world[3]); } mul_m4_m4m4(diff_mat, diff_mat, gpl->layer_mat); return; @@ -2771,12 +2771,12 @@ void BKE_gpencil_update_layer_transforms(const Depsgraph *depsgraph, Object *ob) Object *ob_parent = DEG_get_evaluated_object(depsgraph, gpl->parent); /* calculate new matrix */ if (ELEM(gpl->partype, PAROBJECT, PARSKEL)) { - mul_m4_m4m4(cur_mat, ob->imat, ob_parent->obmat); + mul_m4_m4m4(cur_mat, ob->imat, ob_parent->object_to_world); } else if (gpl->partype == PARBONE) { bPoseChannel *pchan = BKE_pose_channel_find_name(ob_parent->pose, gpl->parsubstr); if (pchan != NULL) { - mul_m4_series(cur_mat, ob->imat, ob_parent->obmat, pchan->pose_mat); + mul_m4_series(cur_mat, ob->imat, ob_parent->object_to_world, pchan->pose_mat); } else { unit_m4(cur_mat); diff --git a/source/blender/blenkernel/intern/gpencil_geom.cc b/source/blender/blenkernel/intern/gpencil_geom.cc index 52fcdef8a43..9297663b157 100644 --- a/source/blender/blenkernel/intern/gpencil_geom.cc +++ b/source/blender/blenkernel/intern/gpencil_geom.cc @@ -789,7 +789,10 @@ bool BKE_gpencil_stroke_stretch(bGPDstroke *gps, /** \name Stroke Trim * \{ */ -bool BKE_gpencil_stroke_trim_points(bGPDstroke *gps, const int index_from, const int index_to) +bool BKE_gpencil_stroke_trim_points(bGPDstroke *gps, + const int index_from, + const int index_to, + const bool keep_point) { bGPDspoint *pt = gps->points, *new_pt; MDeformVert *dv, *new_dv; @@ -800,7 +803,7 @@ bool BKE_gpencil_stroke_trim_points(bGPDstroke *gps, const int index_from, const return false; } - if (new_count == 1) { + if ((!keep_point) && (new_count == 1)) { if (gps->dvert) { BKE_gpencil_free_stroke_weights(gps); MEM_freeN(gps->dvert); @@ -894,7 +897,7 @@ bool BKE_gpencil_stroke_split(bGPdata *gpd, /* Trim the original stroke into a shorter one. * Keep the end point. */ - BKE_gpencil_stroke_trim_points(gps, 0, old_count); + BKE_gpencil_stroke_trim_points(gps, 0, old_count, false); BKE_gpencil_stroke_geometry_update(gpd, gps); return true; } @@ -917,7 +920,7 @@ bool BKE_gpencil_stroke_shrink(bGPDstroke *gps, const float dist, const short mo if (gps->totpoints == 1) { second_last = &pt[1]; if (len_v3v3(&second_last->x, &pt->x) < dist) { - BKE_gpencil_stroke_trim_points(gps, 0, 0); + BKE_gpencil_stroke_trim_points(gps, 0, 0, false); return true; } } @@ -969,7 +972,7 @@ bool BKE_gpencil_stroke_shrink(bGPDstroke *gps, const float dist, const short mo index_start = index_end = 0; /* no length left to cut */ } - BKE_gpencil_stroke_trim_points(gps, index_start, index_end); + BKE_gpencil_stroke_trim_points(gps, index_start, index_end, false); if (gps->totpoints == 0) { return false; @@ -3562,8 +3565,8 @@ void BKE_gpencil_stroke_start_set(bGPDstroke *gps, int start_idx) } bGPDstroke *gps_b = BKE_gpencil_stroke_duplicate(gps, true, false); - BKE_gpencil_stroke_trim_points(gps_b, 0, start_idx - 1); - BKE_gpencil_stroke_trim_points(gps, start_idx, gps->totpoints - 1); + BKE_gpencil_stroke_trim_points(gps_b, 0, start_idx - 1, true); + BKE_gpencil_stroke_trim_points(gps, start_idx, gps->totpoints - 1, true); /* Join both strokes. */ BKE_gpencil_stroke_join(gps, gps_b, false, false, false, false); diff --git a/source/blender/blenkernel/intern/gpencil_modifier.c b/source/blender/blenkernel/intern/gpencil_modifier.c index c84ee2e4a56..1ad7aeed41c 100644 --- a/source/blender/blenkernel/intern/gpencil_modifier.c +++ b/source/blender/blenkernel/intern/gpencil_modifier.c @@ -942,7 +942,7 @@ void BKE_gpencil_modifier_blend_read_data(BlendDataReader *reader, ListBase *lb) BLO_read_data_address(reader, &gpmd->curve_intensity); if (gpmd->curve_intensity) { BKE_curvemapping_blend_read(reader, gpmd->curve_intensity); - /* initialize the curve. Maybe this could be moved to modififer logic */ + /* Initialize the curve. Maybe this could be moved to modifier logic. */ BKE_curvemapping_init(gpmd->curve_intensity); } } diff --git a/source/blender/blenkernel/intern/icons.cc b/source/blender/blenkernel/intern/icons.cc index dc1d23de7e0..7fd0515b52c 100644 --- a/source/blender/blenkernel/intern/icons.cc +++ b/source/blender/blenkernel/intern/icons.cc @@ -530,7 +530,7 @@ void BKE_previewimg_ensure(PreviewImage *prv, const int size) thumb = IMB_thumb_manage(filepath, THB_LARGE, (ThumbSource)source); if (thumb) { - /* PreviewImage assumes premultiplied alhpa... */ + /* #PreviewImage assumes pre-multiplied alpha. */ IMB_premultiply_alpha(thumb); if (do_preview) { diff --git a/source/blender/blenkernel/intern/image.cc b/source/blender/blenkernel/intern/image.cc index 409eb0067b5..eae8b454189 100644 --- a/source/blender/blenkernel/intern/image.cc +++ b/source/blender/blenkernel/intern/image.cc @@ -297,7 +297,7 @@ static void image_foreach_path(ID *id, BPathForeachPathData *bpath_data) /* Put the filepath back together using the new directory and the original file name. */ char new_dir[FILE_MAXDIR]; BLI_split_dir_part(temp_path, new_dir, sizeof(new_dir)); - BLI_join_dirfile(ima->filepath, sizeof(ima->filepath), new_dir, orig_file); + BLI_path_join(ima->filepath, sizeof(ima->filepath), new_dir, orig_file); } } else { @@ -3082,16 +3082,10 @@ void BKE_image_signal(Main *bmain, Image *ima, ImageUser *iuser, int signal) /* Free all but the first tile. */ image_remove_all_tiles(ima); - /* If the remaining tile is generated, we need to again ensure that we - * wouldn't continue to use the old filepath. - * - * Otherwise, if this used to be a UDIM image, get the concrete filepath associated + /* If this used to be a UDIM image, get the concrete filepath associated * with the remaining tile and use that as the new filepath. */ ImageTile *base_tile = BKE_image_get_tile(ima, 0); - if ((base_tile->gen_flag & IMA_GEN_TILE) != 0) { - ima->filepath[0] = '\0'; - } - else if (BKE_image_is_filename_tokenized(ima->filepath)) { + if (BKE_image_is_filename_tokenized(ima->filepath)) { const bool was_relative = BLI_path_is_rel(ima->filepath); eUDIM_TILE_FORMAT tile_format; @@ -3183,10 +3177,14 @@ void BKE_image_signal(Main *bmain, Image *ima, ImageUser *iuser, int signal) * left. */ image_remove_all_tiles(ima); - int remaining_tile_number = ((ImageTile *)ima->tiles.first)->tile_number; + ImageTile *base_tile = BKE_image_get_tile(ima, 0); + int remaining_tile_number = base_tile->tile_number; bool needs_final_cleanup = true; - /* Add in all the new tiles. */ + /* Add in all the new tiles. As the image is proven to be on disk at this point, remove + * the generation flag from the remaining tile in case this was previously a generated + * image. */ + base_tile->gen_flag &= ~IMA_GEN_TILE; LISTBASE_FOREACH (LinkData *, new_tile, &new_tiles) { int new_tile_number = POINTER_AS_INT(new_tile->data); BKE_image_add_tile(ima, new_tile_number, nullptr); @@ -3202,6 +3200,11 @@ void BKE_image_signal(Main *bmain, Image *ima, ImageUser *iuser, int signal) } BLI_freelistN(&new_tiles); } + else if (ima->filepath[0] != '\0') { + /* If the filepath is set at this point remove the generation flag. */ + ImageTile *base_tile = BKE_image_get_tile(ima, 0); + base_tile->gen_flag &= ~IMA_GEN_TILE; + } if (iuser) { image_tag_reload(ima, nullptr, iuser, ima); @@ -3331,7 +3334,7 @@ bool BKE_image_get_tile_info(char *filepath, ListBase *tiles, int *r_tile_start, MEM_SAFE_FREE(udim_pattern); if (all_valid_udim && min_udim <= IMA_UDIM_MAX) { - BLI_join_dirfile(filepath, FILE_MAX, dirname, filename); + BLI_path_join(filepath, FILE_MAX, dirname, filename); *r_tile_start = min_udim; *r_tile_range = max_udim - min_udim + 1; diff --git a/source/blender/blenkernel/intern/image_format.cc b/source/blender/blenkernel/intern/image_format.cc index 8d1aeac76fb..5b861eff166 100644 --- a/source/blender/blenkernel/intern/image_format.cc +++ b/source/blender/blenkernel/intern/image_format.cc @@ -201,6 +201,7 @@ bool BKE_imtype_is_movie(const char imtype) case R_IMF_IMTYPE_H264: case R_IMF_IMTYPE_THEORA: case R_IMF_IMTYPE_XVID: + case R_IMF_IMTYPE_AV1: return true; } return false; @@ -433,7 +434,8 @@ static bool do_add_image_extension(char *string, R_IMF_IMTYPE_FFMPEG, R_IMF_IMTYPE_H264, R_IMF_IMTYPE_THEORA, - R_IMF_IMTYPE_XVID)) { + R_IMF_IMTYPE_XVID, + R_IMF_IMTYPE_AV1)) { if (!BLI_path_extension_check(string, extension_test = ".png")) { extension = extension_test; } @@ -627,7 +629,8 @@ void BKE_image_format_to_imbuf(ImBuf *ibuf, const ImageFormatData *imf) R_IMF_IMTYPE_FFMPEG, R_IMF_IMTYPE_H264, R_IMF_IMTYPE_THEORA, - R_IMF_IMTYPE_XVID)) { + R_IMF_IMTYPE_XVID, + R_IMF_IMTYPE_AV1)) { ibuf->ftype = IMB_FTYPE_PNG; if (imtype == R_IMF_IMTYPE_PNG) { diff --git a/source/blender/blenkernel/intern/image_save.cc b/source/blender/blenkernel/intern/image_save.cc index e227f9cba5e..003211e6288 100644 --- a/source/blender/blenkernel/intern/image_save.cc +++ b/source/blender/blenkernel/intern/image_save.cc @@ -175,12 +175,12 @@ bool BKE_image_save_options_init(ImageSaveOptions *opts, BLI_strncpy(opts->filepath, G.ima, sizeof(opts->filepath)); } else { - BLI_path_join(opts->filepath, sizeof(opts->filepath), "//", DATA_("untitled"), nullptr); + BLI_path_join(opts->filepath, sizeof(opts->filepath), "//", DATA_("untitled")); BLI_path_abs(opts->filepath, BKE_main_blendfile_path(bmain)); } } else { - BLI_path_join(opts->filepath, sizeof(opts->filepath), "//", ima->id.name + 2, nullptr); + BLI_path_join(opts->filepath, sizeof(opts->filepath), "//", ima->id.name + 2); BLI_path_make_safe(opts->filepath); BLI_path_abs(opts->filepath, is_prev_save ? G.ima : BKE_main_blendfile_path(bmain)); } @@ -968,6 +968,7 @@ bool BKE_image_render_write(ReportList *reports, /* optional preview images for exr */ if (ok && (image_format.flag & R_IMF_FLAG_PREVIEW_JPG)) { image_format.imtype = R_IMF_IMTYPE_JPEG90; + image_format.depth = R_IMF_CHAN_DEPTH_8; if (BLI_path_extension_check(filepath, ".exr")) { filepath[strlen(filepath) - 4] = 0; @@ -1025,6 +1026,7 @@ bool BKE_image_render_write(ReportList *reports, /* optional preview images for exr */ if (ok && is_exr_rr && (image_format.flag & R_IMF_FLAG_PREVIEW_JPG)) { image_format.imtype = R_IMF_IMTYPE_JPEG90; + image_format.depth = R_IMF_CHAN_DEPTH_8; if (BLI_path_extension_check(filepath, ".exr")) { filepath[strlen(filepath) - 4] = 0; diff --git a/source/blender/blenkernel/intern/instances.cc b/source/blender/blenkernel/intern/instances.cc new file mode 100644 index 00000000000..4675562e927 --- /dev/null +++ b/source/blender/blenkernel/intern/instances.cc @@ -0,0 +1,337 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +#include "BLI_array_utils.hh" +#include "BLI_cpp_type_make.hh" +#include "BLI_rand.hh" +#include "BLI_task.hh" + +#include "BKE_attribute_math.hh" +#include "BKE_geometry_set.hh" +#include "BKE_instances.hh" + +BLI_CPP_TYPE_MAKE(InstanceReference, blender::bke::InstanceReference, CPPTypeFlags::None) + +namespace blender::bke { + +InstanceReference::InstanceReference(GeometrySet geometry_set) + : type_(Type::GeometrySet), + geometry_set_(std::make_unique<GeometrySet>(std::move(geometry_set))) +{ +} + +void InstanceReference::ensure_owns_direct_data() +{ + if (type_ != Type::GeometrySet) { + return; + } + geometry_set_->ensure_owns_direct_data(); +} + +bool InstanceReference::owns_direct_data() const +{ + if (type_ != Type::GeometrySet) { + /* The object and collection instances are not direct data. */ + return true; + } + return geometry_set_->owns_direct_data(); +} + +Instances::Instances(const Instances &other) + : references_(other.references_), + reference_handles_(other.reference_handles_), + transforms_(other.transforms_), + almost_unique_ids_(other.almost_unique_ids_), + attributes_(other.attributes_) +{ +} + +void Instances::reserve(int min_capacity) +{ + reference_handles_.reserve(min_capacity); + transforms_.reserve(min_capacity); + attributes_.reallocate(min_capacity); +} + +void Instances::resize(int capacity) +{ + reference_handles_.resize(capacity); + transforms_.resize(capacity); + attributes_.reallocate(capacity); +} + +void Instances::add_instance(const int instance_handle, const float4x4 &transform) +{ + BLI_assert(instance_handle >= 0); + BLI_assert(instance_handle < references_.size()); + reference_handles_.append(instance_handle); + transforms_.append(transform); + attributes_.reallocate(this->instances_num()); +} + +blender::Span<int> Instances::reference_handles() const +{ + return reference_handles_; +} + +blender::MutableSpan<int> Instances::reference_handles() +{ + return reference_handles_; +} + +blender::MutableSpan<blender::float4x4> Instances::transforms() +{ + return transforms_; +} +blender::Span<blender::float4x4> Instances::transforms() const +{ + return transforms_; +} + +GeometrySet &Instances::geometry_set_from_reference(const int reference_index) +{ + /* If this assert fails, it means #ensure_geometry_instances must be called first or that the + * reference can't be converted to a geometry set. */ + BLI_assert(references_[reference_index].type() == InstanceReference::Type::GeometrySet); + + /* The const cast is okay because the instance's hash in the set + * is not changed by adjusting the data inside the geometry set. */ + return const_cast<GeometrySet &>(references_[reference_index].geometry_set()); +} + +int Instances::add_reference(const InstanceReference &reference) +{ + return references_.index_of_or_add_as(reference); +} + +blender::Span<InstanceReference> Instances::references() const +{ + return references_; +} + +void Instances::remove(const IndexMask mask) +{ + using namespace blender; + if (mask.is_range() && mask.as_range().start() == 0) { + /* Deleting from the end of the array can be much faster since no data has to be shifted. */ + this->resize(mask.size()); + this->remove_unused_references(); + return; + } + + const Span<int> old_handles = this->reference_handles(); + Vector<int> new_handles(mask.size()); + array_utils::gather(old_handles, mask.indices(), new_handles.as_mutable_span()); + reference_handles_ = std::move(new_handles); + + const Span<float4x4> old_tansforms = this->transforms(); + Vector<float4x4> new_transforms(mask.size()); + array_utils::gather(old_tansforms, mask.indices(), new_transforms.as_mutable_span()); + transforms_ = std::move(new_transforms); + + const bke::CustomDataAttributes &src_attributes = attributes_; + + bke::CustomDataAttributes dst_attributes; + dst_attributes.reallocate(mask.size()); + + src_attributes.foreach_attribute( + [&](const bke::AttributeIDRef &id, const bke::AttributeMetaData &meta_data) { + if (!id.should_be_kept()) { + return true; + } + + GSpan src = *src_attributes.get_for_read(id); + dst_attributes.create(id, meta_data.data_type); + GMutableSpan dst = *dst_attributes.get_for_write(id); + array_utils::gather(src, mask.indices(), dst); + + return true; + }, + ATTR_DOMAIN_INSTANCE); + + attributes_ = std::move(dst_attributes); + this->remove_unused_references(); +} + +void Instances::remove_unused_references() +{ + using namespace blender; + using namespace blender::bke; + + const int tot_instances = this->instances_num(); + const int tot_references_before = references_.size(); + + if (tot_instances == 0) { + /* If there are no instances, no reference is needed. */ + references_.clear(); + return; + } + if (tot_references_before == 1) { + /* There is only one reference and at least one instance. So the only existing reference is + * used. Nothing to do here. */ + return; + } + + Array<bool> usage_by_handle(tot_references_before, false); + std::mutex mutex; + + /* Loop over all instances to see which references are used. */ + threading::parallel_for(IndexRange(tot_instances), 1000, [&](IndexRange range) { + /* Use local counter to avoid lock contention. */ + Array<bool> local_usage_by_handle(tot_references_before, false); + + for (const int i : range) { + const int handle = reference_handles_[i]; + BLI_assert(handle >= 0 && handle < tot_references_before); + local_usage_by_handle[handle] = true; + } + + std::lock_guard lock{mutex}; + for (const int i : IndexRange(tot_references_before)) { + usage_by_handle[i] |= local_usage_by_handle[i]; + } + }); + + if (!usage_by_handle.as_span().contains(false)) { + /* All references are used. */ + return; + } + + /* Create new references and a mapping for the handles. */ + Vector<int> handle_mapping; + VectorSet<InstanceReference> new_references; + int next_new_handle = 0; + bool handles_have_to_be_updated = false; + for (const int old_handle : IndexRange(tot_references_before)) { + if (!usage_by_handle[old_handle]) { + /* Add some dummy value. It won't be read again. */ + handle_mapping.append(-1); + } + else { + const InstanceReference &reference = references_[old_handle]; + handle_mapping.append(next_new_handle); + new_references.add_new(reference); + if (old_handle != next_new_handle) { + handles_have_to_be_updated = true; + } + next_new_handle++; + } + } + references_ = new_references; + + if (!handles_have_to_be_updated) { + /* All remaining handles are the same as before, so they don't have to be updated. This happens + * when unused handles are only at the end. */ + return; + } + + /* Update handles of instances. */ + threading::parallel_for(IndexRange(tot_instances), 1000, [&](IndexRange range) { + for (const int i : range) { + reference_handles_[i] = handle_mapping[reference_handles_[i]]; + } + }); +} + +int Instances::instances_num() const +{ + return transforms_.size(); +} + +int Instances::references_num() const +{ + return references_.size(); +} + +bool Instances::owns_direct_data() const +{ + for (const InstanceReference &reference : references_) { + if (!reference.owns_direct_data()) { + return false; + } + } + return true; +} + +void Instances::ensure_owns_direct_data() +{ + for (const InstanceReference &const_reference : references_) { + /* `const` cast is fine because we are not changing anything that would change the hash of the + * reference. */ + InstanceReference &reference = const_cast<InstanceReference &>(const_reference); + reference.ensure_owns_direct_data(); + } +} + +static blender::Array<int> generate_unique_instance_ids(Span<int> original_ids) +{ + using namespace blender; + Array<int> unique_ids(original_ids.size()); + + Set<int> used_unique_ids; + used_unique_ids.reserve(original_ids.size()); + Vector<int> instances_with_id_collision; + for (const int instance_index : original_ids.index_range()) { + const int original_id = original_ids[instance_index]; + if (used_unique_ids.add(original_id)) { + /* The original id has not been used by another instance yet. */ + unique_ids[instance_index] = original_id; + } + else { + /* The original id of this instance collided with a previous instance, it needs to be looked + * at again in a second pass. Don't generate a new random id here, because this might collide + * with other existing ids. */ + instances_with_id_collision.append(instance_index); + } + } + + Map<int, RandomNumberGenerator> generator_by_original_id; + for (const int instance_index : instances_with_id_collision) { + const int original_id = original_ids[instance_index]; + RandomNumberGenerator &rng = generator_by_original_id.lookup_or_add_cb(original_id, [&]() { + RandomNumberGenerator rng; + rng.seed_random(original_id); + return rng; + }); + + const int max_iteration = 100; + for (int iteration = 0;; iteration++) { + /* Try generating random numbers until an unused one has been found. */ + const int random_id = rng.get_int32(); + if (used_unique_ids.add(random_id)) { + /* This random id is not used by another instance. */ + unique_ids[instance_index] = random_id; + break; + } + if (iteration == max_iteration) { + /* It seems to be very unlikely that we ever run into this case (assuming there are less + * than 2^30 instances). However, if that happens, it's better to use an id that is not + * unique than to be stuck in an infinite loop. */ + unique_ids[instance_index] = original_id; + break; + } + } + } + + return unique_ids; +} + +blender::Span<int> Instances::almost_unique_ids() const +{ + std::lock_guard lock(almost_unique_ids_mutex_); + std::optional<GSpan> instance_ids_gspan = attributes_.get_for_read("id"); + if (instance_ids_gspan) { + Span<int> instance_ids = instance_ids_gspan->typed<int>(); + if (almost_unique_ids_.size() != instance_ids.size()) { + almost_unique_ids_ = generate_unique_instance_ids(instance_ids); + } + } + else { + almost_unique_ids_.reinitialize(this->instances_num()); + for (const int i : almost_unique_ids_.index_range()) { + almost_unique_ids_[i] = i; + } + } + return almost_unique_ids_; +} + +} // namespace blender::bke diff --git a/source/blender/blenkernel/intern/ipo.c b/source/blender/blenkernel/intern/ipo.c index bd655caae2b..a21033a8b91 100644 --- a/source/blender/blenkernel/intern/ipo.c +++ b/source/blender/blenkernel/intern/ipo.c @@ -1147,7 +1147,7 @@ static char *get_rna_access(ID *id, /* 'buf' _must_ be initialized in this block */ /* append preceding bits to path */ - /* NOTE: strings are not escapted and they should be! */ + /* NOTE: strings are not escaped and they should be! */ if ((actname && actname[0]) && (constname && constname[0])) { /* Constraint in Pose-Channel */ char actname_esc[sizeof(((bActionChannel *)NULL)->name) * 2]; diff --git a/source/blender/blenkernel/intern/lattice.c b/source/blender/blenkernel/intern/lattice.c index f6a409ee3f0..0adf162b4eb 100644 --- a/source/blender/blenkernel/intern/lattice.c +++ b/source/blender/blenkernel/intern/lattice.c @@ -355,10 +355,10 @@ void BKE_lattice_resize(Lattice *lt, int uNew, int vNew, int wNew, Object *ltOb) BKE_displist_free(<Ob->runtime.curve_cache->disp); } - copy_m4_m4(mat, ltOb->obmat); - unit_m4(ltOb->obmat); + copy_m4_m4(mat, ltOb->object_to_world); + unit_m4(ltOb->object_to_world); BKE_lattice_deform_coords(ltOb, NULL, vert_coords, uNew * vNew * wNew, 0, NULL, 1.0f); - copy_m4_m4(ltOb->obmat, mat); + copy_m4_m4(ltOb->object_to_world, mat); lt->typeu = typeu; lt->typev = typev; diff --git a/source/blender/blenkernel/intern/lattice_deform.c b/source/blender/blenkernel/intern/lattice_deform.c index 3a1c42b9178..892889aa426 100644 --- a/source/blender/blenkernel/intern/lattice_deform.c +++ b/source/blender/blenkernel/intern/lattice_deform.c @@ -79,15 +79,15 @@ LatticeDeformData *BKE_lattice_deform_data_create(const Object *oblatt, const Ob /* for example with a particle system: (ob == NULL) */ if (ob == NULL) { /* In deform-space, calc matrix. */ - invert_m4_m4(latmat, oblatt->obmat); + invert_m4_m4(latmat, oblatt->object_to_world); /* back: put in deform array */ invert_m4_m4(imat, latmat); } else { /* In deform-space, calc matrix. */ - invert_m4_m4(imat, oblatt->obmat); - mul_m4_m4m4(latmat, imat, ob->obmat); + invert_m4_m4(imat, oblatt->object_to_world); + mul_m4_m4m4(latmat, imat, ob->object_to_world); /* back: put in deform array. */ invert_m4_m4(imat, latmat); diff --git a/source/blender/blenkernel/intern/layer.c b/source/blender/blenkernel/intern/layer.c index fcb0adfde34..5b54f16661c 100644 --- a/source/blender/blenkernel/intern/layer.c +++ b/source/blender/blenkernel/intern/layer.c @@ -614,7 +614,7 @@ static bool layer_collection_hidden(ViewLayer *view_layer, LayerCollection *lc) return true; } - /* Check visiblilty restriction flags */ + /* Check visibility restriction flags */ if (lc->flag & LAYER_COLLECTION_HIDE || lc->collection->flag & COLLECTION_HIDE_VIEWPORT) { return true; } @@ -1049,7 +1049,7 @@ static void layer_collection_objects_sync(ViewLayer *view_layer, } /* Holdout and indirect only */ - if ((layer->flag & LAYER_COLLECTION_HOLDOUT) || (base->object->visibility_flag & OB_HOLDOUT)) { + if ((layer->flag & LAYER_COLLECTION_HOLDOUT)) { base->flag_from_collection |= BASE_HOLDOUT; } if (layer->flag & LAYER_COLLECTION_INDIRECT_ONLY) { diff --git a/source/blender/blenkernel/intern/lib_id.c b/source/blender/blenkernel/intern/lib_id.c index 158aaa961ce..f60234a684d 100644 --- a/source/blender/blenkernel/intern/lib_id.c +++ b/source/blender/blenkernel/intern/lib_id.c @@ -1612,7 +1612,7 @@ static void library_make_local_copying_check(ID *id, if (!BLI_gset_haskey(done_ids, from_id)) { if (BLI_gset_haskey(loop_tags, from_id)) { /* We are in a 'dependency loop' of IDs, this does not say us anything, skip it. - * Note that this is the situation that can lead to archipelagoes of linked data-blocks + * Note that this is the situation that can lead to archipelagos of linked data-blocks * (since all of them have non-local users, they would all be duplicated, * leading to a loop of unused linked data-blocks that cannot be freed since they all use * each other...). */ diff --git a/source/blender/blenkernel/intern/lib_id_delete.c b/source/blender/blenkernel/intern/lib_id_delete.c index f4f5ca7a1d7..c7643c56212 100644 --- a/source/blender/blenkernel/intern/lib_id_delete.c +++ b/source/blender/blenkernel/intern/lib_id_delete.c @@ -16,6 +16,7 @@ #include "BLI_utildefines.h" +#include "BLI_linklist.h" #include "BLI_listbase.h" #include "BKE_anim_data.h" @@ -23,10 +24,10 @@ #include "BKE_idprop.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_remap.h" -#include "BKE_library.h" #include "BKE_main.h" #include "BKE_main_namemap.h" @@ -202,7 +203,6 @@ static size_t id_delete(Main *bmain, const bool do_tagged_deletion) { const int tag = LIB_TAG_DOIT; ListBase *lbarray[INDEX_ID_MAX]; - Link dummy_link = {0}; int base_count, i; /* Used by batch tagged deletion, when we call BKE_id_free then, id is no more in Main database, @@ -217,6 +217,9 @@ static size_t id_delete(Main *bmain, const bool do_tagged_deletion) BKE_main_lock(bmain); if (do_tagged_deletion) { + struct IDRemapper *id_remapper = BKE_id_remapper_create(); + BKE_layer_collection_resync_forbid(); + /* Main idea of batch deletion is to remove all IDs to be deleted from Main database. * This means that we won't have to loop over all deleted IDs to remove usages * of other deleted IDs. @@ -227,7 +230,6 @@ static size_t id_delete(Main *bmain, const bool do_tagged_deletion) bool keep_looping = true; while (keep_looping) { ID *id, *id_next; - ID *last_remapped_id = tagged_deleted_ids.last; keep_looping = false; /* First tag and remove from Main all datablocks directly from target lib. @@ -243,6 +245,7 @@ static size_t id_delete(Main *bmain, const bool do_tagged_deletion) BLI_remlink(lb, id); BKE_main_namemap_remove_name(bmain, id, id->name + 2); BLI_addtail(&tagged_deleted_ids, id); + BKE_id_remapper_add(id_remapper, id, NULL); /* Do not tag as no_main now, we want to unlink it first (lower-level ID management * code has some specific handling of 'no main' IDs that would be a problem in that * case). */ @@ -251,33 +254,38 @@ static size_t id_delete(Main *bmain, const bool do_tagged_deletion) } } } - if (last_remapped_id == NULL) { - dummy_link.next = tagged_deleted_ids.first; - last_remapped_id = (ID *)(&dummy_link); - } - for (id = last_remapped_id->next; id; id = id->next) { - /* Will tag 'never NULL' users of this ID too. - * - * NOTE: #BKE_libblock_unlink() cannot be used here, since it would ignore indirect - * links, this can lead to nasty crashing here in second, actual deleting loop. - * Also, this will also flag users of deleted data that cannot be unlinked - * (object using deleted obdata, etc.), so that they also get deleted. */ - BKE_libblock_remap_locked(bmain, - id, - NULL, - (ID_REMAP_FLAG_NEVER_NULL_USAGE | - ID_REMAP_FORCE_NEVER_NULL_USAGE | - ID_REMAP_FORCE_INTERNAL_RUNTIME_POINTERS)); - /* Since we removed ID from Main, - * we also need to unlink its own other IDs usages ourself. */ - BKE_libblock_relink_ex( - bmain, - id, - NULL, - NULL, - (ID_REMAP_FORCE_INTERNAL_RUNTIME_POINTERS | ID_REMAP_SKIP_USER_CLEAR)); - } + + /* Will tag 'never NULL' users of this ID too. + * + * NOTE: #BKE_libblock_unlink() cannot be used here, since it would ignore indirect + * links, this can lead to nasty crashing here in second, actual deleting loop. + * Also, this will also flag users of deleted data that cannot be unlinked + * (object using deleted obdata, etc.), so that they also get deleted. */ + BKE_libblock_remap_multiple_locked(bmain, + id_remapper, + ID_REMAP_FLAG_NEVER_NULL_USAGE | + ID_REMAP_FORCE_NEVER_NULL_USAGE | + ID_REMAP_FORCE_INTERNAL_RUNTIME_POINTERS); + BKE_id_remapper_clear(id_remapper); + } + + /* Since we removed IDs from Main, their own other IDs usages need to be removed 'manually'. */ + LinkNode *cleanup_ids = NULL; + for (ID *id = tagged_deleted_ids.first; id; id = id->next) { + BLI_linklist_prepend(&cleanup_ids, id); } + BKE_libblock_relink_multiple(bmain, + cleanup_ids, + ID_REMAP_TYPE_CLEANUP, + id_remapper, + ID_REMAP_FORCE_INTERNAL_RUNTIME_POINTERS | + ID_REMAP_SKIP_USER_CLEAR); + + BKE_id_remapper_free(id_remapper); + BLI_linklist_free(cleanup_ids, NULL); + + BKE_layer_collection_resync_allow(); + BKE_main_collection_sync_remap(bmain); /* Now we can safely mark that ID as not being in Main database anymore. */ /* NOTE: This needs to be done in a separate loop than above, otherwise some user-counts of @@ -285,10 +293,14 @@ static size_t id_delete(Main *bmain, const bool do_tagged_deletion) * is never affected). */ for (ID *id = tagged_deleted_ids.first; id; id = id->next) { id->tag |= LIB_TAG_NO_MAIN; + /* User-count needs to be reset artificially, since some usages may not be cleared in batch + * deletion (typically, if one deleted ID uses another deleted ID, this may not be cleared by + * remapping code, depending on order in which these are handled). */ + id->us = ID_FAKE_USERS(id); } } else { - /* First tag all datablocks directly from target lib. + /* First tag all data-blocks directly from target lib. * Note that we go forward here, since we want to check dependencies before users * (e.g. meshes before objects). * Avoids to have to loop twice. */ diff --git a/source/blender/blenkernel/intern/mask_rasterize.c b/source/blender/blenkernel/intern/mask_rasterize.c index 55834d5cf4e..adc0eb5f78c 100644 --- a/source/blender/blenkernel/intern/mask_rasterize.c +++ b/source/blender/blenkernel/intern/mask_rasterize.c @@ -521,7 +521,7 @@ static void layer_bucket_init(MaskRasterLayer *layer, const float pixel_size) } if (1) { - /* now convert linknodes into arrays for faster per pixel access */ + /* Now convert link-nodes into arrays for faster per pixel access. */ uint **buckets_face = MEM_mallocN(bucket_tot * sizeof(*buckets_face), __func__); uint bucket_index; @@ -1186,7 +1186,7 @@ void BKE_maskrasterize_handle_init(MaskRasterHandle *mr_handle, // printf("tris %d, feather tris %d\n", sf_tri_tot, tot_feather_quads); } - /* add trianges */ + /* Add triangles. */ BLI_scanfill_end_arena(&sf_ctx, sf_arena); } diff --git a/source/blender/blenkernel/intern/material.c b/source/blender/blenkernel/intern/material.c index 6c6d2298dbd..59530a6d6a6 100644 --- a/source/blender/blenkernel/intern/material.c +++ b/source/blender/blenkernel/intern/material.c @@ -1450,7 +1450,7 @@ static bool fill_texpaint_slots_cb(bNode *node, void *userdata) NodeTexImage *storage = (NodeTexImage *)node->storage; slot->interp = storage->interpolation; slot->image_user = &storage->iuser; - /* for new renderer, we need to traverse the treeback in search of a UV node */ + /* For new renderer, we need to traverse the tree back in search of a UV node. */ bNode *uvnode = nodetree_uv_node_recursive(node); if (uvnode) { @@ -1512,58 +1512,65 @@ static ePaintSlotFilter material_paint_slot_filter(const struct Object *ob) void BKE_texpaint_slot_refresh_cache(Scene *scene, Material *ma, const struct Object *ob) { - int count = 0; - if (!ma) { return; } const ePaintSlotFilter slot_filter = material_paint_slot_filter(ob); - /* COW needed when adding texture slot on an object with no materials. */ - DEG_id_tag_update(&ma->id, ID_RECALC_SHADING | ID_RECALC_COPY_ON_WRITE); + const TexPaintSlot *prev_texpaintslot = ma->texpaintslot; + const int prev_paint_active_slot = ma->paint_active_slot; + const int prev_paint_clone_slot = ma->paint_clone_slot; + const int prev_tot_slots = ma->tot_slots; - if (ma->texpaintslot) { - MEM_freeN(ma->texpaintslot); - ma->tot_slots = 0; - ma->texpaintslot = NULL; - } + ma->texpaintslot = NULL; + ma->tot_slots = 0; if (scene->toolsettings->imapaint.mode == IMAGEPAINT_MODE_IMAGE) { ma->paint_active_slot = 0; ma->paint_clone_slot = 0; - return; } - - if (!(ma->nodetree)) { + else if (!(ma->nodetree)) { ma->paint_active_slot = 0; ma->paint_clone_slot = 0; - return; } + else { + int count = count_texture_nodes_recursive(ma->nodetree, slot_filter); - count = count_texture_nodes_recursive(ma->nodetree, slot_filter); - - if (count == 0) { - ma->paint_active_slot = 0; - ma->paint_clone_slot = 0; - return; - } + if (count == 0) { + ma->paint_active_slot = 0; + ma->paint_clone_slot = 0; + } + else { + ma->texpaintslot = MEM_callocN(sizeof(*ma->texpaintslot) * count, "texpaint_slots"); - ma->texpaintslot = MEM_callocN(sizeof(*ma->texpaintslot) * count, "texpaint_slots"); + bNode *active_node = nodeGetActivePaintCanvas(ma->nodetree); - bNode *active_node = nodeGetActivePaintCanvas(ma->nodetree); + fill_texpaint_slots_recursive(ma->nodetree, active_node, ob, ma, count, slot_filter); - fill_texpaint_slots_recursive(ma->nodetree, active_node, ob, ma, count, slot_filter); + ma->tot_slots = count; - ma->tot_slots = count; + if (ma->paint_active_slot >= count) { + ma->paint_active_slot = count - 1; + } - if (ma->paint_active_slot >= count) { - ma->paint_active_slot = count - 1; + if (ma->paint_clone_slot >= count) { + ma->paint_clone_slot = count - 1; + } + } } - if (ma->paint_clone_slot >= count) { - ma->paint_clone_slot = count - 1; + /* COW needed when adding texture slot on an object with no materials. + * But do it only when slots actually change to avoid continuous depsgraph updates. */ + if (ma->tot_slots != prev_tot_slots || ma->paint_active_slot != prev_paint_active_slot || + ma->paint_clone_slot != prev_paint_clone_slot || + (ma->texpaintslot && prev_texpaintslot && + memcmp(ma->texpaintslot, prev_texpaintslot, sizeof(*ma->texpaintslot) * ma->tot_slots) != + 0)) { + DEG_id_tag_update(&ma->id, ID_RECALC_SHADING | ID_RECALC_COPY_ON_WRITE); } + + MEM_SAFE_FREE(prev_texpaintslot); } void BKE_texpaint_slots_refresh_object(Scene *scene, struct Object *ob) diff --git a/source/blender/blenkernel/intern/mball_tessellate.cc b/source/blender/blenkernel/intern/mball_tessellate.cc index bb3713e770a..f8a64a7cd8b 100644 --- a/source/blender/blenkernel/intern/mball_tessellate.cc +++ b/source/blender/blenkernel/intern/mball_tessellate.cc @@ -1188,8 +1188,9 @@ static void init_meta(Depsgraph *depsgraph, PROCESS *process, Scene *scene, Obje const eEvaluationMode deg_eval_mode = DEG_get_mode(depsgraph); const short parenting_dupli_transflag = (OB_DUPLIFACES | OB_DUPLIVERTS); - copy_m4_m4(obmat, ob->obmat); /* to cope with duplicators from BKE_scene_base_iter_next */ - invert_m4_m4(obinv, ob->obmat); + copy_m4_m4(obmat, + ob->object_to_world); /* to cope with duplicators from BKE_scene_base_iter_next */ + invert_m4_m4(obinv, ob->object_to_world); BLI_split_name_num(obname, &obnr, ob->id.name + 2, '.'); @@ -1237,13 +1238,13 @@ static void init_meta(Depsgraph *depsgraph, PROCESS *process, Scene *scene, Obje /* when metaball object has zero scale, then MetaElem to this MetaBall * will not be put to mainb array */ - if (has_zero_axis_m4(bob->obmat)) { + if (has_zero_axis_m4(bob->object_to_world)) { zero_size = 1; } else if (bob->parent) { struct Object *pob = bob->parent; while (pob) { - if (has_zero_axis_m4(pob->obmat)) { + if (has_zero_axis_m4(pob->object_to_world)) { zero_size = 1; break; } @@ -1307,7 +1308,7 @@ static void init_meta(Depsgraph *depsgraph, PROCESS *process, Scene *scene, Obje * rotation -> * ml local space */ - mul_m4_series((float(*)[4])new_ml->mat, obinv, bob->obmat, pos, rot); + mul_m4_series((float(*)[4])new_ml->mat, obinv, bob->object_to_world, pos, rot); /* ml local space -> basis object space */ invert_m4_m4((float(*)[4])new_ml->imat, (float(*)[4])new_ml->mat); diff --git a/source/blender/blenkernel/intern/mesh_convert.cc b/source/blender/blenkernel/intern/mesh_convert.cc index 027423f5774..784d35a8d65 100644 --- a/source/blender/blenkernel/intern/mesh_convert.cc +++ b/source/blender/blenkernel/intern/mesh_convert.cc @@ -1313,6 +1313,7 @@ void BKE_mesh_nomain_to_mesh(Mesh *mesh_src, Mesh *mesh_dst, Object *ob) CustomData_duplicate_referenced_layers(&mesh_src->pdata, mesh_src->totpoly); CustomData_duplicate_referenced_layers(&mesh_src->ldata, mesh_src->totloop); + const bool verts_num_changed = mesh_dst->totvert != mesh_src->totvert; mesh_dst->totvert = mesh_src->totvert; mesh_dst->totedge = mesh_src->totedge; mesh_dst->totpoly = mesh_src->totpoly; @@ -1339,11 +1340,10 @@ void BKE_mesh_nomain_to_mesh(Mesh *mesh_src, Mesh *mesh_dst, Object *ob) const int uid_active = ob ? find_object_active_key_uid(*key_dst, *ob) : -1; move_shapekey_layers_to_keyblocks(*mesh_dst, mesh_src->vdata, *key_dst, uid_active); } - else if (mesh_src->totvert != mesh_dst->totvert) { - CLOG_ERROR(&LOG, "Mesh in Main '%s' lost shape keys", mesh_src->id.name); - if (mesh_src->key) { - id_us_min(&mesh_src->key->id); - } + else if (verts_num_changed) { + CLOG_WARN(&LOG, "Shape key data lost when replacing mesh '%s' in Main", mesh_src->id.name); + id_us_min(&mesh_dst->key->id); + mesh_dst->key = nullptr; } } diff --git a/source/blender/blenkernel/intern/mesh_mirror.c b/source/blender/blenkernel/intern/mesh_mirror.c index 261bc3d150b..ce3fc5d99c8 100644 --- a/source/blender/blenkernel/intern/mesh_mirror.c +++ b/source/blender/blenkernel/intern/mesh_mirror.c @@ -152,8 +152,8 @@ Mesh *BKE_mesh_mirror_apply_mirror_on_axis_for_modifier(MirrorModifierData *mmd, /* tmp is a transform from coords relative to the object's own origin, * to coords relative to the mirror object origin */ - invert_m4_m4(tmp, mirror_ob->obmat); - mul_m4_m4m4(tmp, tmp, ob->obmat); + invert_m4_m4(tmp, mirror_ob->object_to_world); + mul_m4_m4m4(tmp, tmp, ob->object_to_world); /* itmp is the reverse transform back to origin-relative coordinates */ invert_m4_m4(itmp, tmp); @@ -169,9 +169,9 @@ Mesh *BKE_mesh_mirror_apply_mirror_on_axis_for_modifier(MirrorModifierData *mmd, /* Account for non-uniform scale in `ob`, see: T87592. */ float ob_scale[3] = { - len_squared_v3(ob->obmat[0]), - len_squared_v3(ob->obmat[1]), - len_squared_v3(ob->obmat[2]), + len_squared_v3(ob->object_to_world[0]), + len_squared_v3(ob->object_to_world[1]), + len_squared_v3(ob->object_to_world[2]), }; /* Scale to avoid precision loss with extreme values. */ const float ob_scale_max = max_fff(UNPACK3(ob_scale)); diff --git a/source/blender/blenkernel/intern/modifier.cc b/source/blender/blenkernel/intern/modifier.cc index fc1a0f47684..92a7c778b68 100644 --- a/source/blender/blenkernel/intern/modifier.cc +++ b/source/blender/blenkernel/intern/modifier.cc @@ -955,7 +955,7 @@ const char *BKE_modifier_path_relbase_from_global(Object *ob) void BKE_modifier_path_init(char *path, int path_maxlen, const char *name) { const char *blendfile_path = BKE_main_blendfile_path_from_global(); - BLI_join_dirfile(path, path_maxlen, blendfile_path[0] ? "//" : BKE_tempdir_session(), name); + BLI_path_join(path, path_maxlen, blendfile_path[0] ? "//" : BKE_tempdir_session(), name); } /** diff --git a/source/blender/blenkernel/intern/nla.c b/source/blender/blenkernel/intern/nla.c index ba63cdff917..c0aff204069 100644 --- a/source/blender/blenkernel/intern/nla.c +++ b/source/blender/blenkernel/intern/nla.c @@ -464,6 +464,7 @@ NlaStrip *BKE_nlastack_add_strip(AnimData *adt, bAction *act, const bool is_libo */ nlt = BKE_nlatrack_add(adt, NULL, is_liboverride); BKE_nlatrack_add_strip(nlt, strip, is_liboverride); + BLI_strncpy(nlt->name, act->id.name + 2, sizeof(nlt->name)); } /* automatically name it too */ @@ -1918,7 +1919,7 @@ bool BKE_nla_action_stash(AnimData *adt, const bool is_liboverride) * NOTE: this must be done *after* adding the strip to the track, or else * the strip locking will prevent the strip from getting added */ - nlt->flag = (NLATRACK_MUTED | NLATRACK_PROTECTED); + nlt->flag |= (NLATRACK_MUTED | NLATRACK_PROTECTED); strip->flag &= ~(NLASTRIP_FLAG_SELECT | NLASTRIP_FLAG_ACTIVE); /* also mark the strip for auto syncing the length, so that the strips accurately @@ -2054,7 +2055,7 @@ bool BKE_nla_tweakmode_enter(AnimData *adt) } /* If block is already in tweak-mode, just leave, but we should report - * that this block is in tweak-mode (as our returncode). */ + * that this block is in tweak-mode (as our return-code). */ if (adt->flag & ADT_NLA_EDIT_ON) { return true; } diff --git a/source/blender/blenkernel/intern/node.cc b/source/blender/blenkernel/intern/node.cc index 654eb06a781..8f8cd02e119 100644 --- a/source/blender/blenkernel/intern/node.cc +++ b/source/blender/blenkernel/intern/node.cc @@ -516,10 +516,6 @@ void ntreeBlendWrite(BlendWriter *writer, bNodeTree *ntree) write_node_socket(writer, sock); } - LISTBASE_FOREACH (bNodeLink *, link, &node->internal_links) { - BLO_write_struct(writer, bNodeLink, link); - } - if (node->storage) { if (ELEM(ntree->type, NTREE_SHADER, NTREE_GEOMETRY) && ELEM(node->type, SH_NODE_CURVE_VEC, SH_NODE_CURVE_RGB, SH_NODE_CURVE_FLOAT)) { @@ -703,13 +699,7 @@ void ntreeBlendReadData(BlendDataReader *reader, ID *owner_id, bNodeTree *ntree) BLO_read_data_address(reader, &node->prop); IDP_BlendDataRead(reader, &node->prop); - BLO_read_list(reader, &node->internal_links); - LISTBASE_FOREACH (bNodeLink *, link, &node->internal_links) { - BLO_read_data_address(reader, &link->fromnode); - BLO_read_data_address(reader, &link->fromsock); - BLO_read_data_address(reader, &link->tonode); - BLO_read_data_address(reader, &link->tosock); - } + BLI_listbase_clear(&node->internal_links); if (node->type == CMP_NODE_MOVIEDISTORTION) { /* Do nothing, this is runtime cache and hence handled by generic code using @@ -2032,21 +2022,29 @@ bNode *nodeFindNodebyName(bNodeTree *ntree, const char *name) bool nodeFindNode(bNodeTree *ntree, bNodeSocket *sock, bNode **r_node, int *r_sockindex) { *r_node = nullptr; + if (!ntree->runtime->topology_cache_is_dirty) { + bNode *node = &sock->owner_node(); + *r_node = node; + if (r_sockindex) { + ListBase *sockets = (sock->in_out == SOCK_IN) ? &node->inputs : &node->outputs; + *r_sockindex = BLI_findindex(sockets, sock); + } + return true; + } LISTBASE_FOREACH (bNode *, node, &ntree->nodes) { ListBase *sockets = (sock->in_out == SOCK_IN) ? &node->inputs : &node->outputs; - int index = 0; - LISTBASE_FOREACH (bNodeSocket *, tsock, sockets) { + int i; + LISTBASE_FOREACH_INDEX (bNodeSocket *, tsock, sockets, i) { if (sock == tsock) { if (r_node != nullptr) { *r_node = node; } if (r_sockindex != nullptr) { - *r_sockindex = index; + *r_sockindex = i; } return true; } - index++; } } return false; @@ -2157,6 +2155,38 @@ void nodeParentsIter(bNode *node, bool (*callback)(bNode *, void *), void *userd } } +bool nodeIsDanglingReroute(const bNodeTree *ntree, const bNode *node) +{ + ntree->ensure_topology_cache(); + BLI_assert(blender::bke::node_tree_runtime::topology_cache_is_available(*ntree)); + BLI_assert(!ntree->has_available_link_cycle()); + + const bNode *iter_node = node; + if (!iter_node->is_reroute()) { + return false; + } + + while (true) { + const blender::Span<const bNodeLink *> links = + iter_node->input_socket(0).directly_linked_links(); + BLI_assert(links.size() <= 1); + if (links.is_empty()) { + return true; + } + const bNodeLink &link = *links[0]; + if (!link.is_available()) { + return false; + } + if (link.is_muted()) { + return false; + } + iter_node = link.fromnode; + if (!iter_node->is_reroute()) { + return false; + } + } +} + /* ************** Add stuff ********** */ void nodeUniqueName(bNodeTree *ntree, bNode *node) diff --git a/source/blender/blenkernel/intern/object.cc b/source/blender/blenkernel/intern/object.cc index 2d949fb5c65..53e6d47860f 100644 --- a/source/blender/blenkernel/intern/object.cc +++ b/source/blender/blenkernel/intern/object.cc @@ -1330,14 +1330,14 @@ void BKE_object_modifier_hook_reset(Object *ob, HookModifierData *hmd) /* Calculate the world-space matrix for the pose-channel target first, * then carry on as usual. */ - mul_m4_m4m4(mat, hmd->object->obmat, pchan->pose_mat); + mul_m4_m4m4(mat, hmd->object->object_to_world, pchan->pose_mat); invert_m4_m4(imat, mat); - mul_m4_m4m4(hmd->parentinv, imat, ob->obmat); + mul_m4_m4m4(hmd->parentinv, imat, ob->object_to_world); } else { - invert_m4_m4(hmd->object->imat, hmd->object->obmat); - mul_m4_m4m4(hmd->parentinv, hmd->object->imat, ob->obmat); + invert_m4_m4(hmd->object->imat, hmd->object->object_to_world); + mul_m4_m4m4(hmd->parentinv, hmd->object->imat, ob->object_to_world); } } } @@ -1355,14 +1355,14 @@ void BKE_object_modifier_gpencil_hook_reset(Object *ob, HookGpencilModifierData /* Calculate the world-space matrix for the pose-channel target first, * then carry on as usual. */ - mul_m4_m4m4(mat, hmd->object->obmat, pchan->pose_mat); + mul_m4_m4m4(mat, hmd->object->object_to_world, pchan->pose_mat); invert_m4_m4(imat, mat); - mul_m4_m4m4(hmd->parentinv, imat, ob->obmat); + mul_m4_m4m4(hmd->parentinv, imat, ob->object_to_world); } else { - invert_m4_m4(hmd->object->imat, hmd->object->obmat); - mul_m4_m4m4(hmd->parentinv, hmd->object->imat, ob->obmat); + invert_m4_m4(hmd->object->imat, hmd->object->object_to_world); + mul_m4_m4m4(hmd->parentinv, hmd->object->imat, ob->object_to_world); } } @@ -1902,6 +1902,7 @@ bool BKE_object_is_in_editmode(const Object *ob) /* Grease Pencil object has no edit mode data. */ return GPENCIL_EDIT_MODE((bGPdata *)ob->data); case OB_CURVES: + /* Curves object has no edit mode data. */ return ob->mode == OB_MODE_EDIT; default: return false; @@ -3101,10 +3102,10 @@ void BKE_object_matrix_local_get(struct Object *ob, float r_mat[4][4]) BKE_object_get_parent_matrix(ob, ob->parent, par_imat); invert_m4(par_imat); - mul_m4_m4m4(r_mat, par_imat, ob->obmat); + mul_m4_m4m4(r_mat, par_imat, ob->object_to_world); } else { - copy_m4_m4(r_mat, ob->obmat); + copy_m4_m4(r_mat, ob->object_to_world); } } @@ -3358,32 +3359,32 @@ void BKE_object_get_parent_matrix(Object *ob, Object *par, float r_parentmat[4][ } if (ok) { - mul_m4_m4m4(r_parentmat, par->obmat, tmat); + mul_m4_m4m4(r_parentmat, par->object_to_world, tmat); } else { - copy_m4_m4(r_parentmat, par->obmat); + copy_m4_m4(r_parentmat, par->object_to_world); } break; } case PARBONE: ob_parbone(ob, par, tmat); - mul_m4_m4m4(r_parentmat, par->obmat, tmat); + mul_m4_m4m4(r_parentmat, par->object_to_world, tmat); break; case PARVERT1: unit_m4(r_parentmat); give_parvert(par, ob->par1, vec); - mul_v3_m4v3(r_parentmat[3], par->obmat, vec); + mul_v3_m4v3(r_parentmat[3], par->object_to_world, vec); break; case PARVERT3: ob_parvert3(ob, par, tmat); - mul_m4_m4m4(r_parentmat, par->obmat, tmat); + mul_m4_m4m4(r_parentmat, par->object_to_world, tmat); break; case PARSKEL: - copy_m4_m4(r_parentmat, par->obmat); + copy_m4_m4(r_parentmat, par->object_to_world); break; } } @@ -3421,7 +3422,7 @@ static void solve_parenting( /* origin, for help line */ if (set_origin) { if ((ob->partype & PARTYPE) == PARSKEL) { - copy_v3_v3(ob->runtime.parent_display_origin, par->obmat[3]); + copy_v3_v3(ob->runtime.parent_display_origin, par->object_to_world[3]); } else { copy_v3_v3(ob->runtime.parent_display_origin, totmat[3]); @@ -3440,10 +3441,10 @@ static void object_where_is_calc_ex(Depsgraph *depsgraph, Object *par = ob->parent; /* calculate parent matrix */ - solve_parenting(ob, par, true, ob->obmat, r_originmat); + solve_parenting(ob, par, true, ob->object_to_world, r_originmat); } else { - BKE_object_to_mat4(ob, ob->obmat); + BKE_object_to_mat4(ob, ob->object_to_world); } /* try to fall back to the scene rigid body world if none given */ @@ -3460,7 +3461,7 @@ static void object_where_is_calc_ex(Depsgraph *depsgraph, } /* set negative scale flag in object */ - if (is_negative_m4(ob->obmat)) { + if (is_negative_m4(ob->object_to_world)) { ob->transflag |= OB_NEG_SCALE; } else { @@ -3506,7 +3507,7 @@ void BKE_object_workob_calc_parent(Depsgraph *depsgraph, Scene *scene, Object *o { BKE_object_workob_clear(workob); - unit_m4(workob->obmat); + unit_m4(workob->object_to_world); unit_m4(workob->parentinv); unit_m4(workob->constinv); @@ -3598,7 +3599,7 @@ void BKE_object_apply_parent_inverse(struct Object *ob) * `inv(parent) @ world = parentinv` * `parentinv = inv(parent) @ world` * - * NOTE: If `ob->obmat` has shear, then this `parentinv` is insufficient because + * NOTE: If `ob->object_to_world` has shear, then this `parentinv` is insufficient because * `parent @ parentinv => shearless result` * * Thus, local will have shear which cannot be decomposed into TRS: @@ -3627,7 +3628,7 @@ void BKE_object_apply_parent_inverse(struct Object *ob) copy_m4_m4(ob_local, ob->parentinv); invert_m4(ob_local); mul_m4_m4_post(ob_local, par_imat); - mul_m4_m4_post(ob_local, ob->obmat); + mul_m4_m4_post(ob_local, ob->object_to_world); /* Send use_compat=False so the rotation is predictable. */ BKE_object_apply_mat4(ob, ob_local, false, false); @@ -3792,7 +3793,7 @@ void BKE_object_dimensions_get(Object *ob, float r_vec[3]) const BoundBox *bb = BKE_object_boundbox_get(ob); if (bb) { float3 scale; - mat4_to_size(scale, ob->obmat); + mat4_to_size(scale, ob->object_to_world); r_vec[0] = fabsf(scale[0]) * (bb->vec[4][0] - bb->vec[0][0]); r_vec[1] = fabsf(scale[1]) * (bb->vec[2][1] - bb->vec[0][1]); @@ -3849,19 +3850,19 @@ void BKE_object_minmax(Object *ob, float r_min[3], float r_max[3], const bool us case OB_FONT: case OB_SURF: { const BoundBox bb = *BKE_curve_boundbox_get(ob); - BKE_boundbox_minmax(&bb, ob->obmat, r_min, r_max); + BKE_boundbox_minmax(&bb, ob->object_to_world, r_min, r_max); changed = true; break; } case OB_MESH: { const BoundBox bb = *BKE_mesh_boundbox_get(ob); - BKE_boundbox_minmax(&bb, ob->obmat, r_min, r_max); + BKE_boundbox_minmax(&bb, ob->object_to_world, r_min, r_max); changed = true; break; } case OB_GPENCIL: { const BoundBox bb = *BKE_gpencil_boundbox_get(ob); - BKE_boundbox_minmax(&bb, ob->obmat, r_min, r_max); + BKE_boundbox_minmax(&bb, ob->object_to_world, r_min, r_max); changed = true; break; } @@ -3874,7 +3875,7 @@ void BKE_object_minmax(Object *ob, float r_min[3], float r_max[3], const bool us for (v = 0; v < lt->pntsv; v++) { for (u = 0; u < lt->pntsu; u++, bp++) { float3 vec; - mul_v3_m4v3(vec, ob->obmat, bp->vec); + mul_v3_m4v3(vec, ob->object_to_world, bp->vec); minmax_v3v3_v3(r_min, r_max, vec); } } @@ -3889,7 +3890,8 @@ void BKE_object_minmax(Object *ob, float r_min[3], float r_max[3], const bool us case OB_MBALL: { float ob_min[3], ob_max[3]; - changed = BKE_mball_minmax_ex((const MetaBall *)ob->data, ob_min, ob_max, ob->obmat, 0); + changed = BKE_mball_minmax_ex( + (const MetaBall *)ob->data, ob_min, ob_max, ob->object_to_world, 0); if (changed) { minmax_v3v3_v3(r_min, r_max, ob_min); minmax_v3v3_v3(r_min, r_max, ob_max); @@ -3898,20 +3900,20 @@ void BKE_object_minmax(Object *ob, float r_min[3], float r_max[3], const bool us } case OB_CURVES: { const BoundBox bb = *BKE_curves_boundbox_get(ob); - BKE_boundbox_minmax(&bb, ob->obmat, r_min, r_max); + BKE_boundbox_minmax(&bb, ob->object_to_world, r_min, r_max); changed = true; break; } case OB_POINTCLOUD: { const BoundBox bb = *BKE_pointcloud_boundbox_get(ob); - BKE_boundbox_minmax(&bb, ob->obmat, r_min, r_max); + BKE_boundbox_minmax(&bb, ob->object_to_world, r_min, r_max); changed = true; break; } case OB_VOLUME: { const BoundBox bb = *BKE_volume_boundbox_get(ob); - BKE_boundbox_minmax(&bb, ob->obmat, r_min, r_max); + BKE_boundbox_minmax(&bb, ob->object_to_world, r_min, r_max); changed = true; break; } @@ -3925,14 +3927,14 @@ void BKE_object_minmax(Object *ob, float r_min[3], float r_max[3], const bool us size *= ob->empty_drawsize; } - minmax_v3v3_v3(r_min, r_max, ob->obmat[3]); + minmax_v3v3_v3(r_min, r_max, ob->object_to_world[3]); float3 vec; - copy_v3_v3(vec, ob->obmat[3]); + copy_v3_v3(vec, ob->object_to_world[3]); add_v3_v3(vec, size); minmax_v3v3_v3(r_min, r_max, vec); - copy_v3_v3(vec, ob->obmat[3]); + copy_v3_v3(vec, ob->object_to_world[3]); sub_v3_v3(vec, size); minmax_v3v3_v3(r_min, r_max, vec); } @@ -3979,12 +3981,12 @@ bool BKE_object_empty_image_data_is_visible_in_view3d(const Object *ob, const Re * however the issue with empty objects being visible when viewed from the side * is only noticeable in orthographic views. */ float3 view_dir; - sub_v3_v3v3(view_dir, rv3d->viewinv[3], ob->obmat[3]); - dot = dot_v3v3(ob->obmat[2], view_dir); + sub_v3_v3v3(view_dir, rv3d->viewinv[3], ob->object_to_world[3]); + dot = dot_v3v3(ob->object_to_world[2], view_dir); eps = 0.0f; } else { - dot = dot_v3v3(ob->obmat[2], rv3d->viewinv[2]); + dot = dot_v3v3(ob->object_to_world[2], rv3d->viewinv[2]); eps = 1e-5f; } if (visibility_flag & OB_EMPTY_IMAGE_HIDE_BACK) { @@ -4001,7 +4003,7 @@ bool BKE_object_empty_image_data_is_visible_in_view3d(const Object *ob, const Re if (visibility_flag & OB_EMPTY_IMAGE_HIDE_NON_AXIS_ALIGNED) { float3 proj, ob_z_axis; - normalize_v3_v3(ob_z_axis, ob->obmat[2]); + normalize_v3_v3(ob_z_axis, ob->object_to_world[2]); project_plane_v3_v3v3(proj, ob_z_axis, rv3d->viewinv[2]); const float proj_length_sq = len_squared_v3(proj); if (proj_length_sq > 1e-5f) { @@ -4193,7 +4195,7 @@ void BKE_scene_foreach_display_point(Depsgraph *depsgraph, DEG_ITER_OBJECT_FLAG_DUPLI; DEG_OBJECT_ITER_BEGIN (°_iter_settings, ob) { if ((ob->base_flag & BASE_SELECTED) != 0) { - BKE_object_foreach_display_point(ob, ob->obmat, func_cb, user_data); + BKE_object_foreach_display_point(ob, ob->object_to_world, func_cb, user_data); } } DEG_OBJECT_ITER_END; @@ -4236,7 +4238,7 @@ void *BKE_object_tfm_backup(Object *ob) copy_v3_v3(obtfm->drotAxis, ob->drotAxis); obtfm->rotAngle = ob->rotAngle; obtfm->drotAngle = ob->drotAngle; - copy_m4_m4(obtfm->obmat, ob->obmat); + copy_m4_m4(obtfm->obmat, ob->object_to_world); copy_m4_m4(obtfm->parentinv, ob->parentinv); copy_m4_m4(obtfm->constinv, ob->constinv); copy_m4_m4(obtfm->imat, ob->imat); @@ -4259,7 +4261,7 @@ void BKE_object_tfm_restore(Object *ob, void *obtfm_pt) copy_v3_v3(ob->drotAxis, obtfm->drotAxis); ob->rotAngle = obtfm->rotAngle; ob->drotAngle = obtfm->drotAngle; - copy_m4_m4(ob->obmat, obtfm->obmat); + copy_m4_m4(ob->object_to_world, obtfm->obmat); copy_m4_m4(ob->parentinv, obtfm->parentinv); copy_m4_m4(ob->constinv, obtfm->constinv); copy_m4_m4(ob->imat, obtfm->imat); @@ -5290,7 +5292,7 @@ KDTree_3d *BKE_object_as_kdtree(Object *ob, int *r_tot) for (i = 0; i < verts.size(); i++) { if (index[i] != ORIGINDEX_NONE) { float co[3]; - mul_v3_m4v3(co, ob->obmat, verts[i].co); + mul_v3_m4v3(co, ob->object_to_world, verts[i].co); BLI_kdtree_3d_insert(tree, index[i], co); tot++; } @@ -5304,7 +5306,7 @@ KDTree_3d *BKE_object_as_kdtree(Object *ob, int *r_tot) for (i = 0; i < tot; i++) { float co[3]; - mul_v3_m4v3(co, ob->obmat, verts[i].co); + mul_v3_m4v3(co, ob->object_to_world, verts[i].co); BLI_kdtree_3d_insert(tree, i, co); } } @@ -5333,7 +5335,7 @@ KDTree_3d *BKE_object_as_kdtree(Object *ob, int *r_tot) a = nu->pntsu; while (a--) { float co[3]; - mul_v3_m4v3(co, ob->obmat, bezt->vec[1]); + mul_v3_m4v3(co, ob->object_to_world, bezt->vec[1]); BLI_kdtree_3d_insert(tree, i++, co); bezt++; } @@ -5345,7 +5347,7 @@ KDTree_3d *BKE_object_as_kdtree(Object *ob, int *r_tot) a = nu->pntsu * nu->pntsv; while (a--) { float co[3]; - mul_v3_m4v3(co, ob->obmat, bp->vec); + mul_v3_m4v3(co, ob->object_to_world, bp->vec); BLI_kdtree_3d_insert(tree, i++, co); bp++; } @@ -5368,7 +5370,7 @@ KDTree_3d *BKE_object_as_kdtree(Object *ob, int *r_tot) for (bp = lt->def; i < tot; bp++) { float co[3]; - mul_v3_m4v3(co, ob->obmat, bp->vec); + mul_v3_m4v3(co, ob->object_to_world, bp->vec); BLI_kdtree_3d_insert(tree, i++, co); } diff --git a/source/blender/blenkernel/intern/object_dupli.cc b/source/blender/blenkernel/intern/object_dupli.cc index 96da99af97e..d029d307d6e 100644 --- a/source/blender/blenkernel/intern/object_dupli.cc +++ b/source/blender/blenkernel/intern/object_dupli.cc @@ -41,6 +41,7 @@ #include "BKE_geometry_set.hh" #include "BKE_global.h" #include "BKE_idprop.h" +#include "BKE_instances.hh" #include "BKE_lattice.h" #include "BKE_main.h" #include "BKE_mesh.h" @@ -70,6 +71,8 @@ using blender::float3; using blender::float4x4; using blender::Span; using blender::Vector; +using blender::bke::InstanceReference; +using blender::bke::Instances; namespace geo_log = blender::nodes::geo_eval_log; /* -------------------------------------------------------------------- */ @@ -194,7 +197,8 @@ static bool copy_dupli_context(DupliContext *r_ctx, /** * Generate a dupli instance. * - * \param mat: is transform of the object relative to current context (including #Object.obmat). + * \param mat: is transform of the object relative to current context (including + * #Object.object_to_world). */ static DupliObject *make_dupli(const DupliContext *ctx, Object *ob, @@ -293,7 +297,7 @@ static DupliObject *make_dupli(const DupliContext *ctx, /** * Recursive dupli-objects. * - * \param space_mat: is the local dupli-space (excluding dupli #Object.obmat). + * \param space_mat: is the local dupli-space (excluding dupli #Object.object_to_world). */ static void make_recursive_duplis(const DupliContext *ctx, Object *ob, @@ -465,8 +469,8 @@ static void make_duplis_collection(const DupliContext *ctx) /* Combine collection offset and `obmat`. */ unit_m4(collection_mat); sub_v3_v3(collection_mat[3], collection->instance_offset); - mul_m4_m4m4(collection_mat, ob->obmat, collection_mat); - /* Don't access 'ob->obmat' from now on. */ + mul_m4_m4m4(collection_mat, ob->object_to_world, collection_mat); + /* Don't access 'ob->object_to_world' from now on. */ eEvaluationMode mode = DEG_get_mode(ctx->depsgraph); FOREACH_COLLECTION_VISIBLE_OBJECT_RECURSIVE_BEGIN (collection, cob, mode) { @@ -474,7 +478,7 @@ static void make_duplis_collection(const DupliContext *ctx) float mat[4][4]; /* Collection dupli-offset, should apply after everything else. */ - mul_m4_m4m4(mat, collection_mat, cob->obmat); + mul_m4_m4m4(mat, collection_mat, cob->object_to_world); make_dupli(ctx, cob, mat, _base_id); @@ -581,7 +585,7 @@ static DupliObject *vertex_dupli(const DupliContext *ctx, /* Make offset relative to inst_ob using relative child transform. */ mul_mat3_m4_v3(child_imat, obmat[3]); /* Apply `obmat` _after_ the local vertex transform. */ - mul_m4_m4m4(obmat, inst_ob->obmat, obmat); + mul_m4_m4m4(obmat, inst_ob->object_to_world, obmat); /* Space matrix is constructed by removing `obmat` transform, * this yields the world-space transform for recursive duplis. */ @@ -605,10 +609,10 @@ static void make_child_duplis_verts_from_mesh(const DupliContext *ctx, const MVert *mvert = vdd->mvert; const int totvert = vdd->totvert; - invert_m4_m4(inst_ob->imat, inst_ob->obmat); + invert_m4_m4(inst_ob->imat, inst_ob->object_to_world); /* Relative transform from parent to child space. */ float child_imat[4][4]; - mul_m4_m4m4(child_imat, inst_ob->imat, ctx->object->obmat); + mul_m4_m4m4(child_imat, inst_ob->imat, ctx->object->object_to_world); for (int i = 0; i < totvert; i++) { DupliObject *dob = vertex_dupli( @@ -627,10 +631,10 @@ static void make_child_duplis_verts_from_editmesh(const DupliContext *ctx, BMEditMesh *em = vdd->em; const bool use_rotation = vdd->params.use_rotation; - invert_m4_m4(inst_ob->imat, inst_ob->obmat); + invert_m4_m4(inst_ob->imat, inst_ob->object_to_world); /* Relative transform from parent to child space. */ float child_imat[4][4]; - mul_m4_m4m4(child_imat, inst_ob->imat, ctx->object->obmat); + mul_m4_m4m4(child_imat, inst_ob->imat, ctx->object->object_to_world); BMVert *v; BMIter iter; @@ -755,7 +759,7 @@ static void make_duplis_font(const DupliContext *ctx) return; } - copy_m4_m4(pmat, par->obmat); + copy_m4_m4(pmat, par->object_to_world); /* In `par` the family name is stored, use this to find the other objects. */ @@ -800,7 +804,7 @@ static void make_duplis_font(const DupliContext *ctx) mul_m4_v3(pmat, vec); - copy_m4_m4(obmat, par->obmat); + copy_m4_m4(obmat, par->object_to_world); if (UNLIKELY(ct->rot != 0.0f)) { float rmat[4][4]; @@ -874,8 +878,8 @@ static void make_duplis_geometry_set_impl(const DupliContext *ctx, } const bool creates_duplis_for_components = component_index >= 1; - const InstancesComponent *component = geometry_set.get_component_for_read<InstancesComponent>(); - if (component == nullptr) { + const Instances *instances = geometry_set.get_instances_for_read(); + if (instances == nullptr) { return; } @@ -890,13 +894,13 @@ static void make_duplis_geometry_set_impl(const DupliContext *ctx, instances_ctx = &new_instances_ctx; } - Span<float4x4> instance_offset_matrices = component->instance_transforms(); - Span<int> instance_reference_handles = component->instance_reference_handles(); - Span<int> almost_unique_ids = component->almost_unique_ids(); - Span<InstanceReference> references = component->references(); + Span<float4x4> instance_offset_matrices = instances->transforms(); + Span<int> reference_handles = instances->reference_handles(); + Span<int> almost_unique_ids = instances->almost_unique_ids(); + Span<InstanceReference> references = instances->references(); for (int64_t i : instance_offset_matrices.index_range()) { - const InstanceReference &reference = references[instance_reference_handles[i]]; + const InstanceReference &reference = references[reference_handles[i]]; const int id = almost_unique_ids[i]; const DupliContext *ctx_for_instance = instances_ctx; @@ -948,7 +952,7 @@ static void make_duplis_geometry_set_impl(const DupliContext *ctx, } float instance_matrix[4][4]; - mul_m4_m4m4(instance_matrix, collection_matrix, object->obmat); + mul_m4_m4m4(instance_matrix, collection_matrix, object->object_to_world); make_dupli(&sub_ctx, object, instance_matrix, object_id++); make_recursive_duplis(&sub_ctx, object, collection_matrix, object_id++); @@ -983,7 +987,7 @@ static void make_duplis_geometry_set_impl(const DupliContext *ctx, static void make_duplis_geometry_set(const DupliContext *ctx) { const GeometrySet *geometry_set = ctx->object->runtime.geometry_set_eval; - make_duplis_geometry_set_impl(ctx, *geometry_set, ctx->object->obmat, false, false); + make_duplis_geometry_set_impl(ctx, *geometry_set, ctx->object->object_to_world, false, false); } static const DupliGenerator gen_dupli_geometry_set = { @@ -1089,7 +1093,7 @@ static DupliObject *face_dupli(const DupliContext *ctx, } /* Apply `obmat` _after_ the local face transform. */ - mul_m4_m4m4(obmat, inst_ob->obmat, obmat); + mul_m4_m4m4(obmat, inst_ob->object_to_world, obmat); /* Space matrix is constructed by removing `obmat` transform, * this yields the world-space transform for recursive duplis. */ @@ -1173,9 +1177,9 @@ static void make_child_duplis_faces_from_mesh(const DupliContext *ctx, float child_imat[4][4]; - invert_m4_m4(inst_ob->imat, inst_ob->obmat); + invert_m4_m4(inst_ob->imat, inst_ob->object_to_world); /* Relative transform from parent to child space. */ - mul_m4_m4m4(child_imat, inst_ob->imat, ctx->object->obmat); + mul_m4_m4m4(child_imat, inst_ob->imat, ctx->object->object_to_world); const float scale_fac = ctx->object->instance_faces_scale; for (a = 0, mp = mpoly; a < totface; a++, mp++) { @@ -1213,9 +1217,9 @@ static void make_child_duplis_faces_from_editmesh(const DupliContext *ctx, BLI_assert((vert_coords == nullptr) || (em->bm->elem_index_dirty & BM_VERT) == 0); - invert_m4_m4(inst_ob->imat, inst_ob->obmat); + invert_m4_m4(inst_ob->imat, inst_ob->object_to_world); /* Relative transform from parent to child space. */ - mul_m4_m4m4(child_imat, inst_ob->imat, ctx->object->obmat); + mul_m4_m4m4(child_imat, inst_ob->imat, ctx->object->object_to_world); const float scale_fac = ctx->object->instance_faces_scale; BM_ITER_MESH_INDEX (f, &iter, em->bm, BM_FACES_OF_MESH, a) { @@ -1345,7 +1349,7 @@ static void make_duplis_particle_system(const DupliContext *ctx, ParticleSystem sim.psys = psys; sim.psmd = psys_get_modifier(par, psys); /* Make sure emitter `imat` is in global coordinates instead of render view coordinates. */ - invert_m4_m4(par->imat, par->obmat); + invert_m4_m4(par->imat, par->object_to_world); /* First check for loops (particle system object used as dupli-object). */ if (part->ren_as == PART_DRAW_OB) { @@ -1532,7 +1536,7 @@ static void make_duplis_particle_system(const DupliContext *ctx, ParticleSystem b = 0; FOREACH_COLLECTION_VISIBLE_OBJECT_RECURSIVE_BEGIN ( part->instance_collection, object, mode) { - copy_m4_m4(tmat, oblist[b]->obmat); + copy_m4_m4(tmat, oblist[b]->object_to_world); /* Apply collection instance offset. */ sub_v3_v3(tmat[3], part->instance_collection->instance_offset); @@ -1555,7 +1559,7 @@ static void make_duplis_particle_system(const DupliContext *ctx, ParticleSystem } else { float obmat[4][4]; - copy_m4_m4(obmat, ob->obmat); + copy_m4_m4(obmat, ob->object_to_world); float vec[3]; copy_v3_v3(vec, obmat[3]); @@ -1749,7 +1753,7 @@ ListBase *object_duplilist_preview(Depsgraph *depsgraph, *viewer_path)) { ctx.preview_base_geometry = &viewer_log->geometry; make_duplis_geometry_set_impl( - &ctx, viewer_log->geometry, ob_eval->obmat, true, ob_eval->type == OB_CURVES); + &ctx, viewer_log->geometry, ob_eval->object_to_world, true, ob_eval->type == OB_CURVES); } } return duplilist; diff --git a/source/blender/blenkernel/intern/object_update.cc b/source/blender/blenkernel/intern/object_update.cc index ceef6404bf0..7ea13bfcc84 100644 --- a/source/blender/blenkernel/intern/object_update.cc +++ b/source/blender/blenkernel/intern/object_update.cc @@ -61,7 +61,7 @@ void BKE_object_eval_local_transform(Depsgraph *depsgraph, Object *ob) DEG_debug_print_eval(depsgraph, __func__, ob->id.name, ob); /* calculate local matrix */ - BKE_object_to_mat4(ob, ob->obmat); + BKE_object_to_mat4(ob, ob->object_to_world); } void BKE_object_eval_parent(Depsgraph *depsgraph, Object *ob) @@ -78,18 +78,18 @@ void BKE_object_eval_parent(Depsgraph *depsgraph, Object *ob) /* get local matrix (but don't calculate it, as that was done already!) */ /* XXX: redundant? */ - copy_m4_m4(locmat, ob->obmat); + copy_m4_m4(locmat, ob->object_to_world); /* get parent effect matrix */ BKE_object_get_parent_matrix(ob, par, totmat); /* total */ mul_m4_m4m4(tmat, totmat, ob->parentinv); - mul_m4_m4m4(ob->obmat, tmat, locmat); + mul_m4_m4m4(ob->object_to_world, tmat, locmat); /* origin, for help line */ if ((ob->partype & PARTYPE) == PARSKEL) { - copy_v3_v3(ob->runtime.parent_display_origin, par->obmat[3]); + copy_v3_v3(ob->runtime.parent_display_origin, par->object_to_world[3]); } else { copy_v3_v3(ob->runtime.parent_display_origin, totmat[3]); @@ -121,9 +121,9 @@ void BKE_object_eval_transform_final(Depsgraph *depsgraph, Object *ob) DEG_debug_print_eval(depsgraph, __func__, ob->id.name, ob); /* Make sure inverse matrix is always up to date. This way users of it * do not need to worry about recalculating it. */ - invert_m4_m4_safe(ob->imat, ob->obmat); + invert_m4_m4_safe(ob->imat, ob->object_to_world); /* Set negative scale flag in object. */ - if (is_negative_m4(ob->obmat)) { + if (is_negative_m4(ob->object_to_world)) { ob->transflag |= OB_NEG_SCALE; } else { @@ -257,7 +257,7 @@ void BKE_object_sync_to_original(Depsgraph *depsgraph, Object *object) /* Base flags. */ object_orig->base_flag = object->base_flag; /* Transformation flags. */ - copy_m4_m4(object_orig->obmat, object->obmat); + copy_m4_m4(object_orig->object_to_world, object->object_to_world); copy_m4_m4(object_orig->imat, object->imat); copy_m4_m4(object_orig->constinv, object->constinv); object_orig->transflag = object->transflag; @@ -292,6 +292,8 @@ void BKE_object_batch_cache_dirty_tag(Object *ob) BKE_lattice_batch_cache_dirty_tag((struct Lattice *)ob->data, BKE_LATTICE_BATCH_DIRTY_ALL); break; case OB_CURVES_LEGACY: + case OB_SURF: + case OB_FONT: BKE_curve_batch_cache_dirty_tag((struct Curve *)ob->data, BKE_CURVE_BATCH_DIRTY_ALL); break; case OB_MBALL: { diff --git a/source/blender/blenkernel/intern/ocean.c b/source/blender/blenkernel/intern/ocean.c index 396c3443a73..bcf382b6022 100644 --- a/source/blender/blenkernel/intern/ocean.c +++ b/source/blender/blenkernel/intern/ocean.c @@ -1144,7 +1144,7 @@ static void cache_filename( break; } - BLI_join_dirfile(cachepath, sizeof(cachepath), path, fname); + BLI_path_join(cachepath, sizeof(cachepath), path, fname); BKE_image_path_from_imtype( string, cachepath, relbase, frame, R_IMF_IMTYPE_OPENEXR, true, true, ""); diff --git a/source/blender/blenkernel/intern/packedFile.c b/source/blender/blenkernel/intern/packedFile.c index 901b42ac0b2..0c9d9f5b048 100644 --- a/source/blender/blenkernel/intern/packedFile.c +++ b/source/blender/blenkernel/intern/packedFile.c @@ -545,7 +545,7 @@ static void unpack_generate_paths(const char *name, break; } if (dir_name) { - BLI_path_join(r_relpath, relpathlen, "//", dir_name, tempname, NULL); + BLI_path_join(r_relpath, relpathlen, "//", dir_name, tempname); } } diff --git a/source/blender/blenkernel/intern/paint.cc b/source/blender/blenkernel/intern/paint.cc index d45ce776b64..a39e53662aa 100644 --- a/source/blender/blenkernel/intern/paint.cc +++ b/source/blender/blenkernel/intern/paint.cc @@ -54,6 +54,7 @@ #include "BKE_object.h" #include "BKE_paint.h" #include "BKE_pbvh.h" +#include "BKE_scene.h" #include "BKE_subdiv_ccg.h" #include "BKE_subsurf.h" @@ -1042,6 +1043,8 @@ eObjectMode BKE_paint_object_mode_from_paintmode(ePaintMode mode) return OB_MODE_TEXTURE_PAINT; case PAINT_MODE_SCULPT_UV: return OB_MODE_EDIT; + case PAINT_MODE_SCULPT_CURVES: + return OB_MODE_SCULPT_CURVES; case PAINT_MODE_INVALID: default: return OB_MODE_OBJECT; @@ -1198,7 +1201,7 @@ void BKE_paint_stroke_get_average(Scene *scene, Object *ob, float stroke[3]) mul_v3_v3fl(stroke, ups->average_stroke_accum, fac); } else { - copy_v3_v3(stroke, ob->obmat[3]); + copy_v3_v3(stroke, ob->object_to_world[3]); } } @@ -1785,8 +1788,8 @@ static void sculpt_update_object( /* If the fully evaluated mesh has the same topology as the deform-only version, use it. * This matters because crazyspace evaluation is very restrictive and excludes even modifiers * that simply recompute vertex weights (which can even include Geometry Nodes). */ - if (me_eval_deform->polys().data() == me_eval->polys().data() && - me_eval_deform->loops().data() == me_eval->loops().data() && + if (me_eval_deform->totpoly == me_eval->totpoly && + me_eval_deform->totloop == me_eval->totloop && me_eval_deform->totvert == me_eval->totvert) { BKE_sculptsession_free_deformMats(ss); @@ -1986,7 +1989,10 @@ bool *BKE_sculpt_hide_poly_ensure(Mesh *mesh) &mesh->pdata, CD_PROP_BOOL, CD_SET_DEFAULT, nullptr, mesh->totpoly, ".hide_poly")); } -int BKE_sculpt_mask_layers_ensure(Object *ob, MultiresModifierData *mmd) +int BKE_sculpt_mask_layers_ensure(Depsgraph *depsgraph, + Main *bmain, + Object *ob, + MultiresModifierData *mmd) { Mesh *me = static_cast<Mesh *>(ob->data); const Span<MPoly> polys = me->polys(); @@ -2045,6 +2051,9 @@ int BKE_sculpt_mask_layers_ensure(Object *ob, MultiresModifierData *mmd) } /* The evaluated multires CCG must be updated to contain the new data. */ DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); + if (depsgraph) { + BKE_scene_graph_evaluated_ensure(depsgraph, bmain); + } ret |= SCULPT_MASK_LAYER_CALC_LOOP; } @@ -2237,7 +2246,8 @@ static PBVH *build_pbvh_from_ccg(Object *ob, SubdivCCG *subdiv_ccg, bool respect (void **)subdiv_ccg->grid_faces, subdiv_ccg->grid_flag_mats, subdiv_ccg->grid_hidden, - base_mesh); + base_mesh, + subdiv_ccg); pbvh_show_mask_set(pbvh, ob->sculpt->show_mask); pbvh_show_face_sets_set(pbvh, ob->sculpt->show_face_sets); return pbvh; @@ -2295,14 +2305,18 @@ PBVH *BKE_sculpt_object_pbvh_ensure(Depsgraph *depsgraph, Object *ob) void BKE_sculpt_bvh_update_from_ccg(PBVH *pbvh, SubdivCCG *subdiv_ccg) { + CCGKey key; + BKE_subdiv_ccg_key_top_level(&key, subdiv_ccg); + BKE_pbvh_grids_update(pbvh, subdiv_ccg->grids, (void **)subdiv_ccg->grid_faces, subdiv_ccg->grid_flag_mats, - subdiv_ccg->grid_hidden); + subdiv_ccg->grid_hidden, + &key); } -bool BKE_sculptsession_use_pbvh_draw(const Object *ob, const View3D * /*v3d*/) +bool BKE_sculptsession_use_pbvh_draw(const Object *ob, const RegionView3D *rv3d) { SculptSession *ss = ob->sculpt; if (ss == nullptr || ss->pbvh == nullptr || ss->mode_type != OB_MODE_SCULPT) { @@ -2310,9 +2324,10 @@ bool BKE_sculptsession_use_pbvh_draw(const Object *ob, const View3D * /*v3d*/) } if (BKE_pbvh_type(ss->pbvh) == PBVH_FACES) { - /* Regular mesh only draws from PBVH without modifiers and shape keys. */ - - return !(ss->shapekey_active || ss->deform_modifiers_active); + /* Regular mesh only draws from PBVH without modifiers and shape keys, or for + * external engines that do not have access to the PBVH like Eevee does. */ + const bool external_engine = rv3d && rv3d->render_engine != nullptr; + return !(ss->shapekey_active || ss->deform_modifiers_active || external_engine); } /* Multires and dyntopo always draw directly from the PBVH. */ diff --git a/source/blender/blenkernel/intern/particle.c b/source/blender/blenkernel/intern/particle.c index d6dd3cf0dbb..f111e2dde17 100644 --- a/source/blender/blenkernel/intern/particle.c +++ b/source/blender/blenkernel/intern/particle.c @@ -2370,8 +2370,8 @@ void precalc_guides(ParticleSimulationData *sim, ListBase *effectors) 0, 0); - mul_m4_v3(sim->ob->obmat, state.co); - mul_mat3_m4_v3(sim->ob->obmat, state.vel); + mul_m4_v3(sim->ob->object_to_world, state.co); + mul_mat3_m4_v3(sim->ob->object_to_world, state.vel); pd_point_from_particle(sim, pa, &state, &point); @@ -2454,8 +2454,8 @@ bool do_guides(Depsgraph *depsgraph, } } - mul_m4_v3(eff->ob->obmat, guidevec); - mul_mat3_m4_v3(eff->ob->obmat, guidedir); + mul_m4_v3(eff->ob->object_to_world, guidevec); + mul_mat3_m4_v3(eff->ob->object_to_world, guidedir); normalize_v3(guidedir); @@ -2956,7 +2956,7 @@ static void psys_thread_create_path(ParticleTask *task, psys_particle_on_emitter( ctx->sim.psmd, cpa_from, cpa_num, DMCACHE_ISCHILD, cpa->fuv, foffset, co, 0, 0, 0, orco); - mul_m4_v3(ob->obmat, co); + mul_m4_v3(ob->object_to_world, co); for (w = 0; w < 4; w++) { sub_v3_v3v3(off1[w], co, key[w]->co); @@ -3419,7 +3419,7 @@ void psys_cache_paths(ParticleSimulationData *sim, float cfra, const bool use_re /* dynamic hair is in object space */ /* keyed and baked are already in global space */ if (hair_mesh) { - mul_m4_v3(sim->ob->obmat, ca->co); + mul_m4_v3(sim->ob->object_to_world, ca->co); } else if (!keyed && !baked && !(psys->flag & PSYS_GLOBAL_HAIR)) { mul_m4_v3(hairmat, ca->co); @@ -3929,7 +3929,7 @@ void psys_mat_hair_to_global( psys_mat_hair_to_object(ob, mesh, from, pa, facemat); - mul_m4_m4m4(hairmat, ob->obmat, facemat); + mul_m4_m4m4(hairmat, ob->object_to_world, facemat); } /************************************************/ @@ -4661,8 +4661,8 @@ void psys_get_particle_on_path(ParticleSimulationData *sim, do_particle_interpolation(psys, p, pa, t, &pind, state); if (pind.mesh) { - mul_m4_v3(sim->ob->obmat, state->co); - mul_mat3_m4_v3(sim->ob->obmat, state->vel); + mul_m4_v3(sim->ob->object_to_world, state->co); + mul_mat3_m4_v3(sim->ob->object_to_world, state->vel); } else if (!keyed && !cached && !(psys->flag & PSYS_GLOBAL_HAIR)) { if ((pa->flag & PARS_REKEY) == 0) { @@ -4685,7 +4685,7 @@ void psys_get_particle_on_path(ParticleSimulationData *sim, } } else if (totchild) { - // invert_m4_m4(imat, ob->obmat); + // invert_m4_m4(imat, ob->object_to_world); /* interpolate childcache directly if it exists */ if (psys->childcache) { @@ -4733,7 +4733,7 @@ void psys_get_particle_on_path(ParticleSimulationData *sim, * positioning it accurately to the surface of the emitter. */ // copy_v3_v3(cpa_1st, co); - // mul_m4_v3(ob->obmat, cpa_1st); + // mul_m4_v3(ob->object_to_world, cpa_1st); pa = psys->particles + cpa->parent; diff --git a/source/blender/blenkernel/intern/particle_child.c b/source/blender/blenkernel/intern/particle_child.c index a890812cfc4..6cc7dbc70d0 100644 --- a/source/blender/blenkernel/intern/particle_child.c +++ b/source/blender/blenkernel/intern/particle_child.c @@ -187,7 +187,7 @@ static void do_kink_spiral(ParticleThreadContext *ctx, zero_v3(kink_base); kink_base[part->kink_axis] = 1.0f; - mul_mat3_m4_v3(ctx->sim.ob->obmat, kink_base); + mul_mat3_m4_v3(ctx->sim.ob->object_to_world, kink_base); /* Fill in invariant part of modifier context. */ ParticleChildModifierContext modifier_ctx = {NULL}; @@ -873,7 +873,7 @@ void do_child_modifiers(const ParticleChildModifierContext *modifier_ctx, part->kink_flat, part->kink, part->kink_axis, - sim->ob->obmat, + sim->ob->object_to_world, smooth_start); } } diff --git a/source/blender/blenkernel/intern/particle_system.c b/source/blender/blenkernel/intern/particle_system.c index c72bbe2fd08..7317318e828 100644 --- a/source/blender/blenkernel/intern/particle_system.c +++ b/source/blender/blenkernel/intern/particle_system.c @@ -750,10 +750,10 @@ void psys_get_birth_coords( /* particles live in global space so */ /* let's convert: */ /* -location */ - mul_m4_v3(ob->obmat, loc); + mul_m4_v3(ob->object_to_world, loc); /* -normal */ - mul_mat3_m4_v3(ob->obmat, nor); + mul_mat3_m4_v3(ob->object_to_world, nor); normalize_v3(nor); /* -tangent */ @@ -771,7 +771,7 @@ void psys_get_birth_coords( fac = -sinf((float)M_PI * (part->tanphase + phase)); madd_v3_v3fl(vtan, utan, fac); - mul_mat3_m4_v3(ob->obmat, vtan); + mul_mat3_m4_v3(ob->object_to_world, vtan); copy_v3_v3(utan, nor); mul_v3_fl(utan, dot_v3v3(vtan, nor)); @@ -786,7 +786,7 @@ void psys_get_birth_coords( r_vel[1] = 2.0f * (psys_frand(psys, p + 11) - 0.5f); r_vel[2] = 2.0f * (psys_frand(psys, p + 12) - 0.5f); - mul_mat3_m4_v3(ob->obmat, r_vel); + mul_mat3_m4_v3(ob->object_to_world, r_vel); normalize_v3(r_vel); } @@ -796,7 +796,7 @@ void psys_get_birth_coords( r_ave[1] = 2.0f * (psys_frand(psys, p + 14) - 0.5f); r_ave[2] = 2.0f * (psys_frand(psys, p + 15) - 0.5f); - mul_mat3_m4_v3(ob->obmat, r_ave); + mul_mat3_m4_v3(ob->object_to_world, r_ave); normalize_v3(r_ave); } @@ -808,7 +808,7 @@ void psys_get_birth_coords( r_rot[3] = 2.0f * (psys_frand(psys, p + 19) - 0.5f); normalize_qt(r_rot); - mat4_to_quat(rot, ob->obmat); + mat4_to_quat(rot, ob->object_to_world); mul_qt_qtqt(r_rot, r_rot, rot); } @@ -822,7 +822,7 @@ void psys_get_birth_coords( /* boids store direction in ave */ if (fabsf(nor[2]) == 1.0f) { - sub_v3_v3v3(state->ave, loc, ob->obmat[3]); + sub_v3_v3v3(state->ave, loc, ob->object_to_world[3]); normalize_v3(state->ave); } else { @@ -868,15 +868,15 @@ void psys_get_birth_coords( /* *emitter object orientation */ if (part->ob_vel[0] != 0.0f) { - normalize_v3_v3(vec, ob->obmat[0]); + normalize_v3_v3(vec, ob->object_to_world[0]); madd_v3_v3fl(vel, vec, part->ob_vel[0]); } if (part->ob_vel[1] != 0.0f) { - normalize_v3_v3(vec, ob->obmat[1]); + normalize_v3_v3(vec, ob->object_to_world[1]); madd_v3_v3fl(vel, vec, part->ob_vel[1]); } if (part->ob_vel[2] != 0.0f) { - normalize_v3_v3(vec, ob->obmat[2]); + normalize_v3_v3(vec, ob->object_to_world[2]); madd_v3_v3fl(vel, vec, part->ob_vel[2]); } @@ -924,7 +924,7 @@ void psys_get_birth_coords( case PART_ROT_OB_X: case PART_ROT_OB_Y: case PART_ROT_OB_Z: - copy_v3_v3(rot_vec, ob->obmat[part->rotmode - PART_ROT_OB_X]); + copy_v3_v3(rot_vec, ob->object_to_world[part->rotmode - PART_ROT_OB_X]); use_global_space = false; break; default: @@ -951,7 +951,7 @@ void psys_get_birth_coords( float q_obmat[4]; float q_imat[4]; - mat4_to_quat(q_obmat, ob->obmat); + mat4_to_quat(q_obmat, ob->object_to_world); invert_qt_qt_normalized(q_imat, q_obmat); if (part->rotmode != PART_ROT_NOR_TAN) { @@ -1639,7 +1639,7 @@ static void sph_springs_modify(ParticleSystem *psys, float dtime) } } - /* Loop through springs backwaqrds - for efficient delete function */ + /* Loop through springs backwards - for efficient delete function. */ for (i = psys->tot_fluidsprings - 1; i >= 0; i--) { if (psys->fluid_springs[i].delete_flag) { sph_spring_delete(psys, i); @@ -3364,7 +3364,7 @@ static void hair_create_input_mesh(ParticleSimulationData *sim, use_hair = psys_hair_use_simulation(pa, max_length); psys_mat_hair_to_object(sim->ob, sim->psmd->mesh_final, psys->part->from, pa, hairmat); - mul_m4_m4m4(root_mat, sim->ob->obmat, hairmat); + mul_m4_m4m4(root_mat, sim->ob->object_to_world, hairmat); normalize_m4(root_mat); bending_stiffness = CLAMPIS( @@ -3555,7 +3555,7 @@ static void save_hair(ParticleSimulationData *sim, float UNUSED(cfra)) HairKey *key, *root; PARTICLE_P; - invert_m4_m4(ob->imat, ob->obmat); + invert_m4_m4(ob->imat, ob->object_to_world); psys->lattice_deform_data = psys_create_lattice_deform_data(sim); @@ -4380,7 +4380,7 @@ static void particles_fluid_step(ParticleSimulationData *sim, mul_v3_v3(pa->state.co, scaleAbs); /* Match domain scale. */ - mul_m4_v3(ob->obmat, pa->state.co); + mul_m4_v3(ob->object_to_world, pa->state.co); /* Add origin offset to particle position. */ zero_v3(tmp); @@ -4764,7 +4764,7 @@ void particle_system_update(struct Depsgraph *depsgraph, float cfra; ParticleSystemModifierData *psmd = psys_get_modifier(ob, psys); - /* drawdata is outdated after ANY change */ + /* Draw data is outdated after ANY change. */ if (psys->pdd) { psys->pdd->flag &= ~PARTICLE_DRAW_DATA_UPDATED; } @@ -4963,7 +4963,7 @@ void particle_system_update(struct Depsgraph *depsgraph, /* Save matrix for duplicators, * at render-time the actual dupli-object's matrix is used so don't update! */ - invert_m4_m4(psys->imat, ob->obmat); + invert_m4_m4(psys->imat, ob->object_to_world); BKE_particle_batch_cache_dirty_tag(psys, BKE_PARTICLE_BATCH_DIRTY_ALL); } diff --git a/source/blender/blenkernel/intern/pbvh.c b/source/blender/blenkernel/intern/pbvh.c index b23fe53e80c..98e89b09060 100644 --- a/source/blender/blenkernel/intern/pbvh.c +++ b/source/blender/blenkernel/intern/pbvh.c @@ -39,8 +39,10 @@ #define LEAF_LIMIT 10000 -//#define PERFCNTRS +/* Uncomment to test that faces are only assigned to one PBVHNode */ +//#define VALIDATE_UNIQUE_NODE_FACES +//#define PERFCNTRS #define STACK_FIXED_DEPTH 100 typedef struct PBVHStack { @@ -422,6 +424,56 @@ static bool leaf_needs_material_split(PBVH *pbvh, int offset, int count) return false; } +static int adjust_partition_faces(PBVH *pbvh, int offset, int mid, int count) +{ + int poly = pbvh->looptri[pbvh->prim_indices[mid]].poly; + + /* Scan backwards. */ + while (mid > offset + 2) { /* First node should have at least 1 primitive */ + if (pbvh->looptri[pbvh->prim_indices[mid - 1]].poly != poly) { + return mid; + } + + mid--; + } + + /* If that didn't work try scanning forward. */ + while (mid < pbvh->totprim + count) { + if (pbvh->looptri[pbvh->prim_indices[mid]].poly != poly) { + break; + } + + mid++; + } + + return mid; +} + +static int adjust_partition_grids(PBVH *pbvh, int offset, int mid, int count) +{ + int poly = BKE_subdiv_ccg_grid_to_face_index(pbvh->subdiv_ccg, pbvh->prim_indices[mid]); + + /* Scan backwards. */ + while (mid > offset + 2) { /* First node should have at least 1 primitive */ + if (BKE_subdiv_ccg_grid_to_face_index(pbvh->subdiv_ccg, pbvh->prim_indices[mid - 1]) != poly) { + return mid; + } + + mid--; + } + + /* If that didn't work try scanning forward. */ + while (mid < pbvh->totprim + count) { + if (BKE_subdiv_ccg_grid_to_face_index(pbvh->subdiv_ccg, pbvh->prim_indices[mid]) != poly) { + break; + } + + mid++; + } + + return mid; +} + /* Recursively build a node in the tree * * vb is the voxel box around all of the primitives contained in @@ -478,6 +530,13 @@ static void build_sub(PBVH *pbvh, int node_index, BB *cb, BBC *prim_bbc, int off end = partition_indices_material(pbvh, offset, offset + count - 1); } + if (pbvh->header.type == PBVH_FACES) { + end = adjust_partition_faces(pbvh, offset, end, count); + } + else { + end = adjust_partition_grids(pbvh, offset, end, count); + } + /* Build children */ build_sub(pbvh, pbvh->nodes[node_index].children_offset, NULL, prim_bbc, offset, end - offset); build_sub(pbvh, @@ -587,6 +646,73 @@ static void pbvh_draw_args_init(PBVH *pbvh, PBVH_GPU_Args *args, PBVHNode *node) } } +#ifdef VALIDATE_UNIQUE_NODE_FACES +static void pbvh_validate_node_prims(PBVH *pbvh) +{ + int totface = 0; + + if (pbvh->header.type == PBVH_BMESH) { + return; + } + + for (int i = 0; i < pbvh->totnode; i++) { + PBVHNode *node = pbvh->nodes + i; + + if (!(node->flag & PBVH_Leaf)) { + continue; + } + + for (int j = 0; j < node->totprim; j++) { + int poly; + + if (pbvh->header.type == PBVH_FACES) { + poly = pbvh->looptri[node->prim_indices[j]].poly; + } + else { + poly = BKE_subdiv_ccg_grid_to_face_index(pbvh->subdiv_ccg, node->prim_indices[j]); + } + + totface = max_ii(totface, poly + 1); + } + } + + int *facemap = (int *)MEM_malloc_arrayN(totface, sizeof(*facemap), __func__); + + for (int i = 0; i < totface; i++) { + facemap[i] = -1; + } + + for (int i = 0; i < pbvh->totnode; i++) { + PBVHNode *node = pbvh->nodes + i; + + if (!(node->flag & PBVH_Leaf)) { + continue; + } + + for (int j = 0; j < node->totprim; j++) { + int poly; + + if (pbvh->header.type == PBVH_FACES) { + poly = pbvh->looptri[node->prim_indices[j]].poly; + } + else { + poly = BKE_subdiv_ccg_grid_to_face_index(pbvh->subdiv_ccg, node->prim_indices[j]); + } + + if (facemap[poly] != -1 && facemap[poly] != i) { + printf("%s: error: face spanned multiple nodes (old: %d new: %d)\n", + __func__, + facemap[poly], + i); + } + + facemap[poly] = i; + } + } + MEM_SAFE_FREE(facemap); +} +#endif + void BKE_pbvh_build_mesh(PBVH *pbvh, Mesh *mesh, const MPoly *mpoly, @@ -645,6 +771,32 @@ void BKE_pbvh_build_mesh(PBVH *pbvh, BB_expand(&cb, bbc->bcentroid); } + /* Ensure all primitives belonging to the same base face + * have the same bounds. This is needed to prevent them + * from being swapped away from each other inside the partition + * array. + */ + for (int i = 0; i < looptri_num; i++) { + const MLoopTri *lt = &looptri[i]; + int poly = lt->poly; + BBC *bbc = prim_bbc + i; + int j = i + 1; + + while (j < looptri_num && looptri[j].poly == poly) { + BBC *bbc2 = prim_bbc + j; + + BB_expand((BB *)bbc, bbc2->bmin); + BB_expand((BB *)bbc, bbc2->bmax); + j++; + } + + j = i + 1; + while (j < looptri_num && looptri[j].poly == poly) { + prim_bbc[j] = prim_bbc[i]; + j++; + } + } + if (looptri_num) { pbvh_build(pbvh, &cb, prim_bbc, looptri_num); } @@ -655,6 +807,10 @@ void BKE_pbvh_build_mesh(PBVH *pbvh, memset(pbvh->vert_bitmap, 0, sizeof(bool) * totvert); BKE_pbvh_update_active_vcol(pbvh, mesh); + +#ifdef VALIDATE_UNIQUE_NODE_FACES + pbvh_validate_node_prims(pbvh); +#endif } void BKE_pbvh_build_grids(PBVH *pbvh, @@ -664,7 +820,8 @@ void BKE_pbvh_build_grids(PBVH *pbvh, void **gridfaces, DMFlagMat *flagmats, BLI_bitmap **grid_hidden, - Mesh *me) + Mesh *me, + SubdivCCG *subdiv_ccg) { const int gridsize = key->grid_size; @@ -675,6 +832,7 @@ void BKE_pbvh_build_grids(PBVH *pbvh, pbvh->totgrid = totgrid; pbvh->gridkey = *key; pbvh->grid_hidden = grid_hidden; + pbvh->subdiv_ccg = subdiv_ccg; pbvh->leaf_limit = max_ii(LEAF_LIMIT / (gridsize * gridsize), 1); /* We need the base mesh attribute layout for PBVH draw. */ @@ -706,11 +864,40 @@ void BKE_pbvh_build_grids(PBVH *pbvh, BB_expand(&cb, bbc->bcentroid); } + /* Ensure all primitives belonging to the same base face + * have the same bounds. This is needed to prevent them + * from being swapped away from each other inside the partition + * array. + */ + for (int i = 0; i < totgrid; i++) { + int poly = BKE_subdiv_ccg_grid_to_face_index(pbvh->subdiv_ccg, i); + + BBC *bbc = prim_bbc + i; + int j = i + 1; + + while (j < totgrid && BKE_subdiv_ccg_grid_to_face_index(pbvh->subdiv_ccg, j) == poly) { + BBC *bbc2 = prim_bbc + j; + + BB_expand((BB *)bbc, bbc2->bmin); + BB_expand((BB *)bbc, bbc2->bmax); + j++; + } + + j = i + 1; + while (j < totgrid && BKE_subdiv_ccg_grid_to_face_index(pbvh->subdiv_ccg, j) == poly) { + prim_bbc[j] = prim_bbc[i]; + j++; + } + } + if (totgrid) { pbvh_build(pbvh, &cb, prim_bbc, totgrid); } MEM_freeN(prim_bbc); +#ifdef VALIDATE_UNIQUE_NODE_FACES + pbvh_validate_node_prims(pbvh); +#endif } PBVH *BKE_pbvh_new(PBVHType type) @@ -719,6 +906,11 @@ PBVH *BKE_pbvh_new(PBVHType type) pbvh->respect_hide = true; pbvh->draw_cache_invalid = true; pbvh->header.type = type; + + /* Initialize this to true, instead of waiting for a draw engine + * to set it. Prevents a crash in draw manager instancing code. + */ + pbvh->is_drawing = true; return pbvh; } @@ -2872,9 +3064,14 @@ void BKE_pbvh_draw_debug_cb(PBVH *pbvh, } } -void BKE_pbvh_grids_update( - PBVH *pbvh, CCGElem **grids, void **gridfaces, DMFlagMat *flagmats, BLI_bitmap **grid_hidden) +void BKE_pbvh_grids_update(PBVH *pbvh, + CCGElem **grids, + void **gridfaces, + DMFlagMat *flagmats, + BLI_bitmap **grid_hidden, + CCGKey *key) { + pbvh->gridkey = *key; pbvh->grids = grids; pbvh->gridfaces = gridfaces; diff --git a/source/blender/blenkernel/intern/pointcache.c b/source/blender/blenkernel/intern/pointcache.c index 5ec69f9bc45..868cdde6d01 100644 --- a/source/blender/blenkernel/intern/pointcache.c +++ b/source/blender/blenkernel/intern/pointcache.c @@ -1317,7 +1317,7 @@ static int ptcache_path(PTCacheID *pid, char *dirname) BLI_path_abs(dirname, blendfilename); } - return BLI_path_slash_ensure(dirname); /* new strlen() */ + return BLI_path_slash_ensure(dirname, MAX_PTCACHE_FILE); /* new strlen() */ } if ((blendfile_path[0] != '\0') || lib) { char file[MAX_PTCACHE_PATH]; /* we don't want the dir, only the file */ @@ -1334,14 +1334,14 @@ static int ptcache_path(PTCacheID *pid, char *dirname) BLI_snprintf(dirname, MAX_PTCACHE_PATH, "//" PTCACHE_PATH "%s", file); BLI_path_abs(dirname, blendfilename); - return BLI_path_slash_ensure(dirname); /* new strlen() */ + return BLI_path_slash_ensure(dirname, MAX_PTCACHE_FILE); /* new strlen() */ } /* use the temp path. this is weak but better than not using point cache at all */ /* temporary directory is assumed to exist and ALWAYS has a trailing slash */ BLI_snprintf(dirname, MAX_PTCACHE_PATH, "%s" PTCACHE_PATH, BKE_tempdir_session()); - return BLI_path_slash_ensure(dirname); /* new strlen() */ + return BLI_path_slash_ensure(dirname, MAX_PTCACHE_FILE); /* new strlen() */ } static size_t ptcache_filepath_ext_append(PTCacheID *pid, @@ -2611,7 +2611,7 @@ void BKE_ptcache_id_clear(PTCacheID *pid, int mode, uint cfra) } #endif - /* clear all files in the temp dir with the prefix of the ID and the ".bphys" suffix */ + /* Clear all files in the temp dir with the prefix of the ID and the `.bphys` suffix. */ switch (mode) { case PTCACHE_CLEAR_ALL: case PTCACHE_CLEAR_BEFORE: @@ -2640,7 +2640,7 @@ void BKE_ptcache_id_clear(PTCacheID *pid, int mode, uint cfra) if (STREQLEN(filepath, de->d_name, len)) { /* Do we have the right prefix. */ if (mode == PTCACHE_CLEAR_ALL) { pid->cache->last_exact = MIN2(pid->cache->startframe, 0); - BLI_join_dirfile(path_full, sizeof(path_full), path, de->d_name); + BLI_path_join(path_full, sizeof(path_full), path, de->d_name); BLI_delete(path_full, false, false); } else { @@ -2650,7 +2650,7 @@ void BKE_ptcache_id_clear(PTCacheID *pid, int mode, uint cfra) if (frame != -1) { if ((mode == PTCACHE_CLEAR_BEFORE && frame < cfra) || (mode == PTCACHE_CLEAR_AFTER && frame > cfra)) { - BLI_join_dirfile(path_full, sizeof(path_full), path, de->d_name); + BLI_path_join(path_full, sizeof(path_full), path, de->d_name); BLI_delete(path_full, false, false); if (pid->cache->cached_frames && frame >= sta && frame <= end) { pid->cache->cached_frames[frame - sta] = 0; @@ -2775,7 +2775,7 @@ void BKE_ptcache_id_time( /* time handling for point cache: * - simulation time is scaled by result of bsystem_time * - for offsetting time only time offset is taken into account, since - * that's always the same and can't be animated. a timeoffset which + * that's always the same and can't be animated. a time-offset which * varies over time is not simple to support. * - field and motion blur offsets are currently ignored, proper solution * is probably to interpolate results from two frames for that .. @@ -3524,7 +3524,7 @@ void BKE_ptcache_disk_cache_rename(PTCacheID *pid, const char *name_src, const c const int frame = ptcache_frame_from_filename(de->d_name, ext); if (frame != -1) { - BLI_join_dirfile(old_path_full, sizeof(old_path_full), path, de->d_name); + BLI_path_join(old_path_full, sizeof(old_path_full), path, de->d_name); ptcache_filepath(pid, new_path_full, frame, true, true); BLI_rename(old_path_full, new_path_full); } diff --git a/source/blender/blenkernel/intern/preferences.c b/source/blender/blenkernel/intern/preferences.c index b2e795901fb..dd76f9eddc1 100644 --- a/source/blender/blenkernel/intern/preferences.c +++ b/source/blender/blenkernel/intern/preferences.c @@ -115,8 +115,7 @@ void BKE_preferences_asset_library_default_add(UserDef *userdef) userdef, DATA_(BKE_PREFS_ASSET_LIBRARY_DEFAULT_NAME), NULL); /* Add new "Default" library under '[doc_path]/Blender/Assets'. */ - BLI_path_join( - library->path, sizeof(library->path), documents_path, N_("Blender"), N_("Assets"), NULL); + BLI_path_join(library->path, sizeof(library->path), documents_path, N_("Blender"), N_("Assets")); } /** \} */ diff --git a/source/blender/blenkernel/intern/rigidbody.c b/source/blender/blenkernel/intern/rigidbody.c index ffc6bc8d7a3..5e91b23bce3 100644 --- a/source/blender/blenkernel/intern/rigidbody.c +++ b/source/blender/blenkernel/intern/rigidbody.c @@ -264,13 +264,13 @@ static RigidBodyCon *rigidbody_copy_constraint(const Object *ob, const int UNUSE RigidBodyCon *rbcN = NULL; if (ob->rigidbody_constraint) { - /* just duplicate the whole struct first (to catch all the settings) */ + /* Just duplicate the whole struct first (to catch all the settings). */ rbcN = MEM_dupallocN(ob->rigidbody_constraint); - /* tag object as needing to be verified */ + /* Tag object as needing to be verified. */ rbcN->flag |= RBC_FLAG_NEEDS_VALIDATE; - /* clear out all the fields which need to be revalidated later */ + /* Clear out all the fields which need to be re-validated later. */ rbcN->physics_constraint = NULL; } @@ -684,7 +684,7 @@ void BKE_rigidbody_calc_volume(Object *ob, float *r_vol) if (totvert > 0 && tottri > 0) { BKE_mesh_calc_volume(mvert, totvert, lt, tottri, mloop, &volume, NULL); - const float volume_scale = mat4_to_volume_scale(ob->obmat); + const float volume_scale = mat4_to_volume_scale(ob->object_to_world); volume *= fabsf(volume_scale); } } @@ -809,7 +809,7 @@ static void rigidbody_validate_sim_object(RigidBodyWorld *rbw, Object *ob, bool return; } - mat4_to_loc_quat(loc, rot, ob->obmat); + mat4_to_loc_quat(loc, rot, ob->object_to_world); rbo->shared->physics_object = RB_body_new(rbo->shared->physics_shape, loc, rot); @@ -974,7 +974,7 @@ static void rigidbody_validate_sim_constraint(RigidBodyWorld *rbw, Object *ob, b rbc->physics_constraint = NULL; } - mat4_to_loc_quat(loc, rot, ob->obmat); + mat4_to_loc_quat(loc, rot, ob->object_to_world); if (rb1 && rb2) { switch (rbc->type) { @@ -1266,7 +1266,7 @@ RigidBodyOb *BKE_rigidbody_create_object(Scene *scene, Object *ob, short type) rbo->mesh_source = RBO_MESH_DEFORM; /* set initial transform */ - mat4_to_loc_quat(rbo->pos, rbo->orn, ob->obmat); + mat4_to_loc_quat(rbo->pos, rbo->orn, ob->object_to_world); /* flag cache as outdated */ BKE_rigidbody_cache_reset(rbw); @@ -1689,7 +1689,7 @@ static void rigidbody_update_sim_ob(Depsgraph *depsgraph, Object *ob, RigidBodyO if (!(rbo->flag & RBO_FLAG_KINEMATIC)) { /* update scale for all non kinematic objects */ float new_scale[3], old_scale[3]; - mat4_to_size(new_scale, ob->obmat); + mat4_to_size(new_scale, ob->object_to_world); RB_body_get_scale(rbo->shared->physics_object, old_scale); /* Avoid updating collision shape AABBs if scale didn't change. */ @@ -1886,7 +1886,7 @@ static ListBase rigidbody_create_substep_data(RigidBodyWorld *rbw) copy_v4_v4(data->old_rot, rot); copy_v3_v3(data->old_scale, scale); - mat4_decompose(loc, rot, scale, ob->obmat); + mat4_decompose(loc, rot, scale, ob->object_to_world); copy_v3_v3(data->new_pos, loc); copy_v4_v4(data->new_rot, rot); @@ -2055,15 +2055,15 @@ void BKE_rigidbody_sync_transforms(RigidBodyWorld *rbw, Object *ob, float ctime) quat_to_mat4(mat, rbo->orn); copy_v3_v3(mat[3], rbo->pos); - mat4_to_size(size, ob->obmat); + mat4_to_size(size, ob->object_to_world); size_to_mat4(size_mat, size); mul_m4_m4m4(mat, mat, size_mat); - copy_m4_m4(ob->obmat, mat); + copy_m4_m4(ob->object_to_world, mat); } /* otherwise set rigid body transform to current obmat */ else { - mat4_to_loc_quat(rbo->pos, rbo->orn, ob->obmat); + mat4_to_loc_quat(rbo->pos, rbo->orn, ob->object_to_world); } } diff --git a/source/blender/blenkernel/intern/scene.cc b/source/blender/blenkernel/intern/scene.cc index fc47fb71bf3..c921cf603de 100644 --- a/source/blender/blenkernel/intern/scene.cc +++ b/source/blender/blenkernel/intern/scene.cc @@ -280,6 +280,9 @@ static void scene_copy_data(Main *bmain, ID *id_dst, const ID *id_src, const int } /* View Layers */ + LISTBASE_FOREACH (ViewLayer *, view_layer, &scene_src->view_layers) { + BKE_view_layer_synced_ensure(scene_src, view_layer); + } BLI_duplicatelist(&scene_dst->view_layers, &scene_src->view_layers); for (ViewLayer *view_layer_src = static_cast<ViewLayer *>(scene_src->view_layers.first), *view_layer_dst = static_cast<ViewLayer *>(scene_dst->view_layers.first); @@ -2275,13 +2278,13 @@ int BKE_scene_base_iter_next( if (iter->dupli_refob != *ob) { if (iter->dupli_refob) { /* Restore previous object's real matrix. */ - copy_m4_m4(iter->dupli_refob->obmat, iter->omat); + copy_m4_m4(iter->dupli_refob->object_to_world, iter->omat); } /* Backup new object's real matrix. */ iter->dupli_refob = *ob; - copy_m4_m4(iter->omat, iter->dupli_refob->obmat); + copy_m4_m4(iter->omat, iter->dupli_refob->object_to_world); } - copy_m4_m4((*ob)->obmat, iter->dupob->mat); + copy_m4_m4((*ob)->object_to_world, iter->dupob->mat); iter->dupob = iter->dupob->next; } @@ -2291,7 +2294,7 @@ int BKE_scene_base_iter_next( if (iter->dupli_refob) { /* Restore last object's real matrix. */ - copy_m4_m4(iter->dupli_refob->obmat, iter->omat); + copy_m4_m4(iter->dupli_refob->object_to_world, iter->omat); iter->dupli_refob = nullptr; } diff --git a/source/blender/blenkernel/intern/screen.c b/source/blender/blenkernel/intern/screen.c index 3e5dbc47c40..2c896788b20 100644 --- a/source/blender/blenkernel/intern/screen.c +++ b/source/blender/blenkernel/intern/screen.c @@ -304,7 +304,7 @@ IDTypeInfo IDType_ID_SCR = { /* ************ Space-type/region-type handling ************** */ -/* keep global; this has to be accessible outside of windowmanager */ +/** Keep global; this has to be accessible outside of window-manager. */ static ListBase spacetypes = {NULL, NULL}; /* not SpaceType itself */ diff --git a/source/blender/blenkernel/intern/softbody.c b/source/blender/blenkernel/intern/softbody.c index 14a7d26a354..4147999bef8 100644 --- a/source/blender/blenkernel/intern/softbody.c +++ b/source/blender/blenkernel/intern/softbody.c @@ -133,9 +133,9 @@ typedef struct SB_thread_context { #define BSF_INTERSECT 1 /* edge intersects collider face */ -/* private definitions for bodypoint states */ -#define SBF_DOFUZZY 1 /* Bodypoint do fuzzy. */ -#define SBF_OUTOFCOLLISION 2 /* Bodypoint does not collide. */ +/* private definitions for body-point states */ +#define SBF_DOFUZZY 1 /* Body-point do fuzzy. */ +#define SBF_OUTOFCOLLISION 2 /* Body-point does not collide. */ #define BFF_INTERSECT 1 /* collider edge intrudes face. */ #define BFF_CLOSEVERT 2 /* collider vertex repulses face. */ @@ -318,7 +318,7 @@ static ccd_Mesh *ccd_mesh_make(Object *ob) /* OBBs for idea1 */ pccd_M->mima = MEM_mallocN(sizeof(ccdf_minmax) * pccd_M->tri_num, "ccd_Mesh_Faces_mima"); - /* anyhoo we need to walk the list of faces and find OBB they live in */ + /* Anyhow we need to walk the list of faces and find OBB they live in. */ for (i = 0, mima = pccd_M->mima, vt = pccd_M->tri; i < pccd_M->tri_num; i++, mima++, vt++) { const float *v; @@ -413,7 +413,7 @@ static void ccd_mesh_update(Object *ob, ccd_Mesh *pccd_M) pccd_M->bbmax[2] = max_ff(pccd_M->bbmax[2], v[2] + hull); } - /* anyhoo we need to walk the list of faces and find OBB they live in */ + /* Anyhow we need to walk the list of faces and find OBB they live in. */ for (i = 0, mima = pccd_M->mima, vt = pccd_M->tri; i < pccd_M->tri_num; i++, mima++, vt++) { const float *v; @@ -2644,7 +2644,7 @@ static void springs_from_mesh(Object *ob) bp = ob->soft->bpoint; for (a = 0; a < me->totvert; a++, bp++) { copy_v3_v3(bp->origS, verts[a].co); - mul_m4_v3(ob->obmat, bp->origS); + mul_m4_v3(ob->object_to_world, bp->origS); } } /* recalculate spring length for meshes here */ @@ -2809,9 +2809,9 @@ static float globallen(float *v1, float *v2, Object *ob) { float p1[3], p2[3]; copy_v3_v3(p1, v1); - mul_m4_v3(ob->obmat, p1); + mul_m4_v3(ob->object_to_world, p1); copy_v3_v3(p2, v2); - mul_m4_v3(ob->obmat, p2); + mul_m4_v3(ob->object_to_world, p2); return len_v3v3(p1, p2); } @@ -3073,7 +3073,7 @@ static void softbody_to_object(Object *ob, float (*vertexCos)[3], int numVerts, SB_estimate_transform(ob, sb->lcom, sb->lrot, sb->lscale); } /* Inverse matrix is not up to date. */ - invert_m4_m4(ob->imat, ob->obmat); + invert_m4_m4(ob->imat, ob->object_to_world); for (a = 0; a < numVerts; a++, bp++) { copy_v3_v3(vertexCos[a], bp->pos); @@ -3223,7 +3223,7 @@ static void softbody_update_positions(Object *ob, /* copy the position of the goals at desired end time */ copy_v3_v3(bp->origE, vertexCos[a]); /* vertexCos came from local world, go global */ - mul_m4_v3(ob->obmat, bp->origE); + mul_m4_v3(ob->object_to_world, bp->origE); /* just to be save give bp->origT a defined value * will be calculated in interpolate_exciter() */ copy_v3_v3(bp->origT, bp->origE); @@ -3279,7 +3279,7 @@ static void softbody_reset(Object *ob, SoftBody *sb, float (*vertexCos)[3], int for (a = 0, bp = sb->bpoint; a < numVerts; a++, bp++) { copy_v3_v3(bp->pos, vertexCos[a]); - mul_m4_v3(ob->obmat, bp->pos); /* Yep, soft-body is global coords. */ + mul_m4_v3(ob->object_to_world, bp->pos); /* Yep, soft-body is global coords. */ copy_v3_v3(bp->origS, bp->pos); copy_v3_v3(bp->origE, bp->pos); copy_v3_v3(bp->origT, bp->pos); diff --git a/source/blender/blenkernel/intern/sound.c b/source/blender/blenkernel/intern/sound.c index d08fba0e657..1aef42ef037 100644 --- a/source/blender/blenkernel/intern/sound.c +++ b/source/blender/blenkernel/intern/sound.c @@ -1129,9 +1129,9 @@ static void sound_update_base(Scene *scene, Object *object, void *new_set) AUD_SequenceEntry_setConeAngleInner(strip->speaker_handle, speaker->cone_angle_inner); AUD_SequenceEntry_setConeVolumeOuter(strip->speaker_handle, speaker->cone_volume_outer); - mat4_to_quat(quat, object->obmat); + mat4_to_quat(quat, object->object_to_world); AUD_SequenceEntry_setAnimationData( - strip->speaker_handle, AUD_AP_LOCATION, scene->r.cfra, object->obmat[3], 1); + strip->speaker_handle, AUD_AP_LOCATION, scene->r.cfra, object->object_to_world[3], 1); AUD_SequenceEntry_setAnimationData( strip->speaker_handle, AUD_AP_ORIENTATION, scene->r.cfra, quat, 1); AUD_SequenceEntry_setAnimationData( @@ -1171,9 +1171,9 @@ void BKE_sound_update_scene(Depsgraph *depsgraph, Scene *scene) } if (scene->camera) { - mat4_to_quat(quat, scene->camera->obmat); + mat4_to_quat(quat, scene->camera->object_to_world); AUD_Sequence_setAnimationData( - scene->sound_scene, AUD_AP_LOCATION, scene->r.cfra, scene->camera->obmat[3], 1); + scene->sound_scene, AUD_AP_LOCATION, scene->r.cfra, scene->camera->object_to_world[3], 1); AUD_Sequence_setAnimationData(scene->sound_scene, AUD_AP_ORIENTATION, scene->r.cfra, quat, 1); } diff --git a/source/blender/blenkernel/intern/unit.c b/source/blender/blenkernel/intern/unit.c index f7ea4c81fbf..f5badfc9e94 100644 --- a/source/blender/blenkernel/intern/unit.c +++ b/source/blender/blenkernel/intern/unit.c @@ -715,7 +715,7 @@ static const char *unit_find_str(const char *str, const char *substr, bool case_ /* Weak unicode support!, so "µm" won't match up be replaced by "m" * since non ascii utf8 values will NEVER return true */ isalpha_or_utf8(*BLI_str_find_prev_char_utf8(str_found, str)) == 0) { - /* Next char cannot be alphanum. */ + /* Next char cannot be alpha-numeric. */ int len_name = strlen(substr); if (!isalpha_or_utf8(*(str_found + len_name))) { diff --git a/source/blender/blenkernel/intern/vfont.c b/source/blender/blenkernel/intern/vfont.c index 7ace1a3aa3b..9f48b9b9c4a 100644 --- a/source/blender/blenkernel/intern/vfont.c +++ b/source/blender/blenkernel/intern/vfont.c @@ -1310,14 +1310,14 @@ static bool vfont_to_curve(Object *ob, float timeofs, sizefac; if (ob != NULL) { - invert_m4_m4(imat, ob->obmat); + invert_m4_m4(imat, ob->object_to_world); } else { unit_m4(imat); } copy_m3_m4(imat3, imat); - copy_m3_m4(cmat, cu->textoncurve->obmat); + copy_m3_m4(cmat, cu->textoncurve->object_to_world); mul_m3_m3m3(cmat, cmat, imat3); sizefac = normalize_v3(cmat[0]) / font_size; diff --git a/source/blender/blenkernel/intern/volume.cc b/source/blender/blenkernel/intern/volume.cc index 7c54b4d3f2f..e81657f9ef0 100644 --- a/source/blender/blenkernel/intern/volume.cc +++ b/source/blender/blenkernel/intern/volume.cc @@ -445,7 +445,7 @@ struct VolumeGrid { * may actually be loaded by another user while this is false. But only after * calling load() and is_loaded changes to true is it safe to access. * - * Const write access to this must be protected by `entry->mutex`. + * `const` write access to this must be protected by `entry->mutex`. */ mutable bool is_loaded; }; @@ -480,7 +480,7 @@ struct VolumeGridVector : public std::list<VolumeGrid> { metadata.reset(); } - /* Mutex for file loading of grids list. Const write access to the fields after this must be + /* Mutex for file loading of grids list. `const` write access to the fields after this must be * protected by locking with this mutex. */ mutable std::mutex mutex; /* Absolute file path that grids have been loaded from. */ diff --git a/source/blender/blenkernel/intern/writeavi.c b/source/blender/blenkernel/intern/writeavi.c index dbdf8cc395d..de2e196c163 100644 --- a/source/blender/blenkernel/intern/writeavi.c +++ b/source/blender/blenkernel/intern/writeavi.c @@ -122,7 +122,8 @@ bMovieHandle *BKE_movie_handle_get(const char imtype) R_IMF_IMTYPE_FFMPEG, R_IMF_IMTYPE_H264, R_IMF_IMTYPE_XVID, - R_IMF_IMTYPE_THEORA)) { + R_IMF_IMTYPE_THEORA, + R_IMF_IMTYPE_AV1)) { mh.start_movie = BKE_ffmpeg_start; mh.append_movie = BKE_ffmpeg_append; mh.end_movie = BKE_ffmpeg_end; diff --git a/source/blender/blenkernel/intern/writeffmpeg.c b/source/blender/blenkernel/intern/writeffmpeg.c index 99df07b6105..ee827cd8cd4 100644 --- a/source/blender/blenkernel/intern/writeffmpeg.c +++ b/source/blender/blenkernel/intern/writeffmpeg.c @@ -299,6 +299,10 @@ static const char **get_file_extensions(int format) static const char *rv[] = {".webm", NULL}; return rv; } + case FFMPEG_AV1: { + static const char *rv[] = {".mp4", ".mkv", NULL}; + return rv; + } default: return NULL; } @@ -455,6 +459,204 @@ static AVRational calc_time_base(uint den, double num, int codec_id) return time_base; } +static const AVCodec *get_av1_encoder( + FFMpegContext *context, RenderData *rd, AVDictionary **opts, int rectx, int recty) +{ + /* There are three possible encoders for AV1: libaom-av1, librav1e, and libsvtav1. librav1e tends + * to give the best compression quality while libsvtav1 tends to be the fastest encoder. One of + * each will be picked based on the preset setting, and if a particular encoder is not available, + * then use the default returned by FFMpeg. */ + const AVCodec *codec = NULL; + switch (context->ffmpeg_preset) { + case FFM_PRESET_BEST: + /* Default to libaom-av1 for BEST preset due to it performing better than rav1e in terms of + * video quality (VMAF scores). Fallback to rav1e if libaom-av1 isn't available. */ + codec = avcodec_find_encoder_by_name("libaom-av1"); + if (!codec) { + codec = avcodec_find_encoder_by_name("librav1e"); + } + break; + case FFM_PRESET_REALTIME: + codec = avcodec_find_encoder_by_name("libsvtav1"); + break; + case FFM_PRESET_GOOD: + default: + codec = avcodec_find_encoder_by_name("libaom-av1"); + break; + } + + /* Use the default AV1 encoder if the specified encoder wasn't found. */ + if (!codec) { + codec = avcodec_find_encoder(AV_CODEC_ID_AV1); + } + + /* Apply AV1 encoder specific settings. */ + if (codec) { + if (STREQ(codec->name, "librav1e")) { + /* Set "tiles" to 8 to enable multi-threaded encoding. */ + if (rd->threads > 8) { + ffmpeg_dict_set_int(opts, "tiles", rd->threads); + } + else { + ffmpeg_dict_set_int(opts, "tiles", 8); + } + + /* Use a reasonable speed setting based on preset. Speed ranges from 0-10. + * Must check context->ffmpeg_preset again in case this encoder was selected due to the + * absence of another. */ + switch (context->ffmpeg_preset) { + case FFM_PRESET_BEST: + ffmpeg_dict_set_int(opts, "speed", 4); + break; + case FFM_PRESET_REALTIME: + ffmpeg_dict_set_int(opts, "speed", 10); + break; + case FFM_PRESET_GOOD: + default: + ffmpeg_dict_set_int(opts, "speed", 6); + break; + } + if (context->ffmpeg_crf >= 0) { + /* librav1e does not use -crf, but uses -qp in the range of 0-255. Calculates the roughly + * equivalent float, and truncates it to an integer. */ + unsigned int qp_value = ((float)context->ffmpeg_crf) * 255.0F / 51.0F; + if (qp_value > 255) { + qp_value = 255; + } + ffmpeg_dict_set_int(opts, "qp", qp_value); + } + /* Set gop_size as rav1e's "--keyint". */ + char buffer[64]; + BLI_snprintf(buffer, sizeof(buffer), "keyint=%d", context->ffmpeg_gop_size); + av_dict_set(opts, "rav1e-params", buffer, 0); + } + else if (STREQ(codec->name, "libsvtav1")) { + /* Set preset value based on ffmpeg_preset. + * Must check context->ffmpeg_preset again in case this encoder was selected due to the + * absence of another. */ + switch (context->ffmpeg_preset) { + case FFM_PRESET_REALTIME: + ffmpeg_dict_set_int(opts, "preset", 8); + break; + case FFM_PRESET_BEST: + ffmpeg_dict_set_int(opts, "preset", 3); + break; + case FFM_PRESET_GOOD: + default: + ffmpeg_dict_set_int(opts, "preset", 5); + break; + } + if (context->ffmpeg_crf >= 0) { + /* libsvtav1 does not support crf until FFmpeg builds since 2022-02-24, use qp as fallback. + */ + ffmpeg_dict_set_int(opts, "qp", context->ffmpeg_crf); + } + } + else if (STREQ(codec->name, "libaom-av1")) { + /* Speed up libaom-av1 encoding by enabling multithreading and setting tiles. */ + ffmpeg_dict_set_int(opts, "row-mt", 1); + const char *tiles_string = NULL; + bool tiles_string_is_dynamic = false; + if (rd->threads > 0) { + /* See if threads is a square. */ + int threads_sqrt = sqrtf(rd->threads); + if (threads_sqrt < 4) { + /* Ensure a default minimum. */ + threads_sqrt = 4; + } + if (is_power_of_2_i(threads_sqrt) && threads_sqrt * threads_sqrt == rd->threads) { + /* Is a square num, therefore just do "sqrt x sqrt" for tiles parameter. */ + int digits = 0; + for (int t_sqrt_copy = threads_sqrt; t_sqrt_copy > 0; t_sqrt_copy /= 10) { + ++digits; + } + /* A char array need only an alignment of 1. */ + char *tiles_string_mut = (char *)calloc(digits * 2 + 2, 1); + BLI_snprintf(tiles_string_mut, digits * 2 + 2, "%dx%d", threads_sqrt, threads_sqrt); + tiles_string_is_dynamic = true; + tiles_string = tiles_string_mut; + } + else { + /* Is not a square num, set greater side based on longer side, or use a square if both + sides are equal. */ + int sqrt_p2 = power_of_2_min_i(threads_sqrt); + if (sqrt_p2 < 2) { + /* Ensure a default minimum. */ + sqrt_p2 = 2; + } + int sqrt_p2_next = power_of_2_min_i((int)rd->threads / sqrt_p2); + if (sqrt_p2_next < 1) { + sqrt_p2_next = 1; + } + if (sqrt_p2 > sqrt_p2_next) { + /* Ensure sqrt_p2_next is greater or equal to sqrt_p2. */ + int temp = sqrt_p2; + sqrt_p2 = sqrt_p2_next; + sqrt_p2_next = temp; + } + int combined_digits = 0; + for (int sqrt_p2_copy = sqrt_p2; sqrt_p2_copy > 0; sqrt_p2_copy /= 10) { + ++combined_digits; + } + for (int sqrt_p2_copy = sqrt_p2_next; sqrt_p2_copy > 0; sqrt_p2_copy /= 10) { + ++combined_digits; + } + /* A char array need only an alignment of 1. */ + char *tiles_string_mut = (char *)calloc(combined_digits + 2, 1); + if (rectx > recty) { + BLI_snprintf(tiles_string_mut, combined_digits + 2, "%dx%d", sqrt_p2_next, sqrt_p2); + } + else if (rectx < recty) { + BLI_snprintf(tiles_string_mut, combined_digits + 2, "%dx%d", sqrt_p2, sqrt_p2_next); + } + else { + BLI_snprintf(tiles_string_mut, combined_digits + 2, "%dx%d", sqrt_p2, sqrt_p2); + } + tiles_string_is_dynamic = true; + tiles_string = tiles_string_mut; + } + } + else { + /* Thread count unknown, default to 8. */ + if (rectx > recty) { + tiles_string = "4x2"; + } + else if (rectx < recty) { + tiles_string = "2x4"; + } + else { + tiles_string = "2x2"; + } + } + av_dict_set(opts, "tiles", tiles_string, 0); + if (tiles_string_is_dynamic) { + free((void *)tiles_string); + } + /* libaom-av1 uses "cpu-used" instead of "preset" for defining compression quality. + * This value is in a range from 0-8. 0 and 8 are extremes, but we will allow 8. + * Must check context->ffmpeg_preset again in case this encoder was selected due to the + * absence of another. */ + switch (context->ffmpeg_preset) { + case FFM_PRESET_REALTIME: + ffmpeg_dict_set_int(opts, "cpu-used", 8); + break; + case FFM_PRESET_BEST: + ffmpeg_dict_set_int(opts, "cpu-used", 4); + break; + case FFM_PRESET_GOOD: + default: + ffmpeg_dict_set_int(opts, "cpu-used", 6); + break; + } + + /* CRF related settings is similar to H264 for libaom-av1, so we will rely on those settings + * applied later. */ + } + } + + return codec; +} + /* prepare a video stream for the output file */ static AVStream *alloc_video_stream(FFMpegContext *context, @@ -480,7 +682,14 @@ static AVStream *alloc_video_stream(FFMpegContext *context, /* Set up the codec context */ - codec = avcodec_find_encoder(codec_id); + if (codec_id == AV_CODEC_ID_AV1) { + /* Use get_av1_encoder() to get the ideal (hopefully) encoder for AV1 based + * on given parameters, and also set up opts. */ + codec = get_av1_encoder(context, rd, &opts, rectx, recty); + } + else { + codec = avcodec_find_encoder(codec_id); + } if (!codec) { fprintf(stderr, "Couldn't find valid video codec\n"); context->video_codec = NULL; @@ -568,7 +777,9 @@ static AVStream *alloc_video_stream(FFMpegContext *context, default: printf("Unknown preset number %i, ignoring.\n", context->ffmpeg_preset); } - if (preset_name != NULL) { + /* "codec_id != AV_CODEC_ID_AV1" is required due to "preset" already being set by an AV1 codec. + */ + if (preset_name != NULL && codec_id != AV_CODEC_ID_AV1) { av_dict_set(&opts, "preset", preset_name, 0); } if (deadline_name != NULL) { @@ -806,7 +1017,7 @@ static AVStream *alloc_audio_stream(FFMpegContext *context, return NULL; } - /* need to prevent floating point exception when using vorbis audio codec, + /* Need to prevent floating point exception when using VORBIS audio codec, * initialize this value in the same way as it's done in FFmpeg itself (sergey) */ c->time_base.num = 1; c->time_base.den = c->sample_rate; @@ -951,6 +1162,9 @@ static int start_ffmpeg_impl(FFMpegContext *context, case FFMPEG_FLV: video_codec = AV_CODEC_ID_FLV1; break; + case FFMPEG_AV1: + video_codec = AV_CODEC_ID_AV1; + break; default: /* These containers are not restricted to any specific codec types. * Currently we expect these to be .avi, .mov, .mkv, and .mp4. @@ -1482,6 +1696,18 @@ void BKE_ffmpeg_preset_set(RenderData *rd, int preset) rd->ffcodecdata.mux_packet_size = 2048; rd->ffcodecdata.mux_rate = 10080000; break; + case FFMPEG_PRESET_AV1: + rd->ffcodecdata.type = FFMPEG_AV1; + rd->ffcodecdata.codec = AV_CODEC_ID_AV1; + rd->ffcodecdata.video_bitrate = 6000; + rd->ffcodecdata.gop_size = is_ntsc ? 18 : 15; + rd->ffcodecdata.rc_max_rate = 9000; + rd->ffcodecdata.rc_min_rate = 0; + rd->ffcodecdata.rc_buffer_size = 224 * 8; + rd->ffcodecdata.mux_packet_size = 2048; + rd->ffcodecdata.mux_rate = 10080000; + + break; } } @@ -1521,6 +1747,12 @@ void BKE_ffmpeg_image_type_verify(RenderData *rd, const ImageFormatData *imf) audio = 1; } } + else if (imf->imtype == R_IMF_IMTYPE_AV1) { + if (rd->ffcodecdata.codec != AV_CODEC_ID_AV1) { + BKE_ffmpeg_preset_set(rd, FFMPEG_PRESET_AV1); + audio = 1; + } + } if (audio && rd->ffcodecdata.audio_codec < 0) { rd->ffcodecdata.audio_codec = AV_CODEC_ID_NONE; diff --git a/source/blender/blenlib/BLI_array_utils.hh b/source/blender/blenlib/BLI_array_utils.hh index 95b3bde10f4..264ac00e034 100644 --- a/source/blender/blenlib/BLI_array_utils.hh +++ b/source/blender/blenlib/BLI_array_utils.hh @@ -42,6 +42,11 @@ void gather(const GVArray &src, IndexMask indices, GMutableSpan dst, int64_t gra /** * Fill the destination span by gathering indexed values from the `src` array. */ +void gather(GSpan src, IndexMask indices, GMutableSpan dst, int64_t grain_size = 4096); + +/** + * Fill the destination span by gathering indexed values from the `src` array. + */ template<typename T> inline void gather(const VArray<T> &src, const IndexMask indices, diff --git a/source/blender/blenlib/BLI_math_matrix.h b/source/blender/blenlib/BLI_math_matrix.h index 7e1b7c2ba56..538474f58b6 100644 --- a/source/blender/blenlib/BLI_math_matrix.h +++ b/source/blender/blenlib/BLI_math_matrix.h @@ -624,7 +624,7 @@ void BLI_space_transform_apply_normal(const struct SpaceTransform *data, float n void BLI_space_transform_invert_normal(const struct SpaceTransform *data, float no[3]); #define BLI_SPACE_TRANSFORM_SETUP(data, local, target) \ - BLI_space_transform_from_matrices((data), (local)->obmat, (target)->obmat) + BLI_space_transform_from_matrices((data), (local)->object_to_world, (target)->object_to_world) /** \} */ diff --git a/source/blender/blenlib/BLI_path_util.h b/source/blender/blenlib/BLI_path_util.h index 1e45e76afe1..1b723ab038d 100644 --- a/source/blender/blenlib/BLI_path_util.h +++ b/source/blender/blenlib/BLI_path_util.h @@ -7,7 +7,9 @@ */ #include "BLI_compiler_attrs.h" +#include "BLI_compiler_compat.h" #include "BLI_utildefines.h" +#include "BLI_utildefines_variadic.h" #ifdef __cplusplus extern "C" { @@ -66,20 +68,25 @@ const char *BLI_path_extension(const char *filepath) ATTR_NONNULL(); /** * Append a filename to a dir, ensuring slash separates. + * \return The new length of `dst`. */ -void BLI_path_append(char *__restrict dst, size_t maxlen, const char *__restrict file) +size_t BLI_path_append(char *__restrict dst, size_t maxlen, const char *__restrict file) ATTR_NONNULL(); /** - * Simple appending of filename to dir, does not check for valid path! - * Puts result into `dst`, which may be same area as `dir`. - * - * \note Consider using #BLI_path_join for more general path joining - * that de-duplicates separators and can handle an arbitrary number of paths. + * A version of #BLI_path_append that ensures a trailing slash if there is space in `dst`. + * \return The new length of `dst`. + */ +size_t BLI_path_append_dir(char *__restrict dst, size_t maxlen, const char *__restrict dir) + ATTR_NONNULL(); + +/** + * See #BLI_path_join doc-string. */ -void BLI_join_dirfile(char *__restrict dst, - size_t maxlen, - const char *__restrict dir, - const char *__restrict file) ATTR_NONNULL(); +size_t BLI_path_join_array(char *__restrict dst, + const size_t dst_len, + const char *path_array[], + const int path_array_num); + /** * Join multiple strings into a path, ensuring only a single path separator between each, * and trailing slash is kept. @@ -95,8 +102,92 @@ void BLI_join_dirfile(char *__restrict dst, * \note If you want a trailing slash, add `SEP_STR` as the last path argument, * duplicate slashes will be cleaned up. */ -size_t BLI_path_join(char *__restrict dst, size_t dst_len, const char *path, ...) - ATTR_NONNULL(1, 3) ATTR_SENTINEL(0); +#define BLI_path_join(...) VA_NARGS_CALL_OVERLOAD(_BLI_path_join_, __VA_ARGS__) + +#define _BLI_PATH_JOIN_ARGS_1 char *__restrict dst, size_t dst_len, const char *a +#define _BLI_PATH_JOIN_ARGS_2 _BLI_PATH_JOIN_ARGS_1, const char *b +#define _BLI_PATH_JOIN_ARGS_3 _BLI_PATH_JOIN_ARGS_2, const char *c +#define _BLI_PATH_JOIN_ARGS_4 _BLI_PATH_JOIN_ARGS_3, const char *d +#define _BLI_PATH_JOIN_ARGS_5 _BLI_PATH_JOIN_ARGS_4, const char *e +#define _BLI_PATH_JOIN_ARGS_6 _BLI_PATH_JOIN_ARGS_5, const char *f +#define _BLI_PATH_JOIN_ARGS_7 _BLI_PATH_JOIN_ARGS_6, const char *g +#define _BLI_PATH_JOIN_ARGS_8 _BLI_PATH_JOIN_ARGS_7, const char *h +#define _BLI_PATH_JOIN_ARGS_9 _BLI_PATH_JOIN_ARGS_8, const char *i +#define _BLI_PATH_JOIN_ARGS_10 _BLI_PATH_JOIN_ARGS_9, const char *j + +BLI_INLINE size_t _BLI_path_join_3(_BLI_PATH_JOIN_ARGS_1) ATTR_NONNULL(); +BLI_INLINE size_t _BLI_path_join_4(_BLI_PATH_JOIN_ARGS_2) ATTR_NONNULL(); +BLI_INLINE size_t _BLI_path_join_5(_BLI_PATH_JOIN_ARGS_3) ATTR_NONNULL(); +BLI_INLINE size_t _BLI_path_join_6(_BLI_PATH_JOIN_ARGS_4) ATTR_NONNULL(); +BLI_INLINE size_t _BLI_path_join_7(_BLI_PATH_JOIN_ARGS_5) ATTR_NONNULL(); +BLI_INLINE size_t _BLI_path_join_8(_BLI_PATH_JOIN_ARGS_6) ATTR_NONNULL(); +BLI_INLINE size_t _BLI_path_join_9(_BLI_PATH_JOIN_ARGS_7) ATTR_NONNULL(); +BLI_INLINE size_t _BLI_path_join_10(_BLI_PATH_JOIN_ARGS_8) ATTR_NONNULL(); +BLI_INLINE size_t _BLI_path_join_11(_BLI_PATH_JOIN_ARGS_9) ATTR_NONNULL(); +BLI_INLINE size_t _BLI_path_join_12(_BLI_PATH_JOIN_ARGS_10) ATTR_NONNULL(); + +BLI_INLINE size_t _BLI_path_join_3(_BLI_PATH_JOIN_ARGS_1) +{ + const char *path_array[] = {a}; + return BLI_path_join_array(dst, dst_len, path_array, ARRAY_SIZE(path_array)); +} +BLI_INLINE size_t _BLI_path_join_4(_BLI_PATH_JOIN_ARGS_2) +{ + const char *path_array[] = {a, b}; + return BLI_path_join_array(dst, dst_len, path_array, ARRAY_SIZE(path_array)); +} +BLI_INLINE size_t _BLI_path_join_5(_BLI_PATH_JOIN_ARGS_3) +{ + const char *path_array[] = {a, b, c}; + return BLI_path_join_array(dst, dst_len, path_array, ARRAY_SIZE(path_array)); +} +BLI_INLINE size_t _BLI_path_join_6(_BLI_PATH_JOIN_ARGS_4) +{ + const char *path_array[] = {a, b, c, d}; + return BLI_path_join_array(dst, dst_len, path_array, ARRAY_SIZE(path_array)); +} +BLI_INLINE size_t _BLI_path_join_7(_BLI_PATH_JOIN_ARGS_5) +{ + const char *path_array[] = {a, b, c, d, e}; + return BLI_path_join_array(dst, dst_len, path_array, ARRAY_SIZE(path_array)); +} +BLI_INLINE size_t _BLI_path_join_8(_BLI_PATH_JOIN_ARGS_6) +{ + const char *path_array[] = {a, b, c, d, e, f}; + return BLI_path_join_array(dst, dst_len, path_array, ARRAY_SIZE(path_array)); +} +BLI_INLINE size_t _BLI_path_join_9(_BLI_PATH_JOIN_ARGS_7) +{ + const char *path_array[] = {a, b, c, d, e, f, g}; + return BLI_path_join_array(dst, dst_len, path_array, ARRAY_SIZE(path_array)); +} +BLI_INLINE size_t _BLI_path_join_10(_BLI_PATH_JOIN_ARGS_8) +{ + const char *path_array[] = {a, b, c, d, e, f, g, h}; + return BLI_path_join_array(dst, dst_len, path_array, ARRAY_SIZE(path_array)); +} +BLI_INLINE size_t _BLI_path_join_11(_BLI_PATH_JOIN_ARGS_9) +{ + const char *path_array[] = {a, b, c, d, e, f, g, h, i}; + return BLI_path_join_array(dst, dst_len, path_array, ARRAY_SIZE(path_array)); +} +BLI_INLINE size_t _BLI_path_join_12(_BLI_PATH_JOIN_ARGS_10) +{ + const char *path_array[] = {a, b, c, d, e, f, g, h, i, j}; + return BLI_path_join_array(dst, dst_len, path_array, ARRAY_SIZE(path_array)); +} + +#undef _BLI_PATH_JOIN_ARGS_1 +#undef _BLI_PATH_JOIN_ARGS_2 +#undef _BLI_PATH_JOIN_ARGS_3 +#undef _BLI_PATH_JOIN_ARGS_4 +#undef _BLI_PATH_JOIN_ARGS_5 +#undef _BLI_PATH_JOIN_ARGS_6 +#undef _BLI_PATH_JOIN_ARGS_7 +#undef _BLI_PATH_JOIN_ARGS_8 +#undef _BLI_PATH_JOIN_ARGS_9 +#undef _BLI_PATH_JOIN_ARGS_10 + /** * Like Python's `os.path.basename()` * @@ -134,7 +225,7 @@ const char *BLI_path_slash_rfind(const char *string) ATTR_NONNULL() ATTR_WARN_UN * Appends a slash to string if there isn't one there already. * Returns the new length of the string. */ -int BLI_path_slash_ensure(char *string) ATTR_NONNULL(); +int BLI_path_slash_ensure(char *string, size_t string_maxlen) ATTR_NONNULL(1); /** * Removes the last slash and everything after it to the end of string, if there is one. */ @@ -230,7 +321,7 @@ void BLI_path_normalize(const char *relabase, char *path) ATTR_NONNULL(2); * * \note Same as #BLI_path_normalize but adds a trailing slash. */ -void BLI_path_normalize_dir(const char *relabase, char *dir) ATTR_NONNULL(2); +void BLI_path_normalize_dir(const char *relabase, char *dir, size_t dir_maxlen) ATTR_NONNULL(2); /** * Make given name safe to be used in paths. @@ -273,6 +364,8 @@ bool BLI_path_make_safe(char *path) ATTR_NONNULL(1); * * Replaces path with the path of its parent directory, returning true if * it was able to find a parent directory within the path. + * + * On success, the resulting path will always have a trailing slash. */ bool BLI_path_parent_dir(char *path) ATTR_NONNULL(); /** diff --git a/source/blender/blenlib/BLI_string.h b/source/blender/blenlib/BLI_string.h index 15926e8f2d2..17abcf52ecc 100644 --- a/source/blender/blenlib/BLI_string.h +++ b/source/blender/blenlib/BLI_string.h @@ -309,6 +309,28 @@ void BLI_str_format_byte_unit(char dst[15], long long int bytes, bool base_10) A */ void BLI_str_format_decimal_unit(char dst[7], int number_to_format) ATTR_NONNULL(); /** + * Format a count to up to 3 places (plus minus sign, plus '\0' terminator) string using long + * number names abbreviations. Used to produce a compact representation of large numbers as + * integers. + * + * It shows a lower bound instead of rounding the number. + * + * 1 -> 1 + * 15 -> 15 + * 155 -> 155 + * 1555 -> 1K + * 15555 -> 15K + * 155555 -> .1M + * 1555555 -> 1M + * 15555555 -> 15M + * 155555555 -> .1B + * 1000000000 -> 1B + * ... + * + * Length of 5 is the maximum of the resulting string, for example, `-15K\0`. + */ +void BLI_str_format_integer_unit(char dst[5], int number_to_format) ATTR_NONNULL(); +/** * Compare two strings without regard to case. * * \retval True if the strings are equal, false otherwise. diff --git a/source/blender/blenlib/BLI_uvproject.h b/source/blender/blenlib/BLI_uvproject.h index 75f39de6b7f..a94fd796121 100644 --- a/source/blender/blenlib/BLI_uvproject.h +++ b/source/blender/blenlib/BLI_uvproject.h @@ -15,7 +15,7 @@ struct ProjCameraInfo; /** * Create UV info from the camera, needs to be freed. * - * \param rotmat: can be `obedit->obmat` when uv project is used. + * \param rotmat: can be `obedit->object_to_world` when uv project is used. * \param winx, winy: can be from `scene->r.xsch / ysch`. */ struct ProjCameraInfo *BLI_uvproject_camera_info(struct Object *ob, diff --git a/source/blender/blenlib/intern/BLI_filelist.c b/source/blender/blenlib/intern/BLI_filelist.c index 1ce6beab933..4bcb023691a 100644 --- a/source/blender/blenlib/intern/BLI_filelist.c +++ b/source/blender/blenlib/intern/BLI_filelist.c @@ -174,7 +174,7 @@ static void bli_builddir(struct BuildDirCtx *dir_ctx, const char *dirname) struct direntry *file = &dir_ctx->files[dir_ctx->files_num]; while (dlink) { char fullname[PATH_MAX]; - BLI_join_dirfile(fullname, sizeof(fullname), dirname, dlink->name); + BLI_path_join(fullname, sizeof(fullname), dirname, dlink->name); memset(file, 0, sizeof(struct direntry)); file->relname = dlink->name; file->path = BLI_strdup(fullname); diff --git a/source/blender/blenlib/intern/array_utils.cc b/source/blender/blenlib/intern/array_utils.cc index a837d6aceec..2a231228dcb 100644 --- a/source/blender/blenlib/intern/array_utils.cc +++ b/source/blender/blenlib/intern/array_utils.cc @@ -28,4 +28,9 @@ void gather(const GVArray &src, }); } +void gather(const GSpan src, const IndexMask indices, GMutableSpan dst, const int64_t grain_size) +{ + gather(GVArray::ForSpan(src), indices, dst, grain_size); +} + } // namespace blender::array_utils diff --git a/source/blender/blenlib/intern/fileops.c b/source/blender/blenlib/intern/fileops.c index 3abd482d6b3..005de1f85b4 100644 --- a/source/blender/blenlib/intern/fileops.c +++ b/source/blender/blenlib/intern/fileops.c @@ -401,7 +401,7 @@ static bool delete_recursive(const char *dir) /* dir listing produces dir path without trailing slash... */ BLI_strncpy(path, fl->path, sizeof(path)); - BLI_path_slash_ensure(path); + BLI_path_slash_ensure(path, sizeof(path)); if (delete_recursive(path)) { err = true; @@ -627,7 +627,7 @@ static void join_dirfile_alloc(char **dst, size_t *alloc_len, const char *dir, c *alloc_len = len; - BLI_join_dirfile(*dst, len + 1, dir, file); + BLI_path_join(*dst, len + 1, dir, file); } static char *strip_last_slash(const char *dir) @@ -1184,7 +1184,7 @@ static const char *check_destination(const char *file, const char *to) len = strlen(to) + strlen(filename) + 1; path = MEM_callocN(len + 1, "check_destination path"); - BLI_join_dirfile(path, len + 1, to, filename); + BLI_path_join(path, len + 1, to, filename); MEM_freeN(str); diff --git a/source/blender/blenlib/intern/kdtree_impl.h b/source/blender/blenlib/intern/kdtree_impl.h index 6614f1bf964..f7993eb5adc 100644 --- a/source/blender/blenlib/intern/kdtree_impl.h +++ b/source/blender/blenlib/intern/kdtree_impl.h @@ -11,9 +11,9 @@ #include "BLI_strict_flags.h" #include "BLI_utildefines.h" -#define _CONCAT_AUX(MACRO_ARG1, MACRO_ARG2) MACRO_ARG1##MACRO_ARG2 -#define _CONCAT(MACRO_ARG1, MACRO_ARG2) _CONCAT_AUX(MACRO_ARG1, MACRO_ARG2) -#define BLI_kdtree_nd_(id) _CONCAT(KDTREE_PREFIX_ID, _##id) +#define _BLI_KDTREE_CONCAT_AUX(MACRO_ARG1, MACRO_ARG2) MACRO_ARG1##MACRO_ARG2 +#define _BLI_KDTREE_CONCAT(MACRO_ARG1, MACRO_ARG2) _BLI_KDTREE_CONCAT_AUX(MACRO_ARG1, MACRO_ARG2) +#define BLI_kdtree_nd_(id) _BLI_KDTREE_CONCAT(KDTREE_PREFIX_ID, _##id) typedef struct KDTreeNode_head { uint left, right; diff --git a/source/blender/blenlib/intern/list_sort_impl.h b/source/blender/blenlib/intern/list_sort_impl.h index e1b93986f4a..7c38fc60b29 100644 --- a/source/blender/blenlib/intern/list_sort_impl.h +++ b/source/blender/blenlib/intern/list_sort_impl.h @@ -47,24 +47,25 @@ #endif #ifdef SORT_IMPL_USE_THUNK -# define THUNK_APPEND1(a, thunk) a, thunk -# define THUNK_PREPEND2(thunk, a, b) thunk, a, b +# define BLI_LIST_THUNK_APPEND1(a, thunk) a, thunk +# define BLI_LIST_THUNK_PREPEND2(thunk, a, b) thunk, a, b #else -# define THUNK_APPEND1(a, thunk) a -# define THUNK_PREPEND2(thunk, a, b) a, b +# define BLI_LIST_THUNK_APPEND1(a, thunk) a +# define BLI_LIST_THUNK_PREPEND2(thunk, a, b) a, b #endif -#define _CONCAT_AUX(MACRO_ARG1, MACRO_ARG2) MACRO_ARG1##MACRO_ARG2 -#define _CONCAT(MACRO_ARG1, MACRO_ARG2) _CONCAT_AUX(MACRO_ARG1, MACRO_ARG2) -#define _SORT_PREFIX(id) _CONCAT(SORT_IMPL_FUNC, _##id) +#define _BLI_LIST_SORT_CONCAT_AUX(MACRO_ARG1, MACRO_ARG2) MACRO_ARG1##MACRO_ARG2 +#define _BLI_LIST_SORT_CONCAT(MACRO_ARG1, MACRO_ARG2) \ + _BLI_LIST_SORT_CONCAT_AUX(MACRO_ARG1, MACRO_ARG2) +#define _BLI_LIST_SORT_PREFIX(id) _BLI_LIST_SORT_CONCAT(SORT_IMPL_FUNC, _##id) /* local identifiers */ -#define SortInfo _SORT_PREFIX(SortInfo) -#define CompareFn _SORT_PREFIX(CompareFn) -#define init_sort_info _SORT_PREFIX(init_sort_info) -#define merge_lists _SORT_PREFIX(merge_lists) -#define sweep_up _SORT_PREFIX(sweep_up) -#define insert_list _SORT_PREFIX(insert_list) +#define SortInfo _BLI_LIST_SORT_PREFIX(SortInfo) +#define CompareFn _BLI_LIST_SORT_PREFIX(CompareFn) +#define init_sort_info _BLI_LIST_SORT_PREFIX(init_sort_info) +#define merge_lists _BLI_LIST_SORT_PREFIX(merge_lists) +#define sweep_up _BLI_LIST_SORT_PREFIX(sweep_up) +#define insert_list _BLI_LIST_SORT_PREFIX(insert_list) typedef int (*CompareFn)( #ifdef SORT_IMPL_USE_THUNK @@ -159,7 +160,7 @@ BLI_INLINE list_node *merge_lists(list_node *first, list_node *list = NULL; list_node **pos = &list; while (first && second) { - if (func(THUNK_PREPEND2(thunk, SORT_ARG(first), SORT_ARG(second))) > 0) { + if (func(BLI_LIST_THUNK_PREPEND2(thunk, SORT_ARG(first), SORT_ARG(second))) > 0) { *pos = second; second = second->next; } @@ -181,7 +182,7 @@ BLI_INLINE list_node *sweep_up(struct SortInfo *si, list_node *list, unsigned in { unsigned int i; for (i = si->min_rank; i < upto; i++) { - list = merge_lists(si->ranks[i], list, THUNK_APPEND1(si->func, si->thunk)); + list = merge_lists(si->ranks[i], list, BLI_LIST_THUNK_APPEND1(si->func, si->thunk)); si->ranks[i] = NULL; } return list; @@ -225,17 +226,19 @@ BLI_INLINE void insert_list(struct SortInfo *si, list_node *list, unsigned int r // printf("Rank '%d' should not exceed " STRINGIFY(MAX_RANKS), rank); rank = MAX_RANKS; } - list = merge_lists(sweep_up(si, NULL, si->n_ranks), list, THUNK_APPEND1(si->func, si->thunk)); + list = merge_lists( + sweep_up(si, NULL, si->n_ranks), list, BLI_LIST_THUNK_APPEND1(si->func, si->thunk)); for (i = si->n_ranks; i < rank; i++) { si->ranks[i] = NULL; } } else { if (rank) { - list = merge_lists(sweep_up(si, NULL, rank), list, THUNK_APPEND1(si->func, si->thunk)); + list = merge_lists( + sweep_up(si, NULL, rank), list, BLI_LIST_THUNK_APPEND1(si->func, si->thunk)); } for (i = rank; i < si->n_ranks && si->ranks[i]; i++) { - list = merge_lists(si->ranks[i], list, THUNK_APPEND1(si->func, si->thunk)); + list = merge_lists(si->ranks[i], list, BLI_LIST_THUNK_APPEND1(si->func, si->thunk)); si->ranks[i] = NULL; } } @@ -281,7 +284,7 @@ BLI_INLINE list_node *list_sort_do(list_node *list, list_node *next = list->next; list_node *tail = next->next; - if (func(THUNK_PREPEND2(thunk, SORT_ARG(list), SORT_ARG(next))) > 0) { + if (func(BLI_LIST_THUNK_PREPEND2(thunk, SORT_ARG(list), SORT_ARG(next))) > 0) { next->next = list; next = list; list = list->next; @@ -296,8 +299,8 @@ BLI_INLINE list_node *list_sort_do(list_node *list, return sweep_up(&si, list, si.n_ranks); } -#undef _CONCAT_AUX -#undef _CONCAT +#undef _BLI_LIST_SORT_CONCAT_AUX +#undef _BLI_LIST_SORT_CONCAT #undef _SORT_PREFIX #undef SortInfo @@ -310,6 +313,6 @@ BLI_INLINE list_node *list_sort_do(list_node *list, #undef list_node #undef list_sort_do -#undef THUNK_APPEND1 -#undef THUNK_PREPEND2 +#undef BLI_LIST_THUNK_APPEND1 +#undef BLI_LIST_THUNK_PREPEND2 #undef SORT_ARG diff --git a/source/blender/blenlib/intern/path_util.c b/source/blender/blenlib/intern/path_util.c index 6ff4d57aecb..3a87b39a446 100644 --- a/source/blender/blenlib/intern/path_util.c +++ b/source/blender/blenlib/intern/path_util.c @@ -153,6 +153,19 @@ void BLI_path_normalize(const char *relabase, char *path) */ #ifdef WIN32 + + while ((start = strstr(path, "\\.\\"))) { + eind = start + strlen("\\.\\") - 1; + memmove(start, eind, strlen(eind) + 1); + } + + /* remove two consecutive backslashes, but skip the UNC prefix, + * which needs to be preserved */ + while ((start = strstr(path + BLI_path_unc_prefix_len(path), "\\\\"))) { + eind = start + strlen("\\\\") - 1; + memmove(start, eind, strlen(eind) + 1); + } + while ((start = strstr(path, "\\..\\"))) { eind = start + strlen("\\..\\") - 1; a = start - path - 1; @@ -170,18 +183,18 @@ void BLI_path_normalize(const char *relabase, char *path) } } - while ((start = strstr(path, "\\.\\"))) { - eind = start + strlen("\\.\\") - 1; +#else + + while ((start = strstr(path, "/./"))) { + eind = start + (3 - 1) /* strlen("/./") - 1 */; memmove(start, eind, strlen(eind) + 1); } - /* remove two consecutive backslashes, but skip the UNC prefix, - * which needs to be preserved */ - while ((start = strstr(path + BLI_path_unc_prefix_len(path), "\\\\"))) { - eind = start + strlen("\\\\") - 1; + while ((start = strstr(path, "//"))) { + eind = start + (2 - 1) /* strlen("//") - 1 */; memmove(start, eind, strlen(eind) + 1); } -#else + while ((start = strstr(path, "/../"))) { a = start - path - 1; if (a > 0) { @@ -206,19 +219,10 @@ void BLI_path_normalize(const char *relabase, char *path) } } - while ((start = strstr(path, "/./"))) { - eind = start + (3 - 1) /* strlen("/./") - 1 */; - memmove(start, eind, strlen(eind) + 1); - } - - while ((start = strstr(path, "//"))) { - eind = start + (2 - 1) /* strlen("//") - 1 */; - memmove(start, eind, strlen(eind) + 1); - } #endif } -void BLI_path_normalize_dir(const char *relabase, char *dir) +void BLI_path_normalize_dir(const char *relabase, char *dir, size_t dir_maxlen) { /* Would just create an unexpected "/" path, just early exit entirely. */ if (dir[0] == '\0') { @@ -226,7 +230,7 @@ void BLI_path_normalize_dir(const char *relabase, char *dir) } BLI_path_normalize(relabase, dir); - BLI_path_slash_ensure(dir); + BLI_path_slash_ensure(dir, dir_maxlen); } bool BLI_filename_make_safe_ex(char *fname, bool allow_tokens) @@ -622,18 +626,38 @@ bool BLI_path_suffix(char *string, size_t maxlen, const char *suffix, const char bool BLI_path_parent_dir(char *path) { - const char parent_dir[] = {'.', '.', SEP, '\0'}; /* "../" or "..\\" */ - char tmp[FILE_MAX + 4]; - - BLI_join_dirfile(tmp, sizeof(tmp), path, parent_dir); - BLI_path_normalize(NULL, tmp); /* does all the work of normalizing the path for us */ + char tmp[FILE_MAX]; - if (!BLI_path_extension_check(tmp, parent_dir)) { - strcpy(path, tmp); /* We assume the parent directory is always shorter. */ - return true; + STRNCPY(tmp, path); + /* Does all the work of normalizing the path for us. + * + * NOTE(@campbellbarton): While it's possible strip text after the second last slash, + * this would have to be clever and skip cases like "/./" & multiple slashes. + * Since this ends up solving some of the same problems as #BLI_path_normalize, + * call this function instead of attempting to handle them separately. */ + BLI_path_normalize(NULL, tmp); + + /* Use #BLI_path_name_at_index instead of checking if the strings ends with `parent_dir` + * to ensure the logic isn't confused by: + * - Directory names that happen to end with `..`. + * - When `path` is empty, the contents will be `../` + * which would cause checking for a tailing `/../` fail. + * Extracting the span of the final directory avoids both these issues. */ + int tail_ofs = 0, tail_len = 0; + if (!BLI_path_name_at_index(tmp, -1, &tail_ofs, &tail_len)) { + return false; + } + if (tail_len == 1) { + /* Last path is ".", as normalize should remove this, it's safe to assume failure. + * This happens when the input a single period (possibly with slashes before or after). */ + if (tmp[tail_ofs] == '.') { + return false; + } } - return false; + memcpy(path, tmp, tail_ofs); + path[tail_ofs] = '\0'; + return true; } bool BLI_path_parent_dir_until_exists(char *dir) @@ -1025,7 +1049,7 @@ bool BLI_path_abs_from_cwd(char *path, const size_t maxlen) if (BLI_current_working_dir(cwd, sizeof(cwd))) { char origpath[FILE_MAX]; BLI_strncpy(origpath, path, FILE_MAX); - BLI_join_dirfile(path, maxlen, cwd, origpath); + BLI_path_join(path, maxlen, cwd, origpath); } else { printf("Could not get the current working directory - $PWD for an unknown reason.\n"); @@ -1431,73 +1455,50 @@ const char *BLI_path_extension(const char *filepath) return extension; } -void BLI_path_append(char *__restrict dst, const size_t maxlen, const char *__restrict file) +size_t BLI_path_append(char *__restrict dst, const size_t maxlen, const char *__restrict file) { size_t dirlen = BLI_strnlen(dst, maxlen); - /* inline BLI_path_slash_ensure */ + /* Inline #BLI_path_slash_ensure. */ if ((dirlen > 0) && (dst[dirlen - 1] != SEP)) { dst[dirlen++] = SEP; dst[dirlen] = '\0'; } if (dirlen >= maxlen) { - return; /* fills the path */ + return dirlen; /* fills the path */ } - BLI_strncpy(dst + dirlen, file, maxlen - dirlen); + return dirlen + BLI_strncpy_rlen(dst + dirlen, file, maxlen - dirlen); } -void BLI_join_dirfile(char *__restrict dst, - const size_t maxlen, - const char *__restrict dir, - const char *__restrict file) +size_t BLI_path_append_dir(char *__restrict dst, const size_t maxlen, const char *__restrict dir) { -#ifdef DEBUG_STRSIZE - memset(dst, 0xff, sizeof(*dst) * maxlen); -#endif - size_t dirlen = BLI_strnlen(dir, maxlen); - - /* Arguments can't match. */ - BLI_assert(!ELEM(dst, dir, file)); - - /* Files starting with a separator cause a double-slash which could later be interpreted - * as a relative path where: `dir == "/"` and `file == "/file"` would result in "//file". */ - BLI_assert(file[0] != SEP); - - if (dirlen == maxlen) { - memcpy(dst, dir, dirlen); - dst[dirlen - 1] = '\0'; - return; /* dir fills the path */ - } - - memcpy(dst, dir, dirlen + 1); - - if (dirlen + 1 >= maxlen) { - return; /* fills the path */ - } - - /* inline BLI_path_slash_ensure */ - if ((dirlen > 0) && !ELEM(dst[dirlen - 1], SEP, ALTSEP)) { - dst[dirlen++] = SEP; - dst[dirlen] = '\0'; - } - - if (dirlen >= maxlen) { - return; /* fills the path */ + size_t dirlen = BLI_path_append(dst, maxlen, dir); + if (dirlen + 1 < maxlen) { + /* Inline #BLI_path_slash_ensure. */ + if ((dirlen > 0) && (dst[dirlen - 1] != SEP)) { + dst[dirlen++] = SEP; + dst[dirlen] = '\0'; + } } - - BLI_strncpy(dst + dirlen, file, maxlen - dirlen); + return dirlen; } -size_t BLI_path_join(char *__restrict dst, const size_t dst_len, const char *path, ...) +size_t BLI_path_join_array(char *__restrict dst, + const size_t dst_len, + const char *path_array[], + const int path_array_num) { + BLI_assert(path_array_num > 0); #ifdef DEBUG_STRSIZE memset(dst, 0xff, sizeof(*dst) * dst_len); #endif if (UNLIKELY(dst_len == 0)) { return 0; } + const char *path = path_array[0]; + const size_t dst_last = dst_len - 1; size_t ofs = BLI_strncpy_rlen(dst, path, dst_len); @@ -1505,37 +1506,58 @@ size_t BLI_path_join(char *__restrict dst, const size_t dst_len, const char *pat return ofs; } +#ifdef WIN32 + /* Special case "//" for relative paths, don't use separator #SEP + * as this has a special meaning on both WIN32 & UNIX. + * Without this check joining `"//", "path"`. results in `"//\path"`. */ + if (ofs != 0) { + size_t i; + for (i = 0; i < ofs; i++) { + if (dst[i] != '/') { + break; + } + } + if (i == ofs) { + /* All slashes, keep them as-is, and join the remaining path array. */ + return path_array_num > 1 ? + BLI_path_join_array( + dst + ofs, dst_len - ofs, &path_array[1], path_array_num - 1) : + ofs; + } + } +#endif + /* Remove trailing slashes, unless there are *only* trailing slashes * (allow `//` or `//some_path` as the first argument). */ bool has_trailing_slash = false; if (ofs != 0) { size_t len = ofs; - while ((len != 0) && ELEM(path[len - 1], SEP, ALTSEP)) { + while ((len != 0) && (path[len - 1] == SEP)) { len -= 1; } + if (len != 0) { ofs = len; } has_trailing_slash = (path[len] != '\0'); } - va_list args; - va_start(args, path); - while ((path = (const char *)va_arg(args, const char *))) { + for (int path_index = 1; path_index < path_array_num; path_index++) { + path = path_array[path_index]; has_trailing_slash = false; const char *path_init = path; - while (ELEM(path[0], SEP, ALTSEP)) { + while (path[0] == SEP) { path++; } size_t len = strlen(path); if (len != 0) { - while ((len != 0) && ELEM(path[len - 1], SEP, ALTSEP)) { + while ((len != 0) && (path[len - 1] == SEP)) { len -= 1; } if (len != 0) { /* the very first path may have a slash at the end */ - if (ofs && !ELEM(dst[ofs - 1], SEP, ALTSEP)) { + if (ofs && (dst[ofs - 1] != SEP)) { dst[ofs++] = SEP; if (ofs == dst_last) { break; @@ -1556,10 +1578,9 @@ size_t BLI_path_join(char *__restrict dst, const size_t dst_len, const char *pat has_trailing_slash = (path_init != path); } } - va_end(args); if (has_trailing_slash) { - if ((ofs != dst_last) && (ofs != 0) && (ELEM(dst[ofs - 1], SEP, ALTSEP) == 0)) { + if ((ofs != dst_last) && (ofs != 0) && (dst[ofs - 1] != SEP)) { dst[ofs++] = SEP; } } @@ -1587,7 +1608,7 @@ bool BLI_path_name_at_index(const char *__restrict path, int i = 0; while (true) { const char c = path[i]; - if (ELEM(c, SEP, ALTSEP, '\0')) { + if (ELEM(c, SEP, '\0')) { if (prev + 1 != i) { prev += 1; if (index_step == index) { @@ -1614,7 +1635,7 @@ bool BLI_path_name_at_index(const char *__restrict path, int i = prev - 1; while (true) { const char c = i >= 0 ? path[i] : '\0'; - if (ELEM(c, SEP, ALTSEP, '\0')) { + if (ELEM(c, SEP, '\0')) { if (prev - 1 != i) { i += 1; if (index_step == index) { @@ -1662,7 +1683,7 @@ bool BLI_path_contains(const char *container_path, const char *containee_path) /* Add a trailing slash to prevent same-prefix directories from matching. * e.g. "/some/path" doesn't contain "/some/path_lib". */ - BLI_path_slash_ensure(container_native); + BLI_path_slash_ensure(container_native, sizeof(container_native)); return BLI_str_startswith(containee_native, container_native); } @@ -1697,13 +1718,17 @@ const char *BLI_path_slash_rfind(const char *string) return (lfslash > lbslash) ? lfslash : lbslash; } -int BLI_path_slash_ensure(char *string) +int BLI_path_slash_ensure(char *string, size_t string_maxlen) { int len = strlen(string); + BLI_assert(len < string_maxlen); if (len == 0 || string[len - 1] != SEP) { - string[len] = SEP; - string[len + 1] = '\0'; - return len + 1; + /* Avoid unlikely buffer overflow. */ + if (len + 1 < string_maxlen) { + string[len] = SEP; + string[len + 1] = '\0'; + return len + 1; + } } return len; } diff --git a/source/blender/blenlib/intern/string.c b/source/blender/blenlib/intern/string.c index 89d31c5e93f..755d2dbd55d 100644 --- a/source/blender/blenlib/intern/string.c +++ b/source/blender/blenlib/intern/string.c @@ -1176,4 +1176,34 @@ void BLI_str_format_decimal_unit(char dst[7], int number_to_format) BLI_snprintf(dst, dst_len, "%.*f%s", decimals, number_to_format_converted, units[order]); } +void BLI_str_format_integer_unit(char dst[5], const int number_to_format) +{ + float number_to_format_converted = number_to_format; + int order = 0; + const float base = 1000; + const char *units[] = {"", "K", "M", "B"}; + const int units_num = ARRAY_SIZE(units); + + while ((fabsf(number_to_format_converted) >= base) && ((order + 1) < units_num)) { + number_to_format_converted /= base; + order++; + } + + const bool add_dot = (abs(number_to_format) > 99999) && fabsf(number_to_format_converted) > 99; + + if (add_dot) { + number_to_format_converted /= 100; + order++; + } + + const size_t dst_len = 5; + BLI_snprintf(dst, + dst_len, + "%s%s%d%s", + number_to_format < 0 ? "-" : "", + add_dot ? "." : "", + (int)floorf(fabsf(number_to_format_converted)), + units[order]); +} + /** \} */ diff --git a/source/blender/blenlib/intern/uvproject.c b/source/blender/blenlib/intern/uvproject.c index 347166bd57d..0398bf0b3fe 100644 --- a/source/blender/blenlib/intern/uvproject.c +++ b/source/blender/blenlib/intern/uvproject.c @@ -129,7 +129,7 @@ ProjCameraInfo *BLI_uvproject_camera_info(Object *ob, float rotmat[4][4], float uci.camsize = uci.do_persp ? tanf(uci.camangle) : camera->ortho_scale; /* account for scaled cameras */ - copy_m4_m4(uci.caminv, ob->obmat); + copy_m4_m4(uci.caminv, ob->object_to_world); normalize_m4(uci.caminv); if (invert_m4(uci.caminv)) { diff --git a/source/blender/blenlib/tests/BLI_path_util_test.cc b/source/blender/blenlib/tests/BLI_path_util_test.cc index 2d415534693..293d353efcc 100644 --- a/source/blender/blenlib/tests/BLI_path_util_test.cc +++ b/source/blender/blenlib/tests/BLI_path_util_test.cc @@ -9,69 +9,166 @@ #include "BLI_string.h" /* -------------------------------------------------------------------- */ -/* tests */ +/** \name Local Utilities + * \{ */ -/* BLI_path_normalize */ -#ifndef _WIN32 -TEST(path_util, Clean) +static void str_replace_char_with_relative_exception(char *str, char src, char dst) { - /* "/./" -> "/" */ - { - char path[FILE_MAX] = "/a/./b/./c/./"; - BLI_path_normalize(nullptr, path); - EXPECT_STREQ("/a/b/c/", path); + /* Always keep "//" or more leading slashes (special meaning). */ + if (src == '/') { + if (str[0] == '/' && str[1] == '/') { + str += 2; + while (*str == '/') { + str++; + } + } } + BLI_str_replace_char(str, src, dst); +} - { - char path[FILE_MAX] = "/./././"; - BLI_path_normalize(nullptr, path); - EXPECT_STREQ("/", path); +static char *str_replace_char_strdup(const char *str, char src, char dst) +{ + if (str == nullptr) { + return nullptr; } + char *str_dupe = strdup(str); + BLI_str_replace_char(str_dupe, src, dst); + return str_dupe; +} - { - char path[FILE_MAX] = "/a/./././b/"; - BLI_path_normalize(nullptr, path); - EXPECT_STREQ("/a/b/", path); - } +/** \} */ - /* "//" -> "/" */ - { - char path[FILE_MAX] = "a////"; - BLI_path_normalize(nullptr, path); - EXPECT_STREQ("a/", path); - } +/* -------------------------------------------------------------------- */ +/** \name Tests for: #BLI_path_normalize + * \{ */ - if (false) /* FIXME */ - { - char path[FILE_MAX] = "./a////"; - BLI_path_normalize(nullptr, path); - EXPECT_STREQ("./a/", path); - } +#define NORMALIZE_WITH_BASEDIR(input, input_base, output) \ + { \ + char path[FILE_MAX] = input; \ + const char *input_base_test = input_base; \ + if (SEP == '\\') { \ + str_replace_char_with_relative_exception(path, '/', '\\'); \ + input_base_test = str_replace_char_strdup(input_base_test, '/', '\\'); \ + } \ + BLI_path_normalize(input_base_test, path); \ + if (SEP == '\\') { \ + BLI_str_replace_char(path, '\\', '/'); \ + if (input_base_test) { \ + free((void *)input_base_test); \ + } \ + } \ + EXPECT_STREQ(output, path); \ + } \ + ((void)0) - /* "foo/bar/../" -> "foo/" */ - { - char path[FILE_MAX] = "/a/b/c/../../../"; - BLI_path_normalize(nullptr, path); - EXPECT_STREQ("/", path); - } +#define NORMALIZE(input, output) NORMALIZE_WITH_BASEDIR(input, nullptr, output) - { - char path[FILE_MAX] = "/a/../a/b/../b/c/../c/"; - BLI_path_normalize(nullptr, path); - EXPECT_STREQ("/a/b/c/", path); - } +/* #BLI_path_normalize: "/./" -> "/" */ +TEST(path_util, Clean_Dot) +{ + NORMALIZE("/./", "/"); + NORMALIZE("/a/./b/./c/./", "/a/b/c/"); + NORMALIZE("/./././", "/"); + NORMALIZE("/a/./././b/", "/a/b/"); +} +/* #BLI_path_normalize: complex "/./" -> "/", "//" -> "/", "./path/../" -> "./". */ +TEST(path_util, Clean_Complex) +{ + NORMALIZE("/a/./b/./c/./.././.././", "/a/"); + NORMALIZE("/a//.//b//.//c//.//..//.//..//.//", "/a/"); +} +/* #BLI_path_normalize: "//" -> "/" */ +TEST(path_util, Clean_DoubleSlash) +{ + NORMALIZE("//", "//"); /* Exception, double forward slash. */ + NORMALIZE(".//", "./"); + NORMALIZE("a////", "a/"); + NORMALIZE("./a////", "./a/"); +} +/* #BLI_path_normalize: "foo/bar/../" -> "foo/" */ +TEST(path_util, Clean_Parent) +{ + NORMALIZE("/a/b/c/../../../", "/"); + NORMALIZE("/a/../a/b/../b/c/../c/", "/a/b/c/"); + NORMALIZE_WITH_BASEDIR("//../", "/a/b/c/", "/a/b/"); +} - { - char path[FILE_MAX] = "//../"; - BLI_path_normalize("/a/b/c/", path); - EXPECT_STREQ("/a/b/", path); - } +#undef NORMALIZE_WITH_BASEDIR +#undef NORMALIZE + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Tests for: #BLI_path_parent_dir + * \{ */ + +#define PARENT_DIR(input, output) \ + { \ + char path[FILE_MAX] = input; \ + if (SEP == '\\') { \ + BLI_str_replace_char(path, '/', '\\'); \ + } \ + BLI_path_parent_dir(path); \ + if (SEP == '\\') { \ + BLI_str_replace_char(path, '\\', '/'); \ + } \ + EXPECT_STREQ(output, path); \ + } \ + ((void)0) + +TEST(path_util, ParentDir_Simple) +{ + PARENT_DIR("/a/b/", "/a/"); + PARENT_DIR("/a/b", "/a/"); + PARENT_DIR("/a", "/"); } -#endif + +TEST(path_util, ParentDir_NOP) +{ + PARENT_DIR("/", "/"); + PARENT_DIR("", ""); + PARENT_DIR(".", "."); + PARENT_DIR("./", "./"); + PARENT_DIR(".//", ".//"); + PARENT_DIR("./.", "./."); +} + +TEST(path_util, ParentDir_TrailingPeriod) +{ + /* Ensure trailing dots aren't confused with parent path. */ + PARENT_DIR("/.../.../.../", "/.../.../"); + PARENT_DIR("/.../.../...", "/.../.../"); + + PARENT_DIR("/a../b../c../", "/a../b../"); + PARENT_DIR("/a../b../c..", "/a../b../"); + + PARENT_DIR("/a./b./c./", "/a./b./"); + PARENT_DIR("/a./b./c.", "/a./b./"); +} + +TEST(path_util, ParentDir_Complex) +{ + PARENT_DIR("./a/", "./"); + PARENT_DIR("./a", "./"); + PARENT_DIR("../a/", "../"); + PARENT_DIR("../a", "../"); +} + +#undef PARENT_DIR + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Tests for: #BLI_path_name_at_index + * \{ */ #define AT_INDEX(str_input, index_input, str_expect) \ { \ char path[] = str_input; \ + /* Test input assumes forward slash, support back-slash on WIN32. */ \ + if (SEP == '\\') { \ + BLI_str_replace_char(path, '/', '\\'); \ + } \ const char *expect = str_expect; \ int index_output, len_output; \ const bool ret = BLI_path_name_at_index(path, index_input, &index_output, &len_output); \ @@ -87,7 +184,6 @@ TEST(path_util, Clean) } \ ((void)0) -/* BLI_path_name_at_index */ TEST(path_util, NameAtIndex_Single) { AT_INDEX("/a", 0, "a"); @@ -166,21 +262,21 @@ TEST(path_util, NameAtIndex_MiscNeg) TEST(path_util, NameAtIndex_MiscComplex) { AT_INDEX("how//now/brown/cow", 0, "how"); - AT_INDEX("//how///now\\/brown/cow", 1, "now"); - AT_INDEX("/how/now\\//brown\\/cow", 2, "brown"); - AT_INDEX("/how/now/brown/cow//\\", 3, "cow"); - AT_INDEX("/how/now/brown/\\cow", 4, nullptr); - AT_INDEX("how/now/brown/\\cow\\", 4, nullptr); + AT_INDEX("//how///now//brown/cow", 1, "now"); + AT_INDEX("/how/now///brown//cow", 2, "brown"); + AT_INDEX("/how/now/brown/cow///", 3, "cow"); + AT_INDEX("/how/now/brown//cow", 4, nullptr); + AT_INDEX("how/now/brown//cow/", 4, nullptr); } TEST(path_util, NameAtIndex_MiscComplexNeg) { AT_INDEX("how//now/brown/cow", -4, "how"); - AT_INDEX("//how///now\\/brown/cow", -3, "now"); - AT_INDEX("/how/now\\//brown\\/cow", -2, "brown"); - AT_INDEX("/how/now/brown/cow//\\", -1, "cow"); - AT_INDEX("/how/now/brown/\\cow", -5, nullptr); - AT_INDEX("how/now/brown/\\cow\\", -5, nullptr); + AT_INDEX("//how///now//brown/cow", -3, "now"); + AT_INDEX("/how/now///brown//cow", -2, "brown"); + AT_INDEX("/how/now/brown/cow///", -1, "cow"); + AT_INDEX("/how/now/brown//cow", -5, nullptr); + AT_INDEX("how/now/brown//cow/", -5, nullptr); } TEST(path_util, NameAtIndex_NoneComplex) @@ -201,21 +297,59 @@ TEST(path_util, NameAtIndex_NoneComplexNeg) #undef AT_INDEX -#define JOIN(str_expect, out_size, ...) \ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Tests for: #BLI_path_join + * \{ */ + +/* For systems with `/` path separator (non WIN32). */ +#define JOIN_FORWARD_SLASH(str_expect, out_size, ...) \ { \ const char *expect = str_expect; \ char result[(out_size) + 1024]; \ - /* check we don't write past the last byte */ \ + /* Check we don't write past the last byte. */ \ result[out_size] = '\0'; \ - BLI_path_join(result, out_size, __VA_ARGS__, NULL); \ - /* simplify expected string */ \ + BLI_path_join(result, out_size, __VA_ARGS__); \ + EXPECT_STREQ(result, expect); \ + EXPECT_EQ(result[out_size], '\0'); \ + } \ + ((void)0) + +/* For systems with `\` path separator (WIN32). + * Perform additional manipulation to behave as if input arguments used `\` separators. + * Needed since #BLI_path_join uses native slashes. */ +#define JOIN_BACK_SLASH(str_expect, out_size, ...) \ + { \ + const char *expect = str_expect; \ + char result[(out_size) + 1024]; \ + const char *input_forward_slash[] = {__VA_ARGS__}; \ + char *input_back_slash[ARRAY_SIZE(input_forward_slash)] = {nullptr}; \ + for (int i = 0; i < ARRAY_SIZE(input_forward_slash); i++) { \ + input_back_slash[i] = strdup(input_forward_slash[i]); \ + BLI_str_replace_char(input_back_slash[i], '/', '\\'); \ + } \ + /* Check we don't write past the last byte. */ \ + result[out_size] = '\0'; \ + BLI_path_join_array(result, \ + out_size, \ + const_cast<const char **>(input_back_slash), \ + ARRAY_SIZE(input_back_slash)); \ BLI_str_replace_char(result, '\\', '/'); \ EXPECT_STREQ(result, expect); \ EXPECT_EQ(result[out_size], '\0'); \ + for (int i = 0; i < ARRAY_SIZE(input_forward_slash); i++) { \ + free(input_back_slash[i]); \ + } \ } \ ((void)0) -/* BLI_path_join */ +#ifdef WIN32 +# define JOIN JOIN_BACK_SLASH +#else +# define JOIN JOIN_FORWARD_SLASH +#endif + TEST(path_util, JoinNop) { JOIN("", 100, ""); @@ -293,9 +427,9 @@ TEST(path_util, JoinTruncateLong) TEST(path_util, JoinComplex) { - JOIN("/a/b/c/d/e/f/g/", 100, "/", "\\a/b", "//////c/d", "", "e\\\\", "f", "g//"); - JOIN("/aa/bb/cc/dd/ee/ff/gg/", 100, "/", "\\aa/bb", "//////cc/dd", "", "ee\\\\", "ff", "gg//"); - JOIN("1/2/3/", 100, "1", "////////", "", "2", "3\\"); + JOIN("/a/b/c/d/e/f/g/", 100, "/", "a/b", "//////c/d", "", "e", "f", "g//"); + JOIN("/aa/bb/cc/dd/ee/ff/gg/", 100, "/", "aa/bb", "//////cc/dd", "", "ee", "ff", "gg//"); + JOIN("1/2/3/", 100, "1", "////////", "", "2", "3///"); } TEST(path_util, JoinRelativePrefix) @@ -306,8 +440,15 @@ TEST(path_util, JoinRelativePrefix) } #undef JOIN +#undef JOIN_BACK_SLASH +#undef JOIN_FORWARD_SLASH + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Tests for: #BLI_path_frame + * \{ */ -/* BLI_path_frame */ TEST(path_util, Frame) { bool ret; @@ -384,7 +525,12 @@ TEST(path_util, Frame) } } -/* BLI_split_dirfile */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Tests for: #BLI_split_dirfile + * \{ */ + TEST(path_util, SplitDirfile) { { @@ -440,6 +586,12 @@ TEST(path_util, SplitDirfile) } } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Tests for: #BLI_path_frame_strip + * \{ */ + #define PATH_FRAME_STRIP(input_path, expect_path, expect_ext) \ { \ char path[FILE_MAX]; \ @@ -451,7 +603,6 @@ TEST(path_util, SplitDirfile) } \ ((void)0) -/* BLI_path_frame_strip */ TEST(path_util, PathFrameStrip) { PATH_FRAME_STRIP("", "", ""); @@ -463,6 +614,12 @@ TEST(path_util, PathFrameStrip) } #undef PATH_FRAME_STRIP +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Tests for: #BLI_path_extension_check + * \{ */ + #define PATH_EXTENSION_CHECK(input_path, input_ext, expect_ext) \ { \ const bool ret = BLI_path_extension_check(input_path, input_ext); \ @@ -475,7 +632,6 @@ TEST(path_util, PathFrameStrip) } \ ((void)0) -/* BLI_path_extension_check */ TEST(path_util, PathExtensionCheck) { PATH_EXTENSION_CHECK("a/b/c.exe", ".exe", ".exe"); @@ -501,6 +657,12 @@ TEST(path_util, PathExtensionCheck) } #undef PATH_EXTENSION_CHECK +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Tests for: #BLI_path_frame_check_chars + * \{ */ + #define PATH_FRAME_CHECK_CHARS(input_path, expect_hasChars) \ { \ const bool ret = BLI_path_frame_check_chars(input_path); \ @@ -513,7 +675,6 @@ TEST(path_util, PathExtensionCheck) } \ ((void)0) -/* BLI_path_frame_check_chars */ TEST(path_util, PathFrameCheckChars) { PATH_FRAME_CHECK_CHARS("a#", true); @@ -533,6 +694,12 @@ TEST(path_util, PathFrameCheckChars) } #undef PATH_FRAME_CHECK_CHARS +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Tests for: #BLI_path_frame_range + * \{ */ + #define PATH_FRAME_RANGE(input_path, sta, end, digits, expect_outpath) \ { \ char path[FILE_MAX]; \ @@ -549,7 +716,6 @@ TEST(path_util, PathFrameCheckChars) } \ ((void)0) -/* BLI_path_frame_range */ TEST(path_util, PathFrameRange) { int dummy = -1; @@ -565,6 +731,12 @@ TEST(path_util, PathFrameRange) } #undef PATH_FRAME_RANGE +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Tests for: #BLI_path_frame_get + * \{ */ + #define PATH_FRAME_GET(input_path, expect_frame, expect_numdigits, expect_pathisvalid) \ { \ char path[FILE_MAX]; \ @@ -582,7 +754,6 @@ TEST(path_util, PathFrameRange) } \ ((void)0) -/* BLI_path_frame_get */ TEST(path_util, PathFrameGet) { PATH_FRAME_GET("001.avi", 1, 3, true); @@ -594,7 +765,12 @@ TEST(path_util, PathFrameGet) } #undef PATH_FRAME_GET -/* BLI_path_extension */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Tests for: #BLI_path_extension + * \{ */ + TEST(path_util, PathExtension) { EXPECT_EQ(nullptr, BLI_path_extension("some.def/file")); @@ -608,62 +784,88 @@ TEST(path_util, PathExtension) EXPECT_STREQ(".001", BLI_path_extension("Text.001")); } -/* BLI_path_rel. */ -#ifndef _WIN32 +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Tests for: #BLI_path_rel + * \{ */ -# define PATH_REL(abs_path, ref_path, rel_path) \ - { \ - char path[FILE_MAX]; \ - BLI_strncpy(path, abs_path, sizeof(path)); \ - BLI_path_rel(path, ref_path); \ - EXPECT_STREQ(rel_path, path); \ +#define PATH_REL(abs_path, ref_path, rel_path) \ + { \ + char path[FILE_MAX]; \ + const char *ref_path_test = ref_path; \ + BLI_strncpy(path, abs_path, sizeof(path)); \ + if (SEP == '\\') { \ + BLI_str_replace_char(path, '/', '\\'); \ + ref_path_test = str_replace_char_strdup(ref_path_test, '/', '\\'); \ } \ - void(0) + BLI_path_rel(path, ref_path_test); \ + if (SEP == '\\') { \ + BLI_str_replace_char(path, '\\', '/'); \ + free((void *)ref_path_test); \ + } \ + EXPECT_STREQ(rel_path, path); \ + } \ + void(0) -TEST(path_util, PathRelPath) +#ifdef WIN32 +# define ABS_PREFIX "C:" +#else +# define ABS_PREFIX "" +#endif + +TEST(path_util, PathRelPath_Simple) { - PATH_REL("/foo/bar/blender.blend", "/foo/bar/", "//blender.blend"); - PATH_REL("/foo/bar/blender.blend", "/foo/bar", "//bar/blender.blend"); + PATH_REL(ABS_PREFIX "/foo/bar/blender.blend", ABS_PREFIX "/foo/bar/", "//blender.blend"); +} - /* Check for potential buffer overflows. */ - { - char abs_path_in[FILE_MAX]; - abs_path_in[0] = '/'; - for (int i = 1; i < FILE_MAX - 1; i++) { - abs_path_in[i] = 'A'; - } - abs_path_in[FILE_MAX - 1] = '\0'; - char abs_path_out[FILE_MAX]; - abs_path_out[0] = '/'; - abs_path_out[1] = '/'; - for (int i = 2; i < FILE_MAX - 1; i++) { - abs_path_out[i] = 'A'; - } - abs_path_out[FILE_MAX - 1] = '\0'; - PATH_REL(abs_path_in, "/", abs_path_out); - - const char *ref_path_in = "/foo/bar/"; - const size_t ref_path_in_len = strlen(ref_path_in); - strcpy(abs_path_in, ref_path_in); - for (int i = ref_path_in_len; i < FILE_MAX - 1; i++) { - abs_path_in[i] = 'A'; - } - abs_path_in[FILE_MAX - 1] = '\0'; - abs_path_out[0] = '/'; - abs_path_out[1] = '/'; - for (int i = 2; i < FILE_MAX - (int(ref_path_in_len) - 1); i++) { - abs_path_out[i] = 'A'; - } - abs_path_out[FILE_MAX - (ref_path_in_len - 1)] = '\0'; - PATH_REL(abs_path_in, ref_path_in, abs_path_out); +TEST(path_util, PathRelPath_SimpleSubdir) +{ + PATH_REL(ABS_PREFIX "/foo/bar/blender.blend", ABS_PREFIX "/foo/bar", "//bar/blender.blend"); +} + +TEST(path_util, PathRelPath_BufferOverflowRoot) +{ + char abs_path_in[FILE_MAX]; + const char *abs_prefix = ABS_PREFIX "/"; + for (int i = STRNCPY_RLEN(abs_path_in, abs_prefix); i < FILE_MAX - 1; i++) { + abs_path_in[i] = 'A'; + } + abs_path_in[FILE_MAX - 1] = '\0'; + char abs_path_out[FILE_MAX]; + for (int i = STRNCPY_RLEN(abs_path_out, "//"); i < FILE_MAX - 1; i++) { + abs_path_out[i] = 'A'; + } + abs_path_out[FILE_MAX - std::max((strlen(abs_prefix) - 1), size_t(1))] = '\0'; + PATH_REL(abs_path_in, abs_prefix, abs_path_out); +} + +TEST(path_util, PathRelPath_BufferOverflowSubdir) +{ + char abs_path_in[FILE_MAX]; + const char *ref_path_in = ABS_PREFIX "/foo/bar/"; + const size_t ref_path_in_len = strlen(ref_path_in); + for (int i = STRNCPY_RLEN(abs_path_in, ref_path_in); i < FILE_MAX - 1; i++) { + abs_path_in[i] = 'A'; } + abs_path_in[FILE_MAX - 1] = '\0'; + char abs_path_out[FILE_MAX]; + for (int i = STRNCPY_RLEN(abs_path_out, "//"); i < FILE_MAX - (int(ref_path_in_len) - 1); i++) { + abs_path_out[i] = 'A'; + } + abs_path_out[FILE_MAX - std::max((ref_path_in_len - 1), size_t(1))] = '\0'; + PATH_REL(abs_path_in, ref_path_in, abs_path_out); } -# undef PATH_REL +#undef PATH_REL +#undef ABS_PREFIX -#endif +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Tests for: #BLI_path_contains + * \{ */ -/* BLI_path_contains */ TEST(path_util, PathContains) { EXPECT_TRUE(BLI_path_contains("/some/path", "/some/path")) << "A path contains itself"; @@ -692,4 +894,6 @@ TEST(path_util, PathContains_Windows_case_insensitive) EXPECT_TRUE(BLI_path_contains("C:\\some\\path", "c:\\SOME\\path\\inside")) << "On Windows path comparison should ignore case"; } -#endif +#endif /* WIN32 */ + +/** \} */ diff --git a/source/blender/blenlib/tests/BLI_string_test.cc b/source/blender/blenlib/tests/BLI_string_test.cc index 9bdf6075c70..d726fbccf20 100644 --- a/source/blender/blenlib/tests/BLI_string_test.cc +++ b/source/blender/blenlib/tests/BLI_string_test.cc @@ -515,6 +515,103 @@ TEST(string, StrFormatDecimalUnits) EXPECT_STREQ("-2.1B", size_str); } +/* BLI_str_format_integer_unit */ +TEST(string, StrFormatIntegerUnits) +{ + char size_str[7]; + int size; + + BLI_str_format_integer_unit(size_str, size = 0); + EXPECT_STREQ("0", size_str); + BLI_str_format_integer_unit(size_str, size = 1); + EXPECT_STREQ("1", size_str); + BLI_str_format_integer_unit(size_str, size = 10); + EXPECT_STREQ("10", size_str); + BLI_str_format_integer_unit(size_str, size = 15); + EXPECT_STREQ("15", size_str); + BLI_str_format_integer_unit(size_str, size = 100); + EXPECT_STREQ("100", size_str); + BLI_str_format_integer_unit(size_str, size = 155); + EXPECT_STREQ("155", size_str); + BLI_str_format_integer_unit(size_str, size = 1000); + EXPECT_STREQ("1K", size_str); + BLI_str_format_integer_unit(size_str, size = 1555); + EXPECT_STREQ("1K", size_str); + BLI_str_format_integer_unit(size_str, size = 10000); + EXPECT_STREQ("10K", size_str); + BLI_str_format_integer_unit(size_str, size = 15555); + EXPECT_STREQ("15K", size_str); + BLI_str_format_integer_unit(size_str, size = 100000); + EXPECT_STREQ(".1M", size_str); + BLI_str_format_integer_unit(size_str, size = 155555); + EXPECT_STREQ(".1M", size_str); + BLI_str_format_integer_unit(size_str, size = 1000000); + EXPECT_STREQ("1M", size_str); + BLI_str_format_integer_unit(size_str, size = 1555555); + EXPECT_STREQ("1M", size_str); + BLI_str_format_integer_unit(size_str, size = 2555555); + EXPECT_STREQ("2M", size_str); + BLI_str_format_integer_unit(size_str, size = 10000000); + EXPECT_STREQ("10M", size_str); + BLI_str_format_integer_unit(size_str, size = 15555555); + EXPECT_STREQ("15M", size_str); + BLI_str_format_integer_unit(size_str, size = 100000000); + EXPECT_STREQ(".1B", size_str); + BLI_str_format_integer_unit(size_str, size = 155555555); + EXPECT_STREQ(".1B", size_str); + BLI_str_format_integer_unit(size_str, size = 255555555); + EXPECT_STREQ(".2B", size_str); + BLI_str_format_integer_unit(size_str, size = 1000000000); + EXPECT_STREQ("1B", size_str); + + /* Largest possible value. */ + BLI_str_format_integer_unit(size_str, size = INT32_MAX); + EXPECT_STREQ("2B", size_str); + + BLI_str_format_integer_unit(size_str, size = -0); + EXPECT_STREQ("0", size_str); + BLI_str_format_integer_unit(size_str, size = -1); + EXPECT_STREQ("-1", size_str); + BLI_str_format_integer_unit(size_str, size = -10); + EXPECT_STREQ("-10", size_str); + BLI_str_format_integer_unit(size_str, size = -15); + EXPECT_STREQ("-15", size_str); + BLI_str_format_integer_unit(size_str, size = -100); + EXPECT_STREQ("-100", size_str); + BLI_str_format_integer_unit(size_str, size = -155); + EXPECT_STREQ("-155", size_str); + BLI_str_format_integer_unit(size_str, size = -1000); + EXPECT_STREQ("-1K", size_str); + BLI_str_format_integer_unit(size_str, size = -1555); + EXPECT_STREQ("-1K", size_str); + BLI_str_format_integer_unit(size_str, size = -10000); + EXPECT_STREQ("-10K", size_str); + BLI_str_format_integer_unit(size_str, size = -15555); + EXPECT_STREQ("-15K", size_str); + BLI_str_format_integer_unit(size_str, size = -100000); + EXPECT_STREQ("-.1M", size_str); + BLI_str_format_integer_unit(size_str, size = -155555); + EXPECT_STREQ("-.1M", size_str); + BLI_str_format_integer_unit(size_str, size = -1000000); + EXPECT_STREQ("-1M", size_str); + BLI_str_format_integer_unit(size_str, size = -1555555); + EXPECT_STREQ("-1M", size_str); + BLI_str_format_integer_unit(size_str, size = -10000000); + EXPECT_STREQ("-10M", size_str); + BLI_str_format_integer_unit(size_str, size = -15555555); + EXPECT_STREQ("-15M", size_str); + BLI_str_format_integer_unit(size_str, size = -100000000); + EXPECT_STREQ("-.1B", size_str); + BLI_str_format_integer_unit(size_str, size = -155555555); + EXPECT_STREQ("-.1B", size_str); + BLI_str_format_integer_unit(size_str, size = -1000000000); + EXPECT_STREQ("-1B", size_str); + + /* Smallest possible value. */ + BLI_str_format_integer_unit(size_str, size = -INT32_MAX); + EXPECT_STREQ("-2B", size_str); +} + struct WordInfo { WordInfo() = default; WordInfo(int start, int end) : start(start), end(end) diff --git a/source/blender/blenloader/BLO_readfile.h b/source/blender/blenloader/BLO_readfile.h index 93040fa01ee..75a1956ce12 100644 --- a/source/blender/blenloader/BLO_readfile.h +++ b/source/blender/blenloader/BLO_readfile.h @@ -182,6 +182,11 @@ void BLO_blendfiledata_free(BlendFileData *bfd); typedef struct BLODataBlockInfo { char name[64]; /* MAX_NAME */ struct AssetMetaData *asset_data; + /* Optimization: Tag data-blocks for which we know there is no preview. + * Knowing this can be used to skip the (potentially expensive) preview loading process. If this + * is set to true it means we looked for a preview and couldn't find one. False may mean that + * either no preview was found, or that it wasn't looked for in the first place. */ + bool no_preview_found; } BLODataBlockInfo; /** diff --git a/source/blender/blenloader/CMakeLists.txt b/source/blender/blenloader/CMakeLists.txt index f0209d1337c..86793d38b0b 100644 --- a/source/blender/blenloader/CMakeLists.txt +++ b/source/blender/blenloader/CMakeLists.txt @@ -47,7 +47,7 @@ set(SRC intern/versioning_400.cc intern/versioning_common.cc intern/versioning_cycles.c - intern/versioning_defaults.c + intern/versioning_defaults.cc intern/versioning_dna.c intern/versioning_legacy.c intern/versioning_userdef.c diff --git a/source/blender/blenloader/intern/readblenentry.cc b/source/blender/blenloader/intern/readblenentry.cc index 55ac2d31277..ead796c0e28 100644 --- a/source/blender/blenloader/intern/readblenentry.cc +++ b/source/blender/blenloader/intern/readblenentry.cc @@ -138,11 +138,15 @@ LinkNode *BLO_blendhandle_get_datablock_info(BlendHandle *bh, BHead *bhead; int tot = 0; + const int sdna_nr_preview_image = DNA_struct_find_nr(fd->filesdna, "PreviewImage"); + for (bhead = blo_bhead_first(fd); bhead; bhead = blo_bhead_next(fd, bhead)) { if (bhead->code == ENDB) { break; } if (bhead->code == ofblocktype) { + BHead *id_bhead = bhead; + const char *name = blo_bhead_id_name(fd, bhead) + 2; AssetMetaData *asset_meta_data = blo_bhead_id_asset_data_address(fd, bhead); @@ -165,6 +169,17 @@ LinkNode *BLO_blendhandle_get_datablock_info(BlendHandle *bh, STRNCPY(info->name, name); info->asset_data = asset_meta_data; + bool has_preview = false; + /* See if we can find a preview in the data of this ID. */ + for (BHead *data_bhead = blo_bhead_next(fd, id_bhead); data_bhead->code == DATA; + data_bhead = blo_bhead_next(fd, data_bhead)) { + if (data_bhead->SDNAnr == sdna_nr_preview_image) { + has_preview = true; + break; + } + } + info->no_preview_found = !has_preview; + BLI_linklist_prepend(&infos, info); tot++; } diff --git a/source/blender/blenloader/intern/readfile.cc b/source/blender/blenloader/intern/readfile.cc index ec1768232c8..569798048f6 100644 --- a/source/blender/blenloader/intern/readfile.cc +++ b/source/blender/blenloader/intern/readfile.cc @@ -2143,7 +2143,7 @@ static void direct_link_id_common( BlendDataReader *reader, Library *current_library, ID *id, ID *id_old, const int tag) { if (!BLO_read_data_is_undo(reader)) { - /* When actually reading a file, we do want to reset/re-generate session uuids. + /* When actually reading a file, we do want to reset/re-generate session UUIDS. * In undo case, we want to re-use existing ones. */ id->session_uuid = MAIN_ID_SESSION_UUID_UNSET; } diff --git a/source/blender/blenloader/intern/versioning_250.c b/source/blender/blenloader/intern/versioning_250.c index 3a39ed04d2a..0b543ad735b 100644 --- a/source/blender/blenloader/intern/versioning_250.c +++ b/source/blender/blenloader/intern/versioning_250.c @@ -630,7 +630,7 @@ static bool seq_sound_proxy_update_cb(Sequence *seq, void *user_data) Main *bmain = (Main *)user_data; if (seq->type == SEQ_TYPE_SOUND_HD) { char str[FILE_MAX]; - BLI_join_dirfile(str, sizeof(str), seq->strip->dir, seq->strip->stripdata->name); + BLI_path_join(str, sizeof(str), seq->strip->dir, seq->strip->stripdata->name); BLI_path_abs(str, BKE_main_blendfile_path(bmain)); seq->sound = BKE_sound_new_file(bmain, str); } diff --git a/source/blender/blenloader/intern/versioning_300.cc b/source/blender/blenloader/intern/versioning_300.cc index 5328107e1f2..a2bd7fd2fd1 100644 --- a/source/blender/blenloader/intern/versioning_300.cc +++ b/source/blender/blenloader/intern/versioning_300.cc @@ -3623,6 +3623,36 @@ void blo_do_versions_300(FileData *fd, Library * /*lib*/, Main *bmain) } } + if (!MAIN_VERSION_ATLEAST(bmain, 304, 4)) { + /* Update brush sculpt settings. */ + LISTBASE_FOREACH (Brush *, brush, &bmain->brushes) { + brush->automasking_cavity_factor = 1.0f; + } + } + + if (!MAIN_VERSION_ATLEAST(bmain, 304, 5)) { + /* Fix for T101622 - update flags of sequence editor regions that were not initialized + * properly. */ + LISTBASE_FOREACH (bScreen *, screen, &bmain->screens) { + LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) { + LISTBASE_FOREACH (SpaceLink *, sl, &area->spacedata) { + ListBase *regionbase = (sl == area->spacedata.first) ? &area->regionbase : + &sl->regionbase; + if (sl->spacetype == SPACE_SEQ) { + LISTBASE_FOREACH (ARegion *, region, regionbase) { + if (region->regiontype == RGN_TYPE_TOOLS) { + region->v2d.flag &= ~V2D_VIEWSYNC_AREA_VERTICAL; + } + if (region->regiontype == RGN_TYPE_CHANNELS) { + region->v2d.flag |= V2D_VIEWSYNC_AREA_VERTICAL; + } + } + } + } + } + } + } + /** * Versioning code until next subversion bump goes here. * diff --git a/source/blender/blenloader/intern/versioning_defaults.c b/source/blender/blenloader/intern/versioning_defaults.cc index 06903865381..da23e9cb49f 100644 --- a/source/blender/blenloader/intern/versioning_defaults.c +++ b/source/blender/blenloader/intern/versioning_defaults.cc @@ -15,6 +15,7 @@ #include "BLI_listbase.h" #include "BLI_math.h" +#include "BLI_math_vec_types.hh" #include "BLI_string.h" #include "BLI_system.h" #include "BLI_utildefines.h" @@ -36,6 +37,7 @@ #include "DNA_workspace_types.h" #include "BKE_appdir.h" +#include "BKE_attribute.hh" #include "BKE_brush.h" #include "BKE_colortools.h" #include "BKE_curveprofile.h" @@ -119,7 +121,7 @@ static void blo_update_defaults_screen(bScreen *screen, if (area->spacetype == SPACE_IMAGE) { if (STREQ(workspace_name, "UV Editing")) { - SpaceImage *sima = area->spacedata.first; + SpaceImage *sima = static_cast<SpaceImage *>(area->spacedata.first); if (sima->mode == SI_MODE_VIEW) { sima->mode = SI_MODE_UV; } @@ -127,7 +129,7 @@ static void blo_update_defaults_screen(bScreen *screen, } else if (area->spacetype == SPACE_ACTION) { /* Show markers region, hide channels and collapse summary in timelines. */ - SpaceAction *saction = area->spacedata.first; + SpaceAction *saction = static_cast<SpaceAction *>(area->spacedata.first); saction->flag |= SACTION_SHOW_MARKERS; if (saction->mode == SACTCONT_TIMELINE) { saction->ads.flag |= ADS_FLAG_SUMMARY_COLLAPSED; @@ -148,15 +150,15 @@ static void blo_update_defaults_screen(bScreen *screen, } } else if (area->spacetype == SPACE_GRAPH) { - SpaceGraph *sipo = area->spacedata.first; + SpaceGraph *sipo = static_cast<SpaceGraph *>(area->spacedata.first); sipo->flag |= SIPO_SHOW_MARKERS; } else if (area->spacetype == SPACE_NLA) { - SpaceNla *snla = area->spacedata.first; + SpaceNla *snla = static_cast<SpaceNla *>(area->spacedata.first); snla->flag |= SNLA_SHOW_MARKERS; } else if (area->spacetype == SPACE_SEQ) { - SpaceSeq *seq = area->spacedata.first; + SpaceSeq *seq = static_cast<SpaceSeq *>(area->spacedata.first); seq->flag |= SEQ_SHOW_MARKERS | SEQ_ZOOM_TO_FIT | SEQ_USE_PROXIES | SEQ_SHOW_OVERLAY; seq->render_size = SEQ_RENDER_SIZE_PROXY_100; seq->timeline_overlay.flag |= SEQ_TIMELINE_SHOW_STRIP_SOURCE | SEQ_TIMELINE_SHOW_STRIP_NAME | @@ -166,12 +168,12 @@ static void blo_update_defaults_screen(bScreen *screen, } else if (area->spacetype == SPACE_TEXT) { /* Show syntax and line numbers in Script workspace text editor. */ - SpaceText *stext = area->spacedata.first; + SpaceText *stext = static_cast<SpaceText *>(area->spacedata.first); stext->showsyntax = true; stext->showlinenrs = true; } else if (area->spacetype == SPACE_VIEW3D) { - View3D *v3d = area->spacedata.first; + View3D *v3d = static_cast<View3D *>(area->spacedata.first); /* Screen space cavity by default for faster performance. */ v3d->shading.cavity_type = V3D_SHADING_CAVITY_CURVATURE; v3d->shading.flag |= V3D_SHADING_SPECULAR_HIGHLIGHT; @@ -195,7 +197,7 @@ static void blo_update_defaults_screen(bScreen *screen, v3d->overlay.normals_constant_screen_size = 7.0f; } else if (area->spacetype == SPACE_CLIP) { - SpaceClip *sclip = area->spacedata.first; + SpaceClip *sclip = static_cast<SpaceClip *>(area->spacedata.first); sclip->around = V3D_AROUND_CENTER_MEDIAN; sclip->mask_info.blend_factor = 0.7f; sclip->mask_info.draw_flag = MASK_DRAWFLAG_SPLINE; @@ -206,7 +208,9 @@ static void blo_update_defaults_screen(bScreen *screen, const bool hide_image_tool_header = STREQ(workspace_name, "Rendering"); LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) { LISTBASE_FOREACH (SpaceLink *, sl, &area->spacedata) { - ListBase *regionbase = (sl == area->spacedata.first) ? &area->regionbase : &sl->regionbase; + ListBase *regionbase = (sl == static_cast<SpaceLink *>(area->spacedata.first)) ? + &area->regionbase : + &sl->regionbase; LISTBASE_FOREACH (ARegion *, region, regionbase) { if (region->regiontype == RGN_TYPE_TOOL_HEADER) { @@ -226,12 +230,12 @@ static void blo_update_defaults_screen(bScreen *screen, if (app_template && STREQ(app_template, "2D_Animation")) { LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) { if (area->spacetype == SPACE_ACTION) { - SpaceAction *saction = area->spacedata.first; + SpaceAction *saction = static_cast<SpaceAction *>(area->spacedata.first); /* Enable Sliders. */ saction->flag |= SACTION_SLIDERS; } else if (area->spacetype == SPACE_VIEW3D) { - View3D *v3d = area->spacedata.first; + View3D *v3d = static_cast<View3D *>(area->spacedata.first); /* Set Material Color by default. */ v3d->shading.color_type = V3D_SHADING_MATERIAL_COLOR; /* Enable Annotations. */ @@ -252,7 +256,7 @@ void BLO_update_defaults_workspace(WorkSpace *workspace, const char *app_templat if (blo_is_builtin_template(app_template)) { /* Clear all tools to use default options instead, ignore the tool saved in the file. */ while (!BLI_listbase_is_empty(&workspace->tools)) { - BKE_workspace_tool_remove(workspace, workspace->tools.first); + BKE_workspace_tool_remove(workspace, static_cast<bToolRef *>(workspace->tools.first)); } /* For 2D animation template. */ @@ -268,7 +272,7 @@ void BLO_update_defaults_workspace(WorkSpace *workspace, const char *app_templat LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) { LISTBASE_FOREACH (ARegion *, region, &area->regionbase) { if (area->spacetype == SPACE_VIEW3D) { - View3D *v3d = area->spacedata.first; + View3D *v3d = static_cast<View3D *>(area->spacedata.first); v3d->shading.flag &= ~V3D_SHADING_CAVITY; copy_v3_fl(v3d->shading.single_color, 1.0f); STRNCPY(v3d->shading.matcap, "basic_1"); @@ -296,7 +300,8 @@ static void blo_update_defaults_scene(Main *bmain, Scene *scene) } /* Rename render layers. */ - BKE_view_layer_rename(bmain, scene, scene->view_layers.first, "ViewLayer"); + BKE_view_layer_rename( + bmain, scene, static_cast<ViewLayer *>(scene->view_layers.first), "ViewLayer"); /* Disable Z pass by default. */ LISTBASE_FOREACH (ViewLayer *, view_layer, &scene->view_layers) { @@ -308,7 +313,7 @@ static void blo_update_defaults_scene(Main *bmain, Scene *scene) scene->eevee.bloom_clamp = 0.0f; scene->eevee.motion_blur_shutter = 0.5f; - copy_v3_v3(scene->display.light_direction, (float[3]){M_SQRT1_3, M_SQRT1_3, M_SQRT1_3}); + copy_v3_v3(scene->display.light_direction, blender::float3(M_SQRT1_3)); copy_v2_fl2(scene->safe_areas.title, 0.1f, 0.05f); copy_v2_fl2(scene->safe_areas.action, 0.035f, 0.035f); @@ -344,9 +349,9 @@ static void blo_update_defaults_scene(Main *bmain, Scene *scene) } /* Correct default startup UV's. */ - Mesh *me = BLI_findstring(&bmain->meshes, "Cube", offsetof(ID, name) + 2); + Mesh *me = static_cast<Mesh *>(BLI_findstring(&bmain->meshes, "Cube", offsetof(ID, name) + 2)); if (me && (me->totloop == 24) && CustomData_has_layer(&me->ldata, CD_MLOOPUV)) { - MLoopUV *mloopuv = CustomData_get_layer(&me->ldata, CD_MLOOPUV); + MLoopUV *mloopuv = static_cast<MLoopUV *>(CustomData_get_layer(&me->ldata, CD_MLOOPUV)); const float uv_values[24][2] = { {0.625, 0.50}, {0.875, 0.50}, {0.875, 0.75}, {0.625, 0.75}, {0.375, 0.75}, {0.625, 0.75}, {0.625, 1.00}, {0.375, 1.00}, {0.375, 0.00}, {0.625, 0.00}, {0.625, 0.25}, {0.375, 0.25}, @@ -373,7 +378,7 @@ static void blo_update_defaults_scene(Main *bmain, Scene *scene) void BLO_update_defaults_startup_blend(Main *bmain, const char *app_template) { /* For all app templates. */ - for (WorkSpace *workspace = bmain->workspaces.first; workspace; workspace = workspace->id.next) { + LISTBASE_FOREACH (WorkSpace *, workspace, &bmain->workspaces) { BLO_update_defaults_workspace(workspace, app_template); } @@ -389,7 +394,8 @@ void BLO_update_defaults_startup_blend(Main *bmain, const char *app_template) do_versions_rename_id(bmain, ID_BR, "Draw Pen", "Pen"); /* Pen Soft brush. */ - brush = (Brush *)do_versions_rename_id(bmain, ID_BR, "Draw Soft", "Pencil Soft"); + brush = reinterpret_cast<Brush *>( + do_versions_rename_id(bmain, ID_BR, "Draw Soft", "Pencil Soft")); if (brush) { brush->gpencil_settings->icon_id = GP_BRUSH_ICON_PEN; } @@ -407,7 +413,8 @@ void BLO_update_defaults_startup_blend(Main *bmain, const char *app_template) do_versions_rename_id(bmain, ID_BR, "Draw Block", "Marker Chisel"); /* Remove useless Fill Area.001 brush. */ - brush = BLI_findstring(&bmain->brushes, "Fill Area.001", offsetof(ID, name) + 2); + brush = static_cast<Brush *>( + BLI_findstring(&bmain->brushes, "Fill Area.001", offsetof(ID, name) + 2)); if (brush) { BKE_id_delete(bmain, brush); } @@ -421,21 +428,24 @@ void BLO_update_defaults_startup_blend(Main *bmain, const char *app_template) do_versions_rename_id(bmain, ID_MA, "Black Dots", "Dots Stroke"); /* Dots Stroke. */ - ma = BLI_findstring(&bmain->materials, "Dots Stroke", offsetof(ID, name) + 2); + ma = static_cast<Material *>( + BLI_findstring(&bmain->materials, "Dots Stroke", offsetof(ID, name) + 2)); if (ma == NULL) { ma = BKE_gpencil_material_add(bmain, "Dots Stroke"); } ma->gp_style->mode = GP_MATERIAL_MODE_DOT; /* Squares Stroke. */ - ma = BLI_findstring(&bmain->materials, "Squares Stroke", offsetof(ID, name) + 2); + ma = static_cast<Material *>( + BLI_findstring(&bmain->materials, "Squares Stroke", offsetof(ID, name) + 2)); if (ma == NULL) { ma = BKE_gpencil_material_add(bmain, "Squares Stroke"); } ma->gp_style->mode = GP_MATERIAL_MODE_SQUARE; /* Change Solid Stroke settings. */ - ma = BLI_findstring(&bmain->materials, "Solid Stroke", offsetof(ID, name) + 2); + ma = static_cast<Material *>( + BLI_findstring(&bmain->materials, "Solid Stroke", offsetof(ID, name) + 2)); if (ma != NULL) { ma->gp_style->mix_rgba[3] = 1.0f; ma->gp_style->texture_offset[0] = -0.5f; @@ -443,7 +453,8 @@ void BLO_update_defaults_startup_blend(Main *bmain, const char *app_template) } /* Change Solid Fill settings. */ - ma = BLI_findstring(&bmain->materials, "Solid Fill", offsetof(ID, name) + 2); + ma = static_cast<Material *>( + BLI_findstring(&bmain->materials, "Solid Fill", offsetof(ID, name) + 2)); if (ma != NULL) { ma->gp_style->flag &= ~GP_MATERIAL_STROKE_SHOW; ma->gp_style->mix_rgba[3] = 1.0f; @@ -451,14 +462,15 @@ void BLO_update_defaults_startup_blend(Main *bmain, const char *app_template) ma->gp_style->mix_factor = 0.5f; } - Object *ob = BLI_findstring(&bmain->objects, "Stroke", offsetof(ID, name) + 2); + Object *ob = static_cast<Object *>( + BLI_findstring(&bmain->objects, "Stroke", offsetof(ID, name) + 2)); if (ob && ob->type == OB_GPENCIL) { ob->dtx |= OB_USE_GPENCIL_LIGHTS; } } /* Reset all grease pencil brushes. */ - Scene *scene = bmain->scenes.first; + Scene *scene = static_cast<Scene *>(bmain->scenes.first); BKE_brush_gpencil_paint_presets(bmain, scene->toolsettings, true); BKE_brush_gpencil_sculpt_presets(bmain, scene->toolsettings, true); BKE_brush_gpencil_vertex_presets(bmain, scene->toolsettings, true); @@ -511,7 +523,7 @@ void BLO_update_defaults_startup_blend(Main *bmain, const char *app_template) } /* Scenes */ - for (Scene *scene = bmain->scenes.first; scene; scene = scene->id.next) { + LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) { blo_update_defaults_scene(bmain, scene); if (app_template && STREQ(app_template, "Video_Editing")) { @@ -537,7 +549,7 @@ void BLO_update_defaults_startup_blend(Main *bmain, const char *app_template) do_versions_rename_id(bmain, ID_LA, "Lamp", "Light"); if (app_template && STREQ(app_template, "2D_Animation")) { - for (Object *object = bmain->objects.first; object; object = object->id.next) { + LISTBASE_FOREACH (Object *, object, &bmain->objects) { if (object->type == OB_GPENCIL) { /* Set grease pencil object in drawing mode */ bGPdata *gpd = (bGPdata *)object->data; @@ -548,7 +560,7 @@ void BLO_update_defaults_startup_blend(Main *bmain, const char *app_template) } } - for (Mesh *mesh = bmain->meshes.first; mesh; mesh = mesh->id.next) { + LISTBASE_FOREACH (Mesh *, mesh, &bmain->meshes) { /* Match default for new meshes. */ mesh->smoothresh = DEG2RADF(30); /* Match voxel remesher options for all existing meshes in templates. */ @@ -565,22 +577,23 @@ void BLO_update_defaults_startup_blend(Main *bmain, const char *app_template) CustomData_free_layers(&mesh->vdata, CD_PAINT_MASK, mesh->totvert); CustomData_free_layers(&mesh->ldata, CD_GRID_PAINT_MASK, mesh->totloop); } + mesh->attributes_for_write().remove(".sculpt_face_set"); } - for (Camera *camera = bmain->cameras.first; camera; camera = camera->id.next) { + LISTBASE_FOREACH (Camera *, camera, &bmain->cameras) { /* Initialize to a useful value. */ camera->dof.focus_distance = 10.0f; camera->dof.aperture_fstop = 2.8f; } - for (Light *light = bmain->lights.first; light; light = light->id.next) { + LISTBASE_FOREACH (Light *, light, &bmain->lights) { /* Fix lights defaults. */ light->clipsta = 0.05f; light->att_dist = 40.0f; } /* Materials */ - for (Material *ma = bmain->materials.first; ma; ma = ma->id.next) { + LISTBASE_FOREACH (Material *, ma, &bmain->materials) { /* Update default material to be a bit more rough. */ ma->roughness = 0.5f; @@ -588,7 +601,8 @@ void BLO_update_defaults_startup_blend(Main *bmain, const char *app_template) LISTBASE_FOREACH (bNode *, node, &ma->nodetree->nodes) { if (node->type == SH_NODE_BSDF_PRINCIPLED) { bNodeSocket *roughness_socket = nodeFindSocket(node, SOCK_IN, "Roughness"); - bNodeSocketValueFloat *roughness_data = roughness_socket->default_value; + bNodeSocketValueFloat *roughness_data = static_cast<bNodeSocketValueFloat *>( + roughness_socket->default_value); roughness_data->value = 0.5f; node->custom2 = SHD_SUBSURFACE_RANDOM_WALK; BKE_ntree_update_tag_node_property(ma->nodetree, node); @@ -606,13 +620,14 @@ void BLO_update_defaults_startup_blend(Main *bmain, const char *app_template) /* Enable for UV sculpt (other brush types will be created as needed), * without this the grab brush will be active but not selectable from the list. */ const char *brush_name = "Grab"; - Brush *brush = BLI_findstring(&bmain->brushes, brush_name, offsetof(ID, name) + 2); + Brush *brush = static_cast<Brush *>( + BLI_findstring(&bmain->brushes, brush_name, offsetof(ID, name) + 2)); if (brush) { brush->ob_mode |= OB_MODE_EDIT; } } - for (Brush *brush = bmain->brushes.first; brush; brush = brush->id.next) { + LISTBASE_FOREACH (Brush *, brush, &bmain->brushes) { brush->blur_kernel_radius = 2; /* Use full strength for all non-sculpt brushes, @@ -632,13 +647,15 @@ void BLO_update_defaults_startup_blend(Main *bmain, const char *app_template) Brush *brush; brush_name = "Smear"; - brush = BLI_findstring(&bmain->brushes, brush_name, offsetof(ID, name) + 2); + brush = static_cast<Brush *>( + BLI_findstring(&bmain->brushes, brush_name, offsetof(ID, name) + 2)); if (brush) { brush->spacing = 3.0; } brush_name = "Draw Sharp"; - brush = BLI_findstring(&bmain->brushes, brush_name, offsetof(ID, name) + 2); + brush = static_cast<Brush *>( + BLI_findstring(&bmain->brushes, brush_name, offsetof(ID, name) + 2)); if (!brush) { brush = BKE_brush_add(bmain, brush_name, OB_MODE_SCULPT); id_us_min(&brush->id); @@ -646,7 +663,8 @@ void BLO_update_defaults_startup_blend(Main *bmain, const char *app_template) } brush_name = "Elastic Deform"; - brush = BLI_findstring(&bmain->brushes, brush_name, offsetof(ID, name) + 2); + brush = static_cast<Brush *>( + BLI_findstring(&bmain->brushes, brush_name, offsetof(ID, name) + 2)); if (!brush) { brush = BKE_brush_add(bmain, brush_name, OB_MODE_SCULPT); id_us_min(&brush->id); @@ -654,7 +672,8 @@ void BLO_update_defaults_startup_blend(Main *bmain, const char *app_template) } brush_name = "Pose"; - brush = BLI_findstring(&bmain->brushes, brush_name, offsetof(ID, name) + 2); + brush = static_cast<Brush *>( + BLI_findstring(&bmain->brushes, brush_name, offsetof(ID, name) + 2)); if (!brush) { brush = BKE_brush_add(bmain, brush_name, OB_MODE_SCULPT); id_us_min(&brush->id); @@ -662,7 +681,8 @@ void BLO_update_defaults_startup_blend(Main *bmain, const char *app_template) } brush_name = "Multi-plane Scrape"; - brush = BLI_findstring(&bmain->brushes, brush_name, offsetof(ID, name) + 2); + brush = static_cast<Brush *>( + BLI_findstring(&bmain->brushes, brush_name, offsetof(ID, name) + 2)); if (!brush) { brush = BKE_brush_add(bmain, brush_name, OB_MODE_SCULPT); id_us_min(&brush->id); @@ -670,7 +690,8 @@ void BLO_update_defaults_startup_blend(Main *bmain, const char *app_template) } brush_name = "Clay Thumb"; - brush = BLI_findstring(&bmain->brushes, brush_name, offsetof(ID, name) + 2); + brush = static_cast<Brush *>( + BLI_findstring(&bmain->brushes, brush_name, offsetof(ID, name) + 2)); if (!brush) { brush = BKE_brush_add(bmain, brush_name, OB_MODE_SCULPT); id_us_min(&brush->id); @@ -678,7 +699,8 @@ void BLO_update_defaults_startup_blend(Main *bmain, const char *app_template) } brush_name = "Cloth"; - brush = BLI_findstring(&bmain->brushes, brush_name, offsetof(ID, name) + 2); + brush = static_cast<Brush *>( + BLI_findstring(&bmain->brushes, brush_name, offsetof(ID, name) + 2)); if (!brush) { brush = BKE_brush_add(bmain, brush_name, OB_MODE_SCULPT); id_us_min(&brush->id); @@ -686,7 +708,8 @@ void BLO_update_defaults_startup_blend(Main *bmain, const char *app_template) } brush_name = "Slide Relax"; - brush = BLI_findstring(&bmain->brushes, brush_name, offsetof(ID, name) + 2); + brush = static_cast<Brush *>( + BLI_findstring(&bmain->brushes, brush_name, offsetof(ID, name) + 2)); if (!brush) { brush = BKE_brush_add(bmain, brush_name, OB_MODE_SCULPT); id_us_min(&brush->id); @@ -694,7 +717,8 @@ void BLO_update_defaults_startup_blend(Main *bmain, const char *app_template) } brush_name = "Paint"; - brush = BLI_findstring(&bmain->brushes, brush_name, offsetof(ID, name) + 2); + brush = static_cast<Brush *>( + BLI_findstring(&bmain->brushes, brush_name, offsetof(ID, name) + 2)); if (!brush) { brush = BKE_brush_add(bmain, brush_name, OB_MODE_SCULPT); id_us_min(&brush->id); @@ -702,7 +726,8 @@ void BLO_update_defaults_startup_blend(Main *bmain, const char *app_template) } brush_name = "Smear"; - brush = BLI_findstring(&bmain->brushes, brush_name, offsetof(ID, name) + 2); + brush = static_cast<Brush *>( + BLI_findstring(&bmain->brushes, brush_name, offsetof(ID, name) + 2)); if (!brush) { brush = BKE_brush_add(bmain, brush_name, OB_MODE_SCULPT); id_us_min(&brush->id); @@ -710,7 +735,8 @@ void BLO_update_defaults_startup_blend(Main *bmain, const char *app_template) } brush_name = "Boundary"; - brush = BLI_findstring(&bmain->brushes, brush_name, offsetof(ID, name) + 2); + brush = static_cast<Brush *>( + BLI_findstring(&bmain->brushes, brush_name, offsetof(ID, name) + 2)); if (!brush) { brush = BKE_brush_add(bmain, brush_name, OB_MODE_SCULPT); id_us_min(&brush->id); @@ -718,7 +744,8 @@ void BLO_update_defaults_startup_blend(Main *bmain, const char *app_template) } brush_name = "Simplify"; - brush = BLI_findstring(&bmain->brushes, brush_name, offsetof(ID, name) + 2); + brush = static_cast<Brush *>( + BLI_findstring(&bmain->brushes, brush_name, offsetof(ID, name) + 2)); if (!brush) { brush = BKE_brush_add(bmain, brush_name, OB_MODE_SCULPT); id_us_min(&brush->id); @@ -726,7 +753,8 @@ void BLO_update_defaults_startup_blend(Main *bmain, const char *app_template) } brush_name = "Draw Face Sets"; - brush = BLI_findstring(&bmain->brushes, brush_name, offsetof(ID, name) + 2); + brush = static_cast<Brush *>( + BLI_findstring(&bmain->brushes, brush_name, offsetof(ID, name) + 2)); if (!brush) { brush = BKE_brush_add(bmain, brush_name, OB_MODE_SCULPT); id_us_min(&brush->id); @@ -734,7 +762,8 @@ void BLO_update_defaults_startup_blend(Main *bmain, const char *app_template) } brush_name = "Multires Displacement Eraser"; - brush = BLI_findstring(&bmain->brushes, brush_name, offsetof(ID, name) + 2); + brush = static_cast<Brush *>( + BLI_findstring(&bmain->brushes, brush_name, offsetof(ID, name) + 2)); if (!brush) { brush = BKE_brush_add(bmain, brush_name, OB_MODE_SCULPT); id_us_min(&brush->id); @@ -742,7 +771,8 @@ void BLO_update_defaults_startup_blend(Main *bmain, const char *app_template) } brush_name = "Multires Displacement Smear"; - brush = BLI_findstring(&bmain->brushes, brush_name, offsetof(ID, name) + 2); + brush = static_cast<Brush *>( + BLI_findstring(&bmain->brushes, brush_name, offsetof(ID, name) + 2)); if (!brush) { brush = BKE_brush_add(bmain, brush_name, OB_MODE_SCULPT); id_us_min(&brush->id); @@ -750,7 +780,7 @@ void BLO_update_defaults_startup_blend(Main *bmain, const char *app_template) } /* Use the same tool icon color in the brush cursor */ - for (brush = bmain->brushes.first; brush; brush = brush->id.next) { + LISTBASE_FOREACH (Brush *, brush, &bmain->brushes) { if (brush->ob_mode & OB_MODE_SCULPT) { BLI_assert(brush->sculpt_tool != 0); BKE_brush_sculpt_reset(brush); diff --git a/source/blender/blenloader/tests/blendfile_loading_base_test.cc b/source/blender/blenloader/tests/blendfile_loading_base_test.cc index 615e30a728e..b657970d45f 100644 --- a/source/blender/blenloader/tests/blendfile_loading_base_test.cc +++ b/source/blender/blenloader/tests/blendfile_loading_base_test.cc @@ -117,7 +117,7 @@ bool BlendfileLoadingBaseTest::blendfile_load(const char *filepath) } char abspath[FILENAME_MAX]; - BLI_path_join(abspath, sizeof(abspath), test_assets_dir.c_str(), filepath, nullptr); + BLI_path_join(abspath, sizeof(abspath), test_assets_dir.c_str(), filepath); BlendFileReadReport bf_reports = {nullptr}; bfile = BLO_read_from_file(abspath, BLO_READ_SKIP_NONE, &bf_reports); diff --git a/source/blender/blentranslation/intern/blt_lang.c b/source/blender/blentranslation/intern/blt_lang.c index 0662adfb9ed..b8523f289c7 100644 --- a/source/blender/blentranslation/intern/blt_lang.c +++ b/source/blender/blentranslation/intern/blt_lang.c @@ -72,7 +72,7 @@ static void fill_locales(void) free_locales(); - BLI_join_dirfile(languages, FILE_MAX, languages_path, "languages"); + BLI_path_join(languages, FILE_MAX, languages_path, "languages"); line = lines = BLI_file_read_as_lines(languages); /* This whole "parsing" code is a bit weak, in that it expects strictly formatted input file... diff --git a/source/blender/bmesh/intern/bmesh_construct.c b/source/blender/bmesh/intern/bmesh_construct.c index 22900ecef85..8125130490a 100644 --- a/source/blender/bmesh/intern/bmesh_construct.c +++ b/source/blender/bmesh/intern/bmesh_construct.c @@ -517,16 +517,16 @@ void BM_mesh_copy_init_customdata_from_mesh_array(BMesh *bm_dst, &me_src->ldata, CD_MASK_BMESH.pmask); if (i == 0) { - CustomData_copy(&me_src->vdata, &bm_dst->vdata, CD_MASK_BMESH.vmask, CD_SET_DEFAULT, 0); - CustomData_copy(&me_src->edata, &bm_dst->edata, CD_MASK_BMESH.emask, CD_SET_DEFAULT, 0); - CustomData_copy(&me_src->ldata, &bm_dst->ldata, CD_MASK_BMESH.lmask, CD_SET_DEFAULT, 0); - CustomData_copy(&me_src->pdata, &bm_dst->pdata, CD_MASK_BMESH.pmask, CD_SET_DEFAULT, 0); + CustomData_copy(&mesh_vdata, &bm_dst->vdata, CD_MASK_BMESH.vmask, CD_SET_DEFAULT, 0); + CustomData_copy(&mesh_edata, &bm_dst->edata, CD_MASK_BMESH.emask, CD_SET_DEFAULT, 0); + CustomData_copy(&mesh_pdata, &bm_dst->pdata, CD_MASK_BMESH.pmask, CD_SET_DEFAULT, 0); + CustomData_copy(&mesh_ldata, &bm_dst->ldata, CD_MASK_BMESH.lmask, CD_SET_DEFAULT, 0); } else { - CustomData_merge(&me_src->vdata, &bm_dst->vdata, CD_MASK_BMESH.vmask, CD_SET_DEFAULT, 0); - CustomData_merge(&me_src->edata, &bm_dst->edata, CD_MASK_BMESH.emask, CD_SET_DEFAULT, 0); - CustomData_merge(&me_src->ldata, &bm_dst->ldata, CD_MASK_BMESH.lmask, CD_SET_DEFAULT, 0); - CustomData_merge(&me_src->pdata, &bm_dst->pdata, CD_MASK_BMESH.pmask, CD_SET_DEFAULT, 0); + CustomData_merge(&mesh_vdata, &bm_dst->vdata, CD_MASK_BMESH.vmask, CD_SET_DEFAULT, 0); + CustomData_merge(&mesh_edata, &bm_dst->edata, CD_MASK_BMESH.emask, CD_SET_DEFAULT, 0); + CustomData_merge(&mesh_pdata, &bm_dst->pdata, CD_MASK_BMESH.pmask, CD_SET_DEFAULT, 0); + CustomData_merge(&mesh_ldata, &bm_dst->ldata, CD_MASK_BMESH.lmask, CD_SET_DEFAULT, 0); } MEM_SAFE_FREE(mesh_vdata.layers); diff --git a/source/blender/bmesh/tools/bmesh_bevel.c b/source/blender/bmesh/tools/bmesh_bevel.c index 8da28af3ca7..c45f9dbe49c 100644 --- a/source/blender/bmesh/tools/bmesh_bevel.c +++ b/source/blender/bmesh/tools/bmesh_bevel.c @@ -2058,7 +2058,7 @@ static void get_profile_point(BevelParams *bp, const Profile *pro, int i, int ns } else { BLI_assert(is_power_of_2_i(nseg) && nseg <= bp->pro_spacing.seg_2); - /* Find spacing between subsamples in prof_co_2. */ + /* Find spacing between sub-samples in `prof_co_2`. */ int subsample_spacing = bp->pro_spacing.seg_2 / nseg; copy_v3_v3(r_co, pro->prof_co_2 + 3 * i * subsample_spacing); } diff --git a/source/blender/bmesh/tools/bmesh_wireframe.c b/source/blender/bmesh/tools/bmesh_wireframe.c index 14ec45f14b0..bdc36559e05 100644 --- a/source/blender/bmesh/tools/bmesh_wireframe.c +++ b/source/blender/bmesh/tools/bmesh_wireframe.c @@ -175,7 +175,7 @@ void BM_mesh_wireframe(BMesh *bm, BMVert **verts_neg = MEM_mallocN(sizeof(BMVert *) * totvert_orig, __func__); BMVert **verts_pos = MEM_mallocN(sizeof(BMVert *) * totvert_orig, __func__); - /* Will over-alloc, but makes for easy lookups by index to keep aligned. */ + /* Will over-allocate, but makes for easy lookups by index to keep aligned. */ BMVert **verts_boundary = use_boundary ? MEM_mallocN(sizeof(BMVert *) * totvert_orig, __func__) : NULL; diff --git a/source/blender/compositor/intern/COM_Debug.cc b/source/blender/compositor/intern/COM_Debug.cc index d0f0be590f6..d184e5540ea 100644 --- a/source/blender/compositor/intern/COM_Debug.cc +++ b/source/blender/compositor/intern/COM_Debug.cc @@ -428,7 +428,7 @@ void DebugInfo::graphviz(const ExecutionSystem *system, StringRefNull name) else { BLI_strncpy(basename, (name + ".dot").c_str(), sizeof(basename)); } - BLI_join_dirfile(filepath, sizeof(filepath), BKE_tempdir_session(), basename); + BLI_path_join(filepath, sizeof(filepath), BKE_tempdir_session(), basename); file_index_++; std::cout << "Writing compositor debug to: " << filepath << "\n"; diff --git a/source/blender/compositor/nodes/COM_OutputFileNode.cc b/source/blender/compositor/nodes/COM_OutputFileNode.cc index c83bcf42efd..fc4270cc222 100644 --- a/source/blender/compositor/nodes/COM_OutputFileNode.cc +++ b/source/blender/compositor/nodes/COM_OutputFileNode.cc @@ -104,7 +104,7 @@ void OutputFileNode::convert_to_operations(NodeConverter &converter, char path[FILE_MAX]; /* combine file path for the input */ - BLI_join_dirfile(path, FILE_MAX, storage->base_path, sockdata->path); + BLI_path_join(path, FILE_MAX, storage->base_path, sockdata->path); NodeOperation *output_operation = nullptr; diff --git a/source/blender/compositor/operations/COM_ConvertOperation.h b/source/blender/compositor/operations/COM_ConvertOperation.h index 16d1e2e6bb5..ffd02ed5a2f 100644 --- a/source/blender/compositor/operations/COM_ConvertOperation.h +++ b/source/blender/compositor/operations/COM_ConvertOperation.h @@ -98,7 +98,7 @@ class ConvertVectorToValueOperation : public ConvertBaseOperation { class ConvertRGBToYCCOperation : public ConvertBaseOperation { private: - /** YCbCr mode (Jpeg, ITU601, ITU709) */ + /** YCbCr mode (JPEG, ITU601, ITU709) */ int mode_; public: @@ -116,7 +116,7 @@ class ConvertRGBToYCCOperation : public ConvertBaseOperation { class ConvertYCCToRGBOperation : public ConvertBaseOperation { private: - /** YCbCr mode (Jpeg, ITU601, ITU709) */ + /** YCbCr mode (JPEG, ITU601, ITU709) */ int mode_; public: diff --git a/source/blender/compositor/realtime_compositor/CMakeLists.txt b/source/blender/compositor/realtime_compositor/CMakeLists.txt index 90cbe0988ad..bab0b5385ec 100644 --- a/source/blender/compositor/realtime_compositor/CMakeLists.txt +++ b/source/blender/compositor/realtime_compositor/CMakeLists.txt @@ -2,7 +2,7 @@ set(INC . - ./algorithms + algorithms ../../blenkernel ../../blenlib ../../gpu diff --git a/source/blender/compositor/realtime_compositor/algorithms/COM_algorithm_parallel_reduction.hh b/source/blender/compositor/realtime_compositor/algorithms/COM_algorithm_parallel_reduction.hh index 9d0851eff84..f6d479f9bbe 100644 --- a/source/blender/compositor/realtime_compositor/algorithms/COM_algorithm_parallel_reduction.hh +++ b/source/blender/compositor/realtime_compositor/algorithms/COM_algorithm_parallel_reduction.hh @@ -27,6 +27,13 @@ float sum_blue(Context &context, GPUTexture *texture); * coefficients to compute the luminance. */ float sum_luminance(Context &context, GPUTexture *texture, float3 luminance_coefficients); +/* Computes the sum of the logarithm of the luminance of all pixels in the given texture, using the + * given luminance coefficients to compute the luminance. */ +float sum_log_luminance(Context &context, GPUTexture *texture, float3 luminance_coefficients); + +/* Computes the sum of the colors of all pixels in the given texture. */ +float4 sum_color(Context &context, GPUTexture *texture); + /* -------------------------------------------------------------------- * Sum Of Squared Difference Reductions. */ @@ -55,4 +62,42 @@ float sum_luminance_squared_difference(Context &context, float3 luminance_coefficients, float subtrahend); +/* -------------------------------------------------------------------- + * Maximum Reductions. + */ + +/* Computes the maximum luminance of all pixels in the given texture, using the given luminance + * coefficients to compute the luminance. */ +float maximum_luminance(Context &context, GPUTexture *texture, float3 luminance_coefficients); + +/* Computes the maximum float of all pixels in the given float texture, limited to the given range. + * Values outside of the given range are ignored. If non of the pixel values are in the range, the + * lower bound of the range is returned. For instance, if the given range is [-10, 10] and the + * image contains the values {2, 5, 11}, the maximum will be 5, since 11 is outside of the range. + * This is particularly useful for Z Depth normalization, since Z Depth can contain near infinite + * values, so enforcing an upper bound is beneficial. */ +float maximum_float_in_range(Context &context, + GPUTexture *texture, + float lower_bound, + float upper_bound); + +/* -------------------------------------------------------------------- + * Minimum Reductions. + */ + +/* Computes the minimum luminance of all pixels in the given texture, using the given luminance + * coefficients to compute the luminance. */ +float minimum_luminance(Context &context, GPUTexture *texture, float3 luminance_coefficients); + +/* Computes the minimum float of all pixels in the given float texture, limited to the given range. + * Values outside of the given range are ignored. If non of the pixel values are in the range, the + * upper bound of the range is returned. For instance, if the given range is [-10, 10] and the + * image contains the values {-11, 2, 5}, the minimum will be 2, since -11 is outside of the range. + * This is particularly useful for Z Depth normalization, since Z Depth can contain near infinite + * values, so enforcing a lower bound is beneficial. */ +float minimum_float_in_range(Context &context, + GPUTexture *texture, + float lower_bound, + float upper_bound); + } // namespace blender::realtime_compositor diff --git a/source/blender/compositor/realtime_compositor/algorithms/intern/algorithm_parallel_reduction.cc b/source/blender/compositor/realtime_compositor/algorithms/intern/algorithm_parallel_reduction.cc index 3266ccd14eb..9672431992d 100644 --- a/source/blender/compositor/realtime_compositor/algorithms/intern/algorithm_parallel_reduction.cc +++ b/source/blender/compositor/realtime_compositor/algorithms/intern/algorithm_parallel_reduction.cc @@ -134,6 +134,34 @@ float sum_luminance(Context &context, GPUTexture *texture, float3 luminance_coef return sum; } +float sum_log_luminance(Context &context, GPUTexture *texture, float3 luminance_coefficients) +{ + GPUShader *shader = context.shader_manager().get("compositor_sum_log_luminance"); + GPU_shader_bind(shader); + + GPU_shader_uniform_3fv(shader, "luminance_coefficients", luminance_coefficients); + + float *reduced_value = parallel_reduction_dispatch(context, texture, shader, GPU_R32F); + const float sum = *reduced_value; + MEM_freeN(reduced_value); + GPU_shader_unbind(); + + return sum; +} + +float4 sum_color(Context &context, GPUTexture *texture) +{ + GPUShader *shader = context.shader_manager().get("compositor_sum_color"); + GPU_shader_bind(shader); + + float *reduced_value = parallel_reduction_dispatch(context, texture, shader, GPU_RGBA32F); + const float4 sum = float4(reduced_value); + MEM_freeN(reduced_value); + GPU_shader_unbind(); + + return sum; +} + /* -------------------------------------------------------------------- * Sum Of Squared Difference Reductions. */ @@ -202,4 +230,80 @@ float sum_luminance_squared_difference(Context &context, return sum; } +/* -------------------------------------------------------------------- + * Maximum Reductions. + */ + +float maximum_luminance(Context &context, GPUTexture *texture, float3 luminance_coefficients) +{ + GPUShader *shader = context.shader_manager().get("compositor_maximum_luminance"); + GPU_shader_bind(shader); + + GPU_shader_uniform_3fv(shader, "luminance_coefficients", luminance_coefficients); + + float *reduced_value = parallel_reduction_dispatch(context, texture, shader, GPU_R32F); + const float maximum = *reduced_value; + MEM_freeN(reduced_value); + GPU_shader_unbind(); + + return maximum; +} + +float maximum_float_in_range(Context &context, + GPUTexture *texture, + float lower_bound, + float upper_bound) +{ + GPUShader *shader = context.shader_manager().get("compositor_maximum_float_in_range"); + GPU_shader_bind(shader); + + GPU_shader_uniform_1f(shader, "lower_bound", lower_bound); + GPU_shader_uniform_1f(shader, "upper_bound", upper_bound); + + float *reduced_value = parallel_reduction_dispatch(context, texture, shader, GPU_R32F); + const float maximum = *reduced_value; + MEM_freeN(reduced_value); + GPU_shader_unbind(); + + return maximum; +} + +/* -------------------------------------------------------------------- + * Minimum Reductions. + */ + +float minimum_luminance(Context &context, GPUTexture *texture, float3 luminance_coefficients) +{ + GPUShader *shader = context.shader_manager().get("compositor_minimum_luminance"); + GPU_shader_bind(shader); + + GPU_shader_uniform_3fv(shader, "luminance_coefficients", luminance_coefficients); + + float *reduced_value = parallel_reduction_dispatch(context, texture, shader, GPU_R32F); + const float minimum = *reduced_value; + MEM_freeN(reduced_value); + GPU_shader_unbind(); + + return minimum; +} + +float minimum_float_in_range(Context &context, + GPUTexture *texture, + float lower_bound, + float upper_bound) +{ + GPUShader *shader = context.shader_manager().get("compositor_minimum_float_in_range"); + GPU_shader_bind(shader); + + GPU_shader_uniform_1f(shader, "lower_bound", lower_bound); + GPU_shader_uniform_1f(shader, "upper_bound", upper_bound); + + float *reduced_value = parallel_reduction_dispatch(context, texture, shader, GPU_R32F); + const float minimum = *reduced_value; + MEM_freeN(reduced_value); + GPU_shader_unbind(); + + return minimum; +} + } // namespace blender::realtime_compositor diff --git a/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc b/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc index f95c0700a47..c84852788fd 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc @@ -453,6 +453,11 @@ static int foreach_id_cow_detect_need_for_update_callback(LibraryIDLinkCallbackD if (id == nullptr) { return IDWALK_RET_NOP; } + if (!ID_TYPE_IS_COW(GS(id->name))) { + /* No need to go further if the id never had a cow copy in the depsgraph. This function is + * only concerned with keeping the mapping between original and COW ids intact. */ + return IDWALK_RET_NOP; + } DepsgraphNodeBuilder *builder = static_cast<DepsgraphNodeBuilder *>(cb_data->user_data); ID *id_cow_self = cb_data->id_self; diff --git a/source/blender/depsgraph/intern/depsgraph_query_iter.cc b/source/blender/depsgraph/intern/depsgraph_query_iter.cc index 4636011e18b..11998860ef3 100644 --- a/source/blender/depsgraph/intern/depsgraph_query_iter.cc +++ b/source/blender/depsgraph/intern/depsgraph_query_iter.cc @@ -191,8 +191,8 @@ bool deg_iterator_duplis_step(DEGObjectIterData *data) bool is_neg_scale = is_negative_m4(dob->mat); SET_FLAG_FROM_TEST(data->temp_dupli_object.transflag, is_neg_scale, OB_NEG_SCALE); - copy_m4_m4(data->temp_dupli_object.obmat, dob->mat); - invert_m4_m4(data->temp_dupli_object.imat, data->temp_dupli_object.obmat); + copy_m4_m4(data->temp_dupli_object.object_to_world, dob->mat); + invert_m4_m4(data->temp_dupli_object.imat, data->temp_dupli_object.object_to_world); data->next_object = &data->temp_dupli_object; BLI_assert(deg::deg_validate_copy_on_write_datablock(&data->temp_dupli_object.id)); return true; diff --git a/source/blender/depsgraph/intern/eval/deg_eval_flush.cc b/source/blender/depsgraph/intern/eval/deg_eval_flush.cc index a5b29ae56a9..62a9158928d 100644 --- a/source/blender/depsgraph/intern/eval/deg_eval_flush.cc +++ b/source/blender/depsgraph/intern/eval/deg_eval_flush.cc @@ -284,7 +284,7 @@ void invalidate_tagged_evaluated_transform(ID *id) switch (id_type) { case ID_OB: { Object *object = (Object *)id; - copy_vn_fl((float *)object->obmat, 16, NAN); + copy_vn_fl((float *)object->object_to_world, 16, NAN); break; } default: diff --git a/source/blender/draw/CMakeLists.txt b/source/blender/draw/CMakeLists.txt index a645bd6b6af..4010b491141 100644 --- a/source/blender/draw/CMakeLists.txt +++ b/source/blender/draw/CMakeLists.txt @@ -71,7 +71,7 @@ set(SRC intern/draw_attributes.cc intern/draw_cache_impl_curve.cc intern/draw_cache_impl_curves.cc - intern/draw_cache_impl_gpencil.c + intern/draw_cache_impl_gpencil.cc intern/draw_cache_impl_lattice.c intern/draw_cache_impl_mesh.cc intern/draw_cache_impl_particles.c @@ -95,6 +95,7 @@ set(SRC intern/draw_manager_text.cc intern/draw_manager_texture.c intern/draw_pbvh.cc + intern/draw_pointcloud.cc intern/draw_select_buffer.c intern/draw_shader.cc intern/draw_texture_pool.cc diff --git a/source/blender/draw/engines/basic/basic_engine.c b/source/blender/draw/engines/basic/basic_engine.c index eee6a5a7cb5..05e62764bb1 100644 --- a/source/blender/draw/engines/basic/basic_engine.c +++ b/source/blender/draw/engines/basic/basic_engine.c @@ -182,7 +182,7 @@ static void basic_cache_populate(void *vedata, Object *ob) } } - const bool use_sculpt_pbvh = BKE_sculptsession_use_pbvh_draw(ob, draw_ctx->v3d) && + const bool use_sculpt_pbvh = BKE_sculptsession_use_pbvh_draw(ob, draw_ctx->rv3d) && !DRW_state_is_image_render(); const bool do_cull = (draw_ctx->v3d && (draw_ctx->v3d->shading.flag & V3D_SHADING_BACKFACE_CULLING)); diff --git a/source/blender/draw/engines/eevee/eevee_lightprobes.c b/source/blender/draw/engines/eevee/eevee_lightprobes.c index 942ab5502c7..eb111610706 100644 --- a/source/blender/draw/engines/eevee/eevee_lightprobes.c +++ b/source/blender/draw/engines/eevee/eevee_lightprobes.c @@ -403,7 +403,7 @@ static bool eevee_lightprobes_culling_test(Object *ob) const float max[3] = {1.0f, 1.0f, 1.0f}; BKE_boundbox_init_from_minmax(&bbox, min, max); - copy_m4_m4(tmp, ob->obmat); + copy_m4_m4(tmp, ob->object_to_world); normalize_v3(tmp[2]); mul_v3_fl(tmp[2], probe->distinf); @@ -445,7 +445,7 @@ void EEVEE_lightprobes_cache_add(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata /* Debug Display */ DRWCallBuffer *grp = vedata->stl->g_data->planar_display_shgrp; if (grp && (probe->flag & LIGHTPROBE_FLAG_SHOW_DATA)) { - DRW_buffer_add_entry(grp, &pinfo->num_planar, ob->obmat); + DRW_buffer_add_entry(grp, &pinfo->num_planar, ob->object_to_world); } pinfo->num_planar++; @@ -488,30 +488,30 @@ void EEVEE_lightprobes_grid_data_from_object(Object *ob, EEVEE_LightGrid *egrid, mul_v3_v3fl(half_cell_dim, cell_dim, 0.5f); /* Matrix converting world space to cell ranges. */ - invert_m4_m4(egrid->mat, ob->obmat); + invert_m4_m4(egrid->mat, ob->object_to_world); /* First cell. */ copy_v3_fl(egrid->corner, -1.0f); add_v3_v3(egrid->corner, half_cell_dim); - mul_m4_v3(ob->obmat, egrid->corner); + mul_m4_v3(ob->object_to_world, egrid->corner); /* Opposite neighbor cell. */ copy_v3_fl3(egrid->increment_x, cell_dim[0], 0.0f, 0.0f); add_v3_v3(egrid->increment_x, half_cell_dim); add_v3_fl(egrid->increment_x, -1.0f); - mul_m4_v3(ob->obmat, egrid->increment_x); + mul_m4_v3(ob->object_to_world, egrid->increment_x); sub_v3_v3(egrid->increment_x, egrid->corner); copy_v3_fl3(egrid->increment_y, 0.0f, cell_dim[1], 0.0f); add_v3_v3(egrid->increment_y, half_cell_dim); add_v3_fl(egrid->increment_y, -1.0f); - mul_m4_v3(ob->obmat, egrid->increment_y); + mul_m4_v3(ob->object_to_world, egrid->increment_y); sub_v3_v3(egrid->increment_y, egrid->corner); copy_v3_fl3(egrid->increment_z, 0.0f, 0.0f, cell_dim[2]); add_v3_v3(egrid->increment_z, half_cell_dim); add_v3_fl(egrid->increment_z, -1.0f); - mul_m4_v3(ob->obmat, egrid->increment_z); + mul_m4_v3(ob->object_to_world, egrid->increment_z); sub_v3_v3(egrid->increment_z, egrid->corner); /* Visibility bias */ @@ -527,7 +527,7 @@ void EEVEE_lightprobes_cube_data_from_object(Object *ob, EEVEE_LightProbe *eprob LightProbe *probe = (LightProbe *)ob->data; /* Update transforms */ - copy_v3_v3(eprobe->position, ob->obmat[3]); + copy_v3_v3(eprobe->position, ob->object_to_world[3]); /* Attenuation */ eprobe->attenuation_type = probe->attenuation_type; @@ -535,7 +535,7 @@ void EEVEE_lightprobes_cube_data_from_object(Object *ob, EEVEE_LightProbe *eprob unit_m4(eprobe->attenuationmat); scale_m4_fl(eprobe->attenuationmat, probe->distinf); - mul_m4_m4m4(eprobe->attenuationmat, ob->obmat, eprobe->attenuationmat); + mul_m4_m4m4(eprobe->attenuationmat, ob->object_to_world, eprobe->attenuationmat); invert_m4(eprobe->attenuationmat); /* Parallax */ @@ -550,7 +550,7 @@ void EEVEE_lightprobes_cube_data_from_object(Object *ob, EEVEE_LightProbe *eprob scale_m4_fl(eprobe->parallaxmat, probe->distinf); } - mul_m4_m4m4(eprobe->parallaxmat, ob->obmat, eprobe->parallaxmat); + mul_m4_m4m4(eprobe->parallaxmat, ob->object_to_world, eprobe->parallaxmat); invert_m4(eprobe->parallaxmat); } @@ -566,8 +566,8 @@ void EEVEE_lightprobes_planar_data_from_object(Object *ob, vis_test->cached = false; /* Computing mtx : matrix that mirror position around object's XY plane. */ - normalize_m4_m4(normat, ob->obmat); /* object > world */ - invert_m4_m4(imat, normat); /* world > object */ + normalize_m4_m4(normat, ob->object_to_world); /* object > world */ + invert_m4_m4(imat, normat); /* world > object */ /* XY reflection plane */ imat[0][2] = -imat[0][2]; imat[1][2] = -imat[1][2]; @@ -576,38 +576,38 @@ void EEVEE_lightprobes_planar_data_from_object(Object *ob, mul_m4_m4m4(eplanar->mtx, normat, imat); /* world > object > mirrored obj > world */ /* Compute clip plane equation / normal. */ - copy_v3_v3(eplanar->plane_equation, ob->obmat[2]); + copy_v3_v3(eplanar->plane_equation, ob->object_to_world[2]); normalize_v3(eplanar->plane_equation); /* plane normal */ - eplanar->plane_equation[3] = -dot_v3v3(eplanar->plane_equation, ob->obmat[3]); + eplanar->plane_equation[3] = -dot_v3v3(eplanar->plane_equation, ob->object_to_world[3]); eplanar->clipsta = probe->clipsta; /* Compute XY clip planes. */ - normalize_v3_v3(eplanar->clip_vec_x, ob->obmat[0]); - normalize_v3_v3(eplanar->clip_vec_y, ob->obmat[1]); + normalize_v3_v3(eplanar->clip_vec_x, ob->object_to_world[0]); + normalize_v3_v3(eplanar->clip_vec_y, ob->object_to_world[1]); float vec[3] = {0.0f, 0.0f, 0.0f}; vec[0] = 1.0f; vec[1] = 0.0f; vec[2] = 0.0f; - mul_m4_v3(ob->obmat, vec); /* Point on the edge */ + mul_m4_v3(ob->object_to_world, vec); /* Point on the edge */ eplanar->clip_edge_x_pos = dot_v3v3(eplanar->clip_vec_x, vec); vec[0] = 0.0f; vec[1] = 1.0f; vec[2] = 0.0f; - mul_m4_v3(ob->obmat, vec); /* Point on the edge */ + mul_m4_v3(ob->object_to_world, vec); /* Point on the edge */ eplanar->clip_edge_y_pos = dot_v3v3(eplanar->clip_vec_y, vec); vec[0] = -1.0f; vec[1] = 0.0f; vec[2] = 0.0f; - mul_m4_v3(ob->obmat, vec); /* Point on the edge */ + mul_m4_v3(ob->object_to_world, vec); /* Point on the edge */ eplanar->clip_edge_x_neg = dot_v3v3(eplanar->clip_vec_x, vec); vec[0] = 0.0f; vec[1] = -1.0f; vec[2] = 0.0f; - mul_m4_v3(ob->obmat, vec); /* Point on the edge */ + mul_m4_v3(ob->object_to_world, vec); /* Point on the edge */ eplanar->clip_edge_y_neg = dot_v3v3(eplanar->clip_vec_y, vec); /* Facing factors */ diff --git a/source/blender/draw/engines/eevee/eevee_lights.c b/source/blender/draw/engines/eevee/eevee_lights.c index 312305a31f7..f8250f9520d 100644 --- a/source/blender/draw/engines/eevee/eevee_lights.c +++ b/source/blender/draw/engines/eevee/eevee_lights.c @@ -132,7 +132,7 @@ static void eevee_light_setup(Object *ob, EEVEE_Light *evli) const float light_threshold = draw_ctx->scene->eevee.light_threshold; /* Position */ - copy_v3_v3(evli->position, ob->obmat[3]); + copy_v3_v3(evli->position, ob->object_to_world[3]); /* Color */ copy_v3_v3(evli->color, &la->r); @@ -153,7 +153,7 @@ static void eevee_light_setup(Object *ob, EEVEE_Light *evli) evli->invsqrdist_volume = 1.0f / max_ff(1e-4f, square_f(att_radius_volume)); /* Vectors */ - normalize_m4_m4_ex(mat, ob->obmat, scale); + normalize_m4_m4_ex(mat, ob->object_to_world, scale); copy_v3_v3(evli->forwardvec, mat[2]); normalize_v3(evli->forwardvec); negate_v3(evli->forwardvec); diff --git a/source/blender/draw/engines/eevee/eevee_materials.c b/source/blender/draw/engines/eevee/eevee_materials.c index f79e4e1d568..b134d7f6dc6 100644 --- a/source/blender/draw/engines/eevee/eevee_materials.c +++ b/source/blender/draw/engines/eevee/eevee_materials.c @@ -759,7 +759,8 @@ BLI_INLINE Material *eevee_object_material_get(Object *ob, int slot, bool holdou BLI_INLINE EeveeMaterialCache eevee_material_cache_get( EEVEE_Data *vedata, EEVEE_ViewLayerData *sldata, Object *ob, int slot, bool is_hair) { - const bool holdout = (ob->base_flag & BASE_HOLDOUT) != 0; + const bool holdout = ((ob->base_flag & BASE_HOLDOUT) != 0) || + ((ob->visibility_flag & OB_HOLDOUT) != 0); EeveeMaterialCache matcache; Material *ma = eevee_object_material_get(ob, slot, holdout); switch (ma->blend_method) { @@ -809,7 +810,7 @@ void EEVEE_materials_cache_populate(EEVEE_Data *vedata, const DRWContextState *draw_ctx = DRW_context_state_get(); Scene *scene = draw_ctx->scene; - bool use_sculpt_pbvh = BKE_sculptsession_use_pbvh_draw(ob, draw_ctx->v3d) && + bool use_sculpt_pbvh = BKE_sculptsession_use_pbvh_draw(ob, draw_ctx->rv3d) && !DRW_state_is_image_render(); if (ob->sculpt && ob->sculpt->pbvh) { @@ -923,17 +924,14 @@ void EEVEE_particle_hair_cache_populate(EEVEE_Data *vedata, if (matcache.depth_grp) { *matcache.depth_grp_p = DRW_shgroup_hair_create_sub( ob, psys, md, matcache.depth_grp, NULL); - DRW_shgroup_add_material_resources(*matcache.depth_grp_p, matcache.shading_gpumat); } if (matcache.shading_grp) { *matcache.shading_grp_p = DRW_shgroup_hair_create_sub( ob, psys, md, matcache.shading_grp, matcache.shading_gpumat); - DRW_shgroup_add_material_resources(*matcache.shading_grp_p, matcache.shading_gpumat); } if (matcache.shadow_grp) { *matcache.shadow_grp_p = DRW_shgroup_hair_create_sub( ob, psys, md, matcache.shadow_grp, NULL); - DRW_shgroup_add_material_resources(*matcache.shadow_grp_p, matcache.shading_gpumat); *cast_shadow = true; } @@ -953,16 +951,13 @@ void EEVEE_object_curves_cache_populate(EEVEE_Data *vedata, if (matcache.depth_grp) { *matcache.depth_grp_p = DRW_shgroup_curves_create_sub(ob, matcache.depth_grp, NULL); - DRW_shgroup_add_material_resources(*matcache.depth_grp_p, matcache.shading_gpumat); } if (matcache.shading_grp) { *matcache.shading_grp_p = DRW_shgroup_curves_create_sub( ob, matcache.shading_grp, matcache.shading_gpumat); - DRW_shgroup_add_material_resources(*matcache.shading_grp_p, matcache.shading_gpumat); } if (matcache.shadow_grp) { *matcache.shadow_grp_p = DRW_shgroup_curves_create_sub(ob, matcache.shadow_grp, NULL); - DRW_shgroup_add_material_resources(*matcache.shadow_grp_p, matcache.shading_gpumat); *cast_shadow = true; } diff --git a/source/blender/draw/engines/eevee/eevee_motion_blur.c b/source/blender/draw/engines/eevee/eevee_motion_blur.c index a3ca19c88e1..9f7fb1c154c 100644 --- a/source/blender/draw/engines/eevee/eevee_motion_blur.c +++ b/source/blender/draw/engines/eevee/eevee_motion_blur.c @@ -292,7 +292,7 @@ void EEVEE_motion_blur_curves_cache_populate(EEVEE_ViewLayerData *UNUSED(sldata) int mb_step = effects->motion_blur_step; /* Store transform. */ - copy_m4_m4(mb_data->obmat[mb_step], ob->obmat); + copy_m4_m4(mb_data->obmat[mb_step], ob->object_to_world); EEVEE_HairMotionData *mb_curves = EEVEE_motion_blur_curves_data_get(mb_data); @@ -362,7 +362,7 @@ void EEVEE_motion_blur_cache_populate(EEVEE_ViewLayerData *UNUSED(sldata), if (mb_data) { int mb_step = effects->motion_blur_step; /* Store transform. */ - copy_m4_m4(mb_data->obmat[mb_step], ob->obmat); + copy_m4_m4(mb_data->obmat[mb_step], ob->object_to_world); EEVEE_GeometryMotionData *mb_geom = EEVEE_motion_blur_geometry_data_get(mb_data); diff --git a/source/blender/draw/engines/eevee/eevee_shadows.c b/source/blender/draw/engines/eevee/eevee_shadows.c index 9e571b1d15b..1cf3c7c6da1 100644 --- a/source/blender/draw/engines/eevee/eevee_shadows.c +++ b/source/blender/draw/engines/eevee/eevee_shadows.c @@ -153,7 +153,7 @@ void EEVEE_shadows_caster_register(EEVEE_ViewLayerData *sldata, Object *ob) for (int i = 0; i < 8; i++) { float vec[3]; copy_v3_v3(vec, bb->vec[i]); - mul_m4_v3(ob->obmat, vec); + mul_m4_v3(ob->object_to_world, vec); minmax_v3v3_v3(min, max, vec); } diff --git a/source/blender/draw/engines/eevee/eevee_volumes.c b/source/blender/draw/engines/eevee/eevee_volumes.c index 05b2bafdb3a..872696a8b7c 100644 --- a/source/blender/draw/engines/eevee/eevee_volumes.c +++ b/source/blender/draw/engines/eevee/eevee_volumes.c @@ -299,7 +299,7 @@ void EEVEE_volumes_cache_object_add(EEVEE_ViewLayerData *sldata, } float size[3]; - mat4_to_size(size, ob->obmat); + mat4_to_size(size, ob->object_to_world); /* Check if any of the axes have 0 length. (see T69070) */ const float epsilon = 1e-8f; if ((size[0] < epsilon) || (size[1] < epsilon) || (size[2] < epsilon)) { diff --git a/source/blender/draw/engines/eevee/shaders/cubemap_lib.glsl b/source/blender/draw/engines/eevee/shaders/cubemap_lib.glsl index 90272400915..5af317b7398 100644 --- a/source/blender/draw/engines/eevee/shaders/cubemap_lib.glsl +++ b/source/blender/draw/engines/eevee/shaders/cubemap_lib.glsl @@ -96,7 +96,7 @@ vec4 cubemap_seamless(sampler2DArray tex, vec4 cubevec, float lod) /* Mix all colors to get the corner color. */ vec4 col3 = (col + col1 + col2) / 3.0; - vec2 mix_fac = uv_border * 0.5; + vec2 mix_fac = saturate(uv_border * 0.5); return mix(mix(col, col2, mix_fac.x), mix(col1, col3, mix_fac.x), mix_fac.y); } else if (any(border)) { @@ -108,7 +108,7 @@ vec4 cubemap_seamless(sampler2DArray tex, vec4 cubevec, float lod) uv = cubemap_face_coord(cubevec.xyz, face); coord = vec3(uv, cubevec.w * 6.0 + face); - float mix_fac = max(uv_border.x, uv_border.y) * 0.5; + float mix_fac = saturate(max(uv_border.x, uv_border.y) * 0.5); return mix(col, textureLod(tex, coord, lod), mix_fac); } else { diff --git a/source/blender/draw/engines/eevee/shaders/effect_dof_scatter_vert.glsl b/source/blender/draw/engines/eevee/shaders/effect_dof_scatter_vert.glsl index 51a351babd3..5f04cdcebfa 100644 --- a/source/blender/draw/engines/eevee/shaders/effect_dof_scatter_vert.glsl +++ b/source/blender/draw/engines/eevee/shaders/effect_dof_scatter_vert.glsl @@ -95,7 +95,11 @@ void main() weights = dof_layer_weight(cocs) * dof_sample_weight(cocs); /* Filter NaNs. */ - weights = select(weights, vec4(0.0), equal(cocs, vec4(0.0))); + for (int i = 0; i < 4; i++) { + if (isnan(weights[i]) || isinf(weights[i])) { + weights[i] = 0.0; + } + } color1 = colors[0] * weights[0]; color2 = colors[1] * weights[1]; diff --git a/source/blender/draw/engines/eevee/shaders/shadow_vert.glsl b/source/blender/draw/engines/eevee/shaders/shadow_vert.glsl index 062a40f35c2..ccf6d6e2042 100644 --- a/source/blender/draw/engines/eevee/shaders/shadow_vert.glsl +++ b/source/blender/draw/engines/eevee/shaders/shadow_vert.glsl @@ -30,7 +30,7 @@ void main() vec3 world_pos = pos; #elif defined(POINTCLOUD_SHADER) pointcloud_get_pos_and_radius(pointPosition, pointRadius); - pointID = gl_VertexID; + pointID = pointcloud_get_point_id(); #else vec3 world_pos = point_object_to_world(pos); #endif diff --git a/source/blender/draw/engines/eevee/shaders/surface_vert.glsl b/source/blender/draw/engines/eevee/shaders/surface_vert.glsl index 8f49c7bd265..7a22b2c53d7 100644 --- a/source/blender/draw/engines/eevee/shaders/surface_vert.glsl +++ b/source/blender/draw/engines/eevee/shaders/surface_vert.glsl @@ -37,7 +37,7 @@ void main() vec3 world_pos = pos; #elif defined(POINTCLOUD_SHADER) pointcloud_get_pos_and_radius(pointPosition, pointRadius); - pointID = gl_VertexID; + pointID = pointcloud_get_point_id(); #else vec3 world_pos = point_object_to_world(pos); #endif diff --git a/source/blender/draw/engines/eevee_next/eevee_light.cc b/source/blender/draw/engines/eevee_next/eevee_light.cc index 8a5de15229d..aa8268dbaa7 100644 --- a/source/blender/draw/engines/eevee_next/eevee_light.cc +++ b/source/blender/draw/engines/eevee_next/eevee_light.cc @@ -58,7 +58,7 @@ void Light::sync(/* ShadowModule &shadows , */ const Object *ob, float threshold this->influence_radius_invsqr_volume = 1.0f / square_f(max_ff(influence_radius_volume, 1e-8f)); this->color = float3(&la->r) * la->energy; - normalize_m4_m4_ex(this->object_mat.ptr(), ob->obmat, scale); + normalize_m4_m4_ex(this->object_mat.ptr(), ob->object_to_world, scale); /* Make sure we have consistent handedness (in case of negatively scaled Z axis). */ float3 cross = math::cross(float3(this->_right), float3(this->_up)); if (math::dot(cross, float3(this->_back)) < 0.0f) { diff --git a/source/blender/draw/engines/eevee_next/eevee_pipeline.cc b/source/blender/draw/engines/eevee_next/eevee_pipeline.cc index e6b37b4ad47..0242f732f27 100644 --- a/source/blender/draw/engines/eevee_next/eevee_pipeline.cc +++ b/source/blender/draw/engines/eevee_next/eevee_pipeline.cc @@ -182,7 +182,7 @@ PassMain::Sub *ForwardPipeline::prepass_transparent_add(const Object *ob, if (blender_mat->blend_flag & MA_BL_CULL_BACKFACE) { state |= DRW_STATE_CULL_BACK; } - float sorting_value = math::dot(float3(ob->obmat[3]), camera_forward_); + float sorting_value = math::dot(float3(ob->object_to_world[3]), camera_forward_); PassMain::Sub *pass = &transparent_ps_.sub(GPU_material_get_name(gpumat), sorting_value); pass->state_set(state); pass->material_set(*inst_.manager, gpumat); @@ -197,7 +197,7 @@ PassMain::Sub *ForwardPipeline::material_transparent_add(const Object *ob, if (blender_mat->blend_flag & MA_BL_CULL_BACKFACE) { state |= DRW_STATE_CULL_BACK; } - float sorting_value = math::dot(float3(ob->obmat[3]), camera_forward_); + float sorting_value = math::dot(float3(ob->object_to_world[3]), camera_forward_); PassMain::Sub *pass = &transparent_ps_.sub(GPU_material_get_name(gpumat), sorting_value); pass->state_set(state); pass->material_set(*inst_.manager, gpumat); diff --git a/source/blender/draw/engines/eevee_next/eevee_sync.cc b/source/blender/draw/engines/eevee_next/eevee_sync.cc index 08cda6f47cf..cbd735ec29c 100644 --- a/source/blender/draw/engines/eevee_next/eevee_sync.cc +++ b/source/blender/draw/engines/eevee_next/eevee_sync.cc @@ -248,17 +248,17 @@ static void gpencil_stroke_sync(bGPDlayer * /*gpl*/, return; } + GPUBatch *geom = DRW_cache_gpencil_get(iter.ob, iter.cfra); + if (show_fill) { - GPUBatch *geom = DRW_cache_gpencil_fills_get(iter.ob, iter.cfra); int vfirst = gps->runtime.fill_start * 3; int vcount = gps->tot_triangles * 3; gpencil_drawcall_add(iter, geom, material, vfirst, vcount, false); } if (show_stroke) { - GPUBatch *geom = DRW_cache_gpencil_strokes_get(iter.ob, iter.cfra); /* Start one vert before to have gl_InstanceID > 0 (see shader). */ - int vfirst = gps->runtime.stroke_start - 1; + int vfirst = gps->runtime.stroke_start * 3; /* Include "potential" cyclic vertex and start adj vertex (see shader). */ int vcount = gps->totpoints + 1 + 1; gpencil_drawcall_add(iter, geom, material, vfirst, vcount, true); diff --git a/source/blender/draw/engines/eevee_next/eevee_velocity.cc b/source/blender/draw/engines/eevee_next/eevee_velocity.cc index b9a78e8547e..52401c8003e 100644 --- a/source/blender/draw/engines/eevee_next/eevee_velocity.cc +++ b/source/blender/draw/engines/eevee_next/eevee_velocity.cc @@ -106,16 +106,16 @@ bool VelocityModule::step_object_sync(Object *ob, vel.obj.ofs[step_] = object_steps_usage[step_]++; vel.obj.resource_id = resource_handle.resource_index(); vel.id = (ID *)ob->data; - object_steps[step_]->get_or_resize(vel.obj.ofs[step_]) = ob->obmat; + object_steps[step_]->get_or_resize(vel.obj.ofs[step_]) = ob->object_to_world; if (step_ == STEP_CURRENT) { /* Replace invalid steps. Can happen if object was hidden in one of those steps. */ if (vel.obj.ofs[STEP_PREVIOUS] == -1) { vel.obj.ofs[STEP_PREVIOUS] = object_steps_usage[STEP_PREVIOUS]++; - object_steps[STEP_PREVIOUS]->get_or_resize(vel.obj.ofs[STEP_PREVIOUS]) = ob->obmat; + object_steps[STEP_PREVIOUS]->get_or_resize(vel.obj.ofs[STEP_PREVIOUS]) = ob->object_to_world; } if (vel.obj.ofs[STEP_NEXT] == -1) { vel.obj.ofs[STEP_NEXT] = object_steps_usage[STEP_NEXT]++; - object_steps[STEP_NEXT]->get_or_resize(vel.obj.ofs[STEP_NEXT]) = ob->obmat; + object_steps[STEP_NEXT]->get_or_resize(vel.obj.ofs[STEP_NEXT]) = ob->object_to_world; } } diff --git a/source/blender/draw/engines/eevee_next/shaders/eevee_geom_gpencil_vert.glsl b/source/blender/draw/engines/eevee_next/shaders/eevee_geom_gpencil_vert.glsl index 38debf14eda..87a5bf71c45 100644 --- a/source/blender/draw/engines/eevee_next/shaders/eevee_geom_gpencil_vert.glsl +++ b/source/blender/draw/engines/eevee_next/shaders/eevee_geom_gpencil_vert.glsl @@ -16,30 +16,18 @@ void main() float hardness; vec2 thickness; - gl_Position = gpencil_vertex(ma, - ma1, - ma2, - ma3, - pos, - pos1, - pos2, - pos3, - uv1, - uv2, - col1, - col2, - fcol1, - /* TODO */ - vec4(1024.0, 1024.0, 1.0 / 1024.0, 1.0 / 1024.0), - interp.P, - interp.N, - g_color, - strength, - g_uvs, - sspos, - aspect, - thickness, - hardness); + gl_Position = gpencil_vertex( + /* TODO */ + vec4(1024.0, 1024.0, 1.0 / 1024.0, 1.0 / 1024.0), + interp.P, + interp.N, + g_color, + strength, + g_uvs, + sspos, + aspect, + thickness, + hardness); #ifdef MAT_VELOCITY /* GPencil do not support deformation motion blur. */ vec3 lP_curr = transform_point(ModelMatrixInverse, interp.P); diff --git a/source/blender/draw/engines/gpencil/gpencil_cache_utils.c b/source/blender/draw/engines/gpencil/gpencil_cache_utils.c index a41918e7e0d..06bf531cded 100644 --- a/source/blender/draw/engines/gpencil/gpencil_cache_utils.c +++ b/source/blender/draw/engines/gpencil/gpencil_cache_utils.c @@ -39,9 +39,9 @@ GPENCIL_tObject *gpencil_object_cache_add(GPENCIL_PrivateData *pd, Object *ob) tgp_ob->layers.first = tgp_ob->layers.last = NULL; tgp_ob->vfx.first = tgp_ob->vfx.last = NULL; - tgp_ob->camera_z = dot_v3v3(pd->camera_z_axis, ob->obmat[3]); + tgp_ob->camera_z = dot_v3v3(pd->camera_z_axis, ob->object_to_world[3]); tgp_ob->is_drawmode3d = (gpd->draw_mode == GP_DRAWMODE_3D) || pd->draw_depth_only; - tgp_ob->object_scale = mat4_to_scale(ob->obmat); + tgp_ob->object_scale = mat4_to_scale(ob->object_to_world); /* Check if any material with holdout flag enabled. */ tgp_ob->do_mat_holdout = false; @@ -71,7 +71,7 @@ GPENCIL_tObject *gpencil_object_cache_add(GPENCIL_PrivateData *pd, Object *ob) add_v3_fl(size, 1e-8f); rescale_m4(mat, size); /* BBox space to World. */ - mul_m4_m4m4(mat, ob->obmat, mat); + mul_m4_m4m4(mat, ob->object_to_world, mat); if (DRW_view_is_persp_get(NULL)) { /* BBox center to camera vector. */ sub_v3_v3v3(tgp_ob->plane_normal, pd->camera_pos, mat[3]); @@ -96,9 +96,9 @@ GPENCIL_tObject *gpencil_object_cache_add(GPENCIL_PrivateData *pd, Object *ob) unit_m4(tgp_ob->plane_mat); copy_v3_v3(tgp_ob->plane_mat[2], tgp_ob->plane_normal); orthogonalize_m4(tgp_ob->plane_mat, 2); - mul_mat3_m4_v3(ob->obmat, size); + mul_mat3_m4_v3(ob->object_to_world, size); float radius = len_v3(size); - mul_m4_v3(ob->obmat, center); + mul_m4_v3(ob->object_to_world, center); rescale_m4(tgp_ob->plane_mat, (float[3]){radius, radius, radius}); copy_v3_v3(tgp_ob->plane_mat[3], center); diff --git a/source/blender/draw/engines/gpencil/gpencil_draw_data.c b/source/blender/draw/engines/gpencil/gpencil_draw_data.c index e54ac99a888..07b72c97875 100644 --- a/source/blender/draw/engines/gpencil/gpencil_draw_data.c +++ b/source/blender/draw/engines/gpencil/gpencil_draw_data.c @@ -387,20 +387,20 @@ void gpencil_light_pool_populate(GPENCIL_LightPool *lightpool, Object *ob) } else if (la->type == LA_AREA) { /* Simulate area lights using a spot light. */ - normalize_m4_m4(mat, ob->obmat); + normalize_m4_m4(mat, ob->object_to_world); invert_m4(mat); gp_light->type = GP_LIGHT_TYPE_SPOT; gp_light->spot_size = cosf(M_PI_2); gp_light->spot_blend = (1.0f - gp_light->spot_size) * 1.0f; } else if (la->type == LA_SUN) { - normalize_v3_v3(gp_light->forward, ob->obmat[2]); + normalize_v3_v3(gp_light->forward, ob->object_to_world[2]); gp_light->type = GP_LIGHT_TYPE_SUN; } else { gp_light->type = GP_LIGHT_TYPE_POINT; } - copy_v4_v4(gp_light->position, ob->obmat[3]); + copy_v4_v4(gp_light->position, ob->object_to_world[3]); copy_v3_v3(gp_light->color, &la->r); mul_v3_fl(gp_light->color, la->energy * light_power_get(la)); diff --git a/source/blender/draw/engines/gpencil/gpencil_engine.c b/source/blender/draw/engines/gpencil/gpencil_engine.c index b24e4c605e4..78e658d35eb 100644 --- a/source/blender/draw/engines/gpencil/gpencil_engine.c +++ b/source/blender/draw/engines/gpencil/gpencil_engine.c @@ -342,7 +342,6 @@ typedef struct gpIterPopulateData { int stroke_index_offset; /* Infos for call batching. */ struct GPUBatch *geom; - bool instancing; int vfirst, vcount; } gpIterPopulateData; @@ -352,12 +351,7 @@ static void gpencil_drawcall_flush(gpIterPopulateData *iter) { #if !DISABLE_BATCHING if (iter->geom != NULL) { - if (iter->instancing) { - DRW_shgroup_call_instance_range(iter->grp, iter->ob, iter->geom, iter->vfirst, iter->vcount); - } - else { - DRW_shgroup_call_range(iter->grp, iter->ob, iter->geom, iter->vfirst, iter->vcount); - } + DRW_shgroup_call_range(iter->grp, iter->ob, iter->geom, iter->vfirst, iter->vcount); } #endif @@ -367,25 +361,22 @@ static void gpencil_drawcall_flush(gpIterPopulateData *iter) } /* Group draw-calls that are consecutive and with the same type. Reduces GPU driver overhead. */ -static void gpencil_drawcall_add( - gpIterPopulateData *iter, struct GPUBatch *geom, bool instancing, int v_first, int v_count) +static void gpencil_drawcall_add(gpIterPopulateData *iter, + struct GPUBatch *geom, + int v_first, + int v_count) { #if DISABLE_BATCHING - if (instancing) { - DRW_shgroup_call_instance_range(iter->grp, iter->ob, geom, v_first, v_count); - } - else { - DRW_shgroup_call_range(iter->grp, iter->ob, geom, v_first, v_count); - } + DRW_shgroup_call_range(iter->grp, iter->ob, geom, v_first, v_count); + return; #endif int last = iter->vfirst + iter->vcount; /* Interrupt draw-call grouping if the sequence is not consecutive. */ - if ((geom != iter->geom) || (v_first - last > 3)) { + if ((geom != iter->geom) || (v_first - last > 0)) { gpencil_drawcall_flush(iter); } iter->geom = geom; - iter->instancing = instancing; if (iter->vfirst == -1) { iter->vfirst = v_first; } @@ -516,22 +507,33 @@ static void gpencil_stroke_cache_populate(bGPDlayer *gpl, bool do_sbuffer = (iter->do_sbuffer_call == DRAW_NOW); + GPUBatch *geom = do_sbuffer ? DRW_cache_gpencil_sbuffer_get(iter->ob, show_fill) : + DRW_cache_gpencil_get(iter->ob, iter->pd->cfra); + if (geom != iter->geom) { + gpencil_drawcall_flush(iter); + + GPUVertBuf *position_tx = do_sbuffer ? + DRW_cache_gpencil_sbuffer_position_buffer_get(iter->ob, + show_fill) : + DRW_cache_gpencil_position_buffer_get(iter->ob, iter->pd->cfra); + GPUVertBuf *color_tx = do_sbuffer ? + DRW_cache_gpencil_sbuffer_color_buffer_get(iter->ob, show_fill) : + DRW_cache_gpencil_color_buffer_get(iter->ob, iter->pd->cfra); + DRW_shgroup_buffer_texture(iter->grp, "gp_pos_tx", position_tx); + DRW_shgroup_buffer_texture(iter->grp, "gp_col_tx", color_tx); + } + if (show_fill) { - GPUBatch *geom = do_sbuffer ? DRW_cache_gpencil_sbuffer_fill_get(iter->ob) : - DRW_cache_gpencil_fills_get(iter->ob, iter->pd->cfra); int vfirst = gps->runtime.fill_start * 3; int vcount = gps->tot_triangles * 3; - gpencil_drawcall_add(iter, geom, false, vfirst, vcount); + gpencil_drawcall_add(iter, geom, vfirst, vcount); } if (show_stroke) { - GPUBatch *geom = do_sbuffer ? DRW_cache_gpencil_sbuffer_stroke_get(iter->ob) : - DRW_cache_gpencil_strokes_get(iter->ob, iter->pd->cfra); - /* Start one vert before to have gl_InstanceID > 0 (see shader). */ - int vfirst = gps->runtime.stroke_start - 1; - /* Include "potential" cyclic vertex and start adj vertex (see shader). */ - int vcount = gps->totpoints + 1 + 1; - gpencil_drawcall_add(iter, geom, true, vfirst, vcount); + int vfirst = gps->runtime.stroke_start * 3; + bool is_cyclic = ((gps->flag & GP_STROKE_CYCLIC) != 0) && (gps->totpoints > 2); + int vcount = (gps->totpoints + (int)is_cyclic) * 2 * 3; + gpencil_drawcall_add(iter, geom, vfirst, vcount); } iter->stroke_index_last = gps->runtime.stroke_start + gps->totpoints + 1; diff --git a/source/blender/draw/engines/gpencil/gpencil_shader_fx.c b/source/blender/draw/engines/gpencil/gpencil_shader_fx.c index a7d8570dbaa..9b1129e77be 100644 --- a/source/blender/draw/engines/gpencil/gpencil_shader_fx.c +++ b/source/blender/draw/engines/gpencil/gpencil_shader_fx.c @@ -96,7 +96,7 @@ static void gpencil_vfx_blur(BlurShaderFxData *fx, Object *ob, gpIterVfxData *it float winmat[4][4], persmat[4][4]; float blur_size[2] = {fx->radius[0], fx->radius[1]}; DRW_view_persmat_get(NULL, persmat, false); - const float w = fabsf(mul_project_m4_v3_zfac(persmat, ob->obmat[3])); + const float w = fabsf(mul_project_m4_v3_zfac(persmat, ob->object_to_world[3])); if (fx->flag & FX_BLUR_DOF_MODE) { /* Compute circle of confusion size. */ @@ -108,7 +108,7 @@ static void gpencil_vfx_blur(BlurShaderFxData *fx, Object *ob, gpIterVfxData *it DRW_view_winmat_get(NULL, winmat, false); const float *vp_size = DRW_viewport_size_get(); float world_pixel_scale = 1.0f / GPENCIL_PIXEL_FACTOR; - float scale = mat4_to_scale(ob->obmat); + float scale = mat4_to_scale(ob->object_to_world); float distance_factor = world_pixel_scale * scale * winmat[1][1] * vp_size[1] / w; mul_v2_fl(blur_size, distance_factor); } @@ -175,11 +175,11 @@ static void gpencil_vfx_rim(RimShaderFxData *fx, Object *ob, gpIterVfxData *iter const float *vp_size = DRW_viewport_size_get(); const float *vp_size_inv = DRW_viewport_invert_size_get(); - const float w = fabsf(mul_project_m4_v3_zfac(persmat, ob->obmat[3])); + const float w = fabsf(mul_project_m4_v3_zfac(persmat, ob->object_to_world[3])); /* Modify by distance to camera and object scale. */ float world_pixel_scale = 1.0f / GPENCIL_PIXEL_FACTOR; - float scale = mat4_to_scale(ob->obmat); + float scale = mat4_to_scale(ob->object_to_world); float distance_factor = (world_pixel_scale * scale * winmat[1][1] * vp_size[1]) / w; mul_v2_fl(offset, distance_factor); mul_v2_v2(offset, vp_size_inv); @@ -248,8 +248,8 @@ static void gpencil_vfx_pixelize(PixelShaderFxData *fx, Object *ob, gpIterVfxDat mul_v2_v2(pixel_size, vp_size_inv); /* Fixed pixelisation center from object center. */ - const float w = fabsf(mul_project_m4_v3_zfac(persmat, ob->obmat[3])); - mul_v3_m4v3(ob_center, persmat, ob->obmat[3]); + const float w = fabsf(mul_project_m4_v3_zfac(persmat, ob->object_to_world[3])); + mul_v3_m4v3(ob_center, persmat, ob->object_to_world[3]); mul_v3_fl(ob_center, 1.0f / w); const bool use_antialiasing = ((fx->flag & FX_PIXEL_FILTER_NEAREST) == 0); @@ -260,7 +260,7 @@ static void gpencil_vfx_pixelize(PixelShaderFxData *fx, Object *ob, gpIterVfxDat /* Modify by distance to camera and object scale. */ float world_pixel_scale = 1.0f / GPENCIL_PIXEL_FACTOR; - float scale = mat4_to_scale(ob->obmat); + float scale = mat4_to_scale(ob->object_to_world); mul_v2_fl(pixel_size, (world_pixel_scale * scale * winmat[1][1] * vp_size[1]) / w); /* Center to texel */ @@ -310,7 +310,9 @@ static void gpencil_vfx_shadow(ShadowShaderFxData *fx, Object *ob, gpIterVfxData const float *vp_size_inv = DRW_viewport_invert_size_get(); const float ratio = vp_size_inv[1] / vp_size_inv[0]; - copy_v3_v3(rot_center, (use_obj_pivot && fx->object) ? fx->object->obmat[3] : ob->obmat[3]); + copy_v3_v3(rot_center, + (use_obj_pivot && fx->object) ? fx->object->object_to_world[3] : + ob->object_to_world[3]); const float w = fabsf(mul_project_m4_v3_zfac(persmat, rot_center)); mul_v3_m4v3(rot_center, persmat, rot_center); @@ -318,7 +320,7 @@ static void gpencil_vfx_shadow(ShadowShaderFxData *fx, Object *ob, gpIterVfxData /* Modify by distance to camera and object scale. */ float world_pixel_scale = 1.0f / GPENCIL_PIXEL_FACTOR; - float scale = mat4_to_scale(ob->obmat); + float scale = mat4_to_scale(ob->object_to_world); float distance_factor = (world_pixel_scale * scale * winmat[1][1] * vp_size[1]) / w; mul_v2_fl(offset, distance_factor); mul_v2_v2(offset, vp_size_inv); @@ -485,13 +487,13 @@ static void gpencil_vfx_wave(WaveShaderFxData *fx, Object *ob, gpIterVfxData *it const float *vp_size = DRW_viewport_size_get(); const float *vp_size_inv = DRW_viewport_invert_size_get(); - const float w = fabsf(mul_project_m4_v3_zfac(persmat, ob->obmat[3])); - mul_v3_m4v3(wave_center, persmat, ob->obmat[3]); + const float w = fabsf(mul_project_m4_v3_zfac(persmat, ob->object_to_world[3])); + mul_v3_m4v3(wave_center, persmat, ob->object_to_world[3]); mul_v3_fl(wave_center, 1.0f / w); /* Modify by distance to camera and object scale. */ float world_pixel_scale = 1.0f / GPENCIL_PIXEL_FACTOR; - float scale = mat4_to_scale(ob->obmat); + float scale = mat4_to_scale(ob->object_to_world); float distance_factor = (world_pixel_scale * scale * winmat[1][1] * vp_size[1]) / w; wave_center[0] = wave_center[0] * 0.5f + 0.5f; @@ -542,7 +544,7 @@ static void gpencil_vfx_swirl(SwirlShaderFxData *fx, Object *UNUSED(ob), gpIterV DRW_view_persmat_get(NULL, persmat, false); const float *vp_size = DRW_viewport_size_get(); - copy_v3_v3(swirl_center, fx->object->obmat[3]); + copy_v3_v3(swirl_center, fx->object->object_to_world[3]); const float w = fabsf(mul_project_m4_v3_zfac(persmat, swirl_center)); mul_v3_m4v3(swirl_center, persmat, swirl_center); @@ -550,7 +552,7 @@ static void gpencil_vfx_swirl(SwirlShaderFxData *fx, Object *UNUSED(ob), gpIterV /* Modify by distance to camera and object scale. */ float world_pixel_scale = 1.0f / GPENCIL_PIXEL_FACTOR; - float scale = mat4_to_scale(fx->object->obmat); + float scale = mat4_to_scale(fx->object->object_to_world); float distance_factor = (world_pixel_scale * scale * winmat[1][1] * vp_size[1]) / w; mul_v2_fl(swirl_center, 0.5f); diff --git a/source/blender/draw/engines/gpencil/gpencil_shader_shared.h b/source/blender/draw/engines/gpencil/gpencil_shader_shared.h index 4c621e955b9..3f0f73e7c13 100644 --- a/source/blender/draw/engines/gpencil/gpencil_shader_shared.h +++ b/source/blender/draw/engines/gpencil/gpencil_shader_shared.h @@ -41,6 +41,9 @@ enum gpLightType { GP_LIGHT_TYPE_AMBIENT = 3u, }; +#define GP_IS_STROKE_VERTEX_BIT (1 << 30) +#define GP_VERTEX_ID_SHIFT 2 + /* Avoid compiler funkiness with enum types not being strongly typed in C. */ #ifndef GPU_SHADER # define gpMaterialFlag uint diff --git a/source/blender/draw/engines/gpencil/shaders/gpencil_common_lib.glsl b/source/blender/draw/engines/gpencil/shaders/gpencil_common_lib.glsl index 7ddfdc5f65c..642939136c8 100644 --- a/source/blender/draw/engines/gpencil/shaders/gpencil_common_lib.glsl +++ b/source/blender/draw/engines/gpencil/shaders/gpencil_common_lib.glsl @@ -1,92 +1,4 @@ -/* Must match C declaration. */ -struct gpMaterial { - vec4 stroke_color; - vec4 fill_color; - vec4 fill_mix_color; - vec4 fill_uv_rot_scale; - vec4 fill_uv_offset; - /* Put float/int at the end to avoid padding error */ - /* Some drivers are completely messing the alignment or the fetches here. - * We are forced to pack these into vec4 otherwise we only get 0.0 as value. */ - vec4 gp_mat_packed_1; - // float stroke_texture_mix; - // float stroke_u_scale; - // float fill_texture_mix; - // int gp_flag; - /* Please ensure 16 byte alignment (multiple of vec4). */ -}; - -#define MATERIAL(m) materials[m + gpMaterialOffset] - -#define stroke_texture_mix gp_mat_packed_1.x -#define stroke_u_scale gp_mat_packed_1.y -#define fill_texture_mix gp_mat_packed_1.z -#define GP_FLAG(m) floatBitsToInt(MATERIAL(m).gp_mat_packed_1.w) - -/* flag */ -#define GP_STROKE_ALIGNMENT_STROKE 1 -#define GP_STROKE_ALIGNMENT_OBJECT 2 -#define GP_STROKE_ALIGNMENT_FIXED 3 -#define GP_STROKE_ALIGNMENT 0x3 -#define GP_STROKE_OVERLAP (1 << 2) -#define GP_STROKE_TEXTURE_USE (1 << 3) -#define GP_STROKE_TEXTURE_STENCIL (1 << 4) -#define GP_STROKE_TEXTURE_PREMUL (1 << 5) -#define GP_STROKE_DOTS (1 << 6) -#define GP_STROKE_HOLDOUT (1 << 7) -#define GP_FILL_HOLDOUT (1 << 8) -#define GP_FILL_TEXTURE_USE (1 << 10) -#define GP_FILL_TEXTURE_PREMUL (1 << 11) -#define GP_FILL_TEXTURE_CLIP (1 << 12) -#define GP_FILL_GRADIENT_USE (1 << 13) -#define GP_FILL_GRADIENT_RADIAL (1 << 14) -/* High bits are used to pass material ID to fragment shader. */ -#define GP_MATID_SHIFT 16 - -/* Multiline defines can crash blender with certain GPU drivers. */ -/* clang-format off */ -#define GP_FILL_FLAGS (GP_FILL_TEXTURE_USE | GP_FILL_TEXTURE_PREMUL | GP_FILL_TEXTURE_CLIP | GP_FILL_GRADIENT_USE | GP_FILL_GRADIENT_RADIAL | GP_FILL_HOLDOUT) -/* clang-format on */ - -#define GP_FLAG_TEST(flag, val) (((flag) & (val)) != 0) - -/* Must match C declaration. */ -struct gpLight { - vec4 color_type; - vec4 right; - vec4 up; - vec4 forward; - vec4 position; - /* Please ensure 16 byte alignment (multiple of vec4). */ -}; - -#define spot_size right.w -#define spot_blend up.w - -#define GP_LIGHT_TYPE_POINT 0.0 -#define GP_LIGHT_TYPE_SPOT 1.0 -#define GP_LIGHT_TYPE_SUN 2.0 -#define GP_LIGHT_TYPE_AMBIENT 3.0 - -#ifdef GP_MATERIAL_BUFFER_LEN - -layout(std140) uniform gpMaterialBlock -{ - gpMaterial materials[GP_MATERIAL_BUFFER_LEN]; -}; - -#endif - -#ifdef GPENCIL_LIGHT_BUFFER_LEN - -layout(std140) uniform gpLightBlock -{ - gpLight lights[GPENCIL_LIGHT_BUFFER_LEN]; -}; - -#endif - /* Must match eGPLayerBlendModes */ #define MODE_REGULAR 0 #define MODE_HARDLIGHT 1 @@ -149,510 +61,3 @@ void blend_mode_output( break; } } - -#ifndef USE_GPU_SHADER_CREATE_INFO - -IN_OUT ShaderStageInterface -{ - vec4 finalColorMul; - vec4 finalColorAdd; - vec3 finalPos; - vec2 finalUvs; - noperspective float strokeThickness; - noperspective float unclampedThickness; - noperspective float strokeHardeness; - flat vec2 strokeAspect; - flat vec2 strokePt1; - flat vec2 strokePt2; - flat int matFlag; - flat float depth; -}; - -#endif - -#ifdef GPU_FRAGMENT_SHADER - -# define linearstep(p0, p1, v) (clamp(((v) - (p0)) / abs((p1) - (p0)), 0.0, 1.0)) - -float stroke_round_cap_mask(vec2 p1, vec2 p2, vec2 aspect, float thickness, float hardfac) -{ - /* We create our own uv space to avoid issues with triangulation and linear - * interpolation artifacts. */ - vec2 line = p2.xy - p1.xy; - vec2 pos = gl_FragCoord.xy - p1.xy; - float line_len = length(line); - float half_line_len = line_len * 0.5; - /* Normalize */ - line = (line_len > 0.0) ? (line / line_len) : vec2(1.0, 0.0); - /* Create a uv space that englobe the whole segment into a capsule. */ - vec2 uv_end; - uv_end.x = max(abs(dot(line, pos) - half_line_len) - half_line_len, 0.0); - uv_end.y = dot(vec2(-line.y, line.x), pos); - /* Divide by stroke radius. */ - uv_end /= thickness; - uv_end *= aspect; - - float dist = clamp(1.0 - length(uv_end) * 2.0, 0.0, 1.0); - if (hardfac > 0.999) { - return step(1e-8, dist); - } - else { - /* Modulate the falloff profile */ - float hardness = 1.0 - hardfac; - dist = pow(dist, mix(0.01, 10.0, hardness)); - return smoothstep(0.0, 1.0, dist); - } -} - -#endif - -uniform vec2 sizeViewport; -uniform vec2 sizeViewportInv; - -/* Per Object */ -uniform bool strokeOrder3d; -uniform int gpMaterialOffset; -uniform float thicknessScale; -uniform float thicknessWorldScale; -#define thicknessIsScreenSpace (thicknessWorldScale < 0.0) - -#ifdef GPU_VERTEX_SHADER - -/* Per Layer */ -uniform float thicknessOffset; -uniform float vertexColorOpacity; -uniform vec4 layerTint; -uniform float layerOpacity; /* Used for onion skin. */ -uniform float strokeIndexOffset = 0.0; - -/* All of these attributes are quad loaded the same way - * as GL_LINES_ADJACENCY would feed a geometry shader: - * - ma reference the previous adjacency point. - * - ma1 reference the current line first point. - * - ma2 reference the current line second point. - * - ma3 reference the next adjacency point. - * Note that we are rendering quad instances and not using any index buffer (except for fills). - */ -/* x is material index, y is stroke_id, z is point_id, w is aspect & rotation & hardness packed. */ -in ivec4 ma; -in ivec4 ma1; -in ivec4 ma2; -in ivec4 ma3; -/* Position contains thickness in 4th component. */ -in vec4 pos; /* Prev adj vert */ -in vec4 pos1; /* Current edge */ -in vec4 pos2; /* Current edge */ -in vec4 pos3; /* Next adj vert */ -/* xy is UV for fills, z is U of stroke, w is strength. */ -in vec4 uv1; -in vec4 uv2; -in vec4 col1; -in vec4 col2; -in vec4 fcol1; -/* WARNING: Max attribute count is actually 14 because OSX OpenGL implementation - * considers gl_VertexID and gl_InstanceID as vertex attribute. (see T74536) */ -# define stroke_id1 ma1.y -# define point_id1 ma1.z -# define thickness1 pos1.w -# define thickness2 pos2.w -# define strength1 uv1.w -# define strength2 uv2.w -/* Packed! need to be decoded. */ -# define hardness1 ma1.w -# define hardness2 ma2.w -# define uvrot1 ma1.w -# define aspect1 ma1.w - -vec2 decode_aspect(int packed_data) -{ - float asp = float(uint(packed_data) & 0x1FFu) * (1.0 / 255.0); - return (asp > 1.0) ? vec2(1.0, (asp - 1.0)) : vec2(asp, 1.0); -} - -float decode_uvrot(int packed_data) -{ - uint udata = uint(packed_data); - float uvrot = 1e-8 + float((udata & 0x1FE00u) >> 9u) * (1.0 / 255.0); - return ((udata & 0x20000u) != 0u) ? -uvrot : uvrot; -} - -float decode_hardness(int packed_data) -{ - return float((uint(packed_data) & 0x3FC0000u) >> 18u) * (1.0 / 255.0); -} - -void discard_vert() -{ - /* We set the vertex at the camera origin to generate 0 fragments. */ - gl_Position = vec4(0.0, 0.0, -3e36, 0.0); -} - -vec2 project_to_screenspace(vec4 v) -{ - return ((v.xy / v.w) * 0.5 + 0.5) * sizeViewport; -} - -vec2 rotate_90deg(vec2 v) -{ - /* Counter Clock-Wise. */ - return vec2(-v.y, v.x); -} - -mat4 model_matrix_get() -{ - return ModelMatrix; -} - -vec3 transform_point(mat4 m, vec3 v) -{ - return (m * vec4(v, 1.0)).xyz; -} - -vec2 safe_normalize(vec2 v) -{ - float len_sqr = dot(v, v); - if (len_sqr > 0.0) { - return v / sqrt(len_sqr); - } - else { - return vec2(1.0, 0.0); - } -} - -vec2 safe_normalize_len(vec2 v, out float len) -{ - len = sqrt(dot(v, v)); - if (len > 0.0) { - return v / len; - } - else { - return vec2(1.0, 0.0); - } -} - -float stroke_thickness_modulate(float thickness) -{ - /* Modify stroke thickness by object and layer factors. */ - thickness *= thicknessScale; - thickness += thicknessOffset; - thickness = max(1.0, thickness); - - if (thicknessIsScreenSpace) { - /* Multiply offset by view Z so that offset is constant in screenspace. - * (e.i: does not change with the distance to camera) */ - thickness *= gl_Position.w; - } - else { - /* World space point size. */ - thickness *= thicknessWorldScale * drw_view.winmat[1][1] * sizeViewport.y; - } - return thickness; -} - -float clamp_small_stroke_thickness(float thickness) -{ - /* To avoid aliasing artifacts, we clamp the line thickness and - * reduce its opacity in the fragment shader. */ - float min_thickness = gl_Position.w * 1.3; - thickness = max(min_thickness, thickness); - - return thickness; -} - -# ifdef GP_MATERIAL_BUFFER_LEN -void color_output(vec4 stroke_col, vec4 vert_col, float vert_strength, float mix_tex) -{ - /* Mix stroke with other colors. */ - vec4 mixed_col = stroke_col; - mixed_col.rgb = mix(mixed_col.rgb, vert_col.rgb, vert_col.a * vertexColorOpacity); - mixed_col.rgb = mix(mixed_col.rgb, layerTint.rgb, layerTint.a); - mixed_col.a *= vert_strength * layerOpacity; - /** - * This is what the fragment shader looks like. - * out = col * finalColorMul + col.a * finalColorAdd. - * finalColorMul is how much of the texture color to keep. - * finalColorAdd is how much of the mixed color to add. - * Note that we never add alpha. This is to keep the texture act as a stencil. - * We do however, modulate the alpha (reduce it). - */ - /* We add the mixed color. This is 100% mix (no texture visible). */ - finalColorMul = vec4(mixed_col.aaa, mixed_col.a); - finalColorAdd = vec4(mixed_col.rgb * mixed_col.a, 0.0); - /* Then we blend according to the texture mix factor. - * Note that we keep the alpha modulation. */ - finalColorMul.rgb *= mix_tex; - finalColorAdd.rgb *= 1.0 - mix_tex; -} -# endif - -void stroke_vertex() -{ - int m = ma1.x; - bool is_dot = false; - bool is_squares = false; - -# ifdef GP_MATERIAL_BUFFER_LEN - if (m != -1) { - is_dot = GP_FLAG_TEST(GP_FLAG(m), GP_STROKE_ALIGNMENT); - is_squares = !GP_FLAG_TEST(GP_FLAG(m), GP_STROKE_DOTS); - } -# endif - - /* Special Case. Stroke with single vert are rendered as dots. Do not discard them. */ - if (!is_dot && ma.x == -1 && ma2.x == -1) { - is_dot = true; - is_squares = false; - } - - /* Endpoints, we discard the vertices. */ - if (ma1.x == -1 || (!is_dot && ma2.x == -1)) { - discard_vert(); - return; - } - - mat4 model_mat = model_matrix_get(); - - /* Avoid using a vertex attribute for quad positioning. */ - float x = float(gl_VertexID & 1) * 2.0 - 1.0; /* [-1..1] */ - float y = float(gl_VertexID & 2) - 1.0; /* [-1..1] */ - - bool use_curr = is_dot || (x == -1.0); - - vec3 wpos_adj = transform_point(model_mat, (use_curr) ? pos.xyz : pos3.xyz); - vec3 wpos1 = transform_point(model_mat, pos1.xyz); - vec3 wpos2 = transform_point(model_mat, pos2.xyz); - - vec4 ndc_adj = point_world_to_ndc(wpos_adj); - vec4 ndc1 = point_world_to_ndc(wpos1); - vec4 ndc2 = point_world_to_ndc(wpos2); - - gl_Position = (use_curr) ? ndc1 : ndc2; - finalPos = (use_curr) ? wpos1 : wpos2; - - vec2 ss_adj = project_to_screenspace(ndc_adj); - vec2 ss1 = project_to_screenspace(ndc1); - vec2 ss2 = project_to_screenspace(ndc2); - /* Screenspace Lines tangents. */ - float line_len; - vec2 line = safe_normalize_len(ss2 - ss1, line_len); - vec2 line_adj = safe_normalize((use_curr) ? (ss1 - ss_adj) : (ss_adj - ss2)); - - float thickness = abs((use_curr) ? thickness1 : thickness2); - thickness = stroke_thickness_modulate(thickness); - float clampedThickness = clamp_small_stroke_thickness(thickness); - - finalUvs = vec2(x, y) * 0.5 + 0.5; - strokeHardeness = decode_hardness(use_curr ? hardness1 : hardness2); - - if (is_dot) { -# ifdef GP_MATERIAL_BUFFER_LEN - int alignement = GP_FLAG(m) & GP_STROKE_ALIGNMENT; - /* For one point strokes use object alignment. */ - if (ma.x == -1 && ma2.x == -1 && alignement == GP_STROKE_ALIGNMENT_STROKE) { - alignement = GP_STROKE_ALIGNMENT_OBJECT; - } -# endif - - vec2 x_axis; -# ifdef GP_MATERIAL_BUFFER_LEN - if (alignement == GP_STROKE_ALIGNMENT_STROKE) { - x_axis = (ma2.x == -1) ? line_adj : line; - } - else if (alignement == GP_STROKE_ALIGNMENT_FIXED) { - /* Default for no-material drawing. */ - x_axis = vec2(1.0, 0.0); - } - else -# endif - { /* GP_STROKE_ALIGNMENT_OBJECT */ - vec4 ndc_x = point_world_to_ndc(wpos1 + model_mat[0].xyz); - vec2 ss_x = project_to_screenspace(ndc_x); - x_axis = safe_normalize(ss_x - ss1); - } - - /* Rotation: Encoded as Cos + Sin sign. */ - float uv_rot = decode_uvrot(uvrot1); - float rot_sin = sqrt(max(0.0, 1.0 - uv_rot * uv_rot)) * sign(uv_rot); - float rot_cos = abs(uv_rot); - x_axis = mat2(rot_cos, -rot_sin, rot_sin, rot_cos) * x_axis; - -# ifdef GP_MATERIAL_BUFFER_LEN - if (is_dot) { - float alignment_cos = MATERIAL(m).fill_uv_offset.z; - float alignment_sin = MATERIAL(m).fill_uv_offset.w; - x_axis = mat2(alignment_cos, -alignment_sin, alignment_sin, alignment_cos) * x_axis; - } -# endif - - vec2 y_axis = rotate_90deg(x_axis); - - strokeAspect = decode_aspect(aspect1); - - x *= strokeAspect.x; - y *= strokeAspect.y; - - /* Invert for vertex shader. */ - strokeAspect = 1.0 / strokeAspect; - - gl_Position.xy += (x * x_axis + y * y_axis) * sizeViewportInv.xy * clampedThickness; - - strokePt1 = ss1; - strokePt2 = ss1 + x_axis * 0.5; - strokeThickness = (is_squares) ? 1e18 : (clampedThickness / gl_Position.w); - unclampedThickness = (is_squares) ? 1e18 : (thickness / gl_Position.w); - } - else { - bool is_stroke_start = (ma.x == -1 && x == -1); - bool is_stroke_end = (ma3.x == -1 && x == 1); - - /* Mitter tangent vector. */ - vec2 miter_tan = safe_normalize(line_adj + line); - float miter_dot = dot(miter_tan, line_adj); - /* Break corners after a certain angle to avoid really thick corners. */ - const float miter_limit = 0.5; /* cos(60°) */ - bool miter_break = (miter_dot < miter_limit); - miter_tan = (miter_break || is_stroke_start || is_stroke_end) ? line : (miter_tan / miter_dot); - - vec2 miter = rotate_90deg(miter_tan); - - strokePt1.xy = ss1; - strokePt2.xy = ss2; - strokeThickness = clampedThickness / gl_Position.w; - unclampedThickness = thickness / gl_Position.w; - strokeAspect = vec2(1.0); - - vec2 screen_ofs = miter * y; - - /* Reminder: we packed the cap flag into the sign of strength and thickness sign. */ - if ((is_stroke_start && strength1 > 0.0) || (is_stroke_end && thickness1 > 0.0) || - (miter_break && !is_stroke_start && !is_stroke_end)) { - screen_ofs += line * x; - } - - gl_Position.xy += screen_ofs * sizeViewportInv.xy * clampedThickness; - - finalUvs.x = (use_curr) ? uv1.z : uv2.z; -# ifdef GP_MATERIAL_BUFFER_LEN - finalUvs.x *= MATERIAL(m).stroke_u_scale; -# endif - } - -# ifdef GP_MATERIAL_BUFFER_LEN - vec4 vert_col = (use_curr) ? col1 : col2; - float vert_strength = abs((use_curr) ? strength1 : strength2); - vec4 stroke_col = MATERIAL(m).stroke_color; - float mix_tex = MATERIAL(m).stroke_texture_mix; - - /* Special case: We don't use vertex color if material Holdout. */ - if (GP_FLAG_TEST(GP_FLAG(m), GP_STROKE_HOLDOUT)) { - vert_col = vec4(0.0); - } - - color_output(stroke_col, vert_col, vert_strength, mix_tex); - - matFlag = GP_FLAG(m) & ~GP_FILL_FLAGS; -# endif - - if (strokeOrder3d) { - /* Use the fragment depth (see fragment shader). */ - depth = -1.0; - } -# ifdef GP_MATERIAL_BUFFER_LEN - else if (GP_FLAG_TEST(GP_FLAG(m), GP_STROKE_OVERLAP)) { - /* Use the index of the point as depth. - * This means the stroke can overlap itself. */ - depth = (point_id1 + strokeIndexOffset + 1.0) * 0.0000002; - } -# endif - else { - /* Use the index of first point of the stroke as depth. - * We render using a greater depth test this means the stroke - * cannot overlap itself. - * We offset by one so that the fill can be overlapped by its stroke. - * The offset is ok since we pad the strokes data because of adjacency infos. */ - depth = (stroke_id1 + strokeIndexOffset + 1.0) * 0.0000002; - } -} - -void fill_vertex() -{ - mat4 model_mat = model_matrix_get(); - - vec3 wpos = transform_point(model_mat, pos1.xyz); - gl_Position = point_world_to_ndc(wpos); - finalPos = wpos; - -# ifdef GP_MATERIAL_BUFFER_LEN - int m = ma1.x; - - vec4 fill_col = MATERIAL(m).fill_color; - float mix_tex = MATERIAL(m).fill_texture_mix; - - /* Special case: We don't modulate alpha in gradient mode. */ - if (GP_FLAG_TEST(GP_FLAG(m), GP_FILL_GRADIENT_USE)) { - fill_col.a = 1.0; - } - - /* Decode fill opacity. */ - vec4 fcol_decode = vec4(fcol1.rgb, floor(fcol1.a / 10.0)); - float fill_opacity = fcol1.a - (fcol_decode.a * 10); - fcol_decode.a /= 10000.0; - - /* Special case: We don't use vertex color if material Holdout. */ - if (GP_FLAG_TEST(GP_FLAG(m), GP_FILL_HOLDOUT)) { - fcol_decode = vec4(0.0); - } - - /* Apply opacity. */ - fill_col.a *= fill_opacity; - /* If factor is > 1 force opacity. */ - if (fill_opacity > 1.0) { - fill_col.a += fill_opacity - 1.0; - } - - fill_col.a = clamp(fill_col.a, 0.0, 1.0); - - color_output(fill_col, fcol_decode, 1.0, mix_tex); - - matFlag = GP_FLAG(m) & GP_FILL_FLAGS; - matFlag |= m << GP_MATID_SHIFT; - - vec2 loc = MATERIAL(m).fill_uv_offset.xy; - mat2x2 rot_scale = mat2x2(MATERIAL(m).fill_uv_rot_scale.xy, MATERIAL(m).fill_uv_rot_scale.zw); - finalUvs = rot_scale * uv1.xy + loc; -# endif - - strokeHardeness = 1.0; - strokeThickness = 1e18; - unclampedThickness = 1e20; - strokeAspect = vec2(1.0); - strokePt1 = strokePt2 = vec2(0.0); - - if (strokeOrder3d) { - /* Use the fragment depth (see fragment shader). */ - depth = -1.0; - /* We still offset the fills a little to avoid overlaps */ - gl_Position.z += 0.000002; - } - else { - /* Use the index of first point of the stroke as depth. */ - depth = (stroke_id1 + strokeIndexOffset) * 0.0000002; - } -} - -void gpencil_vertex() -{ - /* Trick to detect if a drawcall is stroke or fill. - * This does mean that we need to draw an empty stroke segment before starting - * to draw the real stroke segments. */ - bool is_fill = (gl_InstanceID == 0); - - if (!is_fill) { - stroke_vertex(); - } - else { - fill_vertex(); - } -} - -#endif diff --git a/source/blender/draw/engines/gpencil/shaders/gpencil_vert.glsl b/source/blender/draw/engines/gpencil/shaders/gpencil_vert.glsl index 8ed03b23809..2e7544cea29 100644 --- a/source/blender/draw/engines/gpencil/shaders/gpencil_vert.glsl +++ b/source/blender/draw/engines/gpencil/shaders/gpencil_vert.glsl @@ -31,23 +31,11 @@ void main() vec4 vert_color; vec3 vert_N; + ivec4 ma1 = floatBitsToInt(texelFetch(gp_pos_tx, gpencil_stroke_point_id() * 3 + 1)); gpMaterial gp_mat = materials[ma1.x + gpMaterialOffset]; gpMaterialFlag gp_flag = floatBitsToUint(gp_mat._flag); - gl_Position = gpencil_vertex(ma, - ma1, - ma2, - ma3, - pos, - pos1, - pos2, - pos3, - uv1, - uv2, - col1, - col2, - fcol1, - vec4(viewportSize, 1.0 / viewportSize), + gl_Position = gpencil_vertex(vec4(viewportSize, 1.0 / viewportSize), gp_flag, gp_mat._alignment_rot, gp_interp.pos, @@ -60,7 +48,7 @@ void main() gp_interp.thickness, gp_interp.hardness); - if (GPENCIL_IS_STROKE_VERTEX) { + if (gpencil_is_stroke_vertex()) { if (!flag_test(gp_flag, GP_STROKE_ALIGNMENT)) { gp_interp.uv.x *= gp_mat._stroke_u_scale; } @@ -83,7 +71,7 @@ void main() /* Use the index of the point as depth. * This means the stroke can overlap itself. */ float point_index = float(ma1.z); - gp_interp.depth = (point_index + gpStrokeIndexOffset + 1.0) * 0.0000002; + gp_interp.depth = (point_index + gpStrokeIndexOffset + 2.0) * 0.0000002; } else { /* Use the index of first point of the stroke as depth. @@ -92,10 +80,13 @@ void main() * We offset by one so that the fill can be overlapped by its stroke. * The offset is ok since we pad the strokes data because of adjacency infos. */ float stroke_index = float(ma1.y); - gp_interp.depth = (stroke_index + gpStrokeIndexOffset + 1.0) * 0.0000002; + gp_interp.depth = (stroke_index + gpStrokeIndexOffset + 2.0) * 0.0000002; } } else { + int stroke_point_id = gpencil_stroke_point_id(); + vec4 uv1 = texelFetch(gp_pos_tx, stroke_point_id * 3 + 2); + vec4 fcol1 = texelFetch(gp_col_tx, stroke_point_id * 2 + 1); vec4 fill_col = gp_mat.fill_color; /* Special case: We don't modulate alpha in gradient mode. */ @@ -137,7 +128,7 @@ void main() else { /* Use the index of first point of the stroke as depth. */ float stroke_index = float(ma1.y); - gp_interp.depth = (stroke_index + gpStrokeIndexOffset) * 0.0000002; + gp_interp.depth = (stroke_index + gpStrokeIndexOffset + 1.0) * 0.0000002; } } } diff --git a/source/blender/draw/engines/gpencil/shaders/infos/gpencil_info.hh b/source/blender/draw/engines/gpencil/shaders/infos/gpencil_info.hh index edd51e71242..da2776254e6 100644 --- a/source/blender/draw/engines/gpencil/shaders/infos/gpencil_info.hh +++ b/source/blender/draw/engines/gpencil/shaders/infos/gpencil_info.hh @@ -22,10 +22,10 @@ GPU_SHADER_CREATE_INFO(gpencil_geometry) .do_static_compilation(true) .define("GP_LIGHT") .typedef_source("gpencil_defines.h") - .sampler(0, ImageType::FLOAT_2D, "gpFillTexture") - .sampler(1, ImageType::FLOAT_2D, "gpStrokeTexture") - .sampler(2, ImageType::DEPTH_2D, "gpSceneDepthTexture") - .sampler(3, ImageType::FLOAT_2D, "gpMaskTexture") + .sampler(2, ImageType::FLOAT_2D, "gpFillTexture") + .sampler(3, ImageType::FLOAT_2D, "gpStrokeTexture") + .sampler(4, ImageType::DEPTH_2D, "gpSceneDepthTexture") + .sampler(5, ImageType::FLOAT_2D, "gpMaskTexture") .uniform_buf(4, "gpMaterial", "materials[GPENCIL_MATERIAL_BUFFER_LEN]", Frequency::BATCH) .uniform_buf(3, "gpLight", "lights[GPENCIL_LIGHT_BUFFER_LEN]", Frequency::BATCH) .push_constant(Type::VEC2, "viewportSize") diff --git a/source/blender/draw/engines/overlay/overlay_armature.cc b/source/blender/draw/engines/overlay/overlay_armature.cc index 0cf9d91804a..8c9587e7a9a 100644 --- a/source/blender/draw/engines/overlay/overlay_armature.cc +++ b/source/blender/draw/engines/overlay/overlay_armature.cc @@ -441,7 +441,7 @@ static void drw_shgroup_bone_octahedral(ArmatureDrawContext *ctx, const float outline_color[4]) { BoneInstanceData inst_data; - mul_m4_m4m4(inst_data.mat, ctx->ob->obmat, bone_mat); + mul_m4_m4m4(inst_data.mat, ctx->ob->object_to_world, bone_mat); if (ctx->solid) { OVERLAY_bone_instance_data_set_color(&inst_data, bone_color); OVERLAY_bone_instance_data_set_color_hint(&inst_data, hint_color); @@ -461,7 +461,7 @@ static void drw_shgroup_bone_box(ArmatureDrawContext *ctx, const float outline_color[4]) { BoneInstanceData inst_data; - mul_m4_m4m4(inst_data.mat, ctx->ob->obmat, bone_mat); + mul_m4_m4m4(inst_data.mat, ctx->ob->object_to_world, bone_mat); if (ctx->solid) { OVERLAY_bone_instance_data_set_color(&inst_data, bone_color); OVERLAY_bone_instance_data_set_color_hint(&inst_data, hint_color); @@ -479,9 +479,9 @@ static void drw_shgroup_bone_wire(ArmatureDrawContext *ctx, const float color[4]) { float head[3], tail[3]; - mul_v3_m4v3(head, ctx->ob->obmat, bone_mat[3]); + mul_v3_m4v3(head, ctx->ob->object_to_world, bone_mat[3]); add_v3_v3v3(tail, bone_mat[3], bone_mat[1]); - mul_m4_v3(ctx->ob->obmat, tail); + mul_m4_v3(ctx->ob->object_to_world, tail); DRW_buffer_add_entry(ctx->wire, head, color); DRW_buffer_add_entry(ctx->wire, tail, color); @@ -496,9 +496,9 @@ static void drw_shgroup_bone_stick(ArmatureDrawContext *ctx, const float col_tail[4]) { float head[3], tail[3]; - mul_v3_m4v3(head, ctx->ob->obmat, bone_mat[3]); + mul_v3_m4v3(head, ctx->ob->object_to_world, bone_mat[3]); add_v3_v3v3(tail, bone_mat[3], bone_mat[1]); - mul_m4_v3(ctx->ob->obmat, tail); + mul_m4_v3(ctx->ob->object_to_world, tail); DRW_buffer_add_entry(ctx->stick, head, tail, col_wire, col_bone, col_head, col_tail); } @@ -517,11 +517,11 @@ static void drw_shgroup_bone_envelope_distance(ArmatureDrawContext *ctx, mul_m4_v4(bone_mat, head_sph); mul_m4_v4(bone_mat, tail_sph); mul_m4_v4(bone_mat, xaxis); - mul_m4_v4(ctx->ob->obmat, head_sph); - mul_m4_v4(ctx->ob->obmat, tail_sph); - mul_m4_v4(ctx->ob->obmat, xaxis); + mul_m4_v4(ctx->ob->object_to_world, head_sph); + mul_m4_v4(ctx->ob->object_to_world, tail_sph); + mul_m4_v4(ctx->ob->object_to_world, xaxis); sub_v3_v3(xaxis, head_sph); - float obscale = mat4_to_scale(ctx->ob->obmat); + float obscale = mat4_to_scale(ctx->ob->object_to_world); head_sph[3] = *radius_head * obscale; head_sph[3] += *distance * obscale; tail_sph[3] = *radius_tail * obscale; @@ -544,10 +544,10 @@ static void drw_shgroup_bone_envelope(ArmatureDrawContext *ctx, mul_m4_v4(bone_mat, head_sph); mul_m4_v4(bone_mat, tail_sph); mul_m4_v4(bone_mat, xaxis); - mul_m4_v4(ctx->ob->obmat, head_sph); - mul_m4_v4(ctx->ob->obmat, tail_sph); - mul_m4_v4(ctx->ob->obmat, xaxis); - float obscale = mat4_to_scale(ctx->ob->obmat); + mul_m4_v4(ctx->ob->object_to_world, head_sph); + mul_m4_v4(ctx->ob->object_to_world, tail_sph); + mul_m4_v4(ctx->ob->object_to_world, xaxis); + float obscale = mat4_to_scale(ctx->ob->object_to_world); head_sph[3] = *radius_head * obscale; tail_sph[3] = *radius_tail * obscale; @@ -651,7 +651,7 @@ static void drw_shgroup_bone_custom_solid_mesh(ArmatureDrawContext *ctx, DRWCallBuffer *buf; if (surf || edges || ledges) { - mul_m4_m4m4(inst_data.mat, ctx->ob->obmat, bone_mat); + mul_m4_m4m4(inst_data.mat, ctx->ob->object_to_world, bone_mat); } if (surf && ctx->custom_solid) { @@ -692,7 +692,7 @@ static void drw_shgroup_bone_custom_mesh_wire(ArmatureDrawContext *ctx, if (geom) { DRWCallBuffer *buf = custom_bone_instance_shgroup(ctx, ctx->custom_wire, geom); BoneInstanceData inst_data; - mul_m4_m4m4(inst_data.mat, ctx->ob->obmat, bone_mat); + mul_m4_m4m4(inst_data.mat, ctx->ob->object_to_world, bone_mat); OVERLAY_bone_instance_data_set_color_hint(&inst_data, color); OVERLAY_bone_instance_data_set_color(&inst_data, color); DRW_buffer_add_entry_struct(buf, inst_data.mat); @@ -724,7 +724,7 @@ static void drw_shgroup_custom_bone_curve(ArmatureDrawContext *ctx, if (ledges) { BoneInstanceData inst_data; - mul_m4_m4m4(inst_data.mat, ctx->ob->obmat, bone_mat); + mul_m4_m4m4(inst_data.mat, ctx->ob->object_to_world, bone_mat); DRWCallBuffer *buf = custom_bone_instance_shgroup(ctx, ctx->custom_wire, ledges); OVERLAY_bone_instance_data_set_color_hint(&inst_data, outline_color); @@ -785,7 +785,7 @@ static void drw_shgroup_bone_custom_empty(ArmatureDrawContext *ctx, { const float final_color[4] = {color[0], color[1], color[2], 1.0f}; float mat[4][4]; - mul_m4_m4m4(mat, ctx->ob->obmat, bone_mat); + mul_m4_m4m4(mat, ctx->ob->object_to_world, bone_mat); switch (custom->empty_drawtype) { case OB_PLAINAXES: @@ -811,7 +811,7 @@ static void drw_shgroup_bone_point(ArmatureDrawContext *ctx, const float outline_color[4]) { BoneInstanceData inst_data; - mul_m4_m4m4(inst_data.mat, ctx->ob->obmat, bone_mat); + mul_m4_m4m4(inst_data.mat, ctx->ob->object_to_world, bone_mat); if (ctx->point_solid) { OVERLAY_bone_instance_data_set_color(&inst_data, bone_color); OVERLAY_bone_instance_data_set_color_hint(&inst_data, hint_color); @@ -829,7 +829,7 @@ static void drw_shgroup_bone_axes(ArmatureDrawContext *ctx, const float color[4]) { float mat[4][4]; - mul_m4_m4m4(mat, ctx->ob->obmat, bone_mat); + mul_m4_m4m4(mat, ctx->ob->object_to_world, bone_mat); /* Move to bone tail. */ add_v3_v3(mat[3], mat[1]); OVERLAY_empty_shape(ctx->extras, mat, 0.25f, OB_ARROWS, color); @@ -842,8 +842,8 @@ static void drw_shgroup_bone_relationship_lines_ex(ArmatureDrawContext *ctx, const float color[4]) { float s[3], e[3]; - mul_v3_m4v3(s, ctx->ob->obmat, start); - mul_v3_m4v3(e, ctx->ob->obmat, end); + mul_v3_m4v3(s, ctx->ob->object_to_world, start); + mul_v3_m4v3(e, ctx->ob->object_to_world, end); /* reverse order to have less stipple overlap */ OVERLAY_extra_line_dashed(ctx->extras, s, e, color); } @@ -1909,7 +1909,7 @@ static void draw_bone_degrees_of_freedom(ArmatureDrawContext *ctx, bPoseChannel mul_m4_m4m4(posetrans, posetrans, tmp); /* into world space. */ - mul_m4_m4m4(inst_data.mat, ctx->ob->obmat, posetrans); + mul_m4_m4m4(inst_data.mat, ctx->ob->object_to_world, posetrans); if ((pchan->ikflag & BONE_IK_XLIMIT) && (pchan->ikflag & BONE_IK_ZLIMIT)) { bone_instance_data_set_angle_minmax( @@ -2079,7 +2079,7 @@ static void draw_bone_name(ArmatureDrawContext *ctx, float *head = pchan ? pchan->pose_head : eBone->head; float *tail = pchan ? pchan->pose_tail : eBone->tail; mid_v3_v3v3(vec, head, tail); - mul_m4_v3(ctx->ob->obmat, vec); + mul_m4_v3(ctx->ob->object_to_world, vec); DRW_text_cache_add(dt, vec, @@ -2177,7 +2177,8 @@ static bool pchan_culling_test_envelope(const DRWView *view, BoundSphere bsphere; pchan_culling_calc_bsphere(ob, pchan, &bsphere); bsphere.radius += max_ff(pchan->bone->rad_head, pchan->bone->rad_tail) * - mat4_to_size_max_axis(ob->obmat) * mat4_to_size_max_axis(pchan->disp_mat); + mat4_to_size_max_axis(ob->object_to_world) * + mat4_to_size_max_axis(pchan->disp_mat); return DRW_culling_sphere_test(view, &bsphere); } @@ -2188,13 +2189,13 @@ static bool pchan_culling_test_bbone(const DRWView *view, const bArmature *arm = static_cast<bArmature *>(ob->data); BLI_assert(arm->drawtype == ARM_B_BONE); UNUSED_VARS_NDEBUG(arm); - const float ob_scale = mat4_to_size_max_axis(ob->obmat); + const float ob_scale = mat4_to_size_max_axis(ob->object_to_world); const Mat4 *bbones_mat = (const Mat4 *)pchan->draw_data->bbone_matrix; for (int i = pchan->bone->segments; i--; bbones_mat++) { BoundSphere bsphere; float size[3]; mat4_to_size(size, bbones_mat->mat); - mul_v3_m4v3(bsphere.center, ob->obmat, bbones_mat->mat[3]); + mul_v3_m4v3(bsphere.center, ob->object_to_world, bbones_mat->mat[3]); bsphere.radius = len_v3(size) * ob_scale; if (DRW_culling_sphere_test(view, &bsphere)) { return true; diff --git a/source/blender/draw/engines/overlay/overlay_edit_text.cc b/source/blender/draw/engines/overlay/overlay_edit_text.cc index ebadaa530e4..d1bca705ae6 100644 --- a/source/blender/draw/engines/overlay/overlay_edit_text.cc +++ b/source/blender/draw/engines/overlay/overlay_edit_text.cc @@ -119,7 +119,7 @@ static void edit_text_cache_populate_select(OVERLAY_Data *vedata, Object *ob) add_v2_v2(box[3], &sb->x); } v2_quad_corners_to_mat4(box, final_mat); - mul_m4_m4m4(final_mat, ob->obmat, final_mat); + mul_m4_m4m4(final_mat, ob->object_to_world, final_mat); DRW_shgroup_call_obmat(pd->edit_text_selection_grp, geom, final_mat); } @@ -134,7 +134,7 @@ static void edit_text_cache_populate_cursor(OVERLAY_Data *vedata, Object *ob) float mat[4][4]; v2_quad_corners_to_mat4(cursor, mat); - mul_m4_m4m4(mat, ob->obmat, mat); + mul_m4_m4m4(mat, ob->object_to_world, mat); struct GPUBatch *geom = DRW_cache_quad_get(); DRW_shgroup_call_obmat(pd->edit_text_cursor_grp, geom, mat); @@ -162,7 +162,7 @@ static void edit_text_cache_populate_boxes(OVERLAY_Data *vedata, Object *ob) vecs[3][1] -= tb->h; for (int j = 0; j < 4; j++) { - mul_v3_m4v3(vecs[j], ob->obmat, vecs[j]); + mul_v3_m4v3(vecs[j], ob->object_to_world, vecs[j]); } for (int j = 0; j < 4; j++) { OVERLAY_extra_line_dashed(cb, vecs[j], vecs[(j + 1) % 4], color); diff --git a/source/blender/draw/engines/overlay/overlay_extra.cc b/source/blender/draw/engines/overlay/overlay_extra.cc index 114123ab36e..27afe49a17b 100644 --- a/source/blender/draw/engines/overlay/overlay_extra.cc +++ b/source/blender/draw/engines/overlay/overlay_extra.cc @@ -331,7 +331,7 @@ void OVERLAY_empty_cache_populate(OVERLAY_Data *vedata, Object *ob) case OB_EMPTY_CONE: case OB_ARROWS: DRW_object_wire_theme_get(ob, view_layer, &color); - OVERLAY_empty_shape(cb, ob->obmat, ob->empty_drawsize, ob->empty_drawtype, color); + OVERLAY_empty_shape(cb, ob->object_to_world, ob->empty_drawsize, ob->empty_drawtype, color); break; case OB_EMPTY_IMAGE: OVERLAY_image_empty_cache_populate(vedata, ob); @@ -372,7 +372,7 @@ static void OVERLAY_bounds(OVERLAY_ExtraCallBuffers *cb, case OB_BOUND_BOX: size_to_mat4(tmp, size); copy_v3_v3(tmp[3], center); - mul_m4_m4m4(tmp, ob->obmat, tmp); + mul_m4_m4m4(tmp, ob->object_to_world, tmp); DRW_buffer_add_entry(cb->empty_cube, color, tmp); break; case OB_BOUND_SPHERE: @@ -380,7 +380,7 @@ static void OVERLAY_bounds(OVERLAY_ExtraCallBuffers *cb, size[1] = size[2] = size[0]; size_to_mat4(tmp, size); copy_v3_v3(tmp[3], center); - mul_m4_m4m4(tmp, ob->obmat, tmp); + mul_m4_m4m4(tmp, ob->object_to_world, tmp); DRW_buffer_add_entry(cb->empty_sphere, color, tmp); break; case OB_BOUND_CYLINDER: @@ -388,7 +388,7 @@ static void OVERLAY_bounds(OVERLAY_ExtraCallBuffers *cb, size[1] = size[0]; size_to_mat4(tmp, size); copy_v3_v3(tmp[3], center); - mul_m4_m4m4(tmp, ob->obmat, tmp); + mul_m4_m4m4(tmp, ob->object_to_world, tmp); DRW_buffer_add_entry(cb->empty_cylinder, color, tmp); break; case OB_BOUND_CONE: @@ -399,7 +399,7 @@ static void OVERLAY_bounds(OVERLAY_ExtraCallBuffers *cb, /* Cone batch has base at 0 and is pointing towards +Y. */ swap_v3_v3(tmp[1], tmp[2]); tmp[3][2] -= size[2]; - mul_m4_m4m4(tmp, ob->obmat, tmp); + mul_m4_m4m4(tmp, ob->object_to_world, tmp); DRW_buffer_add_entry(cb->empty_cone, color, tmp); break; case OB_BOUND_CAPSULE: @@ -408,14 +408,14 @@ static void OVERLAY_bounds(OVERLAY_ExtraCallBuffers *cb, scale_m4_fl(tmp, size[0]); copy_v2_v2(tmp[3], center); tmp[3][2] = center[2] + max_ff(0.0f, size[2] - size[0]); - mul_m4_m4m4(final_mat, ob->obmat, tmp); + mul_m4_m4m4(final_mat, ob->object_to_world, tmp); DRW_buffer_add_entry(cb->empty_capsule_cap, color, final_mat); negate_v3(tmp[2]); tmp[3][2] = center[2] - max_ff(0.0f, size[2] - size[0]); - mul_m4_m4m4(final_mat, ob->obmat, tmp); + mul_m4_m4m4(final_mat, ob->object_to_world, tmp); DRW_buffer_add_entry(cb->empty_capsule_cap, color, final_mat); tmp[2][2] = max_ff(0.0f, size[2] * 2.0f - size[0] * 2.0f); - mul_m4_m4m4(final_mat, ob->obmat, tmp); + mul_m4_m4m4(final_mat, ob->object_to_world, tmp); DRW_buffer_add_entry(cb->empty_capsule_body, color, final_mat); break; } @@ -489,7 +489,7 @@ static void OVERLAY_texture_space(OVERLAY_ExtraCallBuffers *cb, Object *ob, cons unit_m4(mat); } - mul_m4_m4m4(mat, ob->obmat, mat); + mul_m4_m4m4(mat, ob->object_to_world, mat); DRW_buffer_add_entry(cb->empty_cube, color, mat); } @@ -511,7 +511,7 @@ static void OVERLAY_forcefield(OVERLAY_ExtraCallBuffers *cb, Object *ob, ViewLay }; } instdata; - copy_m4_m4(instdata.mat, ob->obmat); + copy_m4_m4(instdata.mat, ob->object_to_world); instdata.size_x = instdata.size_y = instdata.size_z = ob->empty_drawsize; switch (pd->forcefield) { @@ -531,16 +531,16 @@ static void OVERLAY_forcefield(OVERLAY_ExtraCallBuffers *cb, Object *ob, ViewLay instdata.size_x = instdata.size_y = instdata.size_z = pd->f_strength; float pos[4]; BKE_where_on_path(ob, 0.0f, pos, nullptr, nullptr, nullptr, nullptr); - copy_v3_v3(instdata.pos, ob->obmat[3]); + copy_v3_v3(instdata.pos, ob->object_to_world[3]); translate_m4(instdata.mat, pos[0], pos[1], pos[2]); DRW_buffer_add_entry(cb->field_curve, color, &instdata); BKE_where_on_path(ob, 1.0f, pos, nullptr, nullptr, nullptr, nullptr); - copy_v3_v3(instdata.pos, ob->obmat[3]); + copy_v3_v3(instdata.pos, ob->object_to_world[3]); translate_m4(instdata.mat, pos[0], pos[1], pos[2]); DRW_buffer_add_entry(cb->field_sphere_limit, color, &instdata); /* Restore */ - copy_v3_v3(instdata.pos, ob->obmat[3]); + copy_v3_v3(instdata.pos, ob->object_to_world[3]); } break; } @@ -625,7 +625,7 @@ void OVERLAY_light_cache_populate(OVERLAY_Data *vedata, Object *ob) }; } instdata; - copy_m4_m4(instdata.mat, ob->obmat); + copy_m4_m4(instdata.mat, ob->object_to_world); /* FIXME / TODO: clip_end has no meaning nowadays. * In EEVEE, Only clip_sta is used shadow-mapping. * Clip end is computed automatically based on light power. @@ -708,7 +708,7 @@ void OVERLAY_lightprobe_cache_populate(OVERLAY_Data *vedata, Object *ob) }; } instdata; - copy_m4_m4(instdata.mat, ob->obmat); + copy_m4_m4(instdata.mat, ob->object_to_world); switch (prb->type) { case LIGHTPROBE_TYPE_CUBE: @@ -720,15 +720,15 @@ void OVERLAY_lightprobe_cache_populate(OVERLAY_Data *vedata, Object *ob) if (show_influence) { char shape = (prb->attenuation_type == LIGHTPROBE_SHAPE_BOX) ? OB_CUBE : OB_EMPTY_SPHERE; float f = 1.0f - prb->falloff; - OVERLAY_empty_shape(cb, ob->obmat, prb->distinf, shape, color_p); - OVERLAY_empty_shape(cb, ob->obmat, prb->distinf * f, shape, color_p); + OVERLAY_empty_shape(cb, ob->object_to_world, prb->distinf, shape, color_p); + OVERLAY_empty_shape(cb, ob->object_to_world, prb->distinf * f, shape, color_p); } if (show_parallax) { char shape = (prb->parallax_type == LIGHTPROBE_SHAPE_BOX) ? OB_CUBE : OB_EMPTY_SPHERE; float dist = ((prb->flag & LIGHTPROBE_FLAG_CUSTOM_PARALLAX) != 0) ? prb->distpar : prb->distinf; - OVERLAY_empty_shape(cb, ob->obmat, dist, shape, color_p); + OVERLAY_empty_shape(cb, ob->object_to_world, dist, shape, color_p); } break; case LIGHTPROBE_TYPE_GRID: @@ -738,8 +738,8 @@ void OVERLAY_lightprobe_cache_populate(OVERLAY_Data *vedata, Object *ob) if (show_influence) { float f = 1.0f - prb->falloff; - OVERLAY_empty_shape(cb, ob->obmat, 1.0 + prb->distinf, OB_CUBE, color_p); - OVERLAY_empty_shape(cb, ob->obmat, 1.0 + prb->distinf * f, OB_CUBE, color_p); + OVERLAY_empty_shape(cb, ob->object_to_world, 1.0 + prb->distinf, OB_CUBE, color_p); + OVERLAY_empty_shape(cb, ob->object_to_world, 1.0 + prb->distinf * f, OB_CUBE, color_p); } /* Data dots */ @@ -777,7 +777,7 @@ void OVERLAY_lightprobe_cache_populate(OVERLAY_Data *vedata, Object *ob) zero_v3(instdata.mat[2]); DRW_buffer_add_entry(cb->empty_cube, color_p, &instdata); - normalize_m4_m4(instdata.mat, ob->obmat); + normalize_m4_m4(instdata.mat, ob->object_to_world); OVERLAY_empty_shape(cb, instdata.mat, ob->empty_drawsize, OB_SINGLE_ARROW, color_p); break; } @@ -797,7 +797,7 @@ void OVERLAY_speaker_cache_populate(OVERLAY_Data *vedata, Object *ob) float *color_p; DRW_object_wire_theme_get(ob, view_layer, &color_p); - DRW_buffer_add_entry(cb->speaker, color_p, ob->obmat); + DRW_buffer_add_entry(cb->speaker, color_p, ob->object_to_world); } /** \} */ @@ -890,7 +890,7 @@ static void camera_view3d_reconstruction( float object_imat[4][4]; invert_m4_m4(object_imat, object_mat); - mul_m4_m4m4(tracking_object_mat, ob->obmat, object_imat); + mul_m4_m4m4(tracking_object_mat, ob->object_to_world, object_imat); } ListBase *tracksbase = BKE_tracking_object_get_tracks(tracking, tracking_object); @@ -1132,14 +1132,17 @@ void OVERLAY_camera_cache_populate(OVERLAY_Data *vedata, Object *ob) DRW_object_wire_theme_get(ob, view_layer, &color_p); copy_v4_v4(instdata.color, color_p); - normalize_m4_m4(instdata.mat, ob->obmat); + normalize_m4_m4(instdata.mat, ob->object_to_world); /* BKE_camera_multiview_model_matrix already accounts for scale, don't do it here. */ if (is_selection_camera_stereo) { copy_v3_fl(scale, 1.0f); } else { - copy_v3_fl3(scale, len_v3(ob->obmat[0]), len_v3(ob->obmat[1]), len_v3(ob->obmat[2])); + copy_v3_fl3(scale, + len_v3(ob->object_to_world[0]), + len_v3(ob->object_to_world[1]), + len_v3(ob->object_to_world[2])); /* Avoid division by 0. */ if (ELEM(0.0f, scale[0], scale[1], scale[2])) { return; @@ -1255,7 +1258,7 @@ static void OVERLAY_relationship_lines(OVERLAY_ExtraCallBuffers *cb, if (ob->parent && (DRW_object_visibility_in_active_context(ob->parent) & OB_VISIBLE_SELF)) { float *parent_pos = ob->runtime.parent_display_origin; - OVERLAY_extra_line_dashed(cb, parent_pos, ob->obmat[3], relation_color); + OVERLAY_extra_line_dashed(cb, parent_pos, ob->object_to_world[3], relation_color); } /* Drawing the hook lines. */ @@ -1263,9 +1266,9 @@ static void OVERLAY_relationship_lines(OVERLAY_ExtraCallBuffers *cb, if (md->type == eModifierType_Hook) { HookModifierData *hmd = (HookModifierData *)md; float center[3]; - mul_v3_m4v3(center, ob->obmat, hmd->cent); + mul_v3_m4v3(center, ob->object_to_world, hmd->cent); if (hmd->object) { - OVERLAY_extra_line_dashed(cb, hmd->object->obmat[3], center, relation_color); + OVERLAY_extra_line_dashed(cb, hmd->object->object_to_world[3], center, relation_color); } OVERLAY_extra_point(cb, center, relation_color); } @@ -1275,10 +1278,12 @@ static void OVERLAY_relationship_lines(OVERLAY_ExtraCallBuffers *cb, Object *rbc_ob1 = ob->rigidbody_constraint->ob1; Object *rbc_ob2 = ob->rigidbody_constraint->ob2; if (rbc_ob1 && (DRW_object_visibility_in_active_context(rbc_ob1) & OB_VISIBLE_SELF)) { - OVERLAY_extra_line_dashed(cb, rbc_ob1->obmat[3], ob->obmat[3], relation_color); + OVERLAY_extra_line_dashed( + cb, rbc_ob1->object_to_world[3], ob->object_to_world[3], relation_color); } if (rbc_ob2 && (DRW_object_visibility_in_active_context(rbc_ob2) & OB_VISIBLE_SELF)) { - OVERLAY_extra_line_dashed(cb, rbc_ob2->obmat[3], ob->obmat[3], relation_color); + OVERLAY_extra_line_dashed( + cb, rbc_ob2->object_to_world[3], ob->object_to_world[3], relation_color); } } @@ -1307,7 +1312,8 @@ static void OVERLAY_relationship_lines(OVERLAY_ExtraCallBuffers *cb, } if (camob) { - OVERLAY_extra_line_dashed(cb, camob->obmat[3], ob->obmat[3], constraint_color); + OVERLAY_extra_line_dashed( + cb, camob->object_to_world[3], ob->object_to_world[3], constraint_color); } } else { @@ -1330,7 +1336,7 @@ static void OVERLAY_relationship_lines(OVERLAY_ExtraCallBuffers *cb, else { unit_m4(ct->matrix); } - OVERLAY_extra_line_dashed(cb, ct->matrix[3], ob->obmat[3], constraint_color); + OVERLAY_extra_line_dashed(cb, ct->matrix[3], ob->object_to_world[3], constraint_color); } BKE_constraint_targets_flush(curcon, &targets, true); @@ -1387,7 +1393,7 @@ static void OVERLAY_volume_extra(OVERLAY_ExtraCallBuffers *cb, copy_v3_v3(voxel_cubemat[3], min); /* move small cube into the domain (otherwise its centered on vertex of domain object) */ translate_m4(voxel_cubemat, 1.0f, 1.0f, 1.0f); - mul_m4_m4m4(voxel_cubemat, ob->obmat, voxel_cubemat); + mul_m4_m4m4(voxel_cubemat, ob->object_to_world, voxel_cubemat); DRW_buffer_add_entry(cb->empty_cube, color, voxel_cubemat); } @@ -1493,15 +1499,15 @@ static void OVERLAY_object_center(OVERLAY_ExtraCallBuffers *cb, const bool is_library = ID_REAL_USERS(&ob->id) > 1 || ID_IS_LINKED(ob); BKE_view_layer_synced_ensure(scene, view_layer); if (ob == BKE_view_layer_active_object_get(view_layer)) { - DRW_buffer_add_entry(cb->center_active, ob->obmat[3]); + DRW_buffer_add_entry(cb->center_active, ob->object_to_world[3]); } else if (ob->base_flag & BASE_SELECTED) { DRWCallBuffer *cbuf = (is_library) ? cb->center_selected_lib : cb->center_selected; - DRW_buffer_add_entry(cbuf, ob->obmat[3]); + DRW_buffer_add_entry(cbuf, ob->object_to_world[3]); } else if (pd->v3d_flag & V3D_DRAW_CENTERS) { DRWCallBuffer *cbuf = (is_library) ? cb->center_deselected_lib : cb->center_deselected; - DRW_buffer_add_entry(cbuf, ob->obmat[3]); + DRW_buffer_add_entry(cbuf, ob->object_to_world[3]); } } @@ -1513,7 +1519,7 @@ static void OVERLAY_object_name(Object *ob, int theme_id) UI_GetThemeColor4ubv(theme_id, color); DRW_text_cache_add(dt, - ob->obmat[3], + ob->object_to_world[3], ob->id.name + 2, strlen(ob->id.name + 2), 10, @@ -1571,7 +1577,7 @@ void OVERLAY_extra_cache_populate(OVERLAY_Data *vedata, Object *ob) /* Helpers for when we're transforming origins. */ if (draw_xform) { const float color_xform[4] = {0.15f, 0.15f, 0.15f, 0.7f}; - DRW_buffer_add_entry(cb->origin_xform, color_xform, ob->obmat); + DRW_buffer_add_entry(cb->origin_xform, color_xform, ob->object_to_world); } /* don't show object extras in set's */ if (!from_dupli) { @@ -1591,7 +1597,7 @@ void OVERLAY_extra_cache_populate(OVERLAY_Data *vedata, Object *ob) OVERLAY_collision(cb, ob, color); } if (ob->dtx & OB_AXIS) { - DRW_buffer_add_entry(cb->empty_axes, color, ob->obmat); + DRW_buffer_add_entry(cb->empty_axes, color, ob->object_to_world); } if (draw_volume) { OVERLAY_volume_extra(cb, vedata, ob, md, scene, color); diff --git a/source/blender/draw/engines/overlay/overlay_facing.cc b/source/blender/draw/engines/overlay/overlay_facing.cc index 825036ecd05..44dab0f0a42 100644 --- a/source/blender/draw/engines/overlay/overlay_facing.cc +++ b/source/blender/draw/engines/overlay/overlay_facing.cc @@ -43,7 +43,7 @@ void OVERLAY_facing_cache_populate(OVERLAY_Data *vedata, Object *ob) } const DRWContextState *draw_ctx = DRW_context_state_get(); - const bool use_sculpt_pbvh = BKE_sculptsession_use_pbvh_draw(ob, draw_ctx->v3d) && + const bool use_sculpt_pbvh = BKE_sculptsession_use_pbvh_draw(ob, draw_ctx->rv3d) && !DRW_state_is_image_render(); const bool is_xray = (ob->dtx & OB_DRAW_IN_FRONT) != 0; diff --git a/source/blender/draw/engines/overlay/overlay_fade.cc b/source/blender/draw/engines/overlay/overlay_fade.cc index d6fd4f9127a..b9523a4eac9 100644 --- a/source/blender/draw/engines/overlay/overlay_fade.cc +++ b/source/blender/draw/engines/overlay/overlay_fade.cc @@ -53,7 +53,7 @@ void OVERLAY_fade_cache_populate(OVERLAY_Data *vedata, Object *ob) } const DRWContextState *draw_ctx = DRW_context_state_get(); - const bool use_sculpt_pbvh = BKE_sculptsession_use_pbvh_draw(ob, draw_ctx->v3d) && + const bool use_sculpt_pbvh = BKE_sculptsession_use_pbvh_draw(ob, draw_ctx->rv3d) && !DRW_state_is_image_render(); const bool is_xray = (ob->dtx & OB_DRAW_IN_FRONT) != 0; diff --git a/source/blender/draw/engines/overlay/overlay_gpencil.cc b/source/blender/draw/engines/overlay/overlay_gpencil.cc index 30765b30ce6..f5988d91e72 100644 --- a/source/blender/draw/engines/overlay/overlay_gpencil.cc +++ b/source/blender/draw/engines/overlay/overlay_gpencil.cc @@ -243,7 +243,7 @@ void OVERLAY_gpencil_cache_init(OVERLAY_Data *vedata) copy_v3_v3(col_grid, gpd->grid.color); col_grid[3] = max_ff(v3d->overlay.gpencil_grid_opacity, 0.01f); - copy_m4_m4(mat, ob->obmat); + copy_m4_m4(mat, ob->object_to_world); /* Rotate and scale except align to cursor. */ bGPDlayer *gpl = BKE_gpencil_layer_active_get(gpd); @@ -286,7 +286,7 @@ void OVERLAY_gpencil_cache_init(OVERLAY_Data *vedata) copy_v3_v3(mat[3], cursor->location); } else if (ts->gpencil_v3d_align & GP_PROJECT_VIEWSPACE) { - copy_v3_v3(mat[3], ob->obmat[3]); + copy_v3_v3(mat[3], ob->object_to_world[3]); } translate_m4(mat, gpd->grid.offset[0], gpd->grid.offset[1], 0.0f); @@ -397,7 +397,7 @@ static void overlay_gpencil_draw_stroke_color_name(bGPDlayer * /*gpl*/, UI_GetThemeColor4ubv(theme_id, color); float fpt[3]; - mul_v3_m4v3(fpt, ob->obmat, &pt->x); + mul_v3_m4v3(fpt, ob->object_to_world, &pt->x); struct DRWTextStore *dt = DRW_text_cache_ensure(); DRW_text_cache_add(dt, diff --git a/source/blender/draw/engines/overlay/overlay_image.cc b/source/blender/draw/engines/overlay/overlay_image.cc index f42867622e4..7b99bd6bd18 100644 --- a/source/blender/draw/engines/overlay/overlay_image.cc +++ b/source/blender/draw/engines/overlay/overlay_image.cc @@ -392,7 +392,7 @@ void OVERLAY_image_empty_cache_populate(OVERLAY_Data *vedata, Object *ob) float image_aspect[2]; overlay_image_calc_aspect(ima, size, image_aspect); - copy_m4_m4(mat, ob->obmat); + copy_m4_m4(mat, ob->object_to_world); mul_v3_fl(mat[0], image_aspect[0] * 0.5f * ob->empty_drawsize); mul_v3_fl(mat[1], image_aspect[1] * 0.5f * ob->empty_drawsize); madd_v3_v3fl(mat[3], mat[0], ob->ima_ofs[0] * 2.0f + 1.0f); diff --git a/source/blender/draw/engines/overlay/overlay_lattice.cc b/source/blender/draw/engines/overlay/overlay_lattice.cc index 7b59aa78c89..72c3335d871 100644 --- a/source/blender/draw/engines/overlay/overlay_lattice.cc +++ b/source/blender/draw/engines/overlay/overlay_lattice.cc @@ -52,7 +52,7 @@ void OVERLAY_lattice_cache_populate(OVERLAY_Data *vedata, Object *ob) DRW_object_wire_theme_get(ob, draw_ctx->view_layer, &color); struct GPUBatch *geom = DRW_cache_lattice_wire_get(ob, false); - OVERLAY_extra_wire(cb, geom, ob->obmat, color); + OVERLAY_extra_wire(cb, geom, ob->object_to_world, color); } void OVERLAY_edit_lattice_draw(OVERLAY_Data *vedata) diff --git a/source/blender/draw/engines/overlay/overlay_metaball.cc b/source/blender/draw/engines/overlay/overlay_metaball.cc index 2fc6910fe44..dd0a862337e 100644 --- a/source/blender/draw/engines/overlay/overlay_metaball.cc +++ b/source/blender/draw/engines/overlay/overlay_metaball.cc @@ -45,10 +45,10 @@ static void metaball_instance_data_set( BoneInstanceData *data, Object *ob, const float *pos, const float radius, const float color[4]) { /* Bone point radius is 0.05. Compensate for that. */ - mul_v3_v3fl(data->mat[0], ob->obmat[0], radius / 0.05f); - mul_v3_v3fl(data->mat[1], ob->obmat[1], radius / 0.05f); - mul_v3_v3fl(data->mat[2], ob->obmat[2], radius / 0.05f); - mul_v3_m4v3(data->mat[3], ob->obmat, pos); + mul_v3_v3fl(data->mat[0], ob->object_to_world[0], radius / 0.05f); + mul_v3_v3fl(data->mat[1], ob->object_to_world[1], radius / 0.05f); + mul_v3_v3fl(data->mat[2], ob->object_to_world[2], radius / 0.05f); + mul_v3_m4v3(data->mat[3], ob->object_to_world, pos); /* WATCH: Reminder, alpha is wire-size. */ OVERLAY_bone_instance_data_set_color(data, color); } diff --git a/source/blender/draw/engines/overlay/overlay_mode_transfer.cc b/source/blender/draw/engines/overlay/overlay_mode_transfer.cc index 5222abfc743..79ac92a187c 100644 --- a/source/blender/draw/engines/overlay/overlay_mode_transfer.cc +++ b/source/blender/draw/engines/overlay/overlay_mode_transfer.cc @@ -85,7 +85,7 @@ void OVERLAY_mode_transfer_cache_populate(OVERLAY_Data *vedata, Object *ob) } const DRWContextState *draw_ctx = DRW_context_state_get(); - const bool use_sculpt_pbvh = BKE_sculptsession_use_pbvh_draw(ob, draw_ctx->v3d) && + const bool use_sculpt_pbvh = BKE_sculptsession_use_pbvh_draw(ob, draw_ctx->rv3d) && !DRW_state_is_image_render(); const bool is_xray = (ob->dtx & OB_DRAW_IN_FRONT) != 0; diff --git a/source/blender/draw/engines/overlay/overlay_outline.cc b/source/blender/draw/engines/overlay/overlay_outline.cc index 5ea02376b67..c2df665eba3 100644 --- a/source/blender/draw/engines/overlay/overlay_outline.cc +++ b/source/blender/draw/engines/overlay/overlay_outline.cc @@ -43,7 +43,7 @@ static void gpencil_depth_plane(Object *ob, float r_plane[4]) add_v3_fl(size, 1e-8f); rescale_m4(mat, size); /* BBox space to World. */ - mul_m4_m4m4(mat, ob->obmat, mat); + mul_m4_m4m4(mat, ob->object_to_world, mat); /* BBox center in world space. */ copy_v3_v3(center, mat[3]); /* View Vector. */ @@ -138,6 +138,7 @@ void OVERLAY_outline_cache_init(OVERLAY_Data *vedata) DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo); GPUShader *sh_curves = OVERLAY_shader_outline_prepass_curves(); + pd->outlines_curves_grp = grp = DRW_shgroup_create(sh_curves, psl->outlines_prepass_ps); DRW_shgroup_uniform_bool_copy(grp, "isTransform", (G.moving & G_TRANSFORM_OBJ) != 0); DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo); @@ -172,7 +173,6 @@ void OVERLAY_outline_cache_init(OVERLAY_Data *vedata) typedef struct iterData { Object *ob; DRWShadingGroup *stroke_grp; - DRWShadingGroup *fill_grp; int cfra; float plane[4]; } iterData; @@ -188,17 +188,22 @@ static void gpencil_layer_cache_populate(bGPDlayer *gpl, const bool is_screenspace = (gpd->flag & GP_DATA_STROKE_KEEPTHICKNESS) != 0; const bool is_stroke_order_3d = (gpd->draw_mode == GP_DRAWMODE_3D); - float object_scale = mat4_to_scale(iter->ob->obmat); + float object_scale = mat4_to_scale(iter->ob->object_to_world); /* Negate thickness sign to tag that strokes are in screen space. * Convert to world units (by default, 1 meter = 2000 pixels). */ float thickness_scale = (is_screenspace) ? -1.0f : (gpd->pixfactor / 2000.0f); + GPUVertBuf *position_tx = DRW_cache_gpencil_position_buffer_get(iter->ob, iter->cfra); + GPUVertBuf *color_tx = DRW_cache_gpencil_color_buffer_get(iter->ob, iter->cfra); + DRWShadingGroup *grp = iter->stroke_grp = DRW_shgroup_create_sub(iter->stroke_grp); DRW_shgroup_uniform_bool_copy(grp, "gpStrokeOrder3d", is_stroke_order_3d); DRW_shgroup_uniform_float_copy(grp, "gpThicknessScale", object_scale); DRW_shgroup_uniform_float_copy(grp, "gpThicknessOffset", float(gpl->line_change)); DRW_shgroup_uniform_float_copy(grp, "gpThicknessWorldScale", thickness_scale); DRW_shgroup_uniform_vec4_copy(grp, "gpDepthPlane", iter->plane); + DRW_shgroup_buffer_texture(grp, "gp_pos_tx", position_tx); + DRW_shgroup_buffer_texture(grp, "gp_col_tx", color_tx); } static void gpencil_stroke_cache_populate(bGPDlayer * /*gpl*/, @@ -219,20 +224,19 @@ static void gpencil_stroke_cache_populate(bGPDlayer * /*gpl*/, return; } + struct GPUBatch *geom = DRW_cache_gpencil_get(iter->ob, iter->cfra); + if (show_fill) { - struct GPUBatch *geom = DRW_cache_gpencil_fills_get(iter->ob, iter->cfra); int vfirst = gps->runtime.fill_start * 3; int vcount = gps->tot_triangles * 3; - DRW_shgroup_call_range(iter->fill_grp, iter->ob, geom, vfirst, vcount); + DRW_shgroup_call_range(iter->stroke_grp, iter->ob, geom, vfirst, vcount); } if (show_stroke) { - struct GPUBatch *geom = DRW_cache_gpencil_strokes_get(iter->ob, iter->cfra); - /* Start one vert before to have gl_InstanceID > 0 (see shader). */ - int vfirst = gps->runtime.stroke_start - 1; - /* Include "potential" cyclic vertex and start adj vertex (see shader). */ - int vcount = gps->totpoints + 1 + 1; - DRW_shgroup_call_instance_range(iter->stroke_grp, iter->ob, geom, vfirst, vcount); + int vfirst = gps->runtime.stroke_start * 3; + bool is_cyclic = ((gps->flag & GP_STROKE_CYCLIC) != 0) && (gps->totpoints > 2); + int vcount = (gps->totpoints + (int)is_cyclic) * 2 * 3; + DRW_shgroup_call_range(iter->stroke_grp, iter->ob, geom, vfirst, vcount); } } @@ -247,7 +251,6 @@ static void OVERLAY_outline_gpencil(OVERLAY_PrivateData *pd, Object *ob) iterData iter{}; iter.ob = ob; iter.stroke_grp = pd->outlines_gpencil_grp; - iter.fill_grp = DRW_shgroup_create_sub(pd->outlines_gpencil_grp); iter.cfra = pd->cfra; if (gpd->draw_mode == GP_DRAWMODE_2D) { @@ -280,6 +283,18 @@ static void OVERLAY_outline_curves(OVERLAY_PrivateData *pd, Object *ob) DRW_shgroup_curves_create_sub(ob, shgroup, nullptr); } +static void OVERLAY_outline_pointcloud(OVERLAY_PrivateData *pd, Object *ob) +{ + if (pd->wireframe_mode) { + /* Looks bad in this case. Could be relaxed if we draw a + * wireframe of some sort in the future. */ + return; + } + + DRWShadingGroup *shgroup = pd->outlines_ptcloud_grp; + DRW_shgroup_pointcloud_create_sub(ob, shgroup, nullptr); +} + void OVERLAY_outline_cache_populate(OVERLAY_Data *vedata, Object *ob, OVERLAY_DupliData *dupli, @@ -311,9 +326,8 @@ void OVERLAY_outline_cache_populate(OVERLAY_Data *vedata, return; } - if (ob->type == OB_POINTCLOUD && pd->wireframe_mode) { - /* Looks bad in this case. Could be relaxed if we draw a - * wireframe of some sort in the future. */ + if (ob->type == OB_POINTCLOUD) { + OVERLAY_outline_pointcloud(pd, ob); return; } @@ -336,18 +350,12 @@ void OVERLAY_outline_cache_populate(OVERLAY_Data *vedata, } if (geom) { - shgroup = (ob->type == OB_POINTCLOUD) ? pd->outlines_ptcloud_grp : pd->outlines_grp; + shgroup = pd->outlines_grp; } } if (shgroup && geom) { - if (ob->type == OB_POINTCLOUD) { - /* Draw range to avoid drawcall batching messing up the instance attribute. */ - DRW_shgroup_call_instance_range(shgroup, ob, geom, 0, 0); - } - else { - DRW_shgroup_call(shgroup, geom, ob); - } + DRW_shgroup_call(shgroup, geom, ob); } if (init_dupli) { diff --git a/source/blender/draw/engines/overlay/overlay_particle.cc b/source/blender/draw/engines/overlay/overlay_particle.cc index 6f77a777ba0..c9e3ccba008 100644 --- a/source/blender/draw/engines/overlay/overlay_particle.cc +++ b/source/blender/draw/engines/overlay/overlay_particle.cc @@ -181,14 +181,14 @@ void OVERLAY_particle_cache_populate(OVERLAY_Data *vedata, Object *ob) default: case PART_DRAW_DOT: grp = DRW_shgroup_create_sub(pd->particle_dots_grp); - DRW_shgroup_uniform_vec4_copy(grp, "color", color); + DRW_shgroup_uniform_vec4_copy(grp, "ucolor", color); DRW_shgroup_call(grp, geom, nullptr); break; case PART_DRAW_AXIS: case PART_DRAW_CIRC: case PART_DRAW_CROSS: grp = DRW_shgroup_create_sub(pd->particle_shapes_grp); - DRW_shgroup_uniform_vec4_copy(grp, "color", color); + DRW_shgroup_uniform_vec4_copy(grp, "ucolor", color); shape = DRW_cache_particles_get_prim(draw_as); DRW_shgroup_call_instances_with_attrs(grp, nullptr, shape, geom); break; diff --git a/source/blender/draw/engines/overlay/overlay_sculpt.cc b/source/blender/draw/engines/overlay/overlay_sculpt.cc index 8f142d68350..3377aa5394b 100644 --- a/source/blender/draw/engines/overlay/overlay_sculpt.cc +++ b/source/blender/draw/engines/overlay/overlay_sculpt.cc @@ -37,7 +37,7 @@ void OVERLAY_sculpt_cache_populate(OVERLAY_Data *vedata, Object *ob) struct GPUBatch *sculpt_overlays; PBVH *pbvh = ob->sculpt->pbvh; - const bool use_pbvh = BKE_sculptsession_use_pbvh_draw(ob, draw_ctx->v3d); + const bool use_pbvh = BKE_sculptsession_use_pbvh_draw(ob, draw_ctx->rv3d); if (!pbvh) { /* It is possible to have SculptSession without PBVH. This happens, for example, when toggling diff --git a/source/blender/draw/engines/overlay/overlay_sculpt_curves.cc b/source/blender/draw/engines/overlay/overlay_sculpt_curves.cc index 1bba2a366a5..68de5dcd11d 100644 --- a/source/blender/draw/engines/overlay/overlay_sculpt_curves.cc +++ b/source/blender/draw/engines/overlay/overlay_sculpt_curves.cc @@ -64,7 +64,7 @@ void OVERLAY_sculpt_curves_cache_populate(OVERLAY_Data *vedata, Object *object) ".selection_curve_float"; bool is_point_domain; - GPUTexture **texture = DRW_curves_texture_for_evaluated_attribute( + GPUVertBuf **texture = DRW_curves_texture_for_evaluated_attribute( curves, name, &is_point_domain); if (texture == nullptr) { return; @@ -78,7 +78,7 @@ void OVERLAY_sculpt_curves_cache_populate(OVERLAY_Data *vedata, Object *object) } DRW_shgroup_uniform_bool_copy(grp, "is_point_domain", is_point_domain); - DRW_shgroup_uniform_texture(grp, "selection_tx", *texture); + DRW_shgroup_buffer_texture(grp, "selection_tx", *texture); } void OVERLAY_sculpt_curves_draw(OVERLAY_Data *vedata) diff --git a/source/blender/draw/engines/overlay/overlay_viewer_attribute.cc b/source/blender/draw/engines/overlay/overlay_viewer_attribute.cc index d57ea08d888..fd1657b3d59 100644 --- a/source/blender/draw/engines/overlay/overlay_viewer_attribute.cc +++ b/source/blender/draw/engines/overlay/overlay_viewer_attribute.cc @@ -81,18 +81,16 @@ static void populate_cache_for_instance(Object &object, break; } case OB_POINTCLOUD: { - DRWShadingGroup *sub_grp = DRW_shgroup_create_sub( - pd.viewer_attribute_instance_pointcloud_grp); + DRWShadingGroup *sub_grp = DRW_shgroup_pointcloud_create_sub( + &object, pd.viewer_attribute_pointcloud_grp, nullptr); DRW_shgroup_uniform_vec4_copy(sub_grp, "ucolor", color); - GPUBatch *batch = DRW_cache_pointcloud_surface_get(&object); - DRW_shgroup_call_instance_range(sub_grp, &object, batch, 0, 0); break; } case OB_CURVES_LEGACY: { DRWShadingGroup *sub_grp = DRW_shgroup_create_sub(pd.viewer_attribute_instance_grp); DRW_shgroup_uniform_vec4_copy(sub_grp, "ucolor", color); GPUBatch *batch = DRW_cache_curve_edge_wire_get(&object); - DRW_shgroup_call_obmat(sub_grp, batch, object.obmat); + DRW_shgroup_call_obmat(sub_grp, batch, object.object_to_world); break; } case OB_CURVES: { @@ -123,9 +121,11 @@ static void populate_cache_for_geometry(Object &object, case OB_POINTCLOUD: { PointCloud *pointcloud = static_cast<PointCloud *>(object.data); if (pointcloud->attributes().contains(".viewer")) { - GPUBatch *batch = DRW_cache_pointcloud_surface_viewer_attribute_get(&object); - DRW_shgroup_uniform_float_copy(pd.viewer_attribute_pointcloud_grp, "opacity", opacity); - DRW_shgroup_call_instance_range(pd.viewer_attribute_pointcloud_grp, &object, batch, 0, 0); + GPUVertBuf **vertbuf = DRW_pointcloud_evaluated_attribute(pointcloud, ".viewer"); + DRWShadingGroup *grp = DRW_shgroup_pointcloud_create_sub( + &object, pd.viewer_attribute_pointcloud_grp, nullptr); + DRW_shgroup_uniform_float_copy(grp, "opacity", opacity); + DRW_shgroup_buffer_texture_ref(grp, "attribute_tx", vertbuf); } break; } @@ -135,7 +135,7 @@ static void populate_cache_for_geometry(Object &object, if (curves.attributes().contains(".viewer")) { GPUBatch *batch = DRW_cache_curve_edge_wire_viewer_attribute_get(&object); DRW_shgroup_uniform_float_copy(pd.viewer_attribute_curve_grp, "opacity", opacity); - DRW_shgroup_call_obmat(pd.viewer_attribute_curve_grp, batch, object.obmat); + DRW_shgroup_call_obmat(pd.viewer_attribute_curve_grp, batch, object.object_to_world); } break; } @@ -144,13 +144,13 @@ static void populate_cache_for_geometry(Object &object, const bke::CurvesGeometry &curves = bke::CurvesGeometry::wrap(curves_id->geometry); if (curves.attributes().contains(".viewer")) { bool is_point_domain; - GPUTexture **texture = DRW_curves_texture_for_evaluated_attribute( + GPUVertBuf **texture = DRW_curves_texture_for_evaluated_attribute( curves_id, ".viewer", &is_point_domain); DRWShadingGroup *grp = DRW_shgroup_curves_create_sub( &object, pd.viewer_attribute_curves_grp, nullptr); DRW_shgroup_uniform_float_copy(pd.viewer_attribute_curves_grp, "opacity", opacity); DRW_shgroup_uniform_bool_copy(grp, "is_point_domain", is_point_domain); - DRW_shgroup_uniform_texture(grp, "color_tx", *texture); + DRW_shgroup_buffer_texture(grp, "color_tx", *texture); } break; } diff --git a/source/blender/draw/engines/overlay/overlay_wireframe.cc b/source/blender/draw/engines/overlay/overlay_wireframe.cc index bff1bf46923..7053d0039cf 100644 --- a/source/blender/draw/engines/overlay/overlay_wireframe.cc +++ b/source/blender/draw/engines/overlay/overlay_wireframe.cc @@ -132,12 +132,12 @@ static void wireframe_hair_cache_populate(OVERLAY_Data *vedata, Object *ob, Part if (collection != nullptr) { sub_v3_v3(dupli_mat[3], collection->instance_offset); } - mul_m4_m4m4(dupli_mat, dupli_parent->obmat, dupli_mat); + mul_m4_m4m4(dupli_mat, dupli_parent->object_to_world, dupli_mat); } else { - copy_m4_m4(dupli_mat, dupli_object->ob->obmat); + copy_m4_m4(dupli_mat, dupli_object->ob->object_to_world); invert_m4(dupli_mat); - mul_m4_m4m4(dupli_mat, ob->obmat, dupli_mat); + mul_m4_m4m4(dupli_mat, ob->object_to_world, dupli_mat); } } else { @@ -217,7 +217,7 @@ void OVERLAY_wireframe_cache_populate(OVERLAY_Data *vedata, } if (geom) { - OVERLAY_extra_wire(cb, geom, ob->obmat, color); + OVERLAY_extra_wire(cb, geom, ob->object_to_world, color); } } @@ -230,12 +230,12 @@ void OVERLAY_wireframe_cache_populate(OVERLAY_Data *vedata, if (dupli->wire_shgrp == cb->extra_loose_points) { float *color; DRW_object_wire_theme_get(ob, draw_ctx->view_layer, &color); - OVERLAY_extra_loose_points(cb, dupli->wire_geom, ob->obmat, color); + OVERLAY_extra_loose_points(cb, dupli->wire_geom, ob->object_to_world, color); } else if (dupli->wire_shgrp == cb->extra_wire) { float *color; DRW_object_wire_theme_get(ob, draw_ctx->view_layer, &color); - OVERLAY_extra_wire(cb, dupli->wire_geom, ob->obmat, color); + OVERLAY_extra_wire(cb, dupli->wire_geom, ob->object_to_world, color); } else { DRW_shgroup_call(dupli->wire_shgrp, dupli->wire_geom, ob); @@ -264,7 +264,7 @@ void OVERLAY_wireframe_cache_populate(OVERLAY_Data *vedata, struct GPUBatch *geom = DRW_cache_object_face_wireframe_get(ob); if (geom) { - OVERLAY_extra_loose_points(cb, geom, ob->obmat, color); + OVERLAY_extra_loose_points(cb, geom, ob->object_to_world, color); } return; } @@ -276,7 +276,7 @@ void OVERLAY_wireframe_cache_populate(OVERLAY_Data *vedata, /* Don't do that in edit Mesh mode, unless there is a modifier preview. */ if (use_wire && (!is_mesh || (!is_edit_mode || has_edit_mesh_cage))) { const bool is_sculpt_mode = ((ob->mode & OB_MODE_SCULPT) != 0) && (ob->sculpt != nullptr); - const bool use_sculpt_pbvh = BKE_sculptsession_use_pbvh_draw(ob, draw_ctx->v3d) && + const bool use_sculpt_pbvh = BKE_sculptsession_use_pbvh_draw(ob, draw_ctx->rv3d) && !DRW_state_is_image_render(); const bool is_instance = (ob->base_flag & BASE_FROM_DUPLI); const bool instance_parent_in_edit_mode = is_instance ? DRW_object_is_in_edit_mode( @@ -318,14 +318,14 @@ void OVERLAY_wireframe_cache_populate(OVERLAY_Data *vedata, if (is_mesh_verts_only) { geom = DRW_cache_mesh_all_verts_get(ob); if (geom) { - OVERLAY_extra_loose_points(cb, geom, ob->obmat, color); + OVERLAY_extra_loose_points(cb, geom, ob->object_to_world, color); shgrp = cb->extra_loose_points; } } else { geom = DRW_cache_mesh_loose_edges_get(ob); if (geom) { - OVERLAY_extra_wire(cb, geom, ob->obmat, color); + OVERLAY_extra_wire(cb, geom, ob->object_to_world, color); shgrp = cb->extra_wire; } } diff --git a/source/blender/draw/engines/overlay/shaders/infos/overlay_viewer_attribute_info.hh b/source/blender/draw/engines/overlay/shaders/infos/overlay_viewer_attribute_info.hh index 20d4797b76f..6a0bd03f030 100644 --- a/source/blender/draw/engines/overlay/shaders/infos/overlay_viewer_attribute_info.hh +++ b/source/blender/draw/engines/overlay/shaders/infos/overlay_viewer_attribute_info.hh @@ -27,7 +27,7 @@ GPU_SHADER_CREATE_INFO(overlay_viewer_attribute_pointcloud) .fragment_source("overlay_viewer_attribute_frag.glsl") .fragment_out(0, Type::VEC4, "out_color") .fragment_out(1, Type::VEC4, "lineOutput") - .vertex_in(3, Type::VEC4, "attribute_value") + .sampler(3, ImageType::FLOAT_BUFFER, "attribute_tx") .vertex_out(overlay_viewer_attribute_iface) .additional_info("overlay_viewer_attribute_common", "draw_pointcloud"); diff --git a/source/blender/draw/engines/overlay/shaders/overlay_motion_path_line_vert_no_geom.glsl b/source/blender/draw/engines/overlay/shaders/overlay_motion_path_line_vert_no_geom.glsl index e3ddeb5c6a4..abaa814a4dc 100644 --- a/source/blender/draw/engines/overlay/shaders/overlay_motion_path_line_vert_no_geom.glsl +++ b/source/blender/draw/engines/overlay/shaders/overlay_motion_path_line_vert_no_geom.glsl @@ -108,8 +108,8 @@ void main() vec3 in_pos0 = vertex_fetch_attribute(base_vertex_id, pos, vec3); vec3 in_pos1 = vertex_fetch_attribute(base_vertex_id + 1, pos, vec3); - vec4 out_pos0 = ProjectionMatrix * (ViewMatrix * vec4(in_pos0, 1.0)); - vec4 out_pos1 = ProjectionMatrix * (ViewMatrix * vec4(in_pos1, 1.0)); + vec4 out_pos0 = drw_view.winmat * (drw_view.viewmat * vec4(in_pos0, 1.0)); + vec4 out_pos1 = drw_view.winmat * (drw_view.viewmat * vec4(in_pos1, 1.0)); /* Final calculations required for Geometry Shader alternative. * We need to calculate values for each vertex position to correctly determine the final output @@ -130,28 +130,28 @@ void main() float line_size = float(lineThickness) * sizePixel; if (quad_vertex_id == 0) { - view_clipping_distances(out_pos0); + view_clipping_distances(out_pos0.xyz); interp.color = finalColor_geom[0]; t = edge_dir * (line_size * (is_persp ? out_pos0.w : 1.0)); gl_Position = out_pos0 + vec4(t, 0.0, 0.0); } else if (quad_vertex_id == 1 || quad_vertex_id == 3) { - view_clipping_distances(out_pos0); + view_clipping_distances(out_pos0.xyz); interp.color = finalColor_geom[0]; t = edge_dir * (line_size * (is_persp ? out_pos0.w : 1.0)); gl_Position = out_pos0 - vec4(t, 0.0, 0.0); } else if (quad_vertex_id == 2 || quad_vertex_id == 5) { - view_clipping_distances(out_pos1); + view_clipping_distances(out_pos1.xyz); interp.color = finalColor_geom[1]; t = edge_dir * (line_size * (is_persp ? out_pos1.w : 1.0)); gl_Position = out_pos1 + vec4(t, 0.0, 0.0); } else if (quad_vertex_id == 4) { - view_clipping_distances(out_pos1); + view_clipping_distances(out_pos1.xyz); interp.color = finalColor_geom[1]; t = edge_dir * (line_size * (is_persp ? out_pos1.w : 1.0)); diff --git a/source/blender/draw/engines/overlay/shaders/overlay_outline_prepass_gpencil_vert.glsl b/source/blender/draw/engines/overlay/shaders/overlay_outline_prepass_gpencil_vert.glsl index 7d8fb0c2cb8..851e0884354 100644 --- a/source/blender/draw/engines/overlay/shaders/overlay_outline_prepass_gpencil_vert.glsl +++ b/source/blender/draw/engines/overlay/shaders/overlay_outline_prepass_gpencil_vert.glsl @@ -34,20 +34,7 @@ void main() float unused_strength; vec2 unused_uv; - gl_Position = gpencil_vertex(ma, - ma1, - ma2, - ma3, - pos, - pos1, - pos2, - pos3, - uv1, - uv2, - col1, - col2, - fcol1, - vec4(sizeViewport, sizeViewportInv), + gl_Position = gpencil_vertex(vec4(sizeViewport, sizeViewportInv), world_pos, unused_N, unused_color, diff --git a/source/blender/draw/engines/overlay/shaders/overlay_viewer_attribute_pointcloud_vert.glsl b/source/blender/draw/engines/overlay/shaders/overlay_viewer_attribute_pointcloud_vert.glsl index e706e8f9033..e7b7cafd898 100644 --- a/source/blender/draw/engines/overlay/shaders/overlay_viewer_attribute_pointcloud_vert.glsl +++ b/source/blender/draw/engines/overlay/shaders/overlay_viewer_attribute_pointcloud_vert.glsl @@ -6,5 +6,5 @@ void main() { vec3 world_pos = pointcloud_get_pos(); gl_Position = point_world_to_ndc(world_pos); - finalColor = attribute_value; + finalColor = pointcloud_get_customdata_vec4(attribute_tx); } diff --git a/source/blender/draw/engines/select/select_engine.c b/source/blender/draw/engines/select/select_engine.c index 026a1f52ac1..07e2a42b808 100644 --- a/source/blender/draw/engines/select/select_engine.c +++ b/source/blender/draw/engines/select/select_engine.c @@ -205,7 +205,7 @@ static void select_cache_populate(void *vedata, Object *ob) struct Mesh *me = ob->data; if (e_data.context.select_mode & SCE_SELECT_FACE) { struct GPUBatch *geom_faces = DRW_mesh_batch_cache_get_triangles_with_select_id(me); - DRW_shgroup_call_obmat(stl->g_data->shgrp_depth_only, geom_faces, ob->obmat); + DRW_shgroup_call_obmat(stl->g_data->shgrp_depth_only, geom_faces, ob->object_to_world); } else if (ob->dt >= OB_SOLID) { #ifdef USE_CAGE_OCCLUSION @@ -213,17 +213,17 @@ static void select_cache_populate(void *vedata, Object *ob) #else struct GPUBatch *geom_faces = DRW_mesh_batch_cache_get_surface(me); #endif - DRW_shgroup_call_obmat(stl->g_data->shgrp_depth_only, geom_faces, ob->obmat); + DRW_shgroup_call_obmat(stl->g_data->shgrp_depth_only, geom_faces, ob->object_to_world); } if (e_data.context.select_mode & SCE_SELECT_EDGE) { struct GPUBatch *geom_edges = DRW_mesh_batch_cache_get_edges_with_select_id(me); - DRW_shgroup_call_obmat(stl->g_data->shgrp_depth_only, geom_edges, ob->obmat); + DRW_shgroup_call_obmat(stl->g_data->shgrp_depth_only, geom_edges, ob->object_to_world); } if (e_data.context.select_mode & SCE_SELECT_VERTEX) { struct GPUBatch *geom_verts = DRW_mesh_batch_cache_get_verts_with_select_id(me); - DRW_shgroup_call_obmat(stl->g_data->shgrp_depth_only, geom_verts, ob->obmat); + DRW_shgroup_call_obmat(stl->g_data->shgrp_depth_only, geom_verts, ob->object_to_world); } return; } @@ -231,7 +231,7 @@ static void select_cache_populate(void *vedata, Object *ob) float min[3], max[3]; select_id_object_min_max(ob, min, max); - if (DRW_culling_min_max_test(stl->g_data->view_subregion, ob->obmat, min, max)) { + if (DRW_culling_min_max_test(stl->g_data->view_subregion, ob->object_to_world, min, max)) { if (sel_data == NULL) { sel_data = (SELECTID_ObjectData *)DRW_drawdata_ensure( &ob->id, &draw_engine_select_type, sizeof(SELECTID_ObjectData), NULL, NULL); diff --git a/source/blender/draw/engines/workbench/workbench_engine.c b/source/blender/draw/engines/workbench/workbench_engine.c index fecdad5802c..15a16539a26 100644 --- a/source/blender/draw/engines/workbench/workbench_engine.c +++ b/source/blender/draw/engines/workbench/workbench_engine.c @@ -27,6 +27,7 @@ #include "DNA_mesh_types.h" #include "DNA_modifier_types.h" #include "DNA_node_types.h" +#include "DNA_pointcloud_types.h" #include "ED_paint.h" @@ -266,7 +267,7 @@ static eV3DShadingColorType workbench_color_type_get(WORKBENCH_PrivateData *wpd, const DRWContextState *draw_ctx = DRW_context_state_get(); const bool is_active = (ob == draw_ctx->obact); - const bool is_sculpt_pbvh = BKE_sculptsession_use_pbvh_draw(ob, draw_ctx->v3d) && + const bool is_sculpt_pbvh = BKE_sculptsession_use_pbvh_draw(ob, draw_ctx->rv3d) && !DRW_state_is_image_render(); const bool is_render = DRW_state_is_image_render() && (draw_ctx->v3d == NULL); const bool is_texpaint_mode = is_active && (wpd->ctx_mode == CTX_MODE_PAINT_TEXTURE); @@ -418,7 +419,7 @@ void workbench_cache_populate(void *ved, Object *ob) return; } - if (ELEM(ob->type, OB_MESH, OB_POINTCLOUD)) { + if (ob->type == OB_MESH) { 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); @@ -442,6 +443,12 @@ void workbench_cache_populate(void *ved, Object *ob) DRWShadingGroup *grp = workbench_material_hair_setup(wpd, ob, CURVES_MATERIAL_NR, color_type); DRW_shgroup_curves_create_sub(ob, grp, NULL); } + else if (ob->type == OB_POINTCLOUD) { + int color_type = workbench_color_type_get(wpd, ob, NULL, NULL, NULL); + DRWShadingGroup *grp = workbench_material_ptcloud_setup( + wpd, ob, POINTCLOUD_MATERIAL_NR, color_type); + DRW_shgroup_pointcloud_create_sub(ob, grp, NULL); + } else if (ob->type == OB_VOLUME) { if (wpd->shading.type != OB_WIRE) { int color_type = workbench_color_type_get(wpd, ob, NULL, NULL, NULL); diff --git a/source/blender/draw/engines/workbench/workbench_private.h b/source/blender/draw/engines/workbench/workbench_private.h index 492bce1e571..4aedaf443b9 100644 --- a/source/blender/draw/engines/workbench/workbench_private.h +++ b/source/blender/draw/engines/workbench/workbench_private.h @@ -511,6 +511,11 @@ DRWShadingGroup *workbench_image_setup_ex(WORKBENCH_PrivateData *wpd, #define workbench_image_hair_setup(wpd, ob, mat_nr, ima, iuser, interp) \ workbench_image_setup_ex(wpd, ob, mat_nr, ima, iuser, interp, WORKBENCH_DATATYPE_HAIR) +#define workbench_material_ptcloud_setup(wpd, ob, mat_nr, color_type) \ + workbench_material_setup_ex(wpd, ob, mat_nr, color_type, WORKBENCH_DATATYPE_POINTCLOUD, 0) +#define workbench_image_ptcloud_setup(wpd, ob, mat_nr, ima, iuser, interp) \ + workbench_image_setup_ex(wpd, ob, mat_nr, ima, iuser, interp, WORKBENCH_DATATYPE_POINTCLOUD) + /* workbench_data.c */ void workbench_private_data_alloc(WORKBENCH_StorageList *stl); diff --git a/source/blender/draw/engines/workbench/workbench_shadow.c b/source/blender/draw/engines/workbench/workbench_shadow.c index 0b34e849049..eb4d546648a 100644 --- a/source/blender/draw/engines/workbench/workbench_shadow.c +++ b/source/blender/draw/engines/workbench/workbench_shadow.c @@ -172,7 +172,7 @@ static const BoundBox *workbench_shadow_object_shadow_bbox_get(WORKBENCH_Private { if (oed->shadow_bbox_dirty || wpd->shadow_changed) { float tmp_mat[4][4]; - mul_m4_m4m4(tmp_mat, wpd->shadow_inv, ob->obmat); + mul_m4_m4m4(tmp_mat, wpd->shadow_inv, ob->object_to_world); /* Get AABB in shadow space. */ INIT_MINMAX(oed->shadow_min, oed->shadow_max); diff --git a/source/blender/draw/engines/workbench/workbench_volume.c b/source/blender/draw/engines/workbench/workbench_volume.c index ce7773e7439..7c6df93f5a3 100644 --- a/source/blender/draw/engines/workbench/workbench_volume.c +++ b/source/blender/draw/engines/workbench/workbench_volume.c @@ -237,7 +237,7 @@ static void workbench_volume_object_cache_populate(WORKBENCH_Data *vedata, /* Combined texture to object, and object to world transform. */ float texture_to_world[4][4]; - mul_m4_m4m4(texture_to_world, ob->obmat, grid->texture_to_object); + mul_m4_m4m4(texture_to_world, ob->object_to_world, grid->texture_to_object); if (use_slice) { float invviewmat[4][4]; @@ -291,7 +291,7 @@ static void workbench_volume_object_cache_populate(WORKBENCH_Data *vedata, /* Compute density scale. */ const float density_scale = volume->display.density * - BKE_volume_density_scale(volume, ob->obmat); + BKE_volume_density_scale(volume, ob->object_to_world); DRW_shgroup_uniform_texture(grp, "densityTexture", grid->texture); /* TODO: implement shadow texture, see manta_smoke_calc_transparency. */ diff --git a/source/blender/draw/intern/draw_cache.c b/source/blender/draw/intern/draw_cache.c index 8c6a51442e1..00ac2563c43 100644 --- a/source/blender/draw/intern/draw_cache.c +++ b/source/blender/draw/intern/draw_cache.c @@ -899,8 +899,6 @@ GPUBatch *DRW_cache_object_surface_get(Object *ob) switch (ob->type) { case OB_MESH: return DRW_cache_mesh_surface_get(ob); - case OB_POINTCLOUD: - return DRW_cache_pointcloud_surface_get(ob); default: return NULL; } @@ -959,8 +957,6 @@ GPUBatch **DRW_cache_object_surface_material_get(struct Object *ob, switch (ob->type) { case OB_MESH: return DRW_cache_mesh_surface_shaded_get(ob, gpumat_array, gpumat_array_len); - case OB_POINTCLOUD: - return DRW_cache_pointcloud_surface_shaded_get(ob, gpumat_array, gpumat_array_len); default: return NULL; } @@ -3006,24 +3002,6 @@ GPUBatch *DRW_cache_lattice_vert_overlay_get(Object *ob) /** \name PointCloud * \{ */ -GPUBatch *DRW_cache_pointcloud_get_dots(Object *object) -{ - BLI_assert(object->type == OB_POINTCLOUD); - return DRW_pointcloud_batch_cache_get_dots(object); -} - -GPUBatch *DRW_cache_pointcloud_surface_get(Object *object) -{ - BLI_assert(object->type == OB_POINTCLOUD); - return DRW_pointcloud_batch_cache_get_surface(object); -} - -GPUBatch *DRW_cache_pointcloud_surface_viewer_attribute_get(Object *object) -{ - BLI_assert(object->type == OB_POINTCLOUD); - return DRW_pointcloud_batch_cache_get_surface_viewer_attribute(object); -} - /** \} */ /* -------------------------------------------------------------------- */ @@ -3308,6 +3286,9 @@ void drw_batch_cache_generate_requested(Object *ob) case OB_CURVES: DRW_curves_batch_cache_create_requested(ob); break; + case OB_POINTCLOUD: + DRW_pointcloud_batch_cache_create_requested(ob); + break; /* TODO: all cases. */ default: break; @@ -3358,7 +3339,9 @@ void DRW_batch_cache_free_old(Object *ob, int ctime) case OB_CURVES: DRW_curves_batch_cache_free_old((Curves *)ob->data, ctime); break; - /* TODO: all cases. */ + case OB_POINTCLOUD: + DRW_pointcloud_batch_cache_free_old((PointCloud *)ob->data, ctime); + break; default: break; } diff --git a/source/blender/draw/intern/draw_cache.h b/source/blender/draw/intern/draw_cache.h index 058f28f094d..772cf3b12a5 100644 --- a/source/blender/draw/intern/draw_cache.h +++ b/source/blender/draw/intern/draw_cache.h @@ -13,6 +13,7 @@ extern "C" { struct GPUBatch; struct GPUMaterial; +struct GPUVertBuf; struct ModifierData; struct Object; struct PTCacheEdit; @@ -224,12 +225,6 @@ struct GPUBatch **DRW_cache_curves_surface_shaded_get(struct Object *ob, struct GPUBatch *DRW_cache_curves_face_wireframe_get(struct Object *ob); struct GPUBatch *DRW_cache_curves_edge_detection_get(struct Object *ob, bool *r_is_manifold); -/* PointCloud */ - -struct GPUBatch *DRW_cache_pointcloud_get_dots(struct Object *obj); -struct GPUBatch *DRW_cache_pointcloud_surface_get(struct Object *obj); -struct GPUBatch *DRW_cache_pointcloud_surface_viewer_attribute_get(struct Object *obj); - /* Volume */ typedef struct DRWVolumeGrid { @@ -257,14 +252,17 @@ struct GPUBatch *DRW_cache_volume_selection_surface_get(struct Object *ob); /* GPencil */ -struct GPUBatch *DRW_cache_gpencil_strokes_get(struct Object *ob, int cfra); -struct GPUBatch *DRW_cache_gpencil_fills_get(struct Object *ob, int cfra); +struct GPUBatch *DRW_cache_gpencil_get(struct Object *ob, int cfra); +struct GPUVertBuf *DRW_cache_gpencil_position_buffer_get(struct Object *ob, int cfra); +struct GPUVertBuf *DRW_cache_gpencil_color_buffer_get(struct Object *ob, int cfra); struct GPUBatch *DRW_cache_gpencil_edit_lines_get(struct Object *ob, int cfra); struct GPUBatch *DRW_cache_gpencil_edit_points_get(struct Object *ob, int cfra); struct GPUBatch *DRW_cache_gpencil_edit_curve_handles_get(struct Object *ob, int cfra); struct GPUBatch *DRW_cache_gpencil_edit_curve_points_get(struct Object *ob, int cfra); -struct GPUBatch *DRW_cache_gpencil_sbuffer_stroke_get(struct Object *ob); -struct GPUBatch *DRW_cache_gpencil_sbuffer_fill_get(struct Object *ob); +struct GPUBatch *DRW_cache_gpencil_sbuffer_get(struct Object *ob, bool show_fill); +struct GPUVertBuf *DRW_cache_gpencil_sbuffer_position_buffer_get(struct Object *ob, + bool show_fill); +struct GPUVertBuf *DRW_cache_gpencil_sbuffer_color_buffer_get(struct Object *ob, bool show_fill); int DRW_gpencil_material_count_get(struct bGPdata *gpd); struct GPUBatch *DRW_cache_gpencil_face_wireframe_get(struct Object *ob); diff --git a/source/blender/draw/intern/draw_cache_impl.h b/source/blender/draw/intern/draw_cache_impl.h index c6e8539121f..5aa2203ca68 100644 --- a/source/blender/draw/intern/draw_cache_impl.h +++ b/source/blender/draw/intern/draw_cache_impl.h @@ -80,6 +80,7 @@ void DRW_batch_cache_free_old(struct Object *ob, int ctime); */ void DRW_mesh_batch_cache_free_old(struct Mesh *me, int ctime); void DRW_curves_batch_cache_free_old(struct Curves *curves, int ctime); +void DRW_pointcloud_batch_cache_free_old(struct PointCloud *pointcloud, int ctime); /** \} */ @@ -131,7 +132,7 @@ int DRW_curves_material_count_get(struct Curves *curves); * \return A pointer to location where the texture will be * stored, which will be filled by #DRW_shgroup_curves_create_sub. */ -struct GPUTexture **DRW_curves_texture_for_evaluated_attribute(struct Curves *curves, +struct GPUVertBuf **DRW_curves_texture_for_evaluated_attribute(struct Curves *curves, const char *name, bool *r_is_point_domain); @@ -147,12 +148,11 @@ void DRW_curves_batch_cache_create_requested(struct Object *ob); int DRW_pointcloud_material_count_get(struct PointCloud *pointcloud); +struct GPUVertBuf **DRW_pointcloud_evaluated_attribute(struct PointCloud *pointcloud, + const char *name); struct GPUBatch *DRW_pointcloud_batch_cache_get_dots(struct Object *ob); -struct GPUBatch *DRW_pointcloud_batch_cache_get_surface(struct Object *ob); -struct GPUBatch *DRW_pointcloud_batch_cache_get_surface_viewer_attribute(struct Object *ob); -struct GPUBatch **DRW_cache_pointcloud_surface_shaded_get(struct Object *ob, - struct GPUMaterial **gpumat_array, - uint gpumat_array_len); + +void DRW_pointcloud_batch_cache_create_requested(struct Object *ob); /** \} */ diff --git a/source/blender/draw/intern/draw_cache_impl_curves.cc b/source/blender/draw/intern/draw_cache_impl_curves.cc index 85dd9ca8695..c36b90ec32e 100644 --- a/source/blender/draw/intern/draw_cache_impl_curves.cc +++ b/source/blender/draw/intern/draw_cache_impl_curves.cc @@ -88,13 +88,11 @@ static void curves_discard_attributes(CurvesEvalCache &curves_cache) { for (const int i : IndexRange(GPU_MAX_ATTR)) { GPU_VERTBUF_DISCARD_SAFE(curves_cache.proc_attributes_buf[i]); - DRW_TEXTURE_FREE_SAFE(curves_cache.proc_attributes_tex[i]); } for (const int i : IndexRange(MAX_HAIR_SUBDIV)) { for (const int j : IndexRange(GPU_MAX_ATTR)) { GPU_VERTBUF_DISCARD_SAFE(curves_cache.final[i].attributes_buf[j]); - DRW_TEXTURE_FREE_SAFE(curves_cache.final[i].attributes_tex[j]); } drw_attributes_clear(&curves_cache.final[i].attr_used); @@ -107,17 +105,12 @@ static void curves_batch_cache_clear_data(CurvesEvalCache &curves_cache) GPU_VERTBUF_DISCARD_SAFE(curves_cache.proc_point_buf); GPU_VERTBUF_DISCARD_SAFE(curves_cache.proc_length_buf); GPU_VERTBUF_DISCARD_SAFE(curves_cache.data_edit_points); - DRW_TEXTURE_FREE_SAFE(curves_cache.point_tex); - DRW_TEXTURE_FREE_SAFE(curves_cache.length_tex); GPU_VERTBUF_DISCARD_SAFE(curves_cache.proc_strand_buf); GPU_VERTBUF_DISCARD_SAFE(curves_cache.proc_strand_seg_buf); - DRW_TEXTURE_FREE_SAFE(curves_cache.strand_tex); - DRW_TEXTURE_FREE_SAFE(curves_cache.strand_seg_tex); for (const int i : IndexRange(MAX_HAIR_SUBDIV)) { GPU_VERTBUF_DISCARD_SAFE(curves_cache.final[i].proc_buf); - DRW_TEXTURE_FREE_SAFE(curves_cache.final[i].proc_tex); for (const int j : IndexRange(MAX_THICKRES)) { GPU_BATCH_DISCARD_SAFE(curves_cache.final[i].proc_hairs[j]); } @@ -286,21 +279,6 @@ static void curves_batch_cache_ensure_procedural_pos(const Curves &curves, cache.strands_len}; curves_batch_cache_fill_segments_proc_pos(curves, posTime_data, hairLength_data); - - /* Create vbo immediately to bind to texture buffer. */ - GPU_vertbuf_use(cache.proc_point_buf); - cache.point_tex = GPU_texture_create_from_vertbuf("hair_point", cache.proc_point_buf); - } - - if (gpu_material && cache.proc_length_buf != nullptr && cache.length_tex) { - ListBase gpu_attrs = GPU_material_attributes(gpu_material); - LISTBASE_FOREACH (GPUMaterialAttribute *, attr, &gpu_attrs) { - if (attr->type == CD_HAIRLENGTH) { - GPU_vertbuf_use(cache.proc_length_buf); - cache.length_tex = GPU_texture_create_from_vertbuf("hair_length", cache.proc_length_buf); - break; - } - } } } @@ -363,12 +341,6 @@ static void curves_batch_cache_ensure_procedural_final_attr(CurvesEvalCache &cac /* Those are points! not line segments. */ GPU_vertbuf_data_alloc(final_cache.attributes_buf[index], final_cache.strands_res * cache.strands_len); - - /* Create vbo immediately to bind to texture buffer. */ - GPU_vertbuf_use(final_cache.attributes_buf[index]); - - final_cache.attributes_tex[index] = GPU_texture_create_from_vertbuf( - name, final_cache.attributes_buf[index]); } static void curves_batch_ensure_attribute(const Curves &curves, @@ -379,7 +351,6 @@ static void curves_batch_ensure_attribute(const Curves &curves, { using namespace blender; GPU_VERTBUF_DISCARD_SAFE(cache.proc_attributes_buf[index]); - DRW_TEXTURE_FREE_SAFE(cache.proc_attributes_tex[index]); char sampler_name[32]; drw_curves_get_attribute_sampler_name(request.attribute_name, sampler_name); @@ -414,13 +385,9 @@ static void curves_batch_ensure_attribute(const Curves &curves, attribute.materialize(vbo_span); - GPU_vertbuf_use(attr_vbo); - cache.proc_attributes_tex[index] = GPU_texture_create_from_vertbuf(sampler_name, attr_vbo); - /* Existing final data may have been for a different attribute (with a different name or domain), * free the data. */ GPU_VERTBUF_DISCARD_SAFE(cache.final[subdiv].attributes_buf[index]); - DRW_TEXTURE_FREE_SAFE(cache.final[subdiv].attributes_tex[index]); /* Ensure final data for points. */ if (request.domain == ATTR_DOMAIN_POINT) { @@ -466,19 +433,11 @@ static void curves_batch_cache_ensure_procedural_strand_data(Curves &curves, GPU_vertbuf_attr_get_raw_data(cache.proc_strand_seg_buf, seg_id, &seg_step); curves_batch_cache_fill_strands_data(curves, data_step, seg_step); - - /* Create vbo immediately to bind to texture buffer. */ - GPU_vertbuf_use(cache.proc_strand_buf); - cache.strand_tex = GPU_texture_create_from_vertbuf("curves_strand", cache.proc_strand_buf); - - GPU_vertbuf_use(cache.proc_strand_seg_buf); - cache.strand_seg_tex = GPU_texture_create_from_vertbuf("curves_strand_seg", - cache.proc_strand_seg_buf); } static void curves_batch_cache_ensure_procedural_final_points(CurvesEvalCache &cache, int subdiv) { - /* Same format as point_tex. */ + /* Same format as proc_point_buf. */ GPUVertFormat format = {0}; GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 4, GPU_FETCH_FLOAT); @@ -489,12 +448,6 @@ static void curves_batch_cache_ensure_procedural_final_points(CurvesEvalCache &c /* Those are points! not line segments. */ GPU_vertbuf_data_alloc(cache.final[subdiv].proc_buf, cache.final[subdiv].strands_res * cache.strands_len); - - /* Create vbo immediately to bind to texture buffer. */ - GPU_vertbuf_use(cache.final[subdiv].proc_buf); - - cache.final[subdiv].proc_tex = GPU_texture_create_from_vertbuf("hair_proc", - cache.final[subdiv].proc_buf); } static void curves_batch_cache_fill_segments_indices(const Curves &curves, @@ -583,7 +536,6 @@ static bool curves_ensure_attributes(const Curves &curves, /* Some new attributes have been added, free all and start over. */ for (const int i : IndexRange(GPU_MAX_ATTR)) { GPU_VERTBUF_DISCARD_SAFE(cache.curves_cache.proc_attributes_buf[i]); - DRW_TEXTURE_FREE_SAFE(cache.curves_cache.proc_attributes_tex[i]); } drw_attributes_merge(&final_cache.attr_used, &attrs_needed, cache.render_mutex); } @@ -631,7 +583,7 @@ bool curves_ensure_procedural_data(Curves *curves, } /* Refreshed if active layer or custom data changes. */ - if ((*r_hair_cache)->strand_tex == nullptr) { + if ((*r_hair_cache)->proc_strand_buf == nullptr) { curves_batch_cache_ensure_procedural_strand_data(*curves, cache.curves_cache); } @@ -689,7 +641,7 @@ static void request_attribute(Curves &curves, const char *name) drw_attributes_merge(&final_cache.attr_used, &attributes, cache.render_mutex); } -GPUTexture **DRW_curves_texture_for_evaluated_attribute(Curves *curves, +GPUVertBuf **DRW_curves_texture_for_evaluated_attribute(Curves *curves, const char *name, bool *r_is_point_domain) { @@ -715,10 +667,10 @@ GPUTexture **DRW_curves_texture_for_evaluated_attribute(Curves *curves, switch (final_cache.attr_used.requests[request_i].domain) { case ATTR_DOMAIN_POINT: *r_is_point_domain = true; - return &final_cache.attributes_tex[request_i]; + return &final_cache.attributes_buf[request_i]; case ATTR_DOMAIN_CURVE: *r_is_point_domain = false; - return &cache.curves_cache.proc_attributes_tex[request_i]; + return &cache.curves_cache.proc_attributes_buf[request_i]; default: BLI_assert_unreachable(); return nullptr; diff --git a/source/blender/draw/intern/draw_cache_impl_gpencil.c b/source/blender/draw/intern/draw_cache_impl_gpencil.cc index 7a43c7ee2e6..3d6d2631186 100644 --- a/source/blender/draw/intern/draw_cache_impl_gpencil.c +++ b/source/blender/draw/intern/draw_cache_impl_gpencil.cc @@ -23,12 +23,14 @@ #include "DEG_depsgraph_query.h" #include "BLI_hash.h" +#include "BLI_math_vec_types.hh" #include "BLI_polyfill_2d.h" #include "draw_cache.h" #include "draw_cache_impl.h" #include "../engines/gpencil/gpencil_defines.h" +#include "../engines/gpencil/gpencil_shader_shared.h" #define BEZIER_HANDLE (1 << 3) #define COLOR_SHIFT 5 @@ -41,11 +43,13 @@ typedef struct GpencilBatchCache { /** Instancing Data */ GPUVertBuf *vbo; GPUVertBuf *vbo_col; - /** Fill Topology */ + /** Indices in material order, then stroke order with fill first. + * Strokes can be individually rendered using `gps->runtime.stroke_start` and + * `gps->runtime.fill_start`. */ GPUIndexBuf *ibo; - /** Instancing Batches */ - GPUBatch *stroke_batch; - GPUBatch *fill_batch; + /** Batches */ + GPUBatch *geom_batch; + /** Stroke lines only */ GPUBatch *lines_batch; /** Edit Mode */ @@ -97,7 +101,8 @@ static GpencilBatchCache *gpencil_batch_cache_init(Object *ob, int cfra) GpencilBatchCache *cache = gpd->runtime.gpencil_cache; if (!cache) { - cache = gpd->runtime.gpencil_cache = MEM_callocN(sizeof(*cache), __func__); + cache = gpd->runtime.gpencil_cache = (GpencilBatchCache *)MEM_callocN(sizeof(*cache), + __func__); } else { memset(cache, 0, sizeof(*cache)); @@ -116,8 +121,7 @@ static void gpencil_batch_cache_clear(GpencilBatchCache *cache) } GPU_BATCH_DISCARD_SAFE(cache->lines_batch); - GPU_BATCH_DISCARD_SAFE(cache->fill_batch); - GPU_BATCH_DISCARD_SAFE(cache->stroke_batch); + GPU_BATCH_DISCARD_SAFE(cache->geom_batch); GPU_VERTBUF_DISCARD_SAFE(cache->vbo); GPU_VERTBUF_DISCARD_SAFE(cache->vbo_col); GPU_INDEXBUF_DISCARD_SAFE(cache->ibo); @@ -172,9 +176,10 @@ void DRW_gpencil_batch_cache_free(bGPdata *gpd) /* MUST match the format below. */ typedef struct gpStrokeVert { - int32_t mat, stroke_id, point_id, packed_asp_hard_rot; /** Position and thickness packed in the same attribute. */ float pos[3], thickness; + /** Material Index, Stroke Index, Point Index, Packed aspect + hardness + rotation. */ + int32_t mat, stroke_id, point_id, packed_asp_hard_rot; /** UV and strength packed in the same attribute. */ float uv_fill[2], u_stroke, strength; } gpStrokeVert; @@ -183,12 +188,9 @@ static GPUVertFormat *gpencil_stroke_format(void) { static GPUVertFormat format = {0}; if (format.attr_len == 0) { - GPU_vertformat_attr_add(&format, "ma", GPU_COMP_I32, 4, GPU_FETCH_INT); GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 4, GPU_FETCH_FLOAT); + GPU_vertformat_attr_add(&format, "ma", GPU_COMP_I32, 4, GPU_FETCH_INT); GPU_vertformat_attr_add(&format, "uv", GPU_COMP_F32, 4, GPU_FETCH_FLOAT); - /* IMPORTANT: This means having only 4 attributes - * to fit into GPU module limit of 16 attributes. */ - GPU_vertformat_multiload_enable(&format, 4); } return &format; } @@ -238,9 +240,6 @@ static GPUVertFormat *gpencil_color_format(void) if (format.attr_len == 0) { GPU_vertformat_attr_add(&format, "col", GPU_COMP_F32, 4, GPU_FETCH_FLOAT); GPU_vertformat_attr_add(&format, "fcol", GPU_COMP_F32, 4, GPU_FETCH_FLOAT); - /* IMPORTANT: This means having only 4 attributes - * to fit into GPU module limit of 16 attributes. */ - GPU_vertformat_multiload_enable(&format, 4); } return &format; } @@ -295,7 +294,8 @@ BLI_INLINE int32_t pack_rotation_aspect_hardness(float rot, float asp, float har return packed; } -static void gpencil_buffer_add_point(gpStrokeVert *verts, +static void gpencil_buffer_add_point(GPUIndexBufBuilder *ibo, + gpStrokeVert *verts, gpColorVert *cols, const bGPDstroke *gps, const bGPDspoint *pt, @@ -319,7 +319,7 @@ static void gpencil_buffer_add_point(gpStrokeVert *verts, vert->strength = (round_cap0) ? pt->strength : -pt->strength; vert->u_stroke = pt->uv_fac; - vert->stroke_id = gps->runtime.stroke_start; + vert->stroke_id = gps->runtime.vertex_start; vert->point_id = v; vert->thickness = max_ff(0.0f, gps->thickness * pt->pressure) * (round_cap1 ? 1.0f : -1.0f); /* Tag endpoint material to -1 so they get discarded by vertex shader. */ @@ -329,27 +329,36 @@ static void gpencil_buffer_add_point(gpStrokeVert *verts, vert->packed_asp_hard_rot = pack_rotation_aspect_hardness( pt->uv_rot, aspect_ratio, gps->hardeness); + + if (!is_endpoint) { + /* Issue a Quad per point. */ + /* The attribute loading uses a different shader and will undo this bit packing. */ + int v_mat = (v << GP_VERTEX_ID_SHIFT) | GP_IS_STROKE_VERTEX_BIT; + GPU_indexbuf_add_tri_verts(ibo, v_mat + 0, v_mat + 1, v_mat + 2); + GPU_indexbuf_add_tri_verts(ibo, v_mat + 2, v_mat + 1, v_mat + 3); + } } -static void gpencil_buffer_add_stroke(gpStrokeVert *verts, +static void gpencil_buffer_add_stroke(GPUIndexBufBuilder *ibo, + gpStrokeVert *verts, gpColorVert *cols, const bGPDstroke *gps) { const bGPDspoint *pts = gps->points; int pts_len = gps->totpoints; bool is_cyclic = gpencil_stroke_is_cyclic(gps); - int v = gps->runtime.stroke_start; + int v = gps->runtime.vertex_start; /* First point for adjacency (not drawn). */ int adj_idx = (is_cyclic) ? (pts_len - 1) : min_ii(pts_len - 1, 1); - gpencil_buffer_add_point(verts, cols, gps, &pts[adj_idx], v++, true); + gpencil_buffer_add_point(ibo, verts, cols, gps, &pts[adj_idx], v++, true); for (int i = 0; i < pts_len; i++) { - gpencil_buffer_add_point(verts, cols, gps, &pts[i], v++, false); + gpencil_buffer_add_point(ibo, verts, cols, gps, &pts[i], v++, false); } /* Draw line to first point to complete the loop for cyclic strokes. */ if (is_cyclic) { - gpencil_buffer_add_point(verts, cols, gps, &pts[0], v, false); + gpencil_buffer_add_point(ibo, verts, cols, gps, &pts[0], v, false); /* UV factor needs to be adjusted for the last point to not be equal to the UV factor of the * first point. It should be the factor of the last point plus the distance from the last point * to the first. @@ -360,16 +369,20 @@ static void gpencil_buffer_add_stroke(gpStrokeVert *verts, } /* Last adjacency point (not drawn). */ adj_idx = (is_cyclic) ? 1 : max_ii(0, pts_len - 2); - gpencil_buffer_add_point(verts, cols, gps, &pts[adj_idx], v++, true); + gpencil_buffer_add_point(ibo, verts, cols, gps, &pts[adj_idx], v++, true); } static void gpencil_buffer_add_fill(GPUIndexBufBuilder *ibo, const bGPDstroke *gps) { int tri_len = gps->tot_triangles; - int v = gps->runtime.stroke_start; + int v = gps->runtime.vertex_start + 1; for (int i = 0; i < tri_len; i++) { uint *tri = gps->triangles[i].verts; - GPU_indexbuf_add_tri_verts(ibo, v + tri[0], v + tri[1], v + tri[2]); + /* The attribute loading uses a different shader and will undo this bit packing. */ + GPU_indexbuf_add_tri_verts(ibo, + (v + tri[0]) << GP_VERTEX_ID_SHIFT, + (v + tri[1]) << GP_VERTEX_ID_SHIFT, + (v + tri[2]) << GP_VERTEX_ID_SHIFT); } } @@ -379,10 +392,10 @@ static void gpencil_stroke_iter_cb(bGPDlayer *UNUSED(gpl), void *thunk) { gpIterData *iter = (gpIterData *)thunk; - gpencil_buffer_add_stroke(iter->verts, iter->cols, gps); if (gps->tot_triangles > 0) { gpencil_buffer_add_fill(&iter->ibo, gps); } + gpencil_buffer_add_stroke(&iter->ibo, iter->verts, iter->cols, gps); } static void gpencil_object_verts_count_cb(bGPDlayer *UNUSED(gpl), @@ -391,12 +404,15 @@ static void gpencil_object_verts_count_cb(bGPDlayer *UNUSED(gpl), void *thunk) { gpIterData *iter = (gpIterData *)thunk; - - /* Store first index offset */ - gps->runtime.stroke_start = iter->vert_len; + int stroke_vert_len = gps->totpoints + gpencil_stroke_is_cyclic(gps); + gps->runtime.vertex_start = iter->vert_len; + /* Add additional padding at the start and end. */ + iter->vert_len += 1 + stroke_vert_len + 1; + /* Store first index offset. */ gps->runtime.fill_start = iter->tri_len; - iter->vert_len += gps->totpoints + 2 + gpencil_stroke_is_cyclic(gps); iter->tri_len += gps->tot_triangles; + gps->runtime.stroke_start = iter->tri_len; + iter->tri_len += stroke_vert_len * 2; } static void gpencil_batches_ensure(Object *ob, GpencilBatchCache *cache, int cfra) @@ -406,7 +422,7 @@ static void gpencil_batches_ensure(Object *ob, GpencilBatchCache *cache, int cfr if (cache->vbo == NULL) { /* Should be discarded together. */ BLI_assert(cache->vbo == NULL && cache->ibo == NULL); - BLI_assert(cache->fill_batch == NULL && cache->stroke_batch == NULL); + BLI_assert(cache->geom_batch == NULL); /* TODO/PERF: Could be changed to only do it if needed. * For now it's simpler to assume we always need it * since multiple viewport could or could not need it. @@ -415,29 +431,29 @@ static void gpencil_batches_ensure(Object *ob, GpencilBatchCache *cache, int cfr bool do_onion = true; /* First count how many vertices and triangles are needed for the whole object. */ - gpIterData iter = { - .gpd = gpd, - .verts = NULL, - .ibo = {0}, - .vert_len = 1, /* Start at 1 for the gl_InstanceID trick to work (see vert shader). */ - .tri_len = 0, - .curve_len = 0, - }; + gpIterData iter = {}; + iter.gpd = gpd; + iter.verts = NULL; + iter.ibo = {0}; + iter.vert_len = 0; + iter.tri_len = 0; + iter.curve_len = 0; BKE_gpencil_visible_stroke_advanced_iter( NULL, ob, NULL, gpencil_object_verts_count_cb, &iter, do_onion, cfra); + GPUUsageType vbo_flag = GPU_USAGE_STATIC | GPU_USAGE_FLAG_BUFFER_TEXTURE_ONLY; /* Create VBOs. */ GPUVertFormat *format = gpencil_stroke_format(); GPUVertFormat *format_col = gpencil_color_format(); - cache->vbo = GPU_vertbuf_create_with_format(format); - cache->vbo_col = GPU_vertbuf_create_with_format(format_col); + cache->vbo = GPU_vertbuf_create_with_format_ex(format, vbo_flag); + cache->vbo_col = GPU_vertbuf_create_with_format_ex(format_col, vbo_flag); /* Add extra space at the end of the buffer because of quad load. */ GPU_vertbuf_data_alloc(cache->vbo, iter.vert_len + 2); GPU_vertbuf_data_alloc(cache->vbo_col, iter.vert_len + 2); iter.verts = (gpStrokeVert *)GPU_vertbuf_get_data(cache->vbo); iter.cols = (gpColorVert *)GPU_vertbuf_get_data(cache->vbo_col); /* Create IBO. */ - GPU_indexbuf_init(&iter.ibo, GPU_PRIM_TRIS, iter.tri_len, iter.vert_len); + GPU_indexbuf_init(&iter.ibo, GPU_PRIM_TRIS, iter.tri_len, 0xFFFFFFFFu); /* Fill buffers with data. */ BKE_gpencil_visible_stroke_advanced_iter( @@ -452,33 +468,39 @@ static void gpencil_batches_ensure(Object *ob, GpencilBatchCache *cache, int cfr /* Finish the IBO. */ cache->ibo = GPU_indexbuf_build(&iter.ibo); - /* Create the batches */ - cache->fill_batch = GPU_batch_create(GPU_PRIM_TRIS, cache->vbo, cache->ibo); - GPU_batch_vertbuf_add(cache->fill_batch, cache->vbo_col); - cache->stroke_batch = GPU_batch_create(GPU_PRIM_TRI_STRIP, gpencil_dummy_buffer_get(), NULL); - GPU_batch_instbuf_add_ex(cache->stroke_batch, cache->vbo, 0); - GPU_batch_instbuf_add_ex(cache->stroke_batch, cache->vbo_col, 0); + cache->geom_batch = GPU_batch_create(GPU_PRIM_TRIS, cache->vbo, cache->ibo); + /* Allow creation of buffer texture. */ + GPU_vertbuf_use(cache->vbo); + GPU_vertbuf_use(cache->vbo_col); gpd->flag &= ~GP_DATA_CACHE_IS_DIRTY; cache->is_dirty = false; } } -GPUBatch *DRW_cache_gpencil_strokes_get(Object *ob, int cfra) +GPUBatch *DRW_cache_gpencil_get(Object *ob, int cfra) +{ + GpencilBatchCache *cache = gpencil_batch_cache_get(ob, cfra); + gpencil_batches_ensure(ob, cache, cfra); + + return cache->geom_batch; +} + +GPUVertBuf *DRW_cache_gpencil_position_buffer_get(Object *ob, int cfra) { GpencilBatchCache *cache = gpencil_batch_cache_get(ob, cfra); gpencil_batches_ensure(ob, cache, cfra); - return cache->stroke_batch; + return cache->vbo; } -GPUBatch *DRW_cache_gpencil_fills_get(Object *ob, int cfra) +GPUVertBuf *DRW_cache_gpencil_color_buffer_get(Object *ob, int cfra) { GpencilBatchCache *cache = gpencil_batch_cache_get(ob, cfra); gpencil_batches_ensure(ob, cache, cfra); - return cache->fill_batch; + return cache->vbo_col; } static void gpencil_lines_indices_cb(bGPDlayer *UNUSED(gpl), @@ -489,7 +511,7 @@ static void gpencil_lines_indices_cb(bGPDlayer *UNUSED(gpl), gpIterData *iter = (gpIterData *)thunk; int pts_len = gps->totpoints + gpencil_stroke_is_cyclic(gps); - int start = gps->runtime.stroke_start + 1; + int start = gps->runtime.vertex_start + 1; int end = start + pts_len; for (int i = start; i < end; i++) { GPU_indexbuf_add_generic_vert(&iter->ibo, i); @@ -508,10 +530,9 @@ GPUBatch *DRW_cache_gpencil_face_wireframe_get(Object *ob) if (cache->lines_batch == NULL) { GPUVertBuf *vbo = cache->vbo; - gpIterData iter = { - .gpd = ob->data, - .ibo = {0}, - }; + gpIterData iter = {}; + iter.gpd = (bGPdata *)ob->data; + iter.ibo = {0}; uint vert_len = GPU_vertbuf_get_vertex_len(vbo); GPU_indexbuf_init_ex(&iter.ibo, GPU_PRIM_LINE_STRIP, vert_len, vert_len); @@ -540,7 +561,7 @@ bGPDstroke *DRW_cache_gpencil_sbuffer_stroke_data_get(Object *ob) Brush *brush = gpd->runtime.sbuffer_brush; /* Convert the sbuffer to a bGPDstroke. */ if (gpd->runtime.sbuffer_gps == NULL) { - bGPDstroke *gps = MEM_callocN(sizeof(*gps), "bGPDstroke sbuffer"); + bGPDstroke *gps = (bGPDstroke *)MEM_callocN(sizeof(*gps), "bGPDstroke sbuffer"); gps->totpoints = gpd->runtime.sbuffer_used; gps->mat_nr = max_ii(0, gpd->runtime.matid - 1); gps->flag = gpd->runtime.sbuffer_sflag; @@ -553,7 +574,9 @@ bGPDstroke *DRW_cache_gpencil_sbuffer_stroke_data_get(Object *ob) gps->tot_triangles = max_ii(0, gpd->runtime.sbuffer_used - 2); gps->caps[0] = gps->caps[1] = GP_STROKE_CAP_ROUND; - gps->runtime.stroke_start = 1; /* Add one for the adjacency index. */ + gps->runtime.vertex_start = 0; + gps->runtime.fill_start = 0; + gps->runtime.stroke_start = 0; copy_v4_v4(gps->vert_color_fill, gpd->runtime.vert_color_fill); /* Caps. */ gps->caps[0] = gps->caps[1] = (short)brush->gpencil_settings->caps_type; @@ -563,17 +586,17 @@ bGPDstroke *DRW_cache_gpencil_sbuffer_stroke_data_get(Object *ob) return gpd->runtime.sbuffer_gps; } -static void gpencil_sbuffer_stroke_ensure(bGPdata *gpd, bool do_stroke, bool do_fill) +static void gpencil_sbuffer_stroke_ensure(bGPdata *gpd, bool do_fill) { - tGPspoint *tpoints = gpd->runtime.sbuffer; + tGPspoint *tpoints = (tGPspoint *)gpd->runtime.sbuffer; bGPDstroke *gps = gpd->runtime.sbuffer_gps; int vert_len = gpd->runtime.sbuffer_used; /* DRW_cache_gpencil_sbuffer_stroke_data_get need to have been called previously. */ BLI_assert(gps != NULL); - if (do_stroke && (gpd->runtime.sbuffer_stroke_batch == NULL)) { - gps->points = MEM_mallocN(vert_len * sizeof(*gps->points), __func__); + if (gpd->runtime.sbuffer_batch == NULL) { + gps->points = (bGPDspoint *)MEM_mallocN(vert_len * sizeof(*gps->points), __func__); const DRWContextState *draw_ctx = DRW_context_state_get(); Scene *scene = draw_ctx->scene; @@ -596,36 +619,25 @@ static void gpencil_sbuffer_stroke_ensure(bGPdata *gpd, bool do_stroke, bool do_ /* Calc uv data along the stroke. */ BKE_gpencil_stroke_uv_update(gps); + int tri_len = gps->tot_triangles + (gps->totpoints + gpencil_stroke_is_cyclic(gps)) * 2; + /* Create IBO. */ + GPUIndexBufBuilder ibo_builder; + GPU_indexbuf_init(&ibo_builder, GPU_PRIM_TRIS, tri_len, 0xFFFFFFFFu); /* Create VBO. */ + GPUUsageType vbo_flag = GPU_USAGE_STATIC | GPU_USAGE_FLAG_BUFFER_TEXTURE_ONLY; GPUVertFormat *format = gpencil_stroke_format(); GPUVertFormat *format_color = gpencil_color_format(); - GPUVertBuf *vbo = GPU_vertbuf_create_with_format(format); - GPUVertBuf *vbo_col = GPU_vertbuf_create_with_format(format_color); - /* Add extra space at the end (and start) of the buffer because of quad load and cyclic. */ + GPUVertBuf *vbo = GPU_vertbuf_create_with_format_ex(format, vbo_flag); + GPUVertBuf *vbo_col = GPU_vertbuf_create_with_format_ex(format_color, vbo_flag); + /* Add extra space at the start and end the buffer because of quad load and cyclic. */ GPU_vertbuf_data_alloc(vbo, 1 + vert_len + 1 + 2); GPU_vertbuf_data_alloc(vbo_col, 1 + vert_len + 1 + 2); gpStrokeVert *verts = (gpStrokeVert *)GPU_vertbuf_get_data(vbo); gpColorVert *cols = (gpColorVert *)GPU_vertbuf_get_data(vbo_col); - /* Fill buffers with data. */ - gpencil_buffer_add_stroke(verts, cols, gps); - - GPUBatch *batch = GPU_batch_create(GPU_PRIM_TRI_STRIP, gpencil_dummy_buffer_get(), NULL); - GPU_batch_instbuf_add_ex(batch, vbo, true); - GPU_batch_instbuf_add_ex(batch, vbo_col, true); - - gpd->runtime.sbuffer_stroke_batch = batch; - - MEM_freeN(gps->points); - } - - if (do_fill && (gpd->runtime.sbuffer_fill_batch == NULL)) { - /* Create IBO. */ - GPUIndexBufBuilder ibo_builder; - GPU_indexbuf_init(&ibo_builder, GPU_PRIM_TRIS, gps->tot_triangles, vert_len); - - if (gps->tot_triangles > 0) { - float(*tpoints2d)[2] = MEM_mallocN(sizeof(*tpoints2d) * vert_len, __func__); + /* Create fill indices. */ + if (do_fill && gps->tot_triangles > 0) { + float(*tpoints2d)[2] = (float(*)[2])MEM_mallocN(sizeof(*tpoints2d) * vert_len, __func__); /* Triangulate in 2D. */ for (int i = 0; i < vert_len; i++) { copy_v2_v2(tpoints2d[i], tpoints[i].m_xy); @@ -633,51 +645,72 @@ static void gpencil_sbuffer_stroke_ensure(bGPdata *gpd, bool do_stroke, bool do_ /* Compute directly inside the IBO data buffer. */ /* OPTI: This is a bottleneck if the stroke is very long. */ BLI_polyfill_calc(tpoints2d, (uint)vert_len, 0, (uint(*)[3])ibo_builder.data); - /* Add stroke start offset. */ + /* Add stroke start offset and shift. */ for (int i = 0; i < gps->tot_triangles * 3; i++) { - ibo_builder.data[i] += gps->runtime.stroke_start; + ibo_builder.data[i] = (ibo_builder.data[i] + 1) << GP_VERTEX_ID_SHIFT; } /* HACK since we didn't use the builder API to avoid another malloc and copy, * we need to set the number of indices manually. */ ibo_builder.index_len = gps->tot_triangles * 3; + ibo_builder.index_min = 0; + /* For this case, do not allow index compaction to avoid yet another preprocessing step. */ + ibo_builder.index_max = 0xFFFFFFFFu - 1u; + + gps->runtime.stroke_start = gps->tot_triangles; MEM_freeN(tpoints2d); } - GPUIndexBuf *ibo = GPU_indexbuf_build(&ibo_builder); - GPUVertBuf *vbo = gpd->runtime.sbuffer_stroke_batch->inst[0]; - GPUVertBuf *vbo_col = gpd->runtime.sbuffer_stroke_batch->inst[1]; + /* Fill buffers with data. */ + gpencil_buffer_add_stroke(&ibo_builder, verts, cols, gps); - GPUBatch *batch = GPU_batch_create_ex(GPU_PRIM_TRIS, vbo, ibo, GPU_BATCH_OWNS_INDEX); - GPU_batch_vertbuf_add(batch, vbo_col); + GPUBatch *batch = GPU_batch_create_ex(GPU_PRIM_TRIS, + gpencil_dummy_buffer_get(), + GPU_indexbuf_build(&ibo_builder), + GPU_BATCH_OWNS_INDEX); - gpd->runtime.sbuffer_fill_batch = batch; + gpd->runtime.sbuffer_position_buf = vbo; + gpd->runtime.sbuffer_color_buf = vbo_col; + gpd->runtime.sbuffer_batch = batch; + + MEM_freeN(gps->points); } } -GPUBatch *DRW_cache_gpencil_sbuffer_stroke_get(Object *ob) +GPUBatch *DRW_cache_gpencil_sbuffer_get(Object *ob, bool show_fill) { bGPdata *gpd = (bGPdata *)ob->data; - gpencil_sbuffer_stroke_ensure(gpd, true, false); + /* Fill batch also need stroke batch to be created (vbo is shared). */ + gpencil_sbuffer_stroke_ensure(gpd, show_fill); - return gpd->runtime.sbuffer_stroke_batch; + return gpd->runtime.sbuffer_batch; } -GPUBatch *DRW_cache_gpencil_sbuffer_fill_get(Object *ob) +GPUVertBuf *DRW_cache_gpencil_sbuffer_position_buffer_get(Object *ob, bool show_fill) { bGPdata *gpd = (bGPdata *)ob->data; /* Fill batch also need stroke batch to be created (vbo is shared). */ - gpencil_sbuffer_stroke_ensure(gpd, true, true); + gpencil_sbuffer_stroke_ensure(gpd, show_fill); - return gpd->runtime.sbuffer_fill_batch; + return gpd->runtime.sbuffer_position_buf; +} + +GPUVertBuf *DRW_cache_gpencil_sbuffer_color_buffer_get(Object *ob, bool show_fill) +{ + bGPdata *gpd = (bGPdata *)ob->data; + /* Fill batch also need stroke batch to be created (vbo is shared). */ + gpencil_sbuffer_stroke_ensure(gpd, show_fill); + + return gpd->runtime.sbuffer_color_buf; } void DRW_cache_gpencil_sbuffer_clear(Object *ob) { bGPdata *gpd = (bGPdata *)ob->data; MEM_SAFE_FREE(gpd->runtime.sbuffer_gps); - GPU_BATCH_DISCARD_SAFE(gpd->runtime.sbuffer_fill_batch); - GPU_BATCH_DISCARD_SAFE(gpd->runtime.sbuffer_stroke_batch); + GPU_BATCH_DISCARD_SAFE(gpd->runtime.sbuffer_batch); + GPU_VERTBUF_DISCARD_SAFE(gpd->runtime.sbuffer_position_buf); + GPU_VERTBUF_DISCARD_SAFE(gpd->runtime.sbuffer_color_buf); } /** \} */ @@ -728,7 +761,7 @@ static void gpencil_edit_stroke_iter_cb(bGPDlayer *gpl, { gpEditIterData *iter = (gpEditIterData *)thunk; const int v_len = gps->totpoints; - const int v = gps->runtime.stroke_start + 1; + const int v = gps->runtime.vertex_start + 1; MDeformVert *dvert = ((iter->vgindex > -1) && gps->dvert) ? gps->dvert : NULL; gpEditVert *vert_ptr = iter->verts + v; @@ -743,9 +776,12 @@ static void gpencil_edit_stroke_iter_cb(bGPDlayer *gpl, vert_ptr->weight = gpencil_point_edit_weight(dvert, i, iter->vgindex); vert_ptr++; } - /* Draw line to first point to complete the loop for cyclic strokes. */ - vert_ptr->vflag = sflag | gpencil_point_edit_flag(layer_lock, &gps->points[0], 0, v_len); - vert_ptr->weight = gpencil_point_edit_weight(dvert, 0, iter->vgindex); + + if (gpencil_stroke_is_cyclic(gps)) { + /* Draw line to first point to complete the loop for cyclic strokes. */ + vert_ptr->vflag = sflag | gpencil_point_edit_flag(layer_lock, &gps->points[0], 0, v_len); + vert_ptr->weight = gpencil_point_edit_weight(dvert, 0, iter->vgindex); + } } static void gpencil_edit_curve_stroke_count_cb(bGPDlayer *gpl, @@ -876,14 +912,13 @@ static void gpencil_edit_batches_ensure(Object *ob, GpencilBatchCache *cache, in /* Curve Handles and Points for Editing. */ if (cache->edit_curve_vbo == NULL) { - gpIterData iterdata = { - .gpd = gpd, - .verts = NULL, - .ibo = {0}, - .vert_len = 0, - .tri_len = 0, - .curve_len = 0, - }; + gpIterData iterdata = {}; + iterdata.gpd = gpd; + iterdata.verts = NULL; + iterdata.ibo = {0}; + iterdata.vert_len = 0; + iterdata.tri_len = 0; + iterdata.curve_len = 0; /* Create VBO. */ GPUVertFormat *format = gpencil_edit_curve_format(); diff --git a/source/blender/draw/intern/draw_cache_impl_mesh.cc b/source/blender/draw/intern/draw_cache_impl_mesh.cc index d3e071c14e7..031de3e4ef2 100644 --- a/source/blender/draw/intern/draw_cache_impl_mesh.cc +++ b/source/blender/draw/intern/draw_cache_impl_mesh.cc @@ -560,16 +560,7 @@ static bool mesh_batch_cache_valid(Object *object, Mesh *me) return false; } - if (object->sculpt && object->sculpt->pbvh) { - if (cache->pbvh_is_drawing != BKE_pbvh_is_drawing(object->sculpt->pbvh)) { - return false; - } - - if (BKE_pbvh_is_drawing(object->sculpt->pbvh) && - BKE_pbvh_draw_cache_invalid(object->sculpt->pbvh)) { - return false; - } - } + /* Note: PBVH draw data should not be checked here. */ if (cache->is_editmode != (me->edit_mesh != nullptr)) { return false; @@ -1443,7 +1434,6 @@ void DRW_mesh_batch_cache_create_requested(struct TaskGraph *task_graph, } } - /* Verify that all surface batches have needed attribute layers. */ /* TODO(fclem): We could be a bit smarter here and only do it per @@ -1486,7 +1476,8 @@ void DRW_mesh_batch_cache_create_requested(struct TaskGraph *task_graph, mesh_cd_layers_type_merge(&cache->cd_used_over_time, cache->cd_needed); mesh_cd_layers_type_clear(&cache->cd_needed); - drw_attributes_merge(&cache->attr_used_over_time, &cache->attr_needed, me->runtime->render_mutex); + drw_attributes_merge( + &cache->attr_used_over_time, &cache->attr_needed, me->runtime->render_mutex); drw_attributes_clear(&cache->attr_needed); } @@ -1898,7 +1889,7 @@ void DRW_mesh_batch_cache_create_requested(struct TaskGraph *task_graph, is_editmode, is_paint_mode, is_mode_active, - ob->obmat, + ob->object_to_world, false, true, scene, @@ -1915,7 +1906,7 @@ void DRW_mesh_batch_cache_create_requested(struct TaskGraph *task_graph, is_editmode, is_paint_mode, is_mode_active, - ob->obmat, + ob->object_to_world, false, false, scene, @@ -1931,7 +1922,7 @@ void DRW_mesh_batch_cache_create_requested(struct TaskGraph *task_graph, is_editmode, is_paint_mode, is_mode_active, - ob->obmat, + ob->object_to_world, true, false, do_cage, @@ -1952,7 +1943,7 @@ void DRW_mesh_batch_cache_create_requested(struct TaskGraph *task_graph, is_editmode, is_paint_mode, is_mode_active, - ob->obmat, + ob->object_to_world, true, false, scene, diff --git a/source/blender/draw/intern/draw_cache_impl_particles.c b/source/blender/draw/intern/draw_cache_impl_particles.c index 9c1784b1de2..8facea4333f 100644 --- a/source/blender/draw/intern/draw_cache_impl_particles.c +++ b/source/blender/draw/intern/draw_cache_impl_particles.c @@ -173,13 +173,9 @@ static void particle_batch_cache_clear_hair(ParticleHairCache *hair_cache) /* TODO: more granular update tagging. */ GPU_VERTBUF_DISCARD_SAFE(hair_cache->proc_point_buf); GPU_VERTBUF_DISCARD_SAFE(hair_cache->proc_length_buf); - DRW_TEXTURE_FREE_SAFE(hair_cache->point_tex); - DRW_TEXTURE_FREE_SAFE(hair_cache->length_tex); GPU_VERTBUF_DISCARD_SAFE(hair_cache->proc_strand_buf); GPU_VERTBUF_DISCARD_SAFE(hair_cache->proc_strand_seg_buf); - DRW_TEXTURE_FREE_SAFE(hair_cache->strand_tex); - DRW_TEXTURE_FREE_SAFE(hair_cache->strand_seg_tex); for (int i = 0; i < MAX_MTFACE; i++) { GPU_VERTBUF_DISCARD_SAFE(hair_cache->proc_uv_buf[i]); @@ -192,7 +188,6 @@ static void particle_batch_cache_clear_hair(ParticleHairCache *hair_cache) for (int i = 0; i < MAX_HAIR_SUBDIV; i++) { GPU_VERTBUF_DISCARD_SAFE(hair_cache->final[i].proc_buf); - DRW_TEXTURE_FREE_SAFE(hair_cache->final[i].proc_tex); for (int j = 0; j < MAX_THICKRES; j++) { GPU_BATCH_DISCARD_SAFE(hair_cache->final[i].proc_hairs[j]); } @@ -810,7 +805,7 @@ static int particle_batch_cache_fill_strands_data(ParticleSystem *psys, static void particle_batch_cache_ensure_procedural_final_points(ParticleHairCache *cache, int subdiv) { - /* Same format as point_tex. */ + /* Same format as proc_point_buf. */ GPUVertFormat format = {0}; GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 4, GPU_FETCH_FLOAT); @@ -823,12 +818,6 @@ static void particle_batch_cache_ensure_procedural_final_points(ParticleHairCach /* Those are points! not line segments. */ GPU_vertbuf_data_alloc(cache->final[subdiv].proc_buf, cache->final[subdiv].strands_res * cache->strands_len); - - /* Create vbo immediately to bind to texture buffer. */ - GPU_vertbuf_use(cache->final[subdiv].proc_buf); - - cache->final[subdiv].proc_tex = GPU_texture_create_from_vertbuf("part_proc", - cache->final[subdiv].proc_buf); } static void particle_batch_cache_ensure_procedural_strand_data(PTCacheEdit *edit, @@ -1034,14 +1023,6 @@ static void particle_batch_cache_ensure_procedural_strand_data(PTCacheEdit *edit MEM_freeN(parent_mcol); } - /* Create vbo immediately to bind to texture buffer. */ - GPU_vertbuf_use(cache->proc_strand_buf); - cache->strand_tex = GPU_texture_create_from_vertbuf("part_strand", cache->proc_strand_buf); - - GPU_vertbuf_use(cache->proc_strand_seg_buf); - cache->strand_seg_tex = GPU_texture_create_from_vertbuf("part_strand_seg", - cache->proc_strand_seg_buf); - for (int i = 0; i < cache->num_uv_layers; i++) { GPU_vertbuf_use(cache->proc_uv_buf[i]); cache->uv_tex[i] = GPU_texture_create_from_vertbuf("part_uv", cache->proc_uv_buf[i]); @@ -1107,7 +1088,7 @@ static void particle_batch_cache_ensure_procedural_indices(PTCacheEdit *edit, static void particle_batch_cache_ensure_procedural_pos(PTCacheEdit *edit, ParticleSystem *psys, ParticleHairCache *cache, - GPUMaterial *gpu_material) + GPUMaterial *UNUSED(gpu_material)) { if (cache->proc_point_buf == NULL) { /* initialize vertex format */ @@ -1149,22 +1130,6 @@ static void particle_batch_cache_ensure_procedural_pos(PTCacheEdit *edit, psys->childcache, child_count, &pos_step, &length_step); } } - - /* Create vbo immediately to bind to texture buffer. */ - GPU_vertbuf_use(cache->proc_point_buf); - cache->point_tex = GPU_texture_create_from_vertbuf("part_point", cache->proc_point_buf); - } - - /* Checking hair length separately, only allocating gpu memory when needed. */ - if (gpu_material && cache->proc_length_buf != NULL && cache->length_tex == NULL) { - ListBase gpu_attrs = GPU_material_attributes(gpu_material); - LISTBASE_FOREACH (GPUMaterialAttribute *, attr, &gpu_attrs) { - if (attr->type == CD_HAIRLENGTH) { - GPU_vertbuf_use(cache->proc_length_buf); - cache->length_tex = GPU_texture_create_from_vertbuf("hair_length", cache->proc_length_buf); - break; - } - } } } @@ -1722,7 +1687,7 @@ bool particles_ensure_procedural_data(Object *object, /* Refreshed on combing and simulation. */ if ((*r_hair_cache)->proc_point_buf == NULL || - (gpu_material && (*r_hair_cache)->length_tex == NULL)) { + (gpu_material && (*r_hair_cache)->proc_length_buf == NULL)) { ensure_seg_pt_count(source.edit, source.psys, &cache->hair); particle_batch_cache_ensure_procedural_pos( source.edit, source.psys, &cache->hair, gpu_material); @@ -1730,7 +1695,7 @@ bool particles_ensure_procedural_data(Object *object, } /* Refreshed if active layer or custom data changes. */ - if ((*r_hair_cache)->strand_tex == NULL) { + if ((*r_hair_cache)->proc_strand_buf == NULL) { particle_batch_cache_ensure_procedural_strand_data( source.edit, source.psys, source.md, &cache->hair); } diff --git a/source/blender/draw/intern/draw_cache_impl_pointcloud.cc b/source/blender/draw/intern/draw_cache_impl_pointcloud.cc index 98531637e57..d64fc581942 100644 --- a/source/blender/draw/intern/draw_cache_impl_pointcloud.cc +++ b/source/blender/draw/intern/draw_cache_impl_pointcloud.cc @@ -23,30 +23,64 @@ #include "BKE_pointcloud.h" #include "GPU_batch.h" +#include "GPU_material.h" -#include "draw_cache_impl.h" /* own include */ +#include "draw_attributes.h" +#include "draw_cache_impl.h" +#include "draw_cache_inline.h" +#include "draw_pointcloud_private.hh" /* own include */ -/* ---------------------------------------------------------------------- */ -/* PointCloud GPUBatch Cache */ +using namespace blender; -struct PointCloudBatchCache { - GPUVertBuf *pos; /* Position and radius. */ - GPUVertBuf *geom; /* Instanced geometry for each point in the cloud (small sphere). */ - GPUVertBuf *attr_viewer; - GPUIndexBuf *geom_indices; +/** \} */ +/* -------------------------------------------------------------------- */ +/** \name GPUBatch cache management + * \{ */ + +struct PointCloudBatchCache { + /* Dot primitive types. */ GPUBatch *dots; + /* Triangle primitive types. */ GPUBatch *surface; GPUBatch **surface_per_mat; - GPUBatch *surface_viewer_attribute; + /* Triangles indices to draw the points. */ + GPUIndexBuf *geom_indices; + + /* Position and radius. */ + GPUVertBuf *pos_rad; + /* Active attribute in 3D view. */ + GPUVertBuf *attr_viewer; + /* Requested attributes */ + GPUVertBuf *attributes_buf[GPU_MAX_ATTR]; + + /** Attributes currently being drawn or about to be drawn. */ + DRW_Attributes attr_used; + /** + * Attributes that were used at some point. This is used for garbage collection, to remove + * attributes that are not used in shaders anymore due to user edits. + */ + DRW_Attributes attr_used_over_time; + + /** + * The last time in seconds that the `attr_used` and `attr_used_over_time` were exactly the same. + * If the delta between this time and the current scene time is greater than the timeout set in + * user preferences (`U.vbotimeout`) then garbage collection is performed. + */ + int last_attr_matching_time; /* settings to determine if cache is invalid */ bool is_dirty; int mat_len; -}; -/* GPUBatch cache management. */ + /** + * The draw cache extraction is currently not multi-threaded for multiple objects, but if it was, + * some locking would be necessary because multiple objects can use the same object data with + * different materials, etc. This is a placeholder to make multi-threading easier in the future. + */ + std::mutex render_mutex; +}; static PointCloudBatchCache *pointcloud_batch_cache_get(PointCloud &pointcloud) { @@ -71,7 +105,7 @@ static void pointcloud_batch_cache_init(PointCloud &pointcloud) PointCloudBatchCache *cache = pointcloud_batch_cache_get(pointcloud); if (!cache) { - cache = MEM_cnew<PointCloudBatchCache>(__func__); + cache = MEM_new<PointCloudBatchCache>(__func__); pointcloud.batch_cache = cache; } else { @@ -100,6 +134,15 @@ void DRW_pointcloud_batch_cache_dirty_tag(PointCloud *pointcloud, int mode) } } +static void pointcloud_discard_attributes(PointCloudBatchCache &cache) +{ + for (const int j : IndexRange(GPU_MAX_ATTR)) { + GPU_VERTBUF_DISCARD_SAFE(cache.attributes_buf[j]); + } + + drw_attributes_clear(&cache.attr_used); +} + static void pointcloud_batch_cache_clear(PointCloud &pointcloud) { PointCloudBatchCache *cache = pointcloud_batch_cache_get(pointcloud); @@ -109,8 +152,7 @@ static void pointcloud_batch_cache_clear(PointCloud &pointcloud) GPU_BATCH_DISCARD_SAFE(cache->dots); GPU_BATCH_DISCARD_SAFE(cache->surface); - GPU_VERTBUF_DISCARD_SAFE(cache->pos); - GPU_VERTBUF_DISCARD_SAFE(cache->geom); + GPU_VERTBUF_DISCARD_SAFE(cache->pos_rad); GPU_VERTBUF_DISCARD_SAFE(cache->attr_viewer); GPU_INDEXBUF_DISCARD_SAFE(cache->geom_indices); @@ -119,8 +161,9 @@ static void pointcloud_batch_cache_clear(PointCloud &pointcloud) GPU_BATCH_DISCARD_SAFE(cache->surface_per_mat[i]); } } - GPU_BATCH_DISCARD_SAFE(cache->surface_viewer_attribute); MEM_SAFE_FREE(cache->surface_per_mat); + + pointcloud_discard_attributes(*cache); } void DRW_pointcloud_batch_cache_validate(PointCloud *pointcloud) @@ -137,61 +180,35 @@ void DRW_pointcloud_batch_cache_free(PointCloud *pointcloud) MEM_SAFE_FREE(pointcloud->batch_cache); } -static void pointcloud_batch_cache_ensure_pos(const PointCloud &pointcloud, - PointCloudBatchCache &cache) +void DRW_pointcloud_batch_cache_free_old(PointCloud *pointcloud, int ctime) { - using namespace blender; - if (cache.pos != nullptr) { + PointCloudBatchCache *cache = pointcloud_batch_cache_get(*pointcloud); + if (!cache) { return; } - const bke::AttributeAccessor attributes = pointcloud.attributes(); - const VArraySpan<float3> positions = attributes.lookup<float3>("position", ATTR_DOMAIN_POINT); - const VArray<float> radii = attributes.lookup<float>("radius", ATTR_DOMAIN_POINT); - /* From the opengl wiki: - * Note that size does not have to exactly match the size used by the vertex shader. If the - * vertex shader has fewer components than the attribute provides, then the extras are ignored. - * If the vertex shader has more components than the array provides, the extras are given - * values from the vector (0, 0, 0, 1) for the missing XYZW components. */ - if (radii) { - static GPUVertFormat format = {0}; - if (format.attr_len == 0) { - GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 4, GPU_FETCH_FLOAT); - } - cache.pos = GPU_vertbuf_create_with_format(&format); - GPU_vertbuf_data_alloc(cache.pos, positions.size()); - const VArraySpan<float> radii_span(radii); - MutableSpan<float4> vbo_data{static_cast<float4 *>(GPU_vertbuf_get_data(cache.pos)), - pointcloud.totpoint}; - threading::parallel_for(vbo_data.index_range(), 4096, [&](IndexRange range) { - for (const int i : range) { - vbo_data[i].x = positions[i].x; - vbo_data[i].y = positions[i].y; - vbo_data[i].z = positions[i].z; - /* TODO(fclem): remove multiplication. Here only for keeping the size correct for now. */ - vbo_data[i].w = radii_span[i] * 100.0f; - } - }); + bool do_discard = false; + + if (drw_attributes_overlap(&cache->attr_used_over_time, &cache->attr_used)) { + cache->last_attr_matching_time = ctime; } - else { - static GPUVertFormat format = {0}; - static uint pos; - if (format.attr_len == 0) { - pos = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT); - } - cache.pos = GPU_vertbuf_create_with_format(&format); - GPU_vertbuf_data_alloc(cache.pos, positions.size()); - GPU_vertbuf_attr_fill(cache.pos, pos, positions.data()); + + if (ctime - cache->last_attr_matching_time > U.vbotimeout) { + do_discard = true; + } + + drw_attributes_clear(&cache->attr_used_over_time); + + if (do_discard) { + pointcloud_discard_attributes(*cache); } } -static const float half_octahedron_normals[5][3] = { - {0.0f, 0.0f, 1.0f}, - {1.0f, 0.0f, 0.0f}, - {0.0f, 1.0f, 0.0f}, - {-1.0f, 0.0f, 0.0f}, - {0.0f, -1.0f, 0.0f}, -}; +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name PointCloud extraction + * \{ */ static const uint half_octahedron_tris[4][3] = { {0, 1, 2}, @@ -200,130 +217,236 @@ static const uint half_octahedron_tris[4][3] = { {0, 4, 1}, }; -static void pointcloud_batch_cache_ensure_geom(PointCloudBatchCache &cache) +static void pointcloud_extract_indices(const PointCloud &pointcloud, PointCloudBatchCache &cache) { - if (cache.geom != nullptr) { - return; + /** \note: Avoid modulo by non-power-of-two in shader. */ + uint32_t vertid_max = pointcloud.totpoint * 32; + uint32_t index_len = pointcloud.totpoint * ARRAY_SIZE(half_octahedron_tris); + + GPUIndexBufBuilder builder; + GPU_indexbuf_init(&builder, GPU_PRIM_TRIS, index_len, vertid_max); + + for (int p = 0; p < pointcloud.totpoint; p++) { + for (int i = 0; i < ARRAY_SIZE(half_octahedron_tris); i++) { + GPU_indexbuf_add_tri_verts(&builder, + half_octahedron_tris[i][0] + p * 32, + half_octahedron_tris[i][1] + p * 32, + half_octahedron_tris[i][2] + p * 32); + } } + GPU_indexbuf_build_in_place(&builder, cache.geom_indices); +} + +static void pointcloud_extract_position_and_radius(const PointCloud &pointcloud, + PointCloudBatchCache &cache) +{ + using namespace blender; + + const bke::AttributeAccessor attributes = pointcloud.attributes(); + const VArraySpan<float3> positions = attributes.lookup<float3>("position", ATTR_DOMAIN_POINT); + const VArray<float> radii = attributes.lookup<float>("radius", ATTR_DOMAIN_POINT); static GPUVertFormat format = {0}; - static uint pos; if (format.attr_len == 0) { - pos = GPU_vertformat_attr_add(&format, "pos_inst", GPU_COMP_F32, 3, GPU_FETCH_FLOAT); - GPU_vertformat_alias_add(&format, "nor"); + GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 4, GPU_FETCH_FLOAT); } - cache.geom = GPU_vertbuf_create_with_format(&format); - GPU_vertbuf_data_alloc(cache.geom, ARRAY_SIZE(half_octahedron_normals)); - - GPU_vertbuf_attr_fill(cache.geom, pos, half_octahedron_normals); - - GPUIndexBufBuilder builder; - GPU_indexbuf_init(&builder, - GPU_PRIM_TRIS, - ARRAY_SIZE(half_octahedron_tris), - ARRAY_SIZE(half_octahedron_normals)); + GPUUsageType usage_flag = GPU_USAGE_STATIC | GPU_USAGE_FLAG_BUFFER_TEXTURE_ONLY; + GPU_vertbuf_init_with_format_ex(cache.pos_rad, &format, usage_flag); - for (int i = 0; i < ARRAY_SIZE(half_octahedron_tris); i++) { - GPU_indexbuf_add_tri_verts(&builder, UNPACK3(half_octahedron_tris[i])); + GPU_vertbuf_data_alloc(cache.pos_rad, positions.size()); + MutableSpan<float4> vbo_data{static_cast<float4 *>(GPU_vertbuf_get_data(cache.pos_rad)), + pointcloud.totpoint}; + if (radii) { + const VArraySpan<float> radii_span(radii); + threading::parallel_for(vbo_data.index_range(), 4096, [&](IndexRange range) { + for (const int i : range) { + vbo_data[i].x = positions[i].x; + vbo_data[i].y = positions[i].y; + vbo_data[i].z = positions[i].z; + /* TODO(fclem): remove multiplication. Here only for keeping the size correct for now. */ + vbo_data[i].w = radii_span[i] * 100.0f; + } + }); + } + else { + threading::parallel_for(vbo_data.index_range(), 4096, [&](IndexRange range) { + for (const int i : range) { + vbo_data[i].x = positions[i].x; + vbo_data[i].y = positions[i].y; + vbo_data[i].z = positions[i].z; + vbo_data[i].w = 1.0f; + } + }); } - - cache.geom_indices = GPU_indexbuf_build(&builder); } -static void pointcloud_batch_cache_ensure_attribute_overlay(const PointCloud &pointcloud, - PointCloudBatchCache &cache) +static void pointcloud_extract_attribute(const PointCloud &pointcloud, + PointCloudBatchCache &cache, + const DRW_AttributeRequest &request, + int index) { using namespace blender; - if (cache.attr_viewer != nullptr) { - return; - } + + GPUVertBuf *&attr_buf = cache.attributes_buf[index]; const bke::AttributeAccessor attributes = pointcloud.attributes(); - const VArray<ColorGeometry4f> colors = attributes.lookup_or_default<ColorGeometry4f>( - ".viewer", ATTR_DOMAIN_POINT, {1.0f, 0.0f, 1.0f, 1.0f}); + + /* TODO(@kevindietrich): float4 is used for scalar attributes as the implicit conversion done + * by OpenGL to vec4 for a scalar `s` will produce a `vec4(s, 0, 0, 1)`. However, following + * the Blender convention, it should be `vec4(s, s, s, 1)`. This could be resolved using a + * similar texture state swizzle to map the attribute correctly as for volume attributes, so we + * can control the conversion ourselves. */ + VArray<ColorGeometry4f> attribute = attributes.lookup_or_default<ColorGeometry4f>( + request.attribute_name, request.domain, {0.0f, 0.0f, 0.0f, 1.0f}); static GPUVertFormat format = {0}; if (format.attr_len == 0) { - GPU_vertformat_attr_add(&format, "attribute_value", GPU_COMP_F32, 4, GPU_FETCH_FLOAT); + GPU_vertformat_attr_add(&format, "attr", GPU_COMP_F32, 4, GPU_FETCH_FLOAT); } - cache.attr_viewer = GPU_vertbuf_create_with_format(&format); - GPU_vertbuf_data_alloc(cache.attr_viewer, pointcloud.totpoint); + GPUUsageType usage_flag = GPU_USAGE_STATIC | GPU_USAGE_FLAG_BUFFER_TEXTURE_ONLY; + GPU_vertbuf_init_with_format_ex(attr_buf, &format, usage_flag); + GPU_vertbuf_data_alloc(attr_buf, pointcloud.totpoint); + MutableSpan<ColorGeometry4f> vbo_data{ - static_cast<ColorGeometry4f *>(GPU_vertbuf_get_data(cache.attr_viewer)), - pointcloud.totpoint}; - colors.materialize(vbo_data); + static_cast<ColorGeometry4f *>(GPU_vertbuf_get_data(attr_buf)), pointcloud.totpoint}; + attribute.materialize(vbo_data); } -GPUBatch *DRW_pointcloud_batch_cache_get_dots(Object *ob) -{ - PointCloud &pointcloud = *static_cast<PointCloud *>(ob->data); - PointCloudBatchCache *cache = pointcloud_batch_cache_get(pointcloud); +/** \} */ - if (cache->dots == nullptr) { - pointcloud_batch_cache_ensure_pos(pointcloud, *cache); - cache->dots = GPU_batch_create(GPU_PRIM_POINTS, cache->pos, nullptr); - } +/* -------------------------------------------------------------------- */ +/** \name Private API + * \{ */ - return cache->dots; +GPUVertBuf *pointcloud_position_and_radius_get(PointCloud *pointcloud) +{ + PointCloudBatchCache *cache = pointcloud_batch_cache_get(*pointcloud); + DRW_vbo_request(nullptr, &cache->pos_rad); + return cache->pos_rad; } -GPUBatch *DRW_pointcloud_batch_cache_get_surface(Object *ob) +GPUBatch **pointcloud_surface_shaded_get(PointCloud *pointcloud, + GPUMaterial **gpu_materials, + int mat_len) { - PointCloud &pointcloud = *static_cast<PointCloud *>(ob->data); - PointCloudBatchCache *cache = pointcloud_batch_cache_get(pointcloud); + PointCloudBatchCache *cache = pointcloud_batch_cache_get(*pointcloud); + DRW_Attributes attrs_needed; + drw_attributes_clear(&attrs_needed); + + for (GPUMaterial *gpu_material : Span<GPUMaterial *>(gpu_materials, mat_len)) { + ListBase gpu_attrs = GPU_material_attributes(gpu_material); + LISTBASE_FOREACH (GPUMaterialAttribute *, gpu_attr, &gpu_attrs) { + const char *name = gpu_attr->name; + + int layer_index; + eCustomDataType type; + eAttrDomain domain = ATTR_DOMAIN_POINT; + if (!drw_custom_data_match_attribute(&pointcloud->pdata, name, &layer_index, &type)) { + continue; + } - if (cache->surface == nullptr) { - pointcloud_batch_cache_ensure_pos(pointcloud, *cache); - pointcloud_batch_cache_ensure_geom(*cache); + drw_attributes_add_request(&attrs_needed, name, type, layer_index, domain); + } + } - cache->surface = GPU_batch_create(GPU_PRIM_TRIS, cache->geom, cache->geom_indices); - GPU_batch_instbuf_add_ex(cache->surface, cache->pos, false); + if (!drw_attributes_overlap(&cache->attr_used, &attrs_needed)) { + /* Some new attributes have been added, free all and start over. */ + for (const int i : IndexRange(GPU_MAX_ATTR)) { + GPU_VERTBUF_DISCARD_SAFE(cache->attributes_buf[i]); + } + drw_attributes_merge(&cache->attr_used, &attrs_needed, cache->render_mutex); } + drw_attributes_merge(&cache->attr_used_over_time, &attrs_needed, cache->render_mutex); + + DRW_batch_request(&cache->surface_per_mat[0]); + return cache->surface_per_mat; +} - return cache->surface; +GPUBatch *pointcloud_surface_get(PointCloud *pointcloud) +{ + PointCloudBatchCache *cache = pointcloud_batch_cache_get(*pointcloud); + return DRW_batch_request(&cache->surface); } -GPUBatch *DRW_pointcloud_batch_cache_get_surface_viewer_attribute(Object *ob) +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name API + * \{ */ + +GPUBatch *DRW_pointcloud_batch_cache_get_dots(Object *ob) { PointCloud &pointcloud = *static_cast<PointCloud *>(ob->data); PointCloudBatchCache *cache = pointcloud_batch_cache_get(pointcloud); + return DRW_batch_request(&cache->dots); +} - if (cache->surface_viewer_attribute == nullptr) { - pointcloud_batch_cache_ensure_pos(pointcloud, *cache); - pointcloud_batch_cache_ensure_geom(*cache); - pointcloud_batch_cache_ensure_attribute_overlay(pointcloud, *cache); +GPUVertBuf **DRW_pointcloud_evaluated_attribute(PointCloud *pointcloud, const char *name) +{ + PointCloudBatchCache &cache = *pointcloud_batch_cache_get(*pointcloud); + + int layer_index; + eCustomDataType type; + eAttrDomain domain = ATTR_DOMAIN_POINT; + if (drw_custom_data_match_attribute(&pointcloud->pdata, name, &layer_index, &type)) { + DRW_Attributes attributes{}; + drw_attributes_add_request(&attributes, name, type, layer_index, domain); + drw_attributes_merge(&cache.attr_used, &attributes, cache.render_mutex); + } - cache->surface_viewer_attribute = GPU_batch_create( - GPU_PRIM_TRIS, cache->geom, cache->geom_indices); - GPU_batch_instbuf_add_ex(cache->surface_viewer_attribute, cache->attr_viewer, false); - GPU_batch_instbuf_add_ex(cache->surface_viewer_attribute, cache->pos, false); + int request_i = -1; + for (const int i : IndexRange(cache.attr_used.num_requests)) { + if (STREQ(cache.attr_used.requests[i].attribute_name, name)) { + request_i = i; + break; + } + } + if (request_i == -1) { + return nullptr; } + return &cache.attributes_buf[request_i]; +} - return cache->surface_viewer_attribute; +int DRW_pointcloud_material_count_get(PointCloud *pointcloud) +{ + return max_ii(1, pointcloud->totcol); } -GPUBatch **DRW_cache_pointcloud_surface_shaded_get(Object *ob, - struct GPUMaterial ** /*gpumat_array*/, - uint gpumat_array_len) +void DRW_pointcloud_batch_cache_create_requested(Object *ob) { - PointCloud &pointcloud = *static_cast<PointCloud *>(ob->data); - PointCloudBatchCache *cache = pointcloud_batch_cache_get(pointcloud); - BLI_assert(cache->mat_len == gpumat_array_len); - UNUSED_VARS(gpumat_array_len); + PointCloud *pointcloud = static_cast<PointCloud *>(ob->data); + PointCloudBatchCache &cache = *pointcloud_batch_cache_get(*pointcloud); - if (cache->surface_per_mat[0] == nullptr) { - pointcloud_batch_cache_ensure_pos(pointcloud, *cache); - pointcloud_batch_cache_ensure_geom(*cache); + if (DRW_batch_requested(cache.dots, GPU_PRIM_POINTS)) { + DRW_vbo_request(cache.dots, &cache.pos_rad); + } - cache->surface_per_mat[0] = GPU_batch_create(GPU_PRIM_TRIS, cache->geom, cache->geom_indices); - GPU_batch_instbuf_add_ex(cache->surface_per_mat[0], cache->pos, false); + if (DRW_batch_requested(cache.surface, GPU_PRIM_TRIS)) { + DRW_ibo_request(cache.surface, &cache.geom_indices); + DRW_vbo_request(cache.surface, &cache.pos_rad); + } + for (int i = 0; i < cache.mat_len; i++) { + if (DRW_batch_requested(cache.surface_per_mat[i], GPU_PRIM_TRIS)) { + /* TODO(fclem): Per material ranges. */ + DRW_ibo_request(cache.surface_per_mat[i], &cache.geom_indices); + } } + for (int j = 0; j < cache.attr_used.num_requests; j++) { + DRW_vbo_request(nullptr, &cache.attributes_buf[j]); - return cache->surface_per_mat; -} + if (DRW_vbo_requested(cache.attributes_buf[j])) { + pointcloud_extract_attribute(*pointcloud, cache, cache.attr_used.requests[j], j); + } + } -int DRW_pointcloud_material_count_get(PointCloud *pointcloud) -{ - return max_ii(1, pointcloud->totcol); + if (DRW_ibo_requested(cache.geom_indices)) { + pointcloud_extract_indices(*pointcloud, cache); + } + + if (DRW_vbo_requested(cache.pos_rad)) { + pointcloud_extract_position_and_radius(*pointcloud, cache); + } } + +/** \} */ diff --git a/source/blender/draw/intern/draw_command.cc b/source/blender/draw/intern/draw_command.cc index 882eda9b31d..10dd63e05dc 100644 --- a/source/blender/draw/intern/draw_command.cc +++ b/source/blender/draw/intern/draw_command.cc @@ -30,6 +30,11 @@ void ShaderBind::execute(RecordingState &state) const } } +void FramebufferBind::execute() const +{ + GPU_framebuffer_bind(framebuffer); +} + void ResourceBind::execute() const { if (slot == -1) { @@ -229,6 +234,11 @@ std::string ShaderBind::serialize() const return std::string(".shader_bind(") + GPU_shader_get_name(shader) + ")"; } +std::string FramebufferBind::serialize() const +{ + return std::string(".framebuffer_bind(") + GPU_framebuffer_get_name(framebuffer) + ")"; +} + std::string ResourceBind::serialize() const { switch (type) { diff --git a/source/blender/draw/intern/draw_command.hh b/source/blender/draw/intern/draw_command.hh index 5307a242e39..ab180cc60b1 100644 --- a/source/blender/draw/intern/draw_command.hh +++ b/source/blender/draw/intern/draw_command.hh @@ -88,6 +88,7 @@ enum class Type : uint8_t { DispatchIndirect, Draw, DrawIndirect, + FramebufferBind, PushConstant, ResourceBind, ShaderBind, @@ -118,6 +119,13 @@ struct ShaderBind { std::string serialize() const; }; +struct FramebufferBind { + GPUFrameBuffer *framebuffer; + + void execute() const; + std::string serialize() const; +}; + struct ResourceBind { eGPUSamplerState sampler; int slot; @@ -473,10 +481,8 @@ class DrawMultiBuf { uint vertex_first, ResourceHandle handle) { - /* Unsupported for now. Use PassSimple. */ - BLI_assert(vertex_first == 0 || vertex_first == -1); - BLI_assert(vertex_len == -1); - UNUSED_VARS_NDEBUG(vertex_len, vertex_first); + /* Custom draw-calls cannot be batched and will produce one group per draw. */ + const bool custom_group = (vertex_first != 0 || vertex_first != -1 || vertex_len != -1); instance_len = instance_len != -1 ? instance_len : 1; @@ -493,8 +499,14 @@ class DrawMultiBuf { bool inverted = handle.has_inverted_handedness(); - if (group_id == uint(-1)) { + DrawPrototype &draw = prototype_buf_.get_or_resize(prototype_count_++); + draw.resource_handle = handle.raw; + draw.instance_len = instance_len; + draw.group_id = group_id; + + if (group_id == uint(-1) || custom_group) { uint new_group_id = group_count_++; + draw.group_id = new_group_id; DrawGroup &group = group_buf_.get_or_resize(new_group_id); group.next = cmd.group_first; @@ -503,11 +515,16 @@ class DrawMultiBuf { group.gpu_batch = batch; group.front_proto_len = 0; group.back_proto_len = 0; + group.vertex_len = vertex_len; + group.vertex_first = vertex_first; + /* Custom group are not to be registered in the group_ids_. */ + if (!custom_group) { + group_id = new_group_id; + } /* For serialization only. */ (inverted ? group.back_proto_len : group.front_proto_len)++; /* Append to list. */ cmd.group_first = new_group_id; - group_id = new_group_id; } else { DrawGroup &group = group_buf_[group_id]; @@ -516,11 +533,6 @@ class DrawMultiBuf { /* For serialization only. */ (inverted ? group.back_proto_len : group.front_proto_len)++; } - - DrawPrototype &draw = prototype_buf_.get_or_resize(prototype_count_++); - draw.group_id = group_id; - draw.resource_handle = handle.raw; - draw.instance_len = instance_len; } void bind(RecordingState &state, diff --git a/source/blender/draw/intern/draw_common.h b/source/blender/draw/intern/draw_common.h index b5e9b3ee8bd..07d245e7dfe 100644 --- a/source/blender/draw/intern/draw_common.h +++ b/source/blender/draw/intern/draw_common.h @@ -88,6 +88,14 @@ void DRW_curves_ubos_pool_free(struct CurvesUniformBufPool *pool); void DRW_curves_update(void); void DRW_curves_free(void); +/* draw_pointcloud.cc */ + +struct DRWShadingGroup *DRW_shgroup_pointcloud_create_sub(struct Object *object, + struct DRWShadingGroup *shgrp_parent, + struct GPUMaterial *gpu_material); +void DRW_pointcloud_init(void); +void DRW_pointcloud_free(void); + /* draw_volume.cc */ /** diff --git a/source/blender/draw/intern/draw_curves.cc b/source/blender/draw/intern/draw_curves.cc index a61769e7a63..ee9ed4666e0 100644 --- a/source/blender/draw/intern/draw_curves.cc +++ b/source/blender/draw/intern/draw_curves.cc @@ -129,25 +129,25 @@ void DRW_curves_ubos_pool_free(CurvesUniformBufPool *pool) static void drw_curves_cache_shgrp_attach_resources(DRWShadingGroup *shgrp, CurvesEvalCache *cache, - GPUTexture *tex, + GPUVertBuf *point_buf, const int subdiv) { - DRW_shgroup_uniform_texture(shgrp, "hairPointBuffer", tex); - DRW_shgroup_uniform_texture(shgrp, "hairStrandBuffer", cache->strand_tex); - DRW_shgroup_uniform_texture(shgrp, "hairStrandSegBuffer", cache->strand_seg_tex); + DRW_shgroup_buffer_texture(shgrp, "hairPointBuffer", point_buf); + DRW_shgroup_buffer_texture(shgrp, "hairStrandBuffer", cache->proc_strand_buf); + DRW_shgroup_buffer_texture(shgrp, "hairStrandSegBuffer", cache->proc_strand_seg_buf); DRW_shgroup_uniform_int(shgrp, "hairStrandsRes", &cache->final[subdiv].strands_res, 1); } static void drw_curves_cache_update_compute(CurvesEvalCache *cache, const int subdiv, const int strands_len, - GPUVertBuf *buffer, - GPUTexture *tex) + GPUVertBuf *output_buf, + GPUVertBuf *input_buf) { GPUShader *shader = curves_eval_shader_get(CURVES_EVAL_CATMULL_ROM); DRWShadingGroup *shgrp = DRW_shgroup_create(shader, g_tf_pass); - drw_curves_cache_shgrp_attach_resources(shgrp, cache, tex, subdiv); - DRW_shgroup_vertex_buffer(shgrp, "posTime", buffer); + drw_curves_cache_shgrp_attach_resources(shgrp, cache, input_buf, subdiv); + DRW_shgroup_vertex_buffer(shgrp, "posTime", output_buf); const int max_strands_per_call = GPU_max_work_group_count(0); int strands_start = 0; @@ -169,7 +169,7 @@ static void drw_curves_cache_update_compute(CurvesEvalCache *cache, const int su } drw_curves_cache_update_compute( - cache, subdiv, strands_len, cache->final[subdiv].proc_buf, cache->point_tex); + cache, subdiv, strands_len, cache->final[subdiv].proc_buf, cache->proc_point_buf); const DRW_Attributes &attrs = cache->final[subdiv].attr_used; for (int i = 0; i < attrs.num_requests; i++) { @@ -182,13 +182,13 @@ static void drw_curves_cache_update_compute(CurvesEvalCache *cache, const int su subdiv, strands_len, cache->final[subdiv].attributes_buf[i], - cache->proc_attributes_tex[i]); + cache->proc_attributes_buf[i]); } } static void drw_curves_cache_update_transform_feedback(CurvesEvalCache *cache, - GPUVertBuf *vbo, - GPUTexture *tex, + GPUVertBuf *output_buf, + GPUVertBuf *input_buf, const int subdiv, const int final_points_len) { @@ -196,14 +196,14 @@ static void drw_curves_cache_update_transform_feedback(CurvesEvalCache *cache, DRWShadingGroup *tf_shgrp = nullptr; if (GPU_transform_feedback_support()) { - tf_shgrp = DRW_shgroup_transform_feedback_create(tf_shader, g_tf_pass, vbo); + tf_shgrp = DRW_shgroup_transform_feedback_create(tf_shader, g_tf_pass, output_buf); } else { tf_shgrp = DRW_shgroup_create(tf_shader, g_tf_pass); CurvesEvalCall *pr_call = MEM_new<CurvesEvalCall>(__func__); pr_call->next = g_tf_calls; - pr_call->vbo = vbo; + pr_call->vbo = output_buf; pr_call->shgrp = tf_shgrp; pr_call->vert_len = final_points_len; g_tf_calls = pr_call; @@ -213,7 +213,7 @@ static void drw_curves_cache_update_transform_feedback(CurvesEvalCache *cache, } BLI_assert(tf_shgrp != nullptr); - drw_curves_cache_shgrp_attach_resources(tf_shgrp, cache, tex, subdiv); + drw_curves_cache_shgrp_attach_resources(tf_shgrp, cache, input_buf, subdiv); DRW_shgroup_call_procedural_points(tf_shgrp, nullptr, final_points_len); } @@ -225,7 +225,7 @@ static void drw_curves_cache_update_transform_feedback(CurvesEvalCache *cache, c } drw_curves_cache_update_transform_feedback( - cache, cache->final[subdiv].proc_buf, cache->point_tex, subdiv, final_points_len); + cache, cache->final[subdiv].proc_buf, cache->proc_point_buf, subdiv, final_points_len); const DRW_Attributes &attrs = cache->final[subdiv].attr_used; for (int i = 0; i < attrs.num_requests; i++) { @@ -236,7 +236,7 @@ static void drw_curves_cache_update_transform_feedback(CurvesEvalCache *cache, c drw_curves_cache_update_transform_feedback(cache, cache->final[subdiv].attributes_buf[i], - cache->proc_attributes_tex[i], + cache->proc_attributes_buf[i], subdiv, final_points_len); } @@ -346,9 +346,9 @@ DRWShadingGroup *DRW_shgroup_curves_create_sub(Object *object, 1.0f); } - DRW_shgroup_uniform_texture(shgrp, "hairPointBuffer", curves_cache->final[subdiv].proc_tex); - if (curves_cache->length_tex) { - DRW_shgroup_uniform_texture(shgrp, "hairLen", curves_cache->length_tex); + DRW_shgroup_buffer_texture(shgrp, "hairPointBuffer", curves_cache->final[subdiv].proc_buf); + if (curves_cache->proc_length_buf) { + DRW_shgroup_buffer_texture(shgrp, "hairLen", curves_cache->proc_length_buf); } const DRW_Attributes &attrs = curves_cache->final[subdiv].attr_used; @@ -359,18 +359,18 @@ DRWShadingGroup *DRW_shgroup_curves_create_sub(Object *object, drw_curves_get_attribute_sampler_name(request.attribute_name, sampler_name); if (request.domain == ATTR_DOMAIN_CURVE) { - if (!curves_cache->proc_attributes_tex[i]) { + if (!curves_cache->proc_attributes_buf[i]) { continue; } - DRW_shgroup_uniform_texture(shgrp, sampler_name, curves_cache->proc_attributes_tex[i]); + DRW_shgroup_buffer_texture(shgrp, sampler_name, curves_cache->proc_attributes_buf[i]); } else { - if (!curves_cache->final[subdiv].attributes_tex[i]) { + if (!curves_cache->final[subdiv].attributes_buf[i]) { continue; } - DRW_shgroup_uniform_texture( - shgrp, sampler_name, curves_cache->final[subdiv].attributes_tex[i]); + DRW_shgroup_buffer_texture( + shgrp, sampler_name, curves_cache->final[subdiv].attributes_buf[i]); } /* Some attributes may not be used in the shader anymore and were not garbage collected yet, so @@ -390,10 +390,15 @@ DRWShadingGroup *DRW_shgroup_curves_create_sub(Object *object, DRW_shgroup_uniform_int(shgrp, "hairStrandsRes", &curves_cache->final[subdiv].strands_res, 1); DRW_shgroup_uniform_int_copy(shgrp, "hairThicknessRes", thickness_res); DRW_shgroup_uniform_float_copy(shgrp, "hairRadShape", hair_rad_shape); - DRW_shgroup_uniform_mat4_copy(shgrp, "hairDupliMatrix", object->obmat); + DRW_shgroup_uniform_mat4_copy(shgrp, "hairDupliMatrix", object->object_to_world); DRW_shgroup_uniform_float_copy(shgrp, "hairRadRoot", hair_rad_root); DRW_shgroup_uniform_float_copy(shgrp, "hairRadTip", hair_rad_tip); DRW_shgroup_uniform_bool_copy(shgrp, "hairCloseTip", hair_close_tip); + if (gpu_material) { + /* \note: This needs to happen before the drawcall to allow correct attribute extraction. + * (see T101896) */ + DRW_shgroup_add_material_resources(shgrp, gpu_material); + } /* TODO(fclem): Until we have a better way to cull the curves and render with orco, bypass * culling test. */ GPUBatch *geom = curves_cache->final[subdiv].proc_hairs[thickness_res - 1]; diff --git a/source/blender/draw/intern/draw_curves_private.h b/source/blender/draw/intern/draw_curves_private.h index a74878ec674..715706fd7a6 100644 --- a/source/blender/draw/intern/draw_curves_private.h +++ b/source/blender/draw/intern/draw_curves_private.h @@ -34,7 +34,6 @@ typedef enum CurvesEvalShader { typedef struct CurvesEvalFinalCache { /* Output of the subdivision stage: vertex buffer sized to subdiv level. */ GPUVertBuf *proc_buf; - GPUTexture *proc_tex; /** Just contains a huge index buffer used to draw the final curves. */ GPUBatch *proc_hairs[MAX_THICKRES]; @@ -61,35 +60,29 @@ typedef struct CurvesEvalFinalCache { /* Output of the subdivision stage: vertex buffers sized to subdiv level. This is only attributes * on point domain. */ GPUVertBuf *attributes_buf[GPU_MAX_ATTR]; - GPUTexture *attributes_tex[GPU_MAX_ATTR]; } CurvesEvalFinalCache; /* Curves procedural display: Evaluation is done on the GPU. */ typedef struct CurvesEvalCache { /* Input control point positions combined with parameter data. */ GPUVertBuf *proc_point_buf; - GPUTexture *point_tex; /* Editmode data (such as selection flags) used by overlay_edit_curve_point.glsl */ GPUVertBuf *data_edit_points; /** Info of control points strands (segment count and base index) */ GPUVertBuf *proc_strand_buf; - GPUTexture *strand_tex; /* Curve length data. */ GPUVertBuf *proc_length_buf; - GPUTexture *length_tex; GPUVertBuf *proc_strand_seg_buf; - GPUTexture *strand_seg_tex; CurvesEvalFinalCache final[MAX_HAIR_SUBDIV]; /* For point attributes, which need subdivision, these buffers contain the input data. * For curve domain attributes, which do not need subdivision, these are the final data. */ GPUVertBuf *proc_attributes_buf[GPU_MAX_ATTR]; - GPUTexture *proc_attributes_tex[GPU_MAX_ATTR]; int strands_len; int elems_len; diff --git a/source/blender/draw/intern/draw_hair.cc b/source/blender/draw/intern/draw_hair.cc index 4e44967e5e9..c5261f26f76 100644 --- a/source/blender/draw/intern/draw_hair.cc +++ b/source/blender/draw/intern/draw_hair.cc @@ -105,9 +105,9 @@ static void drw_hair_particle_cache_shgrp_attach_resources(DRWShadingGroup *shgr ParticleHairCache *cache, const int subdiv) { - DRW_shgroup_uniform_texture(shgrp, "hairPointBuffer", cache->point_tex); - DRW_shgroup_uniform_texture(shgrp, "hairStrandBuffer", cache->strand_tex); - DRW_shgroup_uniform_texture(shgrp, "hairStrandSegBuffer", cache->strand_seg_tex); + DRW_shgroup_buffer_texture(shgrp, "hairPointBuffer", cache->proc_point_buf); + DRW_shgroup_buffer_texture(shgrp, "hairStrandBuffer", cache->proc_strand_buf); + DRW_shgroup_buffer_texture(shgrp, "hairStrandSegBuffer", cache->proc_strand_seg_buf); DRW_shgroup_uniform_int(shgrp, "hairStrandsRes", &cache->final[subdiv].strands_res, 1); } @@ -216,12 +216,12 @@ void DRW_hair_duplimat_get(Object *object, if (collection != nullptr) { sub_v3_v3(dupli_mat[3], collection->instance_offset); } - mul_m4_m4m4(dupli_mat, dupli_parent->obmat, dupli_mat); + mul_m4_m4m4(dupli_mat, dupli_parent->object_to_world, dupli_mat); } else { - copy_m4_m4(dupli_mat, dupli_object->ob->obmat); + copy_m4_m4(dupli_mat, dupli_object->ob->object_to_world); invert_m4(dupli_mat); - mul_m4_m4m4(dupli_mat, object->obmat, dupli_mat); + mul_m4_m4m4(dupli_mat, object->object_to_world, dupli_mat); } } else { @@ -280,9 +280,9 @@ DRWShadingGroup *DRW_shgroup_hair_create_sub(Object *object, float hair_rad_tip = part->rad_tip * part->rad_scale * 0.5f; bool hair_close_tip = (part->shape_flag & PART_SHAPE_CLOSE_TIP) != 0; - DRW_shgroup_uniform_texture(shgrp, "hairPointBuffer", hair_cache->final[subdiv].proc_tex); - if (hair_cache->length_tex) { - DRW_shgroup_uniform_texture(shgrp, "l", hair_cache->length_tex); + DRW_shgroup_buffer_texture(shgrp, "hairPointBuffer", hair_cache->final[subdiv].proc_buf); + if (hair_cache->proc_length_buf) { + DRW_shgroup_buffer_texture(shgrp, "l", hair_cache->proc_length_buf); } DRW_shgroup_uniform_block(shgrp, "drw_curves", *g_dummy_curves_info); @@ -293,6 +293,11 @@ DRWShadingGroup *DRW_shgroup_hair_create_sub(Object *object, DRW_shgroup_uniform_float_copy(shgrp, "hairRadRoot", hair_rad_root); DRW_shgroup_uniform_float_copy(shgrp, "hairRadTip", hair_rad_tip); DRW_shgroup_uniform_bool_copy(shgrp, "hairCloseTip", hair_close_tip); + if (gpu_material) { + /* \note: This needs to happen before the drawcall to allow correct attribute extraction. + * (see T101896) */ + DRW_shgroup_add_material_resources(shgrp, gpu_material); + } /* TODO(fclem): Until we have a better way to cull the hair and render with orco, bypass * culling test. */ GPUBatch *geom = hair_cache->final[subdiv].proc_hairs[thickness_res - 1]; diff --git a/source/blender/draw/intern/draw_hair_private.h b/source/blender/draw/intern/draw_hair_private.h index c7e9e1e22de..a3019ab5aa5 100644 --- a/source/blender/draw/intern/draw_hair_private.h +++ b/source/blender/draw/intern/draw_hair_private.h @@ -29,7 +29,6 @@ struct ParticleSystem; typedef struct ParticleHairFinalCache { /* Output of the subdivision stage: vertex buff sized to subdiv level. */ GPUVertBuf *proc_buf; - GPUTexture *proc_tex; /* Just contains a huge index buffer used to draw the final hair. */ GPUBatch *proc_hairs[MAX_THICKRES]; @@ -44,18 +43,14 @@ typedef struct ParticleHairCache { /* Hair Procedural display: Interpolation is done on the GPU. */ GPUVertBuf *proc_point_buf; /* Input control points */ - GPUTexture *point_tex; /** Infos of control points strands (segment count and base index) */ GPUVertBuf *proc_strand_buf; - GPUTexture *strand_tex; /* Hair Length */ GPUVertBuf *proc_length_buf; - GPUTexture *length_tex; GPUVertBuf *proc_strand_seg_buf; - GPUTexture *strand_seg_tex; GPUVertBuf *proc_uv_buf[MAX_MTFACE]; GPUTexture *uv_tex[MAX_MTFACE]; diff --git a/source/blender/draw/intern/draw_manager.c b/source/blender/draw/intern/draw_manager.c index da77845feb4..4fcfec833eb 100644 --- a/source/blender/draw/intern/draw_manager.c +++ b/source/blender/draw/intern/draw_manager.c @@ -1690,6 +1690,7 @@ void DRW_draw_render_loop_ex(struct Depsgraph *depsgraph, DRW_globals_update(); drw_debug_init(); + DRW_pointcloud_init(); DRW_curves_init(DST.vmempool); DRW_volume_init(DST.vmempool); DRW_smoke_init(DST.vmempool); @@ -1959,20 +1960,6 @@ void DRW_render_gpencil(struct RenderEngine *engine, struct Depsgraph *depsgraph DST.buffer_finish_called = false; } -/* Callback function for RE_engine_update_render_passes to ensure all - * render passes are registered. */ -static void draw_render_result_ensure_pass_cb(void *user_data, - struct Scene *UNUSED(scene), - struct ViewLayer *view_layer, - const char *name, - int channels, - const char *chanid, - eNodeSocketDatatype UNUSED(type)) -{ - RenderEngine *engine = user_data; - RE_engine_add_pass(engine, name, channels, chanid, view_layer->name); -} - void DRW_render_to_image(RenderEngine *engine, struct Depsgraph *depsgraph) { Scene *scene = DEG_get_evaluated_scene(depsgraph); @@ -2023,10 +2010,6 @@ void DRW_render_to_image(RenderEngine *engine, struct Depsgraph *depsgraph) /* set default viewport */ GPU_viewport(0, 0, size[0], size[1]); - /* Update the render passes. This needs to be done before acquiring the render result. */ - RE_engine_update_render_passes( - engine, scene, view_layer, draw_render_result_ensure_pass_cb, engine); - /* Init render result. */ RenderResult *render_result = RE_engine_begin_result(engine, 0, @@ -2071,6 +2054,7 @@ void DRW_render_object_iter( void (*callback)(void *vedata, Object *ob, RenderEngine *engine, struct Depsgraph *depsgraph)) { const DRWContextState *draw_ctx = DRW_context_state_get(); + DRW_pointcloud_init(); DRW_curves_init(DST.vmempool); DRW_volume_init(DST.vmempool); DRW_smoke_init(DST.vmempool); @@ -2131,6 +2115,7 @@ void DRW_custom_pipeline(DrawEngineType *draw_engine_type, drw_manager_init(&DST, NULL, NULL); + DRW_pointcloud_init(); DRW_curves_init(DST.vmempool); DRW_volume_init(DST.vmempool); DRW_smoke_init(DST.vmempool); @@ -2166,6 +2151,7 @@ void DRW_cache_restart(void) DST.buffer_finish_called = false; + DRW_pointcloud_init(); DRW_curves_init(DST.vmempool); DRW_volume_init(DST.vmempool); DRW_smoke_init(DST.vmempool); @@ -2491,6 +2477,7 @@ void DRW_draw_select_loop(struct Depsgraph *depsgraph, /* Init engines */ drw_engines_init(); + DRW_pointcloud_init(); DRW_curves_init(DST.vmempool); DRW_volume_init(DST.vmempool); DRW_smoke_init(DST.vmempool); @@ -2672,6 +2659,7 @@ void DRW_draw_depth_loop(struct Depsgraph *depsgraph, /* Init engines */ drw_engines_init(); + DRW_pointcloud_init(); DRW_curves_init(DST.vmempool); DRW_volume_init(DST.vmempool); DRW_smoke_init(DST.vmempool); @@ -2813,7 +2801,7 @@ void DRW_draw_depth_object( GPU_matrix_projection_set(rv3d->winmat); GPU_matrix_set(rv3d->viewmat); - GPU_matrix_mul(object->obmat); + GPU_matrix_mul(object->object_to_world); /* Setup frame-buffer. */ GPUTexture *depth_tx = GPU_viewport_depth_texture(viewport); @@ -2833,11 +2821,11 @@ void DRW_draw_depth_object( const bool use_clipping_planes = RV3D_CLIPPING_ENABLED(v3d, rv3d); if (use_clipping_planes) { GPU_clip_distances(6); - ED_view3d_clipping_local(rv3d, object->obmat); + ED_view3d_clipping_local(rv3d, object->object_to_world); for (int i = 0; i < 6; i++) { copy_v4_v4(planes.world[i], rv3d->clip_local[i]); } - copy_m4_m4(planes.ModelMatrix, object->obmat); + copy_m4_m4(planes.ModelMatrix, object->object_to_world); } drw_batch_cache_validate(object); @@ -3086,6 +3074,7 @@ void DRW_engines_free(void) GPU_FRAMEBUFFER_FREE_SAFE(g_select_buffer.framebuffer_depth_only); DRW_shaders_free(); + DRW_pointcloud_free(); DRW_curves_free(); DRW_volume_free(); DRW_shape_cache_free(); diff --git a/source/blender/draw/intern/draw_manager_data.cc b/source/blender/draw/intern/draw_manager_data.cc index 9768f1ce9e7..4aa27e2288c 100644 --- a/source/blender/draw/intern/draw_manager_data.cc +++ b/source/blender/draw/intern/draw_manager_data.cc @@ -589,7 +589,7 @@ void DRW_shgroup_buffer_texture(DRWShadingGroup *shgroup, const char *name, GPUVertBuf *vertex_buffer) { - int location = GPU_shader_get_ssbo(shgroup->shader, name); + int location = GPU_shader_get_texture_binding(shgroup->shader, name); if (location == -1) { return; } @@ -606,7 +606,7 @@ void DRW_shgroup_buffer_texture_ref(DRWShadingGroup *shgroup, const char *name, GPUVertBuf **vertex_buffer) { - int location = GPU_shader_get_ssbo(shgroup->shader, name); + int location = GPU_shader_get_texture_binding(shgroup->shader, name); if (location == -1) { return; } @@ -724,8 +724,8 @@ static void drw_call_culling_init(DRWCullingState *cull, Object *ob) float corner[3]; /* Get BoundSphere center and radius from the BoundBox. */ mid_v3_v3v3(cull->bsphere.center, bbox->vec[0], bbox->vec[6]); - mul_v3_m4v3(corner, ob->obmat, bbox->vec[0]); - mul_m4_v3(ob->obmat, cull->bsphere.center); + mul_v3_m4v3(corner, ob->object_to_world, bbox->vec[0]); + mul_m4_v3(ob->object_to_world, cull->bsphere.center); cull->bsphere.radius = len_v3v3(cull->bsphere.center, corner); /* Bypass test for very large objects (see T67319). */ @@ -1017,7 +1017,7 @@ void DRW_shgroup_call_ex(DRWShadingGroup *shgroup, if (G.f & G_FLAG_PICKSEL) { drw_command_set_select_id(shgroup, nullptr, DST.select_id); } - DRWResourceHandle handle = drw_resource_handle(shgroup, ob ? ob->obmat : obmat, ob); + DRWResourceHandle handle = drw_resource_handle(shgroup, ob ? ob->object_to_world : obmat, ob); drw_command_draw(shgroup, geom, handle); /* Culling data. */ @@ -1042,7 +1042,7 @@ void DRW_shgroup_call_range( if (G.f & G_FLAG_PICKSEL) { drw_command_set_select_id(shgroup, nullptr, DST.select_id); } - DRWResourceHandle handle = drw_resource_handle(shgroup, ob ? ob->obmat : nullptr, ob); + DRWResourceHandle handle = drw_resource_handle(shgroup, ob ? ob->object_to_world : nullptr, ob); drw_command_draw_range(shgroup, geom, handle, v_sta, v_num); } @@ -1053,7 +1053,7 @@ void DRW_shgroup_call_instance_range( if (G.f & G_FLAG_PICKSEL) { drw_command_set_select_id(shgroup, nullptr, DST.select_id); } - DRWResourceHandle handle = drw_resource_handle(shgroup, ob ? ob->obmat : nullptr, ob); + DRWResourceHandle handle = drw_resource_handle(shgroup, ob ? ob->object_to_world : nullptr, ob); drw_command_draw_intance_range(shgroup, geom, handle, i_sta, i_num); } @@ -1099,7 +1099,7 @@ static void drw_shgroup_call_procedural_add_ex(DRWShadingGroup *shgroup, if (G.f & G_FLAG_PICKSEL) { drw_command_set_select_id(shgroup, nullptr, DST.select_id); } - DRWResourceHandle handle = drw_resource_handle(shgroup, ob ? ob->obmat : nullptr, ob); + DRWResourceHandle handle = drw_resource_handle(shgroup, ob ? ob->object_to_world : nullptr, ob); drw_command_draw_procedural(shgroup, geom, handle, vert_count); } @@ -1149,7 +1149,7 @@ void DRW_shgroup_call_procedural_indirect(DRWShadingGroup *shgroup, if (G.f & G_FLAG_PICKSEL) { drw_command_set_select_id(shgroup, nullptr, DST.select_id); } - DRWResourceHandle handle = drw_resource_handle(shgroup, ob ? ob->obmat : nullptr, ob); + DRWResourceHandle handle = drw_resource_handle(shgroup, ob ? ob->object_to_world : nullptr, ob); drw_command_draw_indirect(shgroup, geom, handle, indirect_buf); } @@ -1159,7 +1159,7 @@ void DRW_shgroup_call_instances(DRWShadingGroup *shgroup, Object *ob, GPUBatch * if (G.f & G_FLAG_PICKSEL) { drw_command_set_select_id(shgroup, nullptr, DST.select_id); } - DRWResourceHandle handle = drw_resource_handle(shgroup, ob ? ob->obmat : nullptr, ob); + DRWResourceHandle handle = drw_resource_handle(shgroup, ob ? ob->object_to_world : nullptr, ob); drw_command_draw_instance(shgroup, geom, handle, count, false); } @@ -1173,7 +1173,7 @@ void DRW_shgroup_call_instances_with_attrs(DRWShadingGroup *shgroup, if (G.f & G_FLAG_PICKSEL) { drw_command_set_select_id(shgroup, nullptr, DST.select_id); } - DRWResourceHandle handle = drw_resource_handle(shgroup, ob ? ob->obmat : nullptr, ob); + DRWResourceHandle handle = drw_resource_handle(shgroup, ob ? ob->object_to_world : nullptr, ob); GPUBatch *batch = DRW_temp_batch_instance_request( DST.vmempool->idatalist, nullptr, inst_attributes, geom); drw_command_draw_instance(shgroup, batch, handle, 0, true); @@ -1283,7 +1283,7 @@ static void drw_sculpt_get_frustum_planes(Object *ob, float planes[6][4]) * 4x4 matrix is done by multiplying with the transpose inverse. * The inverse cancels out here since we transform by inverse(obmat). */ float tmat[4][4]; - transpose_m4_m4(tmat, ob->obmat); + transpose_m4_m4(tmat, ob->object_to_world); for (int i = 0; i < 6; i++) { mul_m4_v4(tmat, planes[i]); } @@ -1361,7 +1361,7 @@ static void drw_sculpt_generate_calls(DRWSculptCallbackData *scd) if (SCULPT_DEBUG_BUFFERS) { int debug_node_nr = 0; - DRW_debug_modelmat(scd->ob->obmat); + DRW_debug_modelmat(scd->ob->object_to_world); BKE_pbvh_draw_debug_cb( pbvh, (void (*)(PBVHNode * n, void *d, const float min[3], const float max[3], PBVHNodeFlags f)) @@ -1714,23 +1714,32 @@ static void drw_shgroup_init(DRWShadingGroup *shgroup, GPUShader *shader) } #ifdef DEBUG - int debug_print_location = GPU_shader_get_builtin_ssbo(shader, GPU_STORAGE_BUFFER_DEBUG_PRINT); - if (debug_print_location != -1) { - GPUStorageBuf *buf = drw_debug_gpu_print_buf_get(); - drw_shgroup_uniform_create_ex( - shgroup, debug_print_location, DRW_UNIFORM_STORAGE_BLOCK, buf, GPU_SAMPLER_DEFAULT, 0, 1); + /* TODO(Metal): Support Shader debug print. + * This is not currently supported by Metal Backend. */ + if (GPU_backend_get_type() != GPU_BACKEND_METAL) { + int debug_print_location = GPU_shader_get_builtin_ssbo(shader, GPU_STORAGE_BUFFER_DEBUG_PRINT); + if (debug_print_location != -1) { + GPUStorageBuf *buf = drw_debug_gpu_print_buf_get(); + drw_shgroup_uniform_create_ex(shgroup, + debug_print_location, + DRW_UNIFORM_STORAGE_BLOCK, + buf, + GPU_SAMPLER_DEFAULT, + 0, + 1); # ifndef DISABLE_DEBUG_SHADER_PRINT_BARRIER - /* Add a barrier to allow multiple shader writing to the same buffer. */ - DRW_shgroup_barrier(shgroup, GPU_BARRIER_SHADER_STORAGE); + /* Add a barrier to allow multiple shader writing to the same buffer. */ + DRW_shgroup_barrier(shgroup, GPU_BARRIER_SHADER_STORAGE); # endif - } + } - int debug_draw_location = GPU_shader_get_builtin_ssbo(shader, GPU_STORAGE_BUFFER_DEBUG_VERTS); - if (debug_draw_location != -1) { - GPUStorageBuf *buf = drw_debug_gpu_draw_buf_get(); - drw_shgroup_uniform_create_ex( - shgroup, debug_draw_location, DRW_UNIFORM_STORAGE_BLOCK, buf, GPU_SAMPLER_DEFAULT, 0, 1); - /* NOTE(fclem): No barrier as ordering is not important. */ + int debug_draw_location = GPU_shader_get_builtin_ssbo(shader, GPU_STORAGE_BUFFER_DEBUG_VERTS); + if (debug_draw_location != -1) { + GPUStorageBuf *buf = drw_debug_gpu_draw_buf_get(); + drw_shgroup_uniform_create_ex( + shgroup, debug_draw_location, DRW_UNIFORM_STORAGE_BLOCK, buf, GPU_SAMPLER_DEFAULT, 0, 1); + /* NOTE(fclem): No barrier as ordering is not important. */ + } } #endif diff --git a/source/blender/draw/intern/draw_manager_text.cc b/source/blender/draw/intern/draw_manager_text.cc index 100ef528bc8..239f6fcca73 100644 --- a/source/blender/draw/intern/draw_manager_text.cc +++ b/source/blender/draw/intern/draw_manager_text.cc @@ -305,11 +305,11 @@ void DRW_text_edit_mesh_measure_stats(ARegion *region, if (clip_segment_v3_plane_n(v1, v2, clip_planes, 4, v1_clip, v2_clip)) { mid_v3_v3v3(vmid, v1_clip, v2_clip); - mul_m4_v3(ob->obmat, vmid); + mul_m4_v3(ob->object_to_world, vmid); if (do_global) { - mul_mat3_m4_v3(ob->obmat, v1); - mul_mat3_m4_v3(ob->obmat, v2); + mul_mat3_m4_v3(ob->object_to_world, v1); + mul_mat3_m4_v3(ob->object_to_world, v2); } if (unit->system) { @@ -373,7 +373,7 @@ void DRW_text_edit_mesh_measure_stats(ARegion *region, float angle; mid_v3_v3v3(vmid, v1_clip, v2_clip); - mul_m4_v3(ob->obmat, vmid); + mul_m4_v3(ob->object_to_world, vmid); if (use_coords) { copy_v3_v3(no_a, poly_normals[BM_elem_index_get(l_a->f)]); @@ -443,16 +443,16 @@ void DRW_text_edit_mesh_measure_stats(ARegion *region, n += 3; if (do_global) { - mul_mat3_m4_v3(ob->obmat, v1); - mul_mat3_m4_v3(ob->obmat, v2); - mul_mat3_m4_v3(ob->obmat, v3); + mul_mat3_m4_v3(ob->object_to_world, v1); + mul_mat3_m4_v3(ob->object_to_world, v2); + mul_mat3_m4_v3(ob->object_to_world, v3); } area += area_tri_v3(v1, v2, v3); } mul_v3_fl(vmid, 1.0f / float(n)); - mul_m4_v3(ob->obmat, vmid); + mul_m4_v3(ob->object_to_world, vmid); if (unit->system) { numstr_len = BKE_unit_value_as_string( @@ -522,9 +522,9 @@ void DRW_text_edit_mesh_measure_stats(ARegion *region, copy_v3_v3(v2_local, v2); if (do_global) { - mul_mat3_m4_v3(ob->obmat, v1); - mul_mat3_m4_v3(ob->obmat, v2); - mul_mat3_m4_v3(ob->obmat, v3); + mul_mat3_m4_v3(ob->object_to_world, v1); + mul_mat3_m4_v3(ob->object_to_world, v2); + mul_mat3_m4_v3(ob->object_to_world, v3); } float angle = angle_v3v3v3(v1, v2, v3); @@ -535,7 +535,7 @@ void DRW_text_edit_mesh_measure_stats(ARegion *region, (is_rad) ? angle : RAD2DEGF(angle), (is_rad) ? "r" : "°"); interp_v3_v3v3(fvec, vmid, v2_local, 0.8f); - mul_m4_v3(ob->obmat, fvec); + mul_m4_v3(ob->object_to_world, fvec); DRW_text_cache_add(dt, fvec, numstr, numstr_len, 0, 0, txt_flag, col); } } @@ -566,7 +566,7 @@ void DRW_text_edit_mesh_measure_stats(ARegion *region, copy_v3_v3(v1, v->co); } - mul_m4_v3(ob->obmat, v1); + mul_m4_v3(ob->object_to_world, v1); numstr_len = BLI_snprintf_rlen(numstr, sizeof(numstr), "%d", i); DRW_text_cache_add(dt, v1, numstr, numstr_len, 0, 0, txt_flag, col); @@ -595,7 +595,7 @@ void DRW_text_edit_mesh_measure_stats(ARegion *region, if (clip_segment_v3_plane_n(v1, v2, clip_planes, 4, v1_clip, v2_clip)) { mid_v3_v3v3(vmid, v1_clip, v2_clip); - mul_m4_v3(ob->obmat, vmid); + mul_m4_v3(ob->object_to_world, vmid); numstr_len = BLI_snprintf_rlen(numstr, sizeof(numstr), "%d", i); DRW_text_cache_add( @@ -629,7 +629,7 @@ void DRW_text_edit_mesh_measure_stats(ARegion *region, BM_face_calc_center_median(f, v1); } - mul_m4_v3(ob->obmat, v1); + mul_m4_v3(ob->object_to_world, v1); numstr_len = BLI_snprintf_rlen(numstr, sizeof(numstr), "%d", i); DRW_text_cache_add(dt, v1, numstr, numstr_len, 0, 0, txt_flag, col); diff --git a/source/blender/draw/intern/draw_pass.hh b/source/blender/draw/intern/draw_pass.hh index 24dfdd1b97b..892dfdddfcf 100644 --- a/source/blender/draw/intern/draw_pass.hh +++ b/source/blender/draw/intern/draw_pass.hh @@ -14,8 +14,7 @@ * #Pass. Use many #PassSub along with a main #Pass to reduce the overhead and allow groupings of * commands. \note The draw call order inside a batch of multiple draw with the exact same state is * not guaranteed and is not even deterministic. Use a #PassSimple or #PassSortable if ordering is - * needed. \note As of now, it is also quite limited in the type of draw command it can record - * (no custom vertex count, no custom first vertex). + * needed. Custom vertex count and custom first vertex will effectively disable batching. * * `PassSimple`: * Does not have the overhead of #PassMain but does not have the culling and batching optimization. @@ -192,6 +191,12 @@ class PassBase { void shader_set(GPUShader *shader); /** + * Bind a framebuffer. This is equivalent to a deferred GPU_framebuffer_bind() call. + * \note Changes the global GPU state (outside of DRW). + */ + void framebuffer_set(GPUFrameBuffer *framebuffer); + + /** * Bind a material shader along with its associated resources. Any following bind() or * push_constant() call will use its interface. * IMPORTANT: Assumes material is compiled and can be used (no compilation error). @@ -743,6 +748,11 @@ template<class T> inline void PassBase<T>::shader_set(GPUShader *shader) create_command(Type::ShaderBind).shader_bind = {shader}; } +template<class T> inline void PassBase<T>::framebuffer_set(GPUFrameBuffer *framebuffer) +{ + create_command(Type::FramebufferBind).framebuffer_bind = {framebuffer}; +} + template<class T> inline void PassBase<T>::material_set(Manager &manager, GPUMaterial *material) { GPUPass *gpupass = GPU_material_get_pass(material); diff --git a/source/blender/draw/intern/draw_pbvh.cc b/source/blender/draw/intern/draw_pbvh.cc index 880a5a445f4..b25bb42a8a5 100644 --- a/source/blender/draw/intern/draw_pbvh.cc +++ b/source/blender/draw/intern/draw_pbvh.cc @@ -389,12 +389,19 @@ struct PBVHBatches { break; case CD_PBVH_MASK_TYPE: - foreach_grids([&](int /*x*/, int /*y*/, int /*grid_index*/, CCGElem *elems[4], int i) { - float *mask = CCG_elem_mask(&args->ccg_key, elems[i]); + if (args->ccg_key.has_mask) { + foreach_grids([&](int /*x*/, int /*y*/, int /*grid_index*/, CCGElem *elems[4], int i) { + float *mask = CCG_elem_mask(&args->ccg_key, elems[i]); - *static_cast<uchar *>(GPU_vertbuf_raw_step(&access)) = mask ? uchar(*mask * 255.0f) : - 255; - }); + *static_cast<uchar *>(GPU_vertbuf_raw_step(&access)) = uchar(*mask * 255.0f); + }); + } + else { + foreach_grids( + [&](int /*x*/, int /*y*/, int /*grid_index*/, CCGElem * /*elems*/[4], int /*i*/) { + *static_cast<uchar *>(GPU_vertbuf_raw_step(&access)) = 0; + }); + } break; case CD_PBVH_FSET_TYPE: { @@ -944,6 +951,14 @@ struct PBVHBatches { void create_index_faces(PBVH_GPU_Args *args) { + int *mat_index = static_cast<int *>( + CustomData_get_layer_named(args->pdata, CD_PROP_INT32, "material_index")); + + if (mat_index && args->totprim) { + int poly_index = args->mlooptri[args->prim_indices[0]].poly; + material_index = mat_index[poly_index]; + } + /* Calculate number of edges*/ int edge_count = 0; for (int i = 0; i < args->totprim; i++) { @@ -952,6 +967,7 @@ struct PBVHBatches { if (args->hide_poly && args->hide_poly[lt->poly]) { continue; } + int r_edges[3]; BKE_mesh_looptri_get_real_edges(args->me, lt, r_edges); @@ -1023,6 +1039,14 @@ struct PBVHBatches { void create_index_grids(PBVH_GPU_Args *args) { + int *mat_index = static_cast<int *>( + CustomData_get_layer_named(args->pdata, CD_PROP_INT32, "material_index")); + + if (mat_index && args->totprim) { + int poly_index = BKE_subdiv_ccg_grid_to_face_index(args->subdiv_ccg, args->grid_indices[0]); + material_index = mat_index[poly_index]; + } + needs_tri_index = true; int gridsize = args->ccg_key.grid_size; int totgrid = args->totprim; diff --git a/source/blender/draw/intern/draw_pointcloud.cc b/source/blender/draw/intern/draw_pointcloud.cc new file mode 100644 index 00000000000..582dc690cee --- /dev/null +++ b/source/blender/draw/intern/draw_pointcloud.cc @@ -0,0 +1,103 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later + * Copyright 2017 Blender Foundation. All rights reserved. */ + +/** \file + * \ingroup draw + * + * \brief Contains procedural GPU hair drawing methods. + */ + +#include "BLI_string_utils.h" +#include "BLI_utildefines.h" + +#include "DNA_customdata_types.h" +#include "DNA_pointcloud_types.h" + +#include "BKE_curves.hh" +#include "BKE_geometry_set.hh" + +#include "GPU_batch.h" +#include "GPU_capabilities.h" +#include "GPU_compute.h" +#include "GPU_material.h" +#include "GPU_shader.h" +#include "GPU_texture.h" +#include "GPU_vertex_buffer.h" + +#include "DRW_gpu_wrapper.hh" +#include "DRW_render.h" + +#include "draw_attributes.h" +#include "draw_cache_impl.h" +#include "draw_common.h" +#include "draw_manager.h" +#include "draw_pointcloud_private.hh" + +static GPUVertBuf *g_dummy_vbo = nullptr; + +void DRW_pointcloud_init() +{ + if (g_dummy_vbo == nullptr) { + /* initialize vertex format */ + GPUVertFormat format = {0}; + uint dummy_id = GPU_vertformat_attr_add(&format, "dummy", GPU_COMP_F32, 4, GPU_FETCH_FLOAT); + + g_dummy_vbo = GPU_vertbuf_create_with_format_ex( + &format, GPU_USAGE_STATIC | GPU_USAGE_FLAG_BUFFER_TEXTURE_ONLY); + + const float vert[4] = {0.0f, 0.0f, 0.0f, 0.0f}; + GPU_vertbuf_data_alloc(g_dummy_vbo, 1); + GPU_vertbuf_attr_fill(g_dummy_vbo, dummy_id, vert); + } +} + +DRWShadingGroup *DRW_shgroup_pointcloud_create_sub(Object *object, + DRWShadingGroup *shgrp_parent, + GPUMaterial *gpu_material) +{ + PointCloud &pointcloud = *static_cast<PointCloud *>(object->data); + + DRWShadingGroup *shgrp = DRW_shgroup_create_sub(shgrp_parent); + + /* Fix issue with certain driver not drawing anything if there is no texture bound to + * "ac", "au", "u" or "c". */ + DRW_shgroup_buffer_texture(shgrp, "u", g_dummy_vbo); + DRW_shgroup_buffer_texture(shgrp, "au", g_dummy_vbo); + DRW_shgroup_buffer_texture(shgrp, "c", g_dummy_vbo); + DRW_shgroup_buffer_texture(shgrp, "ac", g_dummy_vbo); + + GPUVertBuf *pos_rad_buf = pointcloud_position_and_radius_get(&pointcloud); + DRW_shgroup_buffer_texture(shgrp, "ptcloud_pos_rad_tx", pos_rad_buf); + + if (gpu_material != nullptr) { + + // const DRW_Attributes &attrs = cache->attr_used; + // for (int i = 0; i < attrs.num_requests; i++) { + // const DRW_AttributeRequest &request = attrs.requests[i]; + + // char sampler_name[32]; + // /* \note reusing curve attribute function. */ + // drw_curves_get_attribute_sampler_name(request.attribute_name, sampler_name); + + // GPUTexture *attribute_buf = DRW_pointcloud_evaluated_attribute(&pointcloud); + // if (!cache->attributes_buf[i]) { + // continue; + // } + // DRW_shgroup_buffer_texture_ref(shgrp, sampler_name, attribute_buf); + // } + + /* Only single material supported for now. */ + GPUBatch **geom = pointcloud_surface_shaded_get(&pointcloud, &gpu_material, 1); + DRW_shgroup_call(shgrp, geom[0], object); + } + else { + GPUBatch *geom = pointcloud_surface_get(&pointcloud); + DRW_shgroup_call(shgrp, geom, object); + } + return shgrp; +} + +void DRW_pointcloud_free() +{ + GPU_VERTBUF_DISCARD_SAFE(g_dummy_vbo); +} diff --git a/source/blender/draw/intern/draw_pointcloud_private.hh b/source/blender/draw/intern/draw_pointcloud_private.hh new file mode 100644 index 00000000000..9422d7fbc99 --- /dev/null +++ b/source/blender/draw/intern/draw_pointcloud_private.hh @@ -0,0 +1,19 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later + * Copyright 2021 Blender Foundation. All rights reserved. */ + +/** \file + * \ingroup draw + */ + +#pragma once + +struct PointCloud; +struct GPUBatch; +struct GPUVertBuf; +struct GPUMaterial; + +GPUVertBuf *pointcloud_position_and_radius_get(PointCloud *pointcloud); +GPUBatch **pointcloud_surface_shaded_get(PointCloud *pointcloud, + GPUMaterial **gpu_materials, + int mat_len); +GPUBatch *pointcloud_surface_get(PointCloud *pointcloud); diff --git a/source/blender/draw/intern/draw_resource.hh b/source/blender/draw/intern/draw_resource.hh index 2df38e32ed2..b116d7fe183 100644 --- a/source/blender/draw/intern/draw_resource.hh +++ b/source/blender/draw/intern/draw_resource.hh @@ -31,7 +31,7 @@ inline void ObjectMatrices::sync(const Object &object) { - model = object.obmat; + model = object.object_to_world; model_inverse = object.imat; } diff --git a/source/blender/draw/intern/draw_volume.cc b/source/blender/draw/intern/draw_volume.cc index 2b4b0e3c089..5c1ce7c3111 100644 --- a/source/blender/draw/intern/draw_volume.cc +++ b/source/blender/draw/intern/draw_volume.cc @@ -127,7 +127,7 @@ static DRWShadingGroup *drw_volume_object_grids_init(Object *ob, grp = DRW_shgroup_create_sub(grp); - volume_infos.density_scale = BKE_volume_density_scale(volume, ob->obmat); + volume_infos.density_scale = BKE_volume_density_scale(volume, ob->object_to_world); volume_infos.color_mul = float4(1.0f); volume_infos.temperature_mul = 1.0f; volume_infos.temperature_bias = 0.0f; diff --git a/source/blender/draw/intern/shaders/common_gpencil_lib.glsl b/source/blender/draw/intern/shaders/common_gpencil_lib.glsl index 123c493b572..def841b07aa 100644 --- a/source/blender/draw/intern/shaders/common_gpencil_lib.glsl +++ b/source/blender/draw/intern/shaders/common_gpencil_lib.glsl @@ -90,10 +90,15 @@ float gpencil_clamp_small_stroke_thickness(float thickness, vec4 ndc_pos) #ifdef GPU_VERTEX_SHADER -/* Trick to detect if a drawcall is stroke or fill. - * This does mean that we need to draw an empty stroke segment before starting - * to draw the real stroke segments. */ -# define GPENCIL_IS_STROKE_VERTEX (gl_InstanceID != 0) +int gpencil_stroke_point_id() +{ + return (gl_VertexID & ~GP_IS_STROKE_VERTEX_BIT) >> GP_VERTEX_ID_SHIFT; +} + +bool gpencil_is_stroke_vertex() +{ + return flag_test(gl_VertexID, GP_IS_STROKE_VERTEX_BIT); +} /** * Returns value of gl_Position. @@ -120,20 +125,7 @@ float gpencil_clamp_small_stroke_thickness(float thickness, vec4 ndc_pos) * WARNING: Max attribute count is actually 14 because OSX OpenGL implementation * considers gl_VertexID and gl_InstanceID as vertex attribute. (see T74536) */ -vec4 gpencil_vertex(ivec4 ma, - ivec4 ma1, - ivec4 ma2, - ivec4 ma3, - vec4 pos, - vec4 pos1, - vec4 pos2, - vec4 pos3, - vec4 uv1, - vec4 uv2, - vec4 col1, - vec4 col2, - vec4 fcol1, - vec4 viewport_size, +vec4 gpencil_vertex(vec4 viewport_size, gpMaterialFlag material_flags, vec2 alignment_rot, /* World Position. */ @@ -155,6 +147,24 @@ vec4 gpencil_vertex(ivec4 ma, /* Stroke hardness. */ out float out_hardness) { + int stroke_point_id = (gl_VertexID & ~GP_IS_STROKE_VERTEX_BIT) >> GP_VERTEX_ID_SHIFT; + + /* Attribute Loading. */ + vec4 pos = texelFetch(gp_pos_tx, (stroke_point_id - 1) * 3 + 0); + vec4 pos1 = texelFetch(gp_pos_tx, (stroke_point_id + 0) * 3 + 0); + vec4 pos2 = texelFetch(gp_pos_tx, (stroke_point_id + 1) * 3 + 0); + vec4 pos3 = texelFetch(gp_pos_tx, (stroke_point_id + 2) * 3 + 0); + ivec4 ma = floatBitsToInt(texelFetch(gp_pos_tx, (stroke_point_id - 1) * 3 + 1)); + ivec4 ma1 = floatBitsToInt(texelFetch(gp_pos_tx, (stroke_point_id + 0) * 3 + 1)); + ivec4 ma2 = floatBitsToInt(texelFetch(gp_pos_tx, (stroke_point_id + 1) * 3 + 1)); + ivec4 ma3 = floatBitsToInt(texelFetch(gp_pos_tx, (stroke_point_id + 2) * 3 + 1)); + vec4 uv1 = texelFetch(gp_pos_tx, (stroke_point_id + 0) * 3 + 2); + vec4 uv2 = texelFetch(gp_pos_tx, (stroke_point_id + 1) * 3 + 2); + + vec4 col1 = texelFetch(gp_col_tx, (stroke_point_id + 0) * 2 + 0); + vec4 col2 = texelFetch(gp_col_tx, (stroke_point_id + 1) * 2 + 0); + vec4 fcol1 = texelFetch(gp_col_tx, (stroke_point_id + 0) * 2 + 1); + # define thickness1 pos1.w # define thickness2 pos2.w # define strength1 uv1.w @@ -167,7 +177,7 @@ vec4 gpencil_vertex(ivec4 ma, vec4 out_ndc; - if (GPENCIL_IS_STROKE_VERTEX) { + if (gpencil_is_stroke_vertex()) { bool is_dot = flag_test(material_flags, GP_STROKE_ALIGNMENT); bool is_squares = !flag_test(material_flags, GP_STROKE_DOTS); @@ -177,13 +187,6 @@ vec4 gpencil_vertex(ivec4 ma, is_squares = false; } - /* Endpoints, we discard the vertices. */ - if (ma1.x == -1 || (!is_dot && ma2.x == -1)) { - /* We set the vertex at the camera origin to generate 0 fragments. */ - out_ndc = vec4(0.0, 0.0, -3e36, 0.0); - return out_ndc; - } - /* Avoid using a vertex attribute for quad positioning. */ float x = float(gl_VertexID & 1) * 2.0 - 1.0; /* [-1..1] */ float y = float(gl_VertexID & 2) - 1.0; /* [-1..1] */ @@ -336,8 +339,7 @@ vec4 gpencil_vertex(ivec4 ma, out_N = safe_normalize(N); /* Decode fill opacity. */ - out_color = vec4(fcol1.rgb, floor(fcol1.a / 10.0)); - out_color.a /= 10000.0; + out_color = vec4(fcol1.rgb, floor(fcol1.a / 10.0) / 10000.0); /* We still offset the fills a little to avoid overlaps */ out_ndc.z += 0.000002; @@ -355,20 +357,7 @@ vec4 gpencil_vertex(ivec4 ma, return out_ndc; } -vec4 gpencil_vertex(ivec4 ma, - ivec4 ma1, - ivec4 ma2, - ivec4 ma3, - vec4 pos, - vec4 pos1, - vec4 pos2, - vec4 pos3, - vec4 uv1, - vec4 uv2, - vec4 col1, - vec4 col2, - vec4 fcol1, - vec4 viewport_size, +vec4 gpencil_vertex(vec4 viewport_size, out vec3 out_P, out vec3 out_N, out vec4 out_color, @@ -379,20 +368,7 @@ vec4 gpencil_vertex(ivec4 ma, out vec2 out_thickness, out float out_hardness) { - return gpencil_vertex(ma, - ma1, - ma2, - ma3, - pos, - pos1, - pos2, - pos3, - uv1, - uv2, - col1, - col2, - fcol1, - viewport_size, + return gpencil_vertex(viewport_size, 0u, vec2(1.0, 0.0), out_P, diff --git a/source/blender/draw/intern/shaders/common_pointcloud_lib.glsl b/source/blender/draw/intern/shaders/common_pointcloud_lib.glsl index dd725ad327f..8725e036435 100644 --- a/source/blender/draw/intern/shaders/common_pointcloud_lib.glsl +++ b/source/blender/draw/intern/shaders/common_pointcloud_lib.glsl @@ -2,16 +2,10 @@ /* NOTE: To be used with UNIFORM_RESOURCE_ID and INSTANCED_ATTR as define. */ #pragma BLENDER_REQUIRE(common_view_lib.glsl) -#ifndef DRW_SHADER_SHARED_H - -in vec4 pos; /* Position and radius. */ - -/* ---- Instanced attribs ---- */ - -in vec3 pos_inst; -in vec3 nor; - -#endif +int pointcloud_get_point_id() +{ + return gl_VertexID / 32; +} mat3 pointcloud_get_facing_matrix(vec3 p) { @@ -25,8 +19,10 @@ mat3 pointcloud_get_facing_matrix(vec3 p) /* Returns world center position and radius. */ void pointcloud_get_pos_and_radius(out vec3 outpos, out float outradius) { - outpos = point_object_to_world(pos.xyz); - outradius = dot(abs(mat3(ModelMatrix) * pos.www), vec3(1.0 / 3.0)); + int id = pointcloud_get_point_id(); + vec4 pos_rad = texelFetch(ptcloud_pos_rad_tx, id); + outpos = point_object_to_world(pos_rad.xyz); + outradius = dot(abs(mat3(ModelMatrix) * pos_rad.www), vec3(1.0 / 3.0)); } /* Return world position and normal. */ @@ -38,15 +34,67 @@ void pointcloud_get_pos_and_nor(out vec3 outpos, out vec3 outnor) mat3 facing_mat = pointcloud_get_facing_matrix(p); + /** \note: Avoid modulo by non-power-of-two in shader. See Index buffer setup. */ + int vert_id = gl_VertexID % 32; + vec3 pos_inst = vec3(0.0); + + switch (vert_id) { + case 0: + pos_inst.z = 1.0; + break; + case 1: + pos_inst.x = 1.0; + break; + case 2: + pos_inst.y = 1.0; + break; + case 3: + pos_inst.x = -1.0; + break; + case 4: + pos_inst.y = -1.0; + break; + } + /* TODO(fclem): remove multiplication here. Here only for keeping the size correct for now. */ radius *= 0.01; - outpos = p + (facing_mat * pos_inst) * radius; - outnor = facing_mat * nor; + outnor = facing_mat * pos_inst; + outpos = p + outnor * radius; } -vec3 pointcloud_get_pos(void) +vec3 pointcloud_get_pos() { vec3 outpos, outnor; pointcloud_get_pos_and_nor(outpos, outnor); return outpos; } + +float pointcloud_get_customdata_float(const samplerBuffer cd_buf) +{ + int id = pointcloud_get_point_id(); + return texelFetch(cd_buf, id).r; +} + +vec2 pointcloud_get_customdata_vec2(const samplerBuffer cd_buf) +{ + int id = pointcloud_get_point_id(); + return texelFetch(cd_buf, id).rg; +} + +vec3 pointcloud_get_customdata_vec3(const samplerBuffer cd_buf) +{ + int id = pointcloud_get_point_id(); + return texelFetch(cd_buf, id).rgb; +} + +vec4 pointcloud_get_customdata_vec4(const samplerBuffer cd_buf) +{ + int id = pointcloud_get_point_id(); + return texelFetch(cd_buf, id).rgba; +} + +vec2 pointcloud_get_barycentric(void) +{ + /* TODO: To be implemented. */ + return vec2(0.0); +} diff --git a/source/blender/draw/intern/shaders/draw_view_info.hh b/source/blender/draw/intern/shaders/draw_view_info.hh index 7b500f66a68..23892a39062 100644 --- a/source/blender/draw/intern/shaders/draw_view_info.hh +++ b/source/blender/draw/intern/shaders/draw_view_info.hh @@ -112,9 +112,7 @@ GPU_SHADER_CREATE_INFO(draw_hair) .additional_info("draw_modelmat", "draw_resource_id"); GPU_SHADER_CREATE_INFO(draw_pointcloud) - .vertex_in(0, Type::VEC4, "pos") - .vertex_in(1, Type::VEC3, "pos_inst") - .vertex_in(2, Type::VEC3, "nor") + .sampler(0, ImageType::FLOAT_BUFFER, "ptcloud_pos_rad_tx", Frequency::BATCH) .additional_info("draw_modelmat_instanced_attr", "draw_resource_id_uniform"); GPU_SHADER_CREATE_INFO(draw_volume).additional_info("draw_modelmat", "draw_resource_id_uniform"); @@ -122,26 +120,15 @@ GPU_SHADER_CREATE_INFO(draw_volume).additional_info("draw_modelmat", "draw_resou GPU_SHADER_CREATE_INFO(draw_gpencil) .typedef_source("gpencil_shader_shared.h") .define("DRW_GPENCIL_INFO") - .vertex_in(0, Type::IVEC4, "ma") - .vertex_in(1, Type::IVEC4, "ma1") - .vertex_in(2, Type::IVEC4, "ma2") - .vertex_in(3, Type::IVEC4, "ma3") - .vertex_in(4, Type::VEC4, "pos") - .vertex_in(5, Type::VEC4, "pos1") - .vertex_in(6, Type::VEC4, "pos2") - .vertex_in(7, Type::VEC4, "pos3") - .vertex_in(8, Type::VEC4, "uv1") - .vertex_in(9, Type::VEC4, "uv2") - .vertex_in(10, Type::VEC4, "col1") - .vertex_in(11, Type::VEC4, "col2") - .vertex_in(12, Type::VEC4, "fcol1") + .sampler(0, ImageType::FLOAT_BUFFER, "gp_pos_tx") + .sampler(1, ImageType::FLOAT_BUFFER, "gp_col_tx") /* Per Object */ .push_constant(Type::FLOAT, "gpThicknessScale") /* TODO(fclem): Replace with object info. */ .push_constant(Type::FLOAT, "gpThicknessWorldScale") /* TODO(fclem): Same as above. */ .define("gpThicknessIsScreenSpace", "(gpThicknessWorldScale < 0.0)") /* Per Layer */ .push_constant(Type::FLOAT, "gpThicknessOffset") - .additional_info("draw_modelmat", "draw_resource_id_uniform", "draw_object_infos"); + .additional_info("draw_modelmat", "draw_object_infos"); /** \} */ diff --git a/source/blender/draw/tests/draw_pass_test.cc b/source/blender/draw/tests/draw_pass_test.cc index 394ca8bd3cf..95ab8fa2ef1 100644 --- a/source/blender/draw/tests/draw_pass_test.cc +++ b/source/blender/draw/tests/draw_pass_test.cc @@ -181,12 +181,19 @@ static void test_draw_pass_multi_draw() pass.draw_procedural(GPU_PRIM_LINES, 1, -1, -1, {5}); pass.draw_procedural(GPU_PRIM_POINTS, 6, -1, -1, {5}); pass.draw_procedural(GPU_PRIM_TRIS, 3, -1, -1, {6}); + /* Custom calls should use their own group and never be batched. */ + pass.draw_procedural(GPU_PRIM_TRIS, 2, 2, 2, {7}); + pass.draw_procedural(GPU_PRIM_TRIS, 2, 2, 2, {8}); std::string result = pass.serialize(); std::stringstream expected; expected << ".test.multi_draw" << std::endl; expected << " .shader_bind(gpu_shader_3D_image_color)" << std::endl; expected << " .draw_multi(3)" << std::endl; + expected << " .group(id=4, len=2)" << std::endl; + expected << " .proto(instance_len=2, resource_id=8, front_face)" << std::endl; + expected << " .group(id=3, len=2)" << std::endl; + expected << " .proto(instance_len=2, resource_id=7, front_face)" << std::endl; expected << " .group(id=2, len=1)" << std::endl; expected << " .proto(instance_len=1, resource_id=5, front_face)" << std::endl; expected << " .group(id=1, len=15)" << std::endl; diff --git a/source/blender/editors/animation/anim_motion_paths.c b/source/blender/editors/animation/anim_motion_paths.c index 23c1d68b4d6..4a83bb4c800 100644 --- a/source/blender/editors/animation/anim_motion_paths.c +++ b/source/blender/editors/animation/anim_motion_paths.c @@ -161,11 +161,11 @@ static void motionpaths_calc_bake_targets(ListBase *targets, int cframe) } /* Result must be in world-space. */ - mul_m4_v3(ob_eval->obmat, mpv->co); + mul_m4_v3(ob_eval->object_to_world, mpv->co); } else { /* World-space object location. */ - copy_v3_v3(mpv->co, ob_eval->obmat[3]); + copy_v3_v3(mpv->co, ob_eval->object_to_world[3]); } float mframe = (float)(cframe); diff --git a/source/blender/editors/animation/keyframing.c b/source/blender/editors/animation/keyframing.c index c9957b38853..96a9604a6f5 100644 --- a/source/blender/editors/animation/keyframing.c +++ b/source/blender/editors/animation/keyframing.c @@ -1044,12 +1044,12 @@ static float *visualkey_get_values( Object *ob = ptr->data; /* Loc code is specific... */ if (strstr(identifier, "location")) { - copy_v3_v3(buffer, ob->obmat[3]); + copy_v3_v3(buffer, ob->object_to_world[3]); *r_count = 3; return buffer; } - copy_m4_m4(tmat, ob->obmat); + copy_m4_m4(tmat, ob->object_to_world); rotmode = ob->rotmode; } else if (ptr->type == &RNA_PoseBone) { diff --git a/source/blender/editors/armature/armature_add.c b/source/blender/editors/armature/armature_add.c index 17484b2b0b7..fbdb375b8a6 100644 --- a/source/blender/editors/armature/armature_add.c +++ b/source/blender/editors/armature/armature_add.c @@ -181,13 +181,13 @@ static int armature_click_extrude_exec(bContext *C, wmOperator *UNUSED(op)) const View3DCursor *curs = &scene->cursor; copy_v3_v3(newbone->tail, curs->location); - sub_v3_v3v3(newbone->tail, newbone->tail, obedit->obmat[3]); + sub_v3_v3v3(newbone->tail, newbone->tail, obedit->object_to_world[3]); if (a == 1) { newbone->tail[0] = -newbone->tail[0]; } - copy_m3_m4(mat, obedit->obmat); + copy_m3_m4(mat, obedit->object_to_world); invert_m3_m3(imat, mat); mul_m3_v3(imat, newbone->tail); @@ -1569,7 +1569,7 @@ static int armature_bone_primitive_add_exec(bContext *C, wmOperator *op) copy_v3_v3(curs, CTX_data_scene(C)->cursor.location); /* Get inverse point for head and orientation for tail */ - invert_m4_m4(obedit->imat, obedit->obmat); + invert_m4_m4(obedit->imat, obedit->object_to_world); mul_m4_v3(obedit->imat, curs); if (rv3d && (U.flag & USER_ADD_VIEWALIGNED)) { @@ -1579,7 +1579,7 @@ static int armature_bone_primitive_add_exec(bContext *C, wmOperator *op) unit_m3(obmat); } - copy_m3_m4(viewmat, obedit->obmat); + copy_m3_m4(viewmat, obedit->object_to_world); mul_m3_m3m3(totmat, obmat, viewmat); invert_m3_m3(imat, totmat); diff --git a/source/blender/editors/armature/armature_edit.c b/source/blender/editors/armature/armature_edit.c index 9e828ebd501..810279f1b6c 100644 --- a/source/blender/editors/armature/armature_edit.c +++ b/source/blender/editors/armature/armature_edit.c @@ -113,7 +113,7 @@ void ED_armature_origin_set( /* Find the center-point. */ if (centermode == 2) { copy_v3_v3(cent, cursor); - invert_m4_m4(ob->imat, ob->obmat); + invert_m4_m4(ob->imat, ob->object_to_world); mul_m4_v3(ob->imat, cent); } else { @@ -154,7 +154,7 @@ void ED_armature_origin_set( /* Adjust object location for new center-point. */ if (centermode && (is_editmode == false)) { - mul_mat3_m4_v3(ob->obmat, cent); /* omit translation part */ + mul_mat3_m4_v3(ob->object_to_world, cent); /* omit translation part */ add_v3_v3(ob->loc, cent); } } @@ -282,14 +282,14 @@ static int armature_calc_roll_exec(bContext *C, wmOperator *op) axis_flip = true; } - copy_m3_m4(imat, ob->obmat); + copy_m3_m4(imat, ob->object_to_world); invert_m3(imat); if (type == CALC_ROLL_CURSOR) { /* Cursor */ float cursor_local[3]; const View3DCursor *cursor = &scene->cursor; - invert_m4_m4(ob->imat, ob->obmat); + invert_m4_m4(ob->imat, ob->object_to_world); copy_v3_v3(cursor_local, cursor->location); mul_m4_v3(ob->imat, cursor_local); @@ -730,7 +730,7 @@ static int armature_fill_bones_exec(bContext *C, wmOperator *op) ebp = points.first; /* Get points - cursor (tail) */ - invert_m4_m4(obedit->imat, obedit->obmat); + invert_m4_m4(obedit->imat, obedit->object_to_world); mul_v3_m4v3(curs, obedit->imat, scene->cursor.location); /* Create a bone */ @@ -767,7 +767,7 @@ static int armature_fill_bones_exec(bContext *C, wmOperator *op) float dist_sq_a, dist_sq_b; /* get cursor location */ - invert_m4_m4(obedit->imat, obedit->obmat); + invert_m4_m4(obedit->imat, obedit->object_to_world); mul_v3_m4v3(curs, obedit->imat, scene->cursor.location); /* get distances */ diff --git a/source/blender/editors/armature/armature_relations.c b/source/blender/editors/armature/armature_relations.c index 9f1883ccac0..fccf2964868 100644 --- a/source/blender/editors/armature/armature_relations.c +++ b/source/blender/editors/armature/armature_relations.c @@ -289,7 +289,7 @@ int ED_armature_join_objects_exec(bContext *C, wmOperator *op) /* Inverse transform for all selected armatures in this object, * See #object_join_exec for detailed comment on why the safe version is used. */ - invert_m4_m4_safe_ortho(oimat, ob_active->obmat); + invert_m4_m4_safe_ortho(oimat, ob_active->object_to_world); /* Get edit-bones of active armature to add edit-bones to */ ED_armature_to_edit(arm); @@ -321,7 +321,7 @@ int ED_armature_join_objects_exec(bContext *C, wmOperator *op) // BASACT->flag &= ~OB_MODE_POSE; /* Find the difference matrix */ - mul_m4_m4m4(mat, oimat, ob_iter->obmat); + mul_m4_m4m4(mat, oimat, ob_iter->object_to_world); /* Copy bones and posechannels from the object to the edit armature */ for (pchan = opose->chanbase.first; pchan; pchan = pchann) { diff --git a/source/blender/editors/armature/armature_select.c b/source/blender/editors/armature/armature_select.c index 6b8f790d30f..3ee0510ca7f 100644 --- a/source/blender/editors/armature/armature_select.c +++ b/source/blender/editors/armature/armature_select.c @@ -1601,8 +1601,8 @@ static const EnumPropertyItem prop_similar_types[] = { static float bone_length_squared_worldspace_get(Object *ob, EditBone *ebone) { float v1[3], v2[3]; - mul_v3_mat3_m4v3(v1, ob->obmat, ebone->head); - mul_v3_mat3_m4v3(v2, ob->obmat, ebone->tail); + mul_v3_mat3_m4v3(v1, ob->object_to_world, ebone->head); + mul_v3_mat3_m4v3(v2, ob->object_to_world, ebone->tail); return len_squared_v3v3(v1, v2); } @@ -1650,8 +1650,8 @@ static void bone_direction_worldspace_get(Object *ob, EditBone *ebone, float *r_ copy_v3_v3(v1, ebone->head); copy_v3_v3(v2, ebone->tail); - mul_m4_v3(ob->obmat, v1); - mul_m4_v3(ob->obmat, v2); + mul_m4_v3(ob->object_to_world, v1); + mul_m4_v3(ob->object_to_world, v2); sub_v3_v3v3(r_dir, v1, v2); normalize_v3(r_dir); diff --git a/source/blender/editors/armature/armature_skinning.c b/source/blender/editors/armature/armature_skinning.c index 6155aac621d..3c9c8cf05b3 100644 --- a/source/blender/editors/armature/armature_skinning.c +++ b/source/blender/editors/armature/armature_skinning.c @@ -365,8 +365,8 @@ static void add_verts_to_dgroups(ReportList *reports, copy_v3_v3(tip[j], bone->arm_tail); } - mul_m4_v3(par->obmat, root[j]); - mul_m4_v3(par->obmat, tip[j]); + mul_m4_v3(par->object_to_world, root[j]); + mul_m4_v3(par->object_to_world, tip[j]); /* set selected */ if (wpmode) { @@ -414,7 +414,7 @@ static void add_verts_to_dgroups(ReportList *reports, if (!vertsfilled) { copy_v3_v3(verts[i], mesh_verts[i].co); } - mul_m4_v3(ob->obmat, verts[i]); + mul_m4_v3(ob->object_to_world, verts[i]); } /* compute the weights based on gathered vertices and bones */ @@ -438,7 +438,7 @@ static void add_verts_to_dgroups(ReportList *reports, root, tip, selected, - mat4_to_scale(par->obmat)); + mat4_to_scale(par->object_to_world)); } /* only generated in some cases but can call anyway */ diff --git a/source/blender/editors/armature/armature_utils.c b/source/blender/editors/armature/armature_utils.c index 09174aa5e47..0465606e694 100644 --- a/source/blender/editors/armature/armature_utils.c +++ b/source/blender/editors/armature/armature_utils.c @@ -703,11 +703,11 @@ void ED_armature_from_edit(Main *bmain, bArmature *arm) newBone->inherit_scale_mode = eBone->inherit_scale_mode; if (eBone == arm->act_edbone) { - /* don't change active selection, this messes up separate which uses - * editmode toggle and can separate active bone which is de-selected originally */ + /* Don't change active selection, this messes up separate which uses + * edit-mode toggle and can separate active bone which is de-selected originally. */ - /* important, editbones can be active with only 1 point selected */ - /* newBone->flag |= BONE_SELECTED; */ + /* important, edit-bones can be active with only 1 point selected */ + /* `newBone->flag |= BONE_SELECTED;` */ arm->act_bone = newBone; } newBone->roll = 0.0f; diff --git a/source/blender/editors/armature/meshlaplacian.c b/source/blender/editors/armature/meshlaplacian.c index 567977e51c4..dfb9e8a79fa 100644 --- a/source/blender/editors/armature/meshlaplacian.c +++ b/source/blender/editors/armature/meshlaplacian.c @@ -1788,11 +1788,11 @@ void ED_mesh_deform_bind_callback(Object *object, mmd_orig->bindcagecos = (float *)mdb.cagecos; mmd_orig->verts_num = mdb.verts_num; mmd_orig->cage_verts_num = mdb.cage_verts_num; - copy_m4_m4(mmd_orig->bindmat, mmd_orig->object->obmat); + copy_m4_m4(mmd_orig->bindmat, mmd_orig->object->object_to_world); /* transform bindcagecos to world space */ for (a = 0; a < mdb.cage_verts_num; a++) { - mul_m4_v3(mmd_orig->object->obmat, mmd_orig->bindcagecos + a * 3); + mul_m4_v3(mmd_orig->object->object_to_world, mmd_orig->bindcagecos + a * 3); } /* free */ diff --git a/source/blender/editors/armature/pose_transform.c b/source/blender/editors/armature/pose_transform.c index 2a23615caa3..51071815823 100644 --- a/source/blender/editors/armature/pose_transform.c +++ b/source/blender/editors/armature/pose_transform.c @@ -77,10 +77,10 @@ static void applyarmature_fix_boneparents(const bContext *C, Scene *scene, Objec /* apply current transform from parent (not yet destroyed), * then calculate new parent inverse matrix */ - BKE_object_apply_mat4(ob, ob->obmat, false, false); + BKE_object_apply_mat4(ob, ob->object_to_world, false, false); BKE_object_workob_calc_parent(depsgraph, scene, ob, &workob); - invert_m4_m4(ob->parentinv, workob.obmat); + invert_m4_m4(ob->parentinv, workob.object_to_world); } } } @@ -361,7 +361,7 @@ static void applyarmature_reset_constraints(bPose *pose, const bool use_selected } } -/* set the current pose as the restpose */ +/* Set the current pose as the rest-pose. */ static int apply_armature_pose2bones_exec(bContext *C, wmOperator *op) { Main *bmain = CTX_data_main(C); @@ -404,10 +404,10 @@ static int apply_armature_pose2bones_exec(bContext *C, wmOperator *op) } } - /* Get editbones of active armature to alter */ + /* Get edit-bones of active armature to alter. */ ED_armature_to_edit(arm); - /* get pose of active object and move it out of posemode */ + /* Get pose of active object and move it out of pose-mode. */ pose = ob->pose; if (use_selected) { @@ -429,11 +429,11 @@ static int apply_armature_pose2bones_exec(bContext *C, wmOperator *op) } } - /* convert editbones back to bones, and then free the edit-data */ + /* Convert edit-bones back to bones, and then free the edit-data. */ ED_armature_from_edit(bmain, arm); ED_armature_edit_free(arm); - /* flush positions of posebones */ + /* Flush positions of pose-bones. */ BKE_pose_where_is(depsgraph, scene, ob); /* fix parenting of objects which are bone-parented */ @@ -788,7 +788,7 @@ static int pose_copy_exec(bContext *C, wmOperator *op) * existing on its own. */ BKE_copybuffer_copy_tag_ID(&ob_copy.id); - BLI_join_dirfile(str, sizeof(str), BKE_tempdir_base(), "copybuffer_pose.blend"); + BLI_path_join(str, sizeof(str), BKE_tempdir_base(), "copybuffer_pose.blend"); 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 @@ -844,7 +844,7 @@ static int pose_paste_exec(bContext *C, wmOperator *op) Main *tmp_bmain = BKE_main_new(); STRNCPY(tmp_bmain->filepath, BKE_main_blendfile_path_from_global()); - BLI_join_dirfile(str, sizeof(str), BKE_tempdir_base(), "copybuffer_pose.blend"); + BLI_path_join(str, sizeof(str), BKE_tempdir_base(), "copybuffer_pose.blend"); if (!BKE_copybuffer_read(tmp_bmain, str, op->reports, FILTER_ID_OB)) { BKE_report(op->reports, RPT_ERROR, "Copy buffer is empty"); BKE_main_free(tmp_bmain); diff --git a/source/blender/editors/asset/ED_asset_list.h b/source/blender/editors/asset/ED_asset_list.h index b54f81004f2..3d2aaa3bda1 100644 --- a/source/blender/editors/asset/ED_asset_list.h +++ b/source/blender/editors/asset/ED_asset_list.h @@ -23,6 +23,7 @@ struct wmNotifier; */ void ED_assetlist_storage_fetch(const struct AssetLibraryReference *library_reference, const struct bContext *C); +bool ED_assetlist_is_loaded(const struct AssetLibraryReference *library_reference); void ED_assetlist_ensure_previews_job(const struct AssetLibraryReference *library_reference, const struct bContext *C); void ED_assetlist_clear(const struct AssetLibraryReference *library_reference, struct bContext *C); diff --git a/source/blender/editors/asset/intern/asset_list.cc b/source/blender/editors/asset/intern/asset_list.cc index b0ff5c86520..01a6dc46c48 100644 --- a/source/blender/editors/asset/intern/asset_list.cc +++ b/source/blender/editors/asset/intern/asset_list.cc @@ -422,6 +422,18 @@ void ED_assetlist_storage_fetch(const AssetLibraryReference *library_reference, AssetListStorage::fetch_library(*library_reference, *C); } +bool ED_assetlist_is_loaded(const AssetLibraryReference *library_reference) +{ + AssetList *list = AssetListStorage::lookup_list(*library_reference); + if (!list) { + return false; + } + if (list->needsRefetch()) { + return false; + } + return true; +} + void ED_assetlist_ensure_previews_job(const AssetLibraryReference *library_reference, const bContext *C) { @@ -488,7 +500,7 @@ std::string ED_assetlist_asset_filepath_get(const bContext *C, const char *asset_relpath = asset_handle.file_data->relpath; char path[FILE_MAX_LIBEXTRA]; - BLI_join_dirfile(path, sizeof(path), library_path, asset_relpath); + BLI_path_join(path, sizeof(path), library_path, asset_relpath); return path; } diff --git a/source/blender/editors/asset/intern/asset_ops.cc b/source/blender/editors/asset/intern/asset_ops.cc index 08259090e0c..d1c46a8259f 100644 --- a/source/blender/editors/asset/intern/asset_ops.cc +++ b/source/blender/editors/asset/intern/asset_ops.cc @@ -860,7 +860,7 @@ static bool set_filepath_for_asset_lib(const Main *bmain, struct wmOperator *op) } char file_path[PATH_MAX]; - BLI_join_dirfile(file_path, sizeof(file_path), lib->path, blend_filename); + BLI_path_join(file_path, sizeof(file_path), lib->path, blend_filename); RNA_string_set(op->ptr, "filepath", file_path); return true; diff --git a/source/blender/editors/curve/editcurve.c b/source/blender/editors/curve/editcurve.c index 61e92f0a1c3..2b6cce25bb7 100644 --- a/source/blender/editors/curve/editcurve.c +++ b/source/blender/editors/curve/editcurve.c @@ -4999,7 +4999,7 @@ bool ed_editnurb_spin( invert_m3_m3(persinv, persmat); /* imat and center and size */ - copy_m3_m4(bmat, obedit->obmat); + copy_m3_m4(bmat, obedit->object_to_world); invert_m3_m3(imat, bmat); axis_angle_to_mat3(cmat, axis, M_PI_4); @@ -5095,7 +5095,7 @@ static int spin_exec(bContext *C, wmOperator *op) continue; } - invert_m4_m4(obedit->imat, obedit->obmat); + invert_m4_m4(obedit->imat, obedit->object_to_world); mul_m4_v3(obedit->imat, cent); if (!ed_editnurb_spin(viewmat, v3d, obedit, axis, cent)) { @@ -5574,7 +5574,7 @@ static int add_vertex_exec(bContext *C, wmOperator *op) RNA_float_get_array(op->ptr, "location", location); - invert_m4_m4(imat, obedit->obmat); + invert_m4_m4(imat, obedit->object_to_world); mul_m4_v3(imat, location); if (ed_editcurve_addvert(cu, editnurb, v3d, location)) { @@ -5614,10 +5614,10 @@ static int add_vertex_invoke(bContext *C, wmOperator *op, const wmEvent *event) ED_curve_nurb_vert_selected_find(cu, vc.v3d, &nu, &bezt, &bp); if (bezt) { - mul_v3_m4v3(location, vc.obedit->obmat, bezt->vec[1]); + mul_v3_m4v3(location, vc.obedit->object_to_world, bezt->vec[1]); } else if (bp) { - mul_v3_m4v3(location, vc.obedit->obmat, bp->vec); + mul_v3_m4v3(location, vc.obedit->object_to_world, bp->vec); } else { copy_v3_v3(location, vc.scene->cursor.location); @@ -5662,8 +5662,8 @@ static int add_vertex_invoke(bContext *C, wmOperator *op, const wmEvent *event) /* get the plane */ float plane[4]; /* only normalize to avoid precision errors */ - normalize_v3_v3(plane, vc.obedit->obmat[2]); - plane[3] = -dot_v3v3(plane, vc.obedit->obmat[3]); + normalize_v3_v3(plane, vc.obedit->object_to_world[2]); + plane[3] = -dot_v3v3(plane, vc.obedit->object_to_world[3]); if (fabsf(dot_v3v3(view_dir, plane)) < eps) { /* can't project on an aligned plane. */ @@ -6924,7 +6924,7 @@ int ED_curve_join_objects_exec(bContext *C, wmOperator *op) /* Inverse transform for all selected curves in this object, * See #object_join_exec for detailed comment on why the safe version is used. */ - invert_m4_m4_safe_ortho(imat, ob_active->obmat); + invert_m4_m4_safe_ortho(imat, ob_active->object_to_world); Curve *cu_active = ob_active->data; @@ -6936,7 +6936,7 @@ int ED_curve_join_objects_exec(bContext *C, wmOperator *op) if (cu->nurb.first) { /* watch it: switch order here really goes wrong */ - mul_m4_m4m4(cmat, imat, ob_iter->obmat); + mul_m4_m4m4(cmat, imat, ob_iter->object_to_world); /* Compensate for different bevel depth. */ bool do_radius = false; diff --git a/source/blender/editors/curve/editcurve_paint.c b/source/blender/editors/curve/editcurve_paint.c index 7632f1b1e64..1e91e2f48fc 100644 --- a/source/blender/editors/curve/editcurve_paint.c +++ b/source/blender/editors/curve/editcurve_paint.c @@ -148,7 +148,7 @@ static void stroke_elem_pressure_set(const struct CurveDrawData *cdd, const float adjust = stroke_elem_radius_from_pressure(cdd, pressure) - stroke_elem_radius_from_pressure(cdd, selem->pressure); madd_v3_v3fl(selem->location_local, selem->normal_local, adjust); - mul_v3_m4v3(selem->location_world, cdd->vc.obedit->obmat, selem->location_local); + mul_v3_m4v3(selem->location_world, cdd->vc.obedit->object_to_world, selem->location_local); } selem->pressure = pressure; } @@ -249,7 +249,7 @@ static bool stroke_elem_project_fallback(const struct CurveDrawData *cdd, if (!is_zero_v3(r_normal_world)) { copy_v3_v3(r_normal_local, r_normal_world); - mul_transposed_mat3_m4_v3(cdd->vc.obedit->obmat, r_normal_local); + mul_transposed_mat3_m4_v3(cdd->vc.obedit->object_to_world, r_normal_local); normalize_v3(r_normal_local); } else { @@ -367,7 +367,7 @@ static void curve_draw_stroke_3d(const struct bContext *UNUSED(C), /* scale to edit-mode space */ GPU_matrix_push(); - GPU_matrix_mul(obedit->obmat); + GPU_matrix_mul(obedit->object_to_world); BLI_mempool_iternew(cdd->stroke_elem_pool, &iter); for (selem = BLI_mempool_iterstep(&iter); selem; selem = BLI_mempool_iterstep(&iter)) { @@ -445,7 +445,7 @@ static void curve_draw_event_add(wmOperator *op, const wmEvent *event) struct CurveDrawData *cdd = op->customdata; Object *obedit = cdd->vc.obedit; - invert_m4_m4(obedit->imat, obedit->obmat); + invert_m4_m4(obedit->imat, obedit->object_to_world); struct StrokeElem *selem = BLI_mempool_calloc(cdd->stroke_elem_pool); @@ -758,7 +758,7 @@ static int curve_draw_exec(bContext *C, wmOperator *op) int stroke_len = BLI_mempool_len(cdd->stroke_elem_pool); const bool is_3d = (cu->flag & CU_3D) != 0; - invert_m4_m4(obedit->imat, obedit->obmat); + invert_m4_m4(obedit->imat, obedit->object_to_world); if (BLI_mempool_len(cdd->stroke_elem_pool) == 0) { curve_draw_stroke_from_operator(op); @@ -1073,8 +1073,8 @@ static int curve_draw_invoke(bContext *C, wmOperator *op, const wmEvent *event) if (CU_IS_2D(cu)) { /* 2D overrides other options */ - plane_co = obedit->obmat[3]; - plane_no = obedit->obmat[2]; + plane_co = obedit->object_to_world[3]; + plane_no = obedit->object_to_world[2]; cdd->project.use_plane = true; } else { diff --git a/source/blender/editors/curve/editcurve_pen.c b/source/blender/editors/curve/editcurve_pen.c index f71173f951e..b57ce6fc7cf 100644 --- a/source/blender/editors/curve/editcurve_pen.c +++ b/source/blender/editors/curve/editcurve_pen.c @@ -152,8 +152,8 @@ static void update_location_for_2d_curve(const ViewContext *vc, float location[3 /* Get the plane. */ float plane[4]; /* Only normalize to avoid precision errors. */ - normalize_v3_v3(plane, vc->obedit->obmat[2]); - plane[3] = -dot_v3v3(plane, vc->obedit->obmat[3]); + normalize_v3_v3(plane, vc->obedit->object_to_world[2]); + plane[3] = -dot_v3v3(plane, vc->obedit->object_to_world[3]); if (fabsf(dot_v3v3(view_dir, plane)) < eps) { /* Can't project on an aligned plane. */ @@ -173,7 +173,7 @@ static void update_location_for_2d_curve(const ViewContext *vc, float location[3 } float imat[4][4]; - invert_m4_m4(imat, vc->obedit->obmat); + invert_m4_m4(imat, vc->obedit->object_to_world); mul_m4_v3(imat, location); if (CU_IS_2D(cu)) { @@ -186,7 +186,7 @@ static void screenspace_to_worldspace(const ViewContext *vc, const float depth[3], float r_pos_3d[3]) { - mul_v3_m4v3(r_pos_3d, vc->obedit->obmat, depth); + mul_v3_m4v3(r_pos_3d, vc->obedit->object_to_world, depth); ED_view3d_win_to_3d(vc->v3d, vc->region, r_pos_3d, pos_2d, r_pos_3d); update_location_for_2d_curve(vc, r_pos_3d); } @@ -1082,7 +1082,7 @@ static void extrude_points_from_selected_vertices(const ViewContext *vc, float location[3]; if (sel_exists) { - mul_v3_m4v3(location, vc->obedit->obmat, center); + mul_v3_m4v3(location, vc->obedit->object_to_world, center); } else { copy_v3_v3(location, vc->scene->cursor.location); diff --git a/source/blender/editors/curve/editcurve_select.c b/source/blender/editors/curve/editcurve_select.c index 9c0c580f699..da742dd0c61 100644 --- a/source/blender/editors/curve/editcurve_select.c +++ b/source/blender/editors/curve/editcurve_select.c @@ -1517,7 +1517,7 @@ static void nurb_bezt_direction_worldspace_get(Object *ob, { float rsmat[3][3]; BKE_nurb_bezt_calc_normal(nu, bezt, r_dir); - copy_m3_m4(rsmat, ob->obmat); + copy_m3_m4(rsmat, ob->object_to_world); mul_m3_v3(rsmat, r_dir); normalize_v3(r_dir); } @@ -1526,7 +1526,7 @@ static void nurb_bpoint_direction_worldspace_get(Object *ob, Nurb *nu, BPoint *b { float rsmat[3][3]; BKE_nurb_bpoint_calc_normal(nu, bp, r_dir); - copy_m3_m4(rsmat, ob->obmat); + copy_m3_m4(rsmat, ob->object_to_world); mul_m3_v3(rsmat, r_dir); normalize_v3(r_dir); } diff --git a/source/blender/editors/curves/intern/curves_ops.cc b/source/blender/editors/curves/intern/curves_ops.cc index 38b2b2071b8..1d2b1264477 100644 --- a/source/blender/editors/curves/intern/curves_ops.cc +++ b/source/blender/editors/curves/intern/curves_ops.cc @@ -435,7 +435,7 @@ static bke::CurvesGeometry particles_to_curves(Object &object, ParticleSystem &p bke::CurvesGeometry curves(points_num, curves_num); curves.offsets_for_write().copy_from(curve_offsets); - const float4x4 object_to_world_mat = object.obmat; + const float4x4 object_to_world_mat = object.object_to_world; const float4x4 world_to_object_mat = object_to_world_mat.inverted(); MutableSpan<float3> positions = curves.positions_for_write(); @@ -497,7 +497,7 @@ static int curves_convert_from_particle_system_exec(bContext *C, wmOperator * /* Object *ob_new = BKE_object_add(&bmain, &scene, &view_layer, OB_CURVES, psys_eval->name); Curves *curves_id = static_cast<Curves *>(ob_new->data); - BKE_object_apply_mat4(ob_new, ob_from_orig->obmat, true, false); + BKE_object_apply_mat4(ob_new, ob_from_orig->object_to_world, true, false); bke::CurvesGeometry::wrap(curves_id->geometry) = particles_to_curves(*ob_from_eval, *psys_eval); DEG_relations_tag_update(&bmain); diff --git a/source/blender/editors/gizmo_library/gizmo_library_presets.c b/source/blender/editors/gizmo_library/gizmo_library_presets.c index 1ac4ce0bcdf..465c72dd44f 100644 --- a/source/blender/editors/gizmo_library/gizmo_library_presets.c +++ b/source/blender/editors/gizmo_library/gizmo_library_presets.c @@ -114,7 +114,7 @@ void ED_gizmo_draw_preset_facemap( } GPU_matrix_push(); - GPU_matrix_mul(ob->obmat); + GPU_matrix_mul(ob->object_to_world); ED_draw_object_facemap(depsgraph, ob, color, facemap); GPU_matrix_pop(); diff --git a/source/blender/editors/gpencil/annotate_paint.c b/source/blender/editors/gpencil/annotate_paint.c index 677bf1bb392..2fd58a9cee0 100644 --- a/source/blender/editors/gpencil/annotate_paint.c +++ b/source/blender/editors/gpencil/annotate_paint.c @@ -13,9 +13,6 @@ #include "MEM_guardedalloc.h" -#include "BLI_blenlib.h" -#include "BLI_math.h" -#include "BLI_math_geom.h" #include "BLI_utildefines.h" #include "BLT_translation.h" diff --git a/source/blender/editors/gpencil/gpencil_armature.c b/source/blender/editors/gpencil/gpencil_armature.c index 5f5a4b41b27..2b7e09b7f05 100644 --- a/source/blender/editors/gpencil/gpencil_armature.c +++ b/source/blender/editors/gpencil/gpencil_armature.c @@ -329,8 +329,8 @@ static void gpencil_add_verts_to_dgroups( copy_v3_v3(tip[j], bone->arm_tail); } - mul_m4_v3(ob_arm->obmat, root[j]); - mul_m4_v3(ob_arm->obmat, tip[j]); + mul_m4_v3(ob_arm->object_to_world, root[j]); + mul_m4_v3(ob_arm->object_to_world, tip[j]); selected[j] = 1; @@ -364,7 +364,7 @@ static void gpencil_add_verts_to_dgroups( /* transform stroke points to global space */ for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) { copy_v3_v3(verts[i], &pt->x); - mul_m4_v3(ob->obmat, verts[i]); + mul_m4_v3(ob->object_to_world, verts[i]); } /* loop groups and assign weight */ diff --git a/source/blender/editors/gpencil/gpencil_bake_animation.cc b/source/blender/editors/gpencil/gpencil_bake_animation.cc index 1535fd614fe..4ef2cf9ffd6 100644 --- a/source/blender/editors/gpencil/gpencil_bake_animation.cc +++ b/source/blender/editors/gpencil/gpencil_bake_animation.cc @@ -222,7 +222,7 @@ static int gpencil_bake_grease_pencil_animation_exec(bContext *C, wmOperator *op ushort local_view_bits = (v3d && v3d->localvd) ? v3d->local_view_uuid : 0; ob_gpencil = ED_gpencil_add_object(C, scene->cursor.location, local_view_bits); float invmat[4][4]; - invert_m4_m4(invmat, ob_gpencil->obmat); + invert_m4_m4(invmat, ob_gpencil->object_to_world); bGPdata *gpd_dst = (bGPdata *)ob_gpencil->data; gpd_dst->draw_mode = GP_DRAWMODE_2D; @@ -323,7 +323,7 @@ static int gpencil_bake_grease_pencil_animation_exec(bContext *C, wmOperator *op bGPDspoint *pt = &gps->points[j]; pt->runtime.idx_orig = 0; pt->runtime.pt_orig = nullptr; - mul_m4_v3(ob_eval->obmat, &pt->x); + mul_m4_v3(ob_eval->object_to_world, &pt->x); mul_m4_v3(invmat, &pt->x); } diff --git a/source/blender/editors/gpencil/gpencil_data.c b/source/blender/editors/gpencil/gpencil_data.c index c6d7eb294fb..0417694d7bd 100644 --- a/source/blender/editors/gpencil/gpencil_data.c +++ b/source/blender/editors/gpencil/gpencil_data.c @@ -2914,8 +2914,8 @@ int ED_gpencil_join_objects_exec(bContext *C, wmOperator *op) float offset_global[3]; float offset_local[3]; - sub_v3_v3v3(offset_global, ob_active->loc, ob_iter->obmat[3]); - copy_m3_m4(bmat, ob_active->obmat); + sub_v3_v3v3(offset_global, ob_active->loc, ob_iter->object_to_world[3]); + copy_m3_m4(bmat, ob_active->object_to_world); /* Inverse transform for all selected curves in this object, * See #object_join_exec for detailed comment on why the safe version is used. */ diff --git a/source/blender/editors/gpencil/gpencil_edit.c b/source/blender/editors/gpencil/gpencil_edit.c index 6181b9810e3..f9b40a4c79b 100644 --- a/source/blender/editors/gpencil/gpencil_edit.c +++ b/source/blender/editors/gpencil/gpencil_edit.c @@ -3848,7 +3848,12 @@ static int gpencil_stroke_start_set_exec(bContext *C, wmOperator *op) for (int i = 0; i < gps->totpoints; i++) { pt = &gps->points[i]; if (pt->flag & GP_SPOINT_SELECT) { - BKE_gpencil_stroke_start_set(gps, i); + if (i == gps->totpoints - 1) { + BKE_gpencil_stroke_flip(gps); + } + else { + BKE_gpencil_stroke_start_set(gps, i); + } BKE_gpencil_stroke_geometry_update(gpd, gps); changed = true; break; @@ -4157,7 +4162,7 @@ static int gpencil_stroke_outline_exec(bContext *C, wmOperator *op) Scene *scene = CTX_data_scene(C); Object *cam_ob = scene->camera; if (cam_ob != NULL) { - invert_m4_m4(viewmat, cam_ob->obmat); + invert_m4_m4(viewmat, cam_ob->object_to_world); } break; } @@ -4224,7 +4229,7 @@ static int gpencil_stroke_outline_exec(bContext *C, wmOperator *op) /* Apply layer thickness change. */ gps_duplicate->thickness += gpl->line_change; /* Apply object scale to thickness. */ - gps_duplicate->thickness *= mat4_to_scale(ob->obmat); + gps_duplicate->thickness *= mat4_to_scale(ob->object_to_world); CLAMP_MIN(gps_duplicate->thickness, 1.0f); /* Stroke. */ diff --git a/source/blender/editors/gpencil/gpencil_fill.c b/source/blender/editors/gpencil/gpencil_fill.c index b94b413edc2..5c88e719b8c 100644 --- a/source/blender/editors/gpencil/gpencil_fill.c +++ b/source/blender/editors/gpencil/gpencil_fill.c @@ -317,7 +317,7 @@ static void add_endpoint_radius_help(tGPDfill *tgpf, /* Rotate to object rotation. */ sub_v3_v3(&pt->x, endpoint); - mul_mat3_m4_v3(tgpf->ob->obmat, &pt->x); + mul_mat3_m4_v3(tgpf->ob->object_to_world, &pt->x); add_v3_v3(&pt->x, endpoint); } } diff --git a/source/blender/editors/gpencil/gpencil_mesh.cc b/source/blender/editors/gpencil/gpencil_mesh.cc index d847fbe2aea..2b01fce5bf8 100644 --- a/source/blender/editors/gpencil/gpencil_mesh.cc +++ b/source/blender/editors/gpencil/gpencil_mesh.cc @@ -299,7 +299,7 @@ static int gpencil_bake_mesh_animation_exec(bContext *C, wmOperator *op) angle, thickness, offset, - ob_eval->obmat, + ob_eval->object_to_world, frame_offset, use_seams, use_faces, diff --git a/source/blender/editors/gpencil/gpencil_paint.c b/source/blender/editors/gpencil/gpencil_paint.c index a82288e3377..d2ed1720bf8 100644 --- a/source/blender/editors/gpencil/gpencil_paint.c +++ b/source/blender/editors/gpencil/gpencil_paint.c @@ -936,7 +936,7 @@ static bGPDstroke *gpencil_stroke_to_outline(tGPsdata *p, bGPDstroke *gps) /* Apply layer thickness change. */ gps_duplicate->thickness += gpl->line_change; /* Apply object scale to thickness. */ - gps_duplicate->thickness *= mat4_to_scale(p->ob->obmat); + gps_duplicate->thickness *= mat4_to_scale(p->ob->object_to_world); CLAMP_MIN(gps_duplicate->thickness, 1.0f); /* Stroke. */ diff --git a/source/blender/editors/gpencil/gpencil_sculpt_paint.c b/source/blender/editors/gpencil/gpencil_sculpt_paint.c index 9b934876ebb..515bdeb6188 100644 --- a/source/blender/editors/gpencil/gpencil_sculpt_paint.c +++ b/source/blender/editors/gpencil/gpencil_sculpt_paint.c @@ -671,7 +671,7 @@ static bool gpencil_brush_pinch_apply(tGP_BrushEditData *gso, /* 1) Make this point relative to the cursor/midpoint (dvec) */ float fpt[3]; - mul_v3_m4v3(fpt, gso->object->obmat, &pt->x); + mul_v3_m4v3(fpt, gso->object->object_to_world, &pt->x); sub_v3_v3v3(vec, fpt, gso->dvec); /* 2) Shrink the distance by pulling the point towards the midpoint @@ -743,7 +743,7 @@ static bool gpencil_brush_twist_apply(tGP_BrushEditData *gso, /* Rotate point */ float fpt[3]; - mul_v3_m4v3(fpt, gso->object->obmat, &pt->x); + mul_v3_m4v3(fpt, gso->object->object_to_world, &pt->x); sub_v3_v3v3(vec, fpt, gso->dvec); /* make relative to center * (center is stored in dvec) */ mul_m3_v3(rmat, vec); @@ -1037,7 +1037,7 @@ static void gpencil_brush_clone_add(bContext *C, tGP_BrushEditData *gso) */ for (i = 0, pt = new_stroke->points; i < new_stroke->totpoints; i++, pt++) { /* Rotate around center new position */ - mul_mat3_m4_v3(gso->object->obmat, &pt->x); /* only rotation component */ + mul_mat3_m4_v3(gso->object->object_to_world, &pt->x); /* only rotation component */ /* assume that the delta can just be applied, and then everything works */ add_v3_v3(&pt->x, delta); @@ -1172,7 +1172,7 @@ static bool gpencil_sculpt_brush_init(bContext *C, wmOperator *op) gso->object = ob; if (ob) { float matrix[4][4]; - copy_m4_m4(matrix, ob->obmat); + copy_m4_m4(matrix, ob->object_to_world); zero_axis_bias_m4(matrix); invert_m4_m4(gso->inv_mat, matrix); gso->vrgroup = gso->gpd->vertex_group_active_index - 1; @@ -1202,6 +1202,9 @@ static bool gpencil_sculpt_brush_init(bContext *C, wmOperator *op) gso->automasking_strokes = BLI_ghash_ptr_new(__func__); } else { + if (gso->automasking_strokes != NULL) { + BLI_ghash_free(gso->automasking_strokes, NULL, NULL); + } gso->automasking_strokes = NULL; } /* save mask */ @@ -1292,6 +1295,10 @@ static void gpencil_sculpt_brush_exit(bContext *C, wmOperator *op) } default: + if (gso->stroke_customdata != NULL) { + BLI_ghash_free(gso->stroke_customdata, NULL, NULL); + gso->stroke_customdata = NULL; + } break; } @@ -2075,6 +2082,20 @@ static void gpencil_sculpt_brush_apply_event(bContext *C, wmOperator *op, const if (gso->brush == NULL) { gso->brush = gso->brush_prev; } + Brush *brush = gso->brush; + if (brush->gpencil_settings->sculpt_mode_flag & + (GP_SCULPT_FLAGMODE_AUTOMASK_STROKE | GP_SCULPT_FLAGMODE_AUTOMASK_LAYER | + GP_SCULPT_FLAGMODE_AUTOMASK_MATERIAL)) { + if (gso->automasking_strokes == NULL) { + gso->automasking_strokes = BLI_ghash_ptr_new(__func__); + } + } + else { + if (gso->automasking_strokes != NULL) { + BLI_ghash_free(gso->automasking_strokes, NULL, NULL); + } + gso->automasking_strokes = NULL; + } } else { if (gso->brush_prev != NULL) { diff --git a/source/blender/editors/gpencil/gpencil_utils.c b/source/blender/editors/gpencil/gpencil_utils.c index cc13f667e48..7d814b43196 100644 --- a/source/blender/editors/gpencil/gpencil_utils.c +++ b/source/blender/editors/gpencil/gpencil_utils.c @@ -900,7 +900,7 @@ void ED_gpencil_drawing_reference_get(const Scene *scene, } else { /* use object location */ - copy_v3_v3(r_vec, ob->obmat[3]); + copy_v3_v3(r_vec, ob->object_to_world[3]); /* Apply layer offset. */ bGPdata *gpd = ob->data; bGPDlayer *gpl = BKE_gpencil_layer_active_get(gpd); @@ -984,7 +984,7 @@ void ED_gpencil_project_stroke_to_plane(const Scene *scene, /* if object, apply object rotation */ if (ob && (ob->type == OB_GPENCIL)) { float mat[4][4]; - copy_m4_m4(mat, ob->obmat); + copy_m4_m4(mat, ob->object_to_world); /* move origin to cursor */ if ((ts->gpencil_v3d_align & GP_PROJECT_CURSOR) == 0) { @@ -1206,7 +1206,7 @@ void ED_gpencil_project_point_to_plane(const Scene *scene, /* if object, apply object rotation */ if (ob && (ob->type == OB_GPENCIL)) { float mat[4][4]; - copy_m4_m4(mat, ob->obmat); + copy_m4_m4(mat, ob->object_to_world); if ((ts->gpencil_v3d_align & GP_PROJECT_CURSOR) == 0) { if (gpl != NULL) { add_v3_v3(mat[3], gpl->location); @@ -1233,7 +1233,7 @@ void ED_gpencil_project_point_to_plane(const Scene *scene, /* move origin to object */ if ((ts->gpencil_v3d_align & GP_PROJECT_CURSOR) == 0) { - copy_v3_v3(mat[3], ob->obmat[3]); + copy_v3_v3(mat[3], ob->object_to_world[3]); } mul_mat3_m4_v3(mat, plane_normal); @@ -1365,16 +1365,16 @@ void ED_gpencil_reset_layers_parent(Depsgraph *depsgraph, Object *obact, bGPdata if (gpl->parent != NULL) { /* calculate new matrix */ if (ELEM(gpl->partype, PAROBJECT, PARSKEL)) { - invert_m4_m4(cur_mat, gpl->parent->obmat); - copy_v3_v3(gpl_loc, obact->obmat[3]); + invert_m4_m4(cur_mat, gpl->parent->object_to_world); + copy_v3_v3(gpl_loc, obact->object_to_world[3]); } else if (gpl->partype == PARBONE) { bPoseChannel *pchan = BKE_pose_channel_find_name(gpl->parent->pose, gpl->parsubstr); if (pchan) { float tmp_mat[4][4]; - mul_m4_m4m4(tmp_mat, gpl->parent->obmat, pchan->pose_mat); + mul_m4_m4m4(tmp_mat, gpl->parent->object_to_world, pchan->pose_mat); invert_m4_m4(cur_mat, tmp_mat); - copy_v3_v3(gpl_loc, obact->obmat[3]); + copy_v3_v3(gpl_loc, obact->object_to_world[3]); } } diff --git a/source/blender/editors/gpencil/gpencil_uv.c b/source/blender/editors/gpencil/gpencil_uv.c index 51cb08cf592..0144ffa07c7 100644 --- a/source/blender/editors/gpencil/gpencil_uv.c +++ b/source/blender/editors/gpencil/gpencil_uv.c @@ -138,7 +138,7 @@ static bool gpencil_uv_transform_init(bContext *C, wmOperator *op) opdata->array_loc = NULL; opdata->array_rot = NULL; opdata->array_scale = NULL; - opdata->ob_scale = mat4_to_scale(opdata->ob->obmat); + opdata->ob_scale = mat4_to_scale(opdata->ob->object_to_world); opdata->vinit_rotation[0] = 1.0f; opdata->vinit_rotation[1] = 0.0f; @@ -158,7 +158,7 @@ static bool gpencil_uv_transform_init(bContext *C, wmOperator *op) float r_center[3]; gpencil_stroke_center(gps, r_center); /* Add object location. */ - add_v3_v3(r_center, opdata->ob->obmat[3]); + add_v3_v3(r_center, opdata->ob->object_to_world[3]); add_v3_v3(center, r_center); i++; } diff --git a/source/blender/editors/include/ED_uvedit.h b/source/blender/editors/include/ED_uvedit.h index c8ffbb9acb1..b97cd6a9099 100644 --- a/source/blender/editors/include/ED_uvedit.h +++ b/source/blender/editors/include/ED_uvedit.h @@ -345,12 +345,14 @@ typedef enum { ED_UVPACK_MARGIN_FRACTION, /* Specify a precise fraction of final UV output. */ } eUVPackIsland_MarginMethod; +/** See also #UnwrapOptions. */ struct UVPackIsland_Params { uint rotate : 1; uint only_selected_uvs : 1; uint only_selected_faces : 1; uint use_seams : 1; uint correct_aspect : 1; + bool ignore_pinned; /* Ignore islands which have any pinned UVs. */ eUVPackIsland_MarginMethod margin_method; /* Which formula to use when scaling island margin. */ float margin; /* Additional space to add around each island. */ }; diff --git a/source/blender/editors/include/UI_interface.h b/source/blender/editors/include/UI_interface.h index 2a1941f0d9e..1098266331f 100644 --- a/source/blender/editors/include/UI_interface.h +++ b/source/blender/editors/include/UI_interface.h @@ -784,6 +784,9 @@ void UI_block_set_search_only(uiBlock *block, bool search_only); * Can be called with C==NULL. */ void UI_block_free(const struct bContext *C, uiBlock *block); + +void UI_block_listen(const uiBlock *block, const struct wmRegionListenerParams *listener_params); + /** * Can be called with C==NULL. */ @@ -1683,6 +1686,7 @@ int UI_search_items_find_index(uiSearchItems *items, const char *name); * Adds a hint to the button which draws right aligned, grayed out and never clipped. */ void UI_but_hint_drawstr_set(uiBut *but, const char *string); +void UI_but_icon_indicator_number_set(uiBut *but, const int indicator_number); void UI_but_node_link_set(uiBut *but, struct bNodeSocket *socket, const float draw_color[4]); @@ -2524,6 +2528,7 @@ void uiTemplateNodeView(uiLayout *layout, struct bNodeTree *ntree, struct bNode *node, struct bNodeSocket *input); +void uiTemplateNodeAssetMenuItems(uiLayout *layout, struct bContext *C, const char *catalog_path); void uiTemplateTextureUser(uiLayout *layout, struct bContext *C); /** * Button to quickly show texture in Properties Editor texture tab. @@ -2788,7 +2793,8 @@ typedef struct uiPropertySplitWrapper { uiPropertySplitWrapper uiItemPropertySplitWrapperCreate(uiLayout *parent_layout); void uiItemL(uiLayout *layout, const char *name, int icon); /* label */ -void uiItemL_ex(uiLayout *layout, const char *name, int icon, bool highlight, bool redalert); +struct uiBut *uiItemL_ex( + uiLayout *layout, const char *name, int icon, bool highlight, bool redalert); /** * Helper to add a label and creates a property split layout if needed. */ @@ -3195,9 +3201,6 @@ void UI_interface_tag_script_reload(void); /* Support click-drag motion which presses the button and closes a popover (like a menu). */ #define USE_UI_POPOVER_ONCE -void UI_block_views_listen(const uiBlock *block, - const struct wmRegionListenerParams *listener_params); - bool UI_view_item_is_active(const uiViewItemHandle *item_handle); bool UI_view_item_matches(const uiViewItemHandle *a_handle, const uiViewItemHandle *b_handle); /** diff --git a/source/blender/editors/include/UI_interface.hh b/source/blender/editors/include/UI_interface.hh index 6c756984203..fc03b0218c0 100644 --- a/source/blender/editors/include/UI_interface.hh +++ b/source/blender/editors/include/UI_interface.hh @@ -35,6 +35,7 @@ struct ContextPathItem { std::string name; /* #BIFIconID */ int icon; + int icon_indicator_number; }; void context_path_add_generic(Vector<ContextPathItem> &path, diff --git a/source/blender/editors/include/UI_interface_icons.h b/source/blender/editors/include/UI_interface_icons.h index a1a98a4b08c..9669e242dac 100644 --- a/source/blender/editors/include/UI_interface_icons.h +++ b/source/blender/editors/include/UI_interface_icons.h @@ -27,6 +27,12 @@ typedef struct IconFile { int index; } IconFile; +typedef struct IconTextOverlay { + char text[5]; +} IconTextOverlay; + +#define UI_NO_ICON_OVERLAY_TEXT NULL + #define ICON_DEFAULT_HEIGHT 16 #define ICON_DEFAULT_WIDTH 16 @@ -105,7 +111,8 @@ void UI_icon_draw_ex(float x, float alpha, float desaturate, const uchar mono_color[4], - bool mono_border); + bool mono_border, + const struct IconTextOverlay *text_overlay); void UI_icons_free(void); void UI_icons_free_drawinfo(void *drawinfo); @@ -124,6 +131,9 @@ int UI_icon_from_library(const struct ID *id); int UI_icon_from_object_mode(int mode); int UI_icon_color_from_collection(const struct Collection *collection); +void UI_icon_text_overlay_init_from_count(struct IconTextOverlay *text_overlay, + const int icon_indicator_number); + #ifdef __cplusplus } #endif diff --git a/source/blender/editors/interface/eyedroppers/eyedropper_depth.c b/source/blender/editors/interface/eyedroppers/eyedropper_depth.c index 3fb5a74944b..c6d950112b9 100644 --- a/source/blender/editors/interface/eyedroppers/eyedropper_depth.c +++ b/source/blender/editors/interface/eyedroppers/eyedropper_depth.c @@ -162,7 +162,7 @@ static void depthdropper_depth_sample_pt(bContext *C, View3D *v3d = area->spacedata.first; RegionView3D *rv3d = region->regiondata; /* weak, we could pass in some reference point */ - const float *view_co = v3d->camera ? v3d->camera->obmat[3] : rv3d->viewinv[3]; + const float *view_co = v3d->camera ? v3d->camera->object_to_world[3] : rv3d->viewinv[3]; const int mval[2] = {m_xy[0] - region->winrct.xmin, m_xy[1] - region->winrct.ymin}; copy_v2_v2_int(ddr->name_pos, mval); diff --git a/source/blender/editors/interface/interface.cc b/source/blender/editors/interface/interface.cc index 422fc34aa50..331d1581db5 100644 --- a/source/blender/editors/interface/interface.cc +++ b/source/blender/editors/interface/interface.cc @@ -3474,6 +3474,7 @@ void UI_block_free(const bContext *C, uiBlock *block) BLI_freelistN(&block->saferct); BLI_freelistN(&block->color_pickers.list); + BLI_freelistN(&block->dynamic_listeners); ui_block_free_button_groups(block); ui_block_free_views(block); @@ -3481,6 +3482,20 @@ void UI_block_free(const bContext *C, uiBlock *block) MEM_freeN(block); } +void UI_block_listen(const uiBlock *block, const wmRegionListenerParams *listener_params) +{ + /* Don't need to let invisible blocks (old blocks from previous redraw) listen. */ + if (!block->active) { + return; + } + + LISTBASE_FOREACH (uiBlockDynamicListener *, listener, &block->dynamic_listeners) { + listener->listener_func(listener_params); + } + + ui_block_views_listen(block, listener_params); +} + void UI_blocklist_update_window_matrix(const bContext *C, const ListBase *lb) { ARegion *region = CTX_wm_region(C); @@ -6452,6 +6467,11 @@ void UI_but_hint_drawstr_set(uiBut *but, const char *string) ui_but_add_shortcut(but, string, false); } +void UI_but_icon_indicator_number_set(uiBut *but, const int indicator_number) +{ + UI_icon_text_overlay_init_from_count(&but->icon_overlay_text, indicator_number); +} + 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 e8f552e26a3..74a07d6edc8 100644 --- a/source/blender/editors/interface/interface_context_path.cc +++ b/source/blender/editors/interface/interface_context_path.cc @@ -17,6 +17,8 @@ #include "UI_interface.hh" #include "UI_resources.h" +#include "RNA_prototypes.h" + #include "WM_api.h" namespace blender::ui { @@ -41,7 +43,13 @@ void context_path_add_generic(Vector<ContextPathItem> &path, static_cast<BIFIconID>(RNA_struct_ui_icon(rna_ptr.type)) : icon_override; - path.append({name, int(icon)}); + if (&rna_type == &RNA_NodeTree) { + ID *id = (ID *)ptr; + path.append({name, int(icon), ID_REAL_USERS(id)}); + } + else { + path.append({name, int(icon), 1}); + } } /* -------------------------------------------------------------------- */ @@ -60,7 +68,9 @@ void template_breadcrumbs(uiLayout &layout, Span<ContextPathItem> context_path) if (i > 0) { uiItemL(sub_row, "", ICON_RIGHTARROW_THIN); } - uiItemL(sub_row, context_path[i].name.c_str(), context_path[i].icon); + uiBut *but = uiItemL_ex( + sub_row, context_path[i].name.c_str(), context_path[i].icon, false, false); + UI_but_icon_indicator_number_set(but, context_path[i].icon_indicator_number); } } diff --git a/source/blender/editors/interface/interface_handlers.c b/source/blender/editors/interface/interface_handlers.c index 34f33b71fb8..ac16d41dabe 100644 --- a/source/blender/editors/interface/interface_handlers.c +++ b/source/blender/editors/interface/interface_handlers.c @@ -3519,7 +3519,7 @@ static void ui_textedit_end(bContext *C, uiBut *but, uiHandleButtonData *data) static void ui_textedit_next_but(uiBlock *block, uiBut *actbut, uiHandleButtonData *data) { - /* label and roundbox can overlap real buttons (backdrops...) */ + /* Label and round-box can overlap real buttons (backdrops...). */ if (ELEM(actbut->type, UI_BTYPE_LABEL, UI_BTYPE_SEPR, @@ -3551,7 +3551,7 @@ static void ui_textedit_next_but(uiBlock *block, uiBut *actbut, uiHandleButtonDa static void ui_textedit_prev_but(uiBlock *block, uiBut *actbut, uiHandleButtonData *data) { - /* label and roundbox can overlap real buttons (backdrops...) */ + /* Label and round-box can overlap real buttons (backdrops...). */ if (ELEM(actbut->type, UI_BTYPE_LABEL, UI_BTYPE_SEPR, @@ -3894,7 +3894,7 @@ static void ui_do_but_textedit( } if (event->type == WM_IME_COMPOSITE_EVENT && ime_data->result_len) { if (ELEM(but->type, UI_BTYPE_NUM, UI_BTYPE_NUM_SLIDER) && - strcmp(ime_data->str_result, "\xE3\x80\x82") == 0) { + STREQ(ime_data->str_result, "\xE3\x80\x82")) { /* Convert Ideographic Full Stop (U+3002) to decimal point when entering numbers. */ ui_textedit_insert_ascii(but, data, '.'); } diff --git a/source/blender/editors/interface/interface_icons.c b/source/blender/editors/interface/interface_icons.c index c080dce0f08..9a4f98ebcd6 100644 --- a/source/blender/editors/interface/interface_icons.c +++ b/source/blender/editors/interface/interface_icons.c @@ -415,8 +415,15 @@ static void vicon_collection_color_draw( const float aspect = (float)ICON_DEFAULT_WIDTH / (float)w; - UI_icon_draw_ex( - x, y, ICON_OUTLINER_COLLECTION, aspect, 1.0f, 0.0f, collection_color->color, true); + UI_icon_draw_ex(x, + y, + ICON_OUTLINER_COLLECTION, + aspect, + 1.0f, + 0.0f, + collection_color->color, + true, + UI_NO_ICON_OVERLAY_TEXT); } # define DEF_ICON_COLLECTION_COLOR_DRAW(index, color) \ @@ -444,7 +451,8 @@ static void vicon_strip_color_draw( const float aspect = (float)ICON_DEFAULT_WIDTH / (float)w; - UI_icon_draw_ex(x, y, ICON_SNAP_FACE, aspect, 1.0f, 0.0f, strip_color->color, true); + UI_icon_draw_ex( + x, y, ICON_SNAP_FACE, aspect, 1.0f, 0.0f, strip_color->color, true, UI_NO_ICON_OVERLAY_TEXT); } # define DEF_ICON_STRIP_COLOR_DRAW(index, color) \ @@ -472,8 +480,15 @@ static void vicon_strip_color_draw_library_data_indirect( { const float aspect = (float)ICON_DEFAULT_WIDTH / (float)w; - UI_icon_draw_ex( - x, y, ICON_LIBRARY_DATA_DIRECT, aspect, ICON_INDIRECT_DATA_ALPHA * alpha, 0.0f, NULL, false); + UI_icon_draw_ex(x, + y, + ICON_LIBRARY_DATA_DIRECT, + aspect, + ICON_INDIRECT_DATA_ALPHA * alpha, + 0.0f, + NULL, + false, + UI_NO_ICON_OVERLAY_TEXT); } static void vicon_strip_color_draw_library_data_override_noneditable( @@ -488,7 +503,8 @@ static void vicon_strip_color_draw_library_data_override_noneditable( ICON_INDIRECT_DATA_ALPHA * alpha * 0.75f, 0.0f, NULL, - false); + false, + UI_NO_ICON_OVERLAY_TEXT); } /* Dynamically render icon instead of rendering a plain color to a texture/buffer @@ -923,7 +939,7 @@ static void init_internal_icons(void) char iconfilestr[FILE_MAX]; if (icondir) { - BLI_join_dirfile(iconfilestr, sizeof(iconfilestr), icondir, btheme->tui.iconfile); + BLI_path_join(iconfilestr, sizeof(iconfilestr), icondir, btheme->tui.iconfile); /* if the image is missing bbuf will just be NULL */ bbuf = IMB_loadiffname(iconfilestr, IB_rect, NULL); @@ -1047,7 +1063,7 @@ static void init_iconfile_list(struct ListBase *list) /* check to see if the image is the right size, continue if not */ /* copying strings here should go ok, assuming that we never get back * a complete path to file longer than 256 chars */ - BLI_join_dirfile(iconfilestr, sizeof(iconfilestr), icondir, filename); + BLI_path_join(iconfilestr, sizeof(iconfilestr), icondir, filename); bbuf = IMB_loadiffname(iconfilestr, IB_rect); if (bbuf) { @@ -1716,9 +1732,47 @@ static void icon_draw_texture(float x, int ih, float alpha, const float rgb[3], - bool with_border) -{ - if (g_icon_draw_cache.enabled) { + bool with_border, + const IconTextOverlay *text_overlay) +{ + const float zoom_factor = w / UI_DPI_ICON_SIZE; + float text_width = 0.0f; + + /* No need to show if too zoomed out, otherwise it just adds noise. */ + const bool show_indicator = (text_overlay && text_overlay->text[0] != '\0') && + (zoom_factor > 0.7f); + + if (show_indicator) { + /* Handle the little numbers on top of the icon. */ + uchar text_color[4]; + UI_GetThemeColor3ubv(TH_TEXT, text_color); + text_color[3] = 255; + + uiFontStyle fstyle_small = *UI_FSTYLE_WIDGET; + fstyle_small.points *= zoom_factor; + fstyle_small.points *= 0.8f; + + rcti text_rect = { + .xmax = x + UI_UNIT_X * zoom_factor, + .xmin = x, + .ymax = y, + .ymin = y, + }; + + UI_fontstyle_draw(&fstyle_small, + &text_rect, + text_overlay->text, + sizeof(text_overlay->text), + text_color, + &(struct uiFontStyleDraw_Params){ + .align = UI_STYLE_TEXT_RIGHT, + }); + text_width = (float)UI_fontstyle_string_width(&fstyle_small, text_overlay->text) / UI_UNIT_X / + zoom_factor; + } + + /* Draw the actual icon. */ + if (!show_indicator && g_icon_draw_cache.enabled) { icon_draw_texture_cached(x, y, w, h, ix, iy, iw, ih, alpha, rgb, with_border); return; } @@ -1735,7 +1789,7 @@ static void icon_draw_texture(float x, GPUTexture *texture = with_border ? icongltex.tex[1] : icongltex.tex[0]; - GPUShader *shader = GPU_shader_get_builtin_shader(GPU_SHADER_2D_IMAGE_RECT_COLOR); + GPUShader *shader = GPU_shader_get_builtin_shader(GPU_SHADER_ICON); GPU_shader_bind(shader); const int img_binding = GPU_shader_get_texture_binding(shader, "image"); @@ -1752,6 +1806,7 @@ static void icon_draw_texture(float x, GPU_shader_uniform_vector(shader, rect_tex_loc, 4, 1, (float[4]){x1, y1, x2, y2}); GPU_shader_uniform_vector(shader, rect_geom_loc, 4, 1, (float[4]){x, y, x + w, y + h}); + GPU_shader_uniform_1f(shader, "text_width", text_width); GPU_texture_bind_ex(texture, GPU_SAMPLER_ICON, img_binding, false); @@ -1786,7 +1841,8 @@ static void icon_draw_size(float x, int draw_size, const float desaturate, const uchar mono_rgba[4], - const bool mono_border) + const bool mono_border, + const IconTextOverlay *text_overlay) { bTheme *btheme = UI_GetTheme(); const float fdraw_size = (float)draw_size; @@ -1874,7 +1930,8 @@ static void icon_draw_size(float x, di->data.texture.h, alpha, NULL, - false); + false, + text_overlay); } else if (di->type == ICON_TYPE_MONO_TEXTURE) { /* Monochrome icon that uses text or theme color. */ @@ -1908,7 +1965,8 @@ static void icon_draw_size(float x, di->data.texture.h + 2 * border_texel, color[3], color, - with_border); + with_border, + text_overlay); } else if (di->type == ICON_TYPE_BUFFER) { @@ -2425,17 +2483,27 @@ int UI_icon_color_from_collection(const Collection *collection) void UI_icon_draw(float x, float y, int icon_id) { - UI_icon_draw_ex(x, y, icon_id, U.inv_dpi_fac, 1.0f, 0.0f, NULL, false); + UI_icon_draw_ex(x, y, icon_id, U.inv_dpi_fac, 1.0f, 0.0f, NULL, false, UI_NO_ICON_OVERLAY_TEXT); } void UI_icon_draw_alpha(float x, float y, int icon_id, float alpha) { - UI_icon_draw_ex(x, y, icon_id, U.inv_dpi_fac, alpha, 0.0f, NULL, false); + UI_icon_draw_ex(x, y, icon_id, U.inv_dpi_fac, alpha, 0.0f, NULL, false, UI_NO_ICON_OVERLAY_TEXT); } void UI_icon_draw_preview(float x, float y, int icon_id, float aspect, float alpha, int size) { - icon_draw_size(x, y, icon_id, aspect, alpha, ICON_SIZE_PREVIEW, size, false, NULL, false); + icon_draw_size(x, + y, + icon_id, + aspect, + alpha, + ICON_SIZE_PREVIEW, + size, + false, + NULL, + false, + UI_NO_ICON_OVERLAY_TEXT); } void UI_icon_draw_ex(float x, @@ -2445,7 +2513,8 @@ void UI_icon_draw_ex(float x, float alpha, float desaturate, const uchar mono_color[4], - const bool mono_border) + const bool mono_border, + const IconTextOverlay *text_overlay) { const int draw_size = get_draw_size(ICON_SIZE_ICON); icon_draw_size(x, @@ -2457,7 +2526,19 @@ void UI_icon_draw_ex(float x, draw_size, desaturate, mono_color, - mono_border); + mono_border, + text_overlay); +} + +void UI_icon_text_overlay_init_from_count(IconTextOverlay *text_overlay, + const int icon_indicator_number) +{ + /* The icon indicator is used as an aggregator, no need to show if it is 1. */ + if (icon_indicator_number < 2) { + text_overlay->text[0] = '\0'; + return; + } + BLI_str_format_integer_unit(text_overlay->text, icon_indicator_number); } /* ********** Alert Icons ********** */ diff --git a/source/blender/editors/interface/interface_intern.h b/source/blender/editors/interface/interface_intern.h index 6ef7d346418..982ac1753e1 100644 --- a/source/blender/editors/interface/interface_intern.h +++ b/source/blender/editors/interface/interface_intern.h @@ -23,6 +23,7 @@ struct ARegion; struct AnimationEvalContext; struct CurveMapping; struct CurveProfile; +struct IconTextOverlay; struct ID; struct ImBuf; struct Main; @@ -275,6 +276,9 @@ struct uiBut { uiButPushedStateFunc pushed_state_func; const void *pushed_state_arg; + /** Little indicator (e.g., counter) displayed on top of some icons. */ + struct IconTextOverlay icon_overlay_text; + /* pointer back */ uiBlock *block; }; @@ -473,6 +477,12 @@ typedef enum uiButtonGroupFlag { } uiButtonGroupFlag; ENUM_OPERATORS(uiButtonGroupFlag, UI_BUTTON_GROUP_PANEL_HEADER); +typedef struct uiBlockDynamicListener { + struct uiBlockDynamicListener *next, *prev; + + void (*listener_func)(const struct wmRegionListenerParams *params); +} uiBlockDynamicListener; + struct uiBlock { uiBlock *next, *prev; @@ -495,6 +505,8 @@ struct uiBlock { * state that is persistent over redraws (e.g. collapsed tree-view items). */ ListBase views; + ListBase dynamic_listeners; /* #uiBlockDynamicListener */ + char name[UI_MAX_NAME_STR]; float winmat[4][4]; @@ -1536,6 +1548,8 @@ void ui_interface_tag_script_reload_queries(void); /* interface_view.cc */ void ui_block_free_views(struct uiBlock *block); +void ui_block_views_listen(const uiBlock *block, + const struct wmRegionListenerParams *listener_params); uiViewHandle *ui_block_view_find_matching_in_old_block(const uiBlock *new_block, const uiViewHandle *new_view); diff --git a/source/blender/editors/interface/interface_layout.c b/source/blender/editors/interface/interface_layout.c index c906a5b36f1..a456cef7be6 100644 --- a/source/blender/editors/interface/interface_layout.c +++ b/source/blender/editors/interface/interface_layout.c @@ -3235,7 +3235,7 @@ static uiBut *uiItemL_(uiLayout *layout, const char *name, int icon) return but; } -void uiItemL_ex( +uiBut *uiItemL_ex( uiLayout *layout, const char *name, int icon, const bool highlight, const bool redalert) { uiBut *but = uiItemL_(layout, name, icon); @@ -3248,6 +3248,8 @@ void uiItemL_ex( if (redalert) { UI_but_flag_enable(but, UI_BUT_REDALERT); } + + return but; } void uiItemL(uiLayout *layout, const char *name, int icon) @@ -5812,6 +5814,14 @@ void UI_menutype_draw(bContext *C, MenuType *mt, struct uiLayout *layout) printf("%s: opening menu \"%s\"\n", __func__, mt->idname); } + if (mt->listener) { + /* Forward the menu type listener to the block we're drawing in. */ + uiBlock *block = uiLayoutGetBlock(layout); + uiBlockDynamicListener *listener = MEM_mallocN(sizeof(*listener), "uiBlockDynamicListener"); + listener->listener_func = mt->listener; + BLI_addtail(&block->dynamic_listeners, listener); + } + if (layout->context) { CTX_store_set(C, layout->context); } diff --git a/source/blender/editors/interface/interface_ops.cc b/source/blender/editors/interface/interface_ops.cc index 8b29f1075b8..2d06dd2c465 100644 --- a/source/blender/editors/interface/interface_ops.cc +++ b/source/blender/editors/interface/interface_ops.cc @@ -1859,8 +1859,7 @@ static void edittranslation_find_po_file(const char *root, /* First, full lang code. */ BLI_snprintf(tstr, sizeof(tstr), "%s.po", uilng); - BLI_join_dirfile(path, maxlen, root, uilng); - BLI_path_append(path, maxlen, tstr); + BLI_path_join(path, maxlen, root, uilng, tstr); if (BLI_is_file(path)) { return; } @@ -1885,7 +1884,7 @@ static void edittranslation_find_po_file(const char *root, BLI_strncpy(tstr + szt, tc, sizeof(tstr) - szt); } - BLI_join_dirfile(path, maxlen, root, tstr); + BLI_path_join(path, maxlen, root, tstr); strcat(tstr, ".po"); BLI_path_append(path, maxlen, tstr); if (BLI_is_file(path)) { diff --git a/source/blender/editors/interface/interface_panel.cc b/source/blender/editors/interface/interface_panel.cc index 7a69e2f9b2f..24d8281aad8 100644 --- a/source/blender/editors/interface/interface_panel.cc +++ b/source/blender/editors/interface/interface_panel.cc @@ -1112,7 +1112,8 @@ static void panel_draw_aligned_widgets(const uiStyle *style, 0.7f, 0.0f, title_color, - false); + false, + UI_NO_ICON_OVERLAY_TEXT); GPU_blend(GPU_BLEND_NONE); } @@ -1140,7 +1141,8 @@ static void panel_draw_aligned_widgets(const uiStyle *style, 1.0f, 0.0f, title_color, - false); + false, + UI_NO_ICON_OVERLAY_TEXT); GPU_blend(GPU_BLEND_NONE); } diff --git a/source/blender/editors/interface/interface_region_menu_popup.cc b/source/blender/editors/interface/interface_region_menu_popup.cc index 569f657a544..0d19390d508 100644 --- a/source/blender/editors/interface/interface_region_menu_popup.cc +++ b/source/blender/editors/interface/interface_region_menu_popup.cc @@ -10,6 +10,7 @@ #include <cstdarg> #include <cstdlib> #include <cstring> +#include <functional> #include "MEM_guardedalloc.h" @@ -166,28 +167,80 @@ struct uiPopupMenu { uiBut *but; ARegion *butregion; + /* Menu hash is created from this, to keep a memory of recently opened menus. */ + const char *title; + int mx, my; bool popup, slideout; - uiMenuCreateFunc menu_func; - void *menu_arg; + std::function<void(bContext *C, uiLayout *layout)> menu_func; }; +/** + * \param title: Optional. If set, it will be used to store recently opened menus so they can be + * opened with the mouse over the last chosen entry again. + */ +static void ui_popup_menu_create_block(bContext *C, + uiPopupMenu *pup, + const char *title, + const char *block_name) +{ + const uiStyle *style = UI_style_get_dpi(); + + pup->block = UI_block_begin(C, nullptr, block_name, UI_EMBOSS_PULLDOWN); + if (!pup->but) { + pup->block->flag |= UI_BLOCK_IS_FLIP | UI_BLOCK_NO_FLIP; + } + if (title && title[0]) { + pup->block->flag |= UI_BLOCK_POPUP_MEMORY; + pup->block->puphash = ui_popup_menu_hash(title); + } + pup->layout = UI_block_layout( + pup->block, UI_LAYOUT_VERTICAL, UI_LAYOUT_MENU, 0, 0, 200, 0, UI_MENU_PADDING, style); + + /* NOTE: this intentionally differs from the menu & sub-menu default because many operators + * use popups like this to select one of their options - + * where having invoke doesn't make sense. + * When the menu was opened from a button, use invoke still for compatibility. This used to be + * the default and changing now could cause issues. */ + const wmOperatorCallContext opcontext = pup->but ? WM_OP_INVOKE_REGION_WIN : + WM_OP_EXEC_REGION_WIN; + + uiLayoutSetOperatorContext(pup->layout, opcontext); + + if (pup->but) { + if (pup->but->context) { + uiLayoutContextCopy(pup->layout, pup->but->context); + } + } +} + static uiBlock *ui_block_func_POPUP(bContext *C, uiPopupBlockHandle *handle, void *arg_pup) { uiPopupMenu *pup = static_cast<uiPopupMenu *>(arg_pup); - if (pup->menu_func) { - pup->block->handle = handle; - pup->menu_func(C, pup->layout, pup->menu_arg); - pup->block->handle = nullptr; + int minwidth = 0; + + if (!pup->layout) { + ui_popup_menu_create_block(C, pup, pup->title, __func__); + + if (pup->menu_func) { + pup->block->handle = handle; + pup->menu_func(C, pup->layout); + pup->block->handle = nullptr; + } + + if (uiLayoutGetUnitsX(pup->layout) != 0.0f) { + /* Use the minimum width from the layout if it's set. */ + minwidth = uiLayoutGetUnitsX(pup->layout) * UI_UNIT_X; + } + + pup->layout = nullptr; } /* Find block minimum width. */ - int minwidth; - if (uiLayoutGetUnitsX(pup->layout) != 0.0f) { - /* Use the minimum width from the layout if it's set. */ - minwidth = uiLayoutGetUnitsX(pup->layout) * UI_UNIT_X; + if (minwidth) { + /* Skip. */ } else if (pup->but) { /* Minimum width to enforce. */ @@ -236,7 +289,7 @@ static uiBlock *ui_block_func_POPUP(bContext *C, uiPopupBlockHandle *handle, voi UI_block_flag_enable(block, UI_BLOCK_MOVEMOUSE_QUIT); if (pup->popup) { - int offset[2]; + int offset[2] = {0, 0}; uiBut *but_activate = nullptr; UI_block_flag_enable(block, UI_BLOCK_LOOP | UI_BLOCK_NUMSELECT); @@ -244,36 +297,42 @@ static uiBlock *ui_block_func_POPUP(bContext *C, uiPopupBlockHandle *handle, voi UI_block_direction_set(block, direction); /* offset the mouse position, possibly based on earlier selection */ - uiBut *bt; - if ((block->flag & UI_BLOCK_POPUP_MEMORY) && (bt = ui_popup_menu_memory_get(block))) { - /* position mouse on last clicked item, at 0.8*width of the - * button, so it doesn't overlap the text too much, also note - * the offset is negative because we are inverse moving the - * block to be under the mouse */ - offset[0] = -(bt->rect.xmin + 0.8f * BLI_rctf_size_x(&bt->rect)); - offset[1] = -(bt->rect.ymin + 0.5f * UI_UNIT_Y); - - if (ui_but_is_editable(bt)) { - but_activate = bt; - } - } - else { - /* position mouse at 0.8*width of the button and below the tile - * on the first item */ - offset[0] = 0; - LISTBASE_FOREACH (uiBut *, but_iter, &block->buttons) { - offset[0] = min_ii(offset[0], - -(but_iter->rect.xmin + 0.8f * BLI_rctf_size_x(&but_iter->rect))); + if (!handle->refresh) { + uiBut *bt; + if ((block->flag & UI_BLOCK_POPUP_MEMORY) && (bt = ui_popup_menu_memory_get(block))) { + /* position mouse on last clicked item, at 0.8*width of the + * button, so it doesn't overlap the text too much, also note + * the offset is negative because we are inverse moving the + * block to be under the mouse */ + offset[0] = -(bt->rect.xmin + 0.8f * BLI_rctf_size_x(&bt->rect)); + offset[1] = -(bt->rect.ymin + 0.5f * UI_UNIT_Y); + + if (ui_but_is_editable(bt)) { + but_activate = bt; + } } + else { + /* position mouse at 0.8*width of the button and below the tile + * on the first item */ + offset[0] = 0; + LISTBASE_FOREACH (uiBut *, but_iter, &block->buttons) { + offset[0] = min_ii(offset[0], + -(but_iter->rect.xmin + 0.8f * BLI_rctf_size_x(&but_iter->rect))); + } - offset[1] = 2.1 * UI_UNIT_Y; + offset[1] = 2.1 * UI_UNIT_Y; - LISTBASE_FOREACH (uiBut *, but_iter, &block->buttons) { - if (ui_but_is_editable(but_iter)) { - but_activate = but_iter; - break; + LISTBASE_FOREACH (uiBut *, but_iter, &block->buttons) { + if (ui_but_is_editable(but_iter)) { + but_activate = but_iter; + break; + } } } + copy_v2_v2_int(handle->prev_bounds_offset, offset); + } + else { + copy_v2_v2_int(offset, handle->prev_bounds_offset); } /* in rare cases this is needed since moving the popup @@ -312,27 +371,35 @@ static uiBlock *ui_block_func_POPUP(bContext *C, uiPopupBlockHandle *handle, voi return pup->block; } -uiPopupBlockHandle *ui_popup_menu_create( - bContext *C, ARegion *butregion, uiBut *but, uiMenuCreateFunc menu_func, void *arg) +static void ui_block_free_func_POPUP(void *arg_pup) +{ + uiPopupMenu *pup = static_cast<uiPopupMenu *>(arg_pup); + MEM_delete(pup); +} + +static uiPopupBlockHandle *ui_popup_menu_create( + bContext *C, + ARegion *butregion, + uiBut *but, + const char *title, + std::function<void(bContext *, uiLayout *)> menu_func) { wmWindow *window = CTX_wm_window(C); - const uiStyle *style = UI_style_get_dpi(); - uiPopupMenu *pup = MEM_cnew<uiPopupMenu>(__func__); - pup->block = UI_block_begin(C, nullptr, __func__, UI_EMBOSS_PULLDOWN); - pup->block->flag |= UI_BLOCK_NUMSELECT; /* Default menus to numeric-selection. */ - pup->layout = UI_block_layout( - pup->block, UI_LAYOUT_VERTICAL, UI_LAYOUT_MENU, 0, 0, 200, 0, UI_MENU_PADDING, style); - pup->slideout = but ? ui_block_is_menu(but->block) : false; - pup->but = but; - uiLayoutSetOperatorContext(pup->layout, WM_OP_INVOKE_REGION_WIN); + uiPopupMenu *pup = MEM_new<uiPopupMenu>(__func__); + pup->title = title; + /* menu is created from a callback */ + pup->menu_func = menu_func; + if (but) { + pup->slideout = ui_block_is_menu(but->block); + pup->but = but; + } if (!but) { /* no button to start from, means we are a popup */ pup->mx = window->eventstate->xy[0]; pup->my = window->eventstate->xy[1]; pup->popup = true; - pup->block->flag |= UI_BLOCK_NO_FLIP; } /* some enums reversing is strange, currently we have no good way to * reverse some enum's but not others, so reverse all so the first menu @@ -346,17 +413,10 @@ uiPopupBlockHandle *ui_popup_menu_create( pup->block->flag |= UI_BLOCK_NO_FLIP; } #endif - if (but->context) { - uiLayoutContextCopy(pup->layout, but->context); - } } - /* menu is created from a callback */ - pup->menu_func = menu_func; - pup->menu_arg = arg; - uiPopupBlockHandle *handle = ui_popup_block_create( - C, butregion, but, nullptr, ui_block_func_POPUP, pup, nullptr); + C, butregion, but, nullptr, ui_block_func_POPUP, pup, ui_block_free_func_POPUP); if (!but) { handle->popup = true; @@ -365,68 +425,73 @@ uiPopupBlockHandle *ui_popup_menu_create( WM_event_add_mousemove(window); } - MEM_freeN(pup); - return handle; } +uiPopupBlockHandle *ui_popup_menu_create( + bContext *C, ARegion *butregion, uiBut *but, uiMenuCreateFunc menu_func, void *arg) +{ + return ui_popup_menu_create( + C, butregion, but, nullptr, [menu_func, arg](bContext *C, uiLayout *layout) { + menu_func(C, layout, arg); + }); +} + /** \} */ /* -------------------------------------------------------------------- */ /** \name Popup Menu API with begin & end * \{ */ +static void create_title_button(uiLayout *layout, const char *title, int icon) +{ + uiBlock *block = uiLayoutGetBlock(layout); + char titlestr[256]; + + if (icon) { + BLI_snprintf(titlestr, sizeof(titlestr), " %s", title); + uiDefIconTextBut(block, + UI_BTYPE_LABEL, + 0, + icon, + titlestr, + 0, + 0, + 200, + UI_UNIT_Y, + nullptr, + 0.0, + 0.0, + 0, + 0, + ""); + } + else { + uiBut *but = uiDefBut( + block, UI_BTYPE_LABEL, 0, title, 0, 0, 200, UI_UNIT_Y, nullptr, 0.0, 0.0, 0, 0, ""); + but->drawflag = UI_BUT_TEXT_LEFT; + } + + uiItemS(layout); +} + +/* Used to directly create a popup menu that is not refreshed on redraw. */ uiPopupMenu *UI_popup_menu_begin_ex(bContext *C, const char *title, const char *block_name, int icon) { - const uiStyle *style = UI_style_get_dpi(); - uiPopupMenu *pup = MEM_cnew<uiPopupMenu>(__func__); + uiPopupMenu *pup = MEM_new<uiPopupMenu>(__func__); - pup->block = UI_block_begin(C, nullptr, block_name, UI_EMBOSS_PULLDOWN); - pup->block->flag |= UI_BLOCK_POPUP_MEMORY | UI_BLOCK_IS_FLIP; - pup->block->puphash = ui_popup_menu_hash(title); - pup->layout = UI_block_layout( - pup->block, UI_LAYOUT_VERTICAL, UI_LAYOUT_MENU, 0, 0, 200, 0, UI_MENU_PADDING, style); + pup->title = title; - /* NOTE: this intentionally differs from the menu & sub-menu default because many operators - * use popups like this to select one of their options - - * where having invoke doesn't make sense */ - uiLayoutSetOperatorContext(pup->layout, WM_OP_EXEC_REGION_WIN); + ui_popup_menu_create_block(C, pup, title, block_name); /* create in advance so we can let buttons point to retval already */ pup->block->handle = MEM_cnew<uiPopupBlockHandle>(__func__); - /* create title button */ if (title[0]) { - char titlestr[256]; - - if (icon) { - BLI_snprintf(titlestr, sizeof(titlestr), " %s", title); - uiDefIconTextBut(pup->block, - UI_BTYPE_LABEL, - 0, - icon, - titlestr, - 0, - 0, - 200, - UI_UNIT_Y, - nullptr, - 0.0, - 0.0, - 0, - 0, - ""); - } - else { - uiBut *but = uiDefBut( - pup->block, UI_BTYPE_LABEL, 0, title, 0, 0, 200, UI_UNIT_Y, nullptr, 0.0, 0.0, 0, 0, ""); - but->drawflag = UI_BUT_TEXT_LEFT; - } - - uiItemS(pup->layout); + create_title_button(pup->layout, title, icon); } return pup; @@ -465,7 +530,7 @@ void UI_popup_menu_end(bContext *C, uiPopupMenu *pup) UI_popup_handlers_add(C, &window->modalhandlers, menu, 0); WM_event_add_mousemove(window); - MEM_freeN(pup); + MEM_delete(pup); } bool UI_popup_menu_end_or_cancel(bContext *C, uiPopupMenu *pup) @@ -477,7 +542,7 @@ bool UI_popup_menu_end_or_cancel(bContext *C, uiPopupMenu *pup) UI_block_layout_resolve(pup->block, nullptr, nullptr); MEM_freeN(pup->block->handle); UI_block_free(C, pup->block); - MEM_freeN(pup); + MEM_delete(pup); return false; } @@ -541,6 +606,20 @@ void UI_popup_menu_reports(bContext *C, ReportList *reports) } } +static void ui_popup_menu_create_from_menutype(bContext *C, + MenuType *mt, + const char *title, + const int icon) +{ + uiPopupBlockHandle *handle = ui_popup_menu_create( + C, nullptr, nullptr, title, [mt, title, icon](bContext *C, uiLayout *layout) -> void { + create_title_button(layout, title, icon); + ui_item_menutype_func(C, layout, mt); + }); + + handle->can_refresh = true; +} + int UI_popup_menu_invoke(bContext *C, const char *idname, ReportList *reports) { MenuType *mt = WM_menutype_find(idname, true); @@ -554,14 +633,21 @@ int UI_popup_menu_invoke(bContext *C, const char *idname, ReportList *reports) /* cancel but allow event to pass through, just like operators do */ return (OPERATOR_CANCELLED | OPERATOR_PASS_THROUGH); } + /* For now always recreate menus on redraw that were invoked with this function. Maybe we want to + * make that optional somehow. */ + const bool allow_refresh = true; - uiPopupMenu *pup = UI_popup_menu_begin( - C, CTX_IFACE_(mt->translation_context, mt->label), ICON_NONE); - uiLayout *layout = UI_popup_menu_layout(pup); - - UI_menutype_draw(C, mt, layout); - - UI_popup_menu_end(C, pup); + const char *title = CTX_IFACE_(mt->translation_context, mt->label); + if (allow_refresh) { + ui_popup_menu_create_from_menutype(C, mt, title, ICON_NONE); + } + else { + /* If no refresh is needed, create the block directly. */ + uiPopupMenu *pup = UI_popup_menu_begin(C, title, ICON_NONE); + uiLayout *layout = UI_popup_menu_layout(pup); + UI_menutype_draw(C, mt, layout); + UI_popup_menu_end(C, pup); + } return OPERATOR_INTERFACE; } diff --git a/source/blender/editors/interface/interface_widgets.c b/source/blender/editors/interface/interface_widgets.c index 6ba80e2e0d9..1bad9b34a72 100644 --- a/source/blender/editors/interface/interface_widgets.c +++ b/source/blender/editors/interface/interface_widgets.c @@ -1420,21 +1420,25 @@ static void widget_draw_icon( /* to indicate draggable */ if (ui_but_drag_is_draggable(but) && (but->flag & UI_ACTIVE)) { - UI_icon_draw_ex(xs, ys, icon, aspect, 1.25f, 0.0f, color, has_theme); + UI_icon_draw_ex( + xs, ys, icon, aspect, 1.25f, 0.0f, color, has_theme, &but->icon_overlay_text); } else if (but->flag & (UI_ACTIVE | UI_SELECT | UI_SELECT_DRAW)) { - UI_icon_draw_ex(xs, ys, icon, aspect, alpha, 0.0f, color, has_theme); + UI_icon_draw_ex( + xs, ys, icon, aspect, alpha, 0.0f, color, has_theme, &but->icon_overlay_text); } else if (!((but->icon != ICON_NONE) && UI_but_is_tool(but))) { if (has_theme) { alpha *= 0.8f; } - UI_icon_draw_ex(xs, ys, icon, aspect, alpha, 0.0f, color, has_theme); + UI_icon_draw_ex( + xs, ys, icon, aspect, alpha, 0.0f, color, has_theme, &but->icon_overlay_text); } else { const bTheme *btheme = UI_GetTheme(); const float desaturate = 1.0 - btheme->tui.icon_saturation; - UI_icon_draw_ex(xs, ys, icon, aspect, alpha, desaturate, color, has_theme); + UI_icon_draw_ex( + xs, ys, icon, aspect, alpha, desaturate, color, has_theme, &but->icon_overlay_text); } } @@ -5426,7 +5430,8 @@ void ui_draw_menu_item(const uiFontStyle *fstyle, GPU_blend(GPU_BLEND_ALPHA); /* XXX scale weak get from fstyle? */ - UI_icon_draw_ex(xs, ys, iconid, aspect, 1.0f, 0.0f, wt->wcol.text, false); + UI_icon_draw_ex( + xs, ys, iconid, aspect, 1.0f, 0.0f, wt->wcol.text, false, UI_NO_ICON_OVERLAY_TEXT); GPU_blend(GPU_BLEND_NONE); } diff --git a/source/blender/editors/interface/views/interface_view.cc b/source/blender/editors/interface/views/interface_view.cc index c568a8cab74..71974b4d2f9 100644 --- a/source/blender/editors/interface/views/interface_view.cc +++ b/source/blender/editors/interface/views/interface_view.cc @@ -81,7 +81,7 @@ void ui_block_free_views(uiBlock *block) } } -void UI_block_views_listen(const uiBlock *block, const wmRegionListenerParams *listener_params) +void ui_block_views_listen(const uiBlock *block, const wmRegionListenerParams *listener_params) { ARegion *region = listener_params->region; diff --git a/source/blender/editors/io/io_gpencil_import.c b/source/blender/editors/io/io_gpencil_import.c index c7a6b20af7b..5325965e9a5 100644 --- a/source/blender/editors/io/io_gpencil_import.c +++ b/source/blender/editors/io/io_gpencil_import.c @@ -111,7 +111,7 @@ static int wm_gpencil_import_svg_exec(bContext *C, wmOperator *op) char file_path[FILE_MAX]; RNA_PROP_BEGIN (op->ptr, itemptr, prop) { char *filename = RNA_string_get_alloc(&itemptr, "name", NULL, 0, NULL); - BLI_join_dirfile(file_path, sizeof(file_path), directory, filename); + BLI_path_join(file_path, sizeof(file_path), directory, filename); MEM_freeN(filename); /* Do Import. */ diff --git a/source/blender/editors/io/io_obj.c b/source/blender/editors/io/io_obj.c index 7559cd47b27..27994af8fe7 100644 --- a/source/blender/editors/io/io_obj.c +++ b/source/blender/editors/io/io_obj.c @@ -427,8 +427,7 @@ static int wm_obj_import_exec(bContext *C, wmOperator *op) for (int i = 0; i < files_len; i++) { RNA_property_collection_lookup_int(op->ptr, prop, i, &fileptr); RNA_string_get(&fileptr, "name", file_only); - BLI_join_dirfile( - import_params.filepath, sizeof(import_params.filepath), dir_only, file_only); + BLI_path_join(import_params.filepath, sizeof(import_params.filepath), dir_only, file_only); import_params.clear_selection = (i == 0); OBJ_import(C, &import_params); } diff --git a/source/blender/editors/io/io_stl_ops.c b/source/blender/editors/io/io_stl_ops.c index c27d42a07c0..bbdb494e48a 100644 --- a/source/blender/editors/io/io_stl_ops.c +++ b/source/blender/editors/io/io_stl_ops.c @@ -49,7 +49,7 @@ static int wm_stl_import_execute(bContext *C, wmOperator *op) for (int i = 0; i < files_len; i++) { RNA_property_collection_lookup_int(op->ptr, prop, i, &fileptr); RNA_string_get(&fileptr, "name", file_only); - BLI_join_dirfile(params.filepath, sizeof(params.filepath), dir_only, file_only); + BLI_path_join(params.filepath, sizeof(params.filepath), dir_only, file_only); STL_import(C, ¶ms); } } diff --git a/source/blender/editors/mesh/editface.cc b/source/blender/editors/mesh/editface.cc index 888a8340d51..1c6d1747516 100644 --- a/source/blender/editors/mesh/editface.cc +++ b/source/blender/editors/mesh/editface.cc @@ -383,7 +383,7 @@ bool paintface_minmax(Object *ob, float r_min[3], float r_max[3]) return ok; } - copy_m3_m4(bmat, ob->obmat); + copy_m3_m4(bmat, ob->object_to_world); const Span<MVert> verts = me->verts(); const Span<MPoly> polys = me->polys(); @@ -403,7 +403,7 @@ bool paintface_minmax(Object *ob, float r_min[3], float r_max[3]) const MLoop *ml = &loops[poly.loopstart]; for (int b = 0; b < poly.totloop; b++, ml++) { mul_v3_m3v3(vec, bmat, verts[ml->v].co); - add_v3_v3v3(vec, vec, ob->obmat[3]); + add_v3_v3v3(vec, vec, ob->object_to_world[3]); minmax_v3v3_v3(r_min, r_max, vec); } diff --git a/source/blender/editors/mesh/editmesh_add_gizmo.c b/source/blender/editors/mesh/editmesh_add_gizmo.c index f5090c0143d..ad900c997f8 100644 --- a/source/blender/editors/mesh/editmesh_add_gizmo.c +++ b/source/blender/editors/mesh/editmesh_add_gizmo.c @@ -316,7 +316,7 @@ static int add_primitive_cube_gizmo_exec(bContext *C, wmOperator *op) PropertyRNA *prop_matrix = RNA_struct_find_property(op->ptr, "matrix"); if (RNA_property_is_set(op->ptr, prop_matrix)) { RNA_property_float_get_array(op->ptr, prop_matrix, &matrix[0][0]); - invert_m4_m4(obedit->imat, obedit->obmat); + invert_m4_m4(obedit->imat, obedit->object_to_world); mul_m4_m4m4(matrix, obedit->imat, matrix); } else { diff --git a/source/blender/editors/mesh/editmesh_bevel.c b/source/blender/editors/mesh/editmesh_bevel.c index 3284cd70646..85801668510 100644 --- a/source/blender/editors/mesh/editmesh_bevel.c +++ b/source/blender/editors/mesh/editmesh_bevel.c @@ -244,7 +244,7 @@ static bool edbm_bevel_init(bContext *C, wmOperator *op, const bool is_modal) opdata->ob_store = MEM_malloc_arrayN(ob_store_len, sizeof(*opdata->ob_store), __func__); for (uint ob_index = 0; ob_index < ob_store_len; ob_index++) { Object *obedit = objects[ob_index]; - float scale = mat4_to_scale(obedit->obmat); + float scale = mat4_to_scale(obedit->object_to_world); opdata->max_obj_scale = max_ff(opdata->max_obj_scale, scale); BMEditMesh *em = BKE_editmesh_from_object(obedit); if (em->bm->totvertsel > 0) { diff --git a/source/blender/editors/mesh/editmesh_bisect.c b/source/blender/editors/mesh/editmesh_bisect.c index 5c5a12b3e64..aab33678bec 100644 --- a/source/blender/editors/mesh/editmesh_bisect.c +++ b/source/blender/editors/mesh/editmesh_bisect.c @@ -314,9 +314,9 @@ static int mesh_bisect_exec(bContext *C, wmOperator *op) copy_v3_v3(plane_co_local, plane_co); copy_v3_v3(plane_no_local, plane_no); - invert_m4_m4(imat, obedit->obmat); + invert_m4_m4(imat, obedit->object_to_world); mul_m4_v3(imat, plane_co_local); - mul_transposed_mat3_m4_v3(obedit->obmat, plane_no_local); + mul_transposed_mat3_m4_v3(obedit->object_to_world, plane_no_local); BMOperator bmop; EDBM_op_init( diff --git a/source/blender/editors/mesh/editmesh_extrude.c b/source/blender/editors/mesh/editmesh_extrude.c index 55e9c32e41b..9df3a521cfa 100644 --- a/source/blender/editors/mesh/editmesh_extrude.c +++ b/source/blender/editors/mesh/editmesh_extrude.c @@ -55,8 +55,8 @@ static void edbm_extrude_edge_exclude_mirror( float mtx[4][4]; if (mmd->mirror_ob) { float imtx[4][4]; - invert_m4_m4(imtx, mmd->mirror_ob->obmat); - mul_m4_m4m4(mtx, imtx, obedit->obmat); + invert_m4_m4(imtx, mmd->mirror_ob->object_to_world); + mul_m4_m4m4(mtx, imtx, obedit->object_to_world); } BM_ITER_MESH (edge, &iter, bm, BM_EDGES_OF_MESH) { @@ -293,7 +293,7 @@ static int edbm_extrude_repeat_exec(bContext *C, wmOperator *op) Object *obedit = objects[ob_index]; BMEditMesh *em = BKE_editmesh_from_object(obedit); - copy_m3_m4(tmat, obedit->obmat); + copy_m3_m4(tmat, obedit->object_to_world); invert_m3(tmat); mul_v3_m3v3(offset_local, tmat, offset); @@ -736,7 +736,7 @@ static int edbm_dupli_extrude_cursor_invoke(bContext *C, wmOperator *op, const w } mul_v3_fl(local_center, 1.0f / (float)local_verts_len); - mul_m4_v3(vc.obedit->obmat, local_center); + mul_m4_v3(vc.obedit->object_to_world, local_center); mul_v3_fl(local_center, (float)local_verts_len); add_v3_v3(center, local_center); @@ -761,7 +761,7 @@ static int edbm_dupli_extrude_cursor_invoke(bContext *C, wmOperator *op, const w continue; } - invert_m4_m4(vc.obedit->imat, vc.obedit->obmat); + invert_m4_m4(vc.obedit->imat, vc.obedit->object_to_world); ED_view3d_init_mats_rv3d(vc.obedit, vc.rv3d); float local_center[3]; @@ -823,7 +823,7 @@ static int edbm_dupli_extrude_cursor_invoke(bContext *C, wmOperator *op, const w /* center */ copy_v3_v3(ofs, local_center); - mul_m4_v3(vc.obedit->obmat, ofs); /* view space */ + mul_m4_v3(vc.obedit->object_to_world, ofs); /* view space */ ED_view3d_win_to_3d_int(vc.v3d, vc.region, ofs, event->mval, ofs); mul_m4_v3(vc.obedit->imat, ofs); /* back in object space */ diff --git a/source/blender/editors/mesh/editmesh_extrude_screw.c b/source/blender/editors/mesh/editmesh_extrude_screw.c index be2d04b14a1..9d0bcfe4e90 100644 --- a/source/blender/editors/mesh/editmesh_extrude_screw.c +++ b/source/blender/editors/mesh/editmesh_extrude_screw.c @@ -102,11 +102,11 @@ static int edbm_screw_exec(bContext *C, wmOperator *op) continue; } - copy_v3_v3(nor, obedit->obmat[2]); + copy_v3_v3(nor, obedit->object_to_world[2]); /* calculate dvec */ - mul_v3_m4v3(v1_co_global, obedit->obmat, v1->co); - mul_v3_m4v3(v2_co_global, obedit->obmat, v2->co); + mul_v3_m4v3(v1_co_global, obedit->object_to_world, v1->co); + mul_v3_m4v3(v2_co_global, obedit->object_to_world, v2->co); sub_v3_v3v3(dvec, v1_co_global, v2_co_global); mul_v3_fl(dvec, 1.0f / steps); @@ -126,7 +126,7 @@ static int edbm_screw_exec(bContext *C, wmOperator *op) dvec, turns * steps, DEG2RADF(360.0f * turns), - obedit->obmat, + obedit->object_to_world, false)) { continue; } diff --git a/source/blender/editors/mesh/editmesh_extrude_spin.c b/source/blender/editors/mesh/editmesh_extrude_spin.c index 1b9c98db5eb..756d7f73d10 100644 --- a/source/blender/editors/mesh/editmesh_extrude_spin.c +++ b/source/blender/editors/mesh/editmesh_extrude_spin.c @@ -77,7 +77,7 @@ static int edbm_spin_exec(bContext *C, wmOperator *op) d, steps, -angle, - obedit->obmat, + obedit->object_to_world, use_normal_flip, dupli, use_auto_merge)) { diff --git a/source/blender/editors/mesh/editmesh_extrude_spin_gizmo.c b/source/blender/editors/mesh/editmesh_extrude_spin_gizmo.c index 687f06c8dcf..19e23f4f212 100644 --- a/source/blender/editors/mesh/editmesh_extrude_spin_gizmo.c +++ b/source/blender/editors/mesh/editmesh_extrude_spin_gizmo.c @@ -362,7 +362,7 @@ static void gizmo_mesh_spin_init_refresh(const bContext *C, wmGizmoGroup *gzgrou } if (totsel) { mul_v3_fl(select_center, 1.0f / totsel); - mul_m4_v3(obedit->obmat, select_center); + mul_m4_v3(obedit->object_to_world, select_center); copy_v3_v3(ggd->data.select_center, select_center); ggd->data.use_select_center = true; } diff --git a/source/blender/editors/mesh/editmesh_inset.c b/source/blender/editors/mesh/editmesh_inset.c index 068e6215c26..fa4ae7f984c 100644 --- a/source/blender/editors/mesh/editmesh_inset.c +++ b/source/blender/editors/mesh/editmesh_inset.c @@ -136,7 +136,7 @@ static bool edbm_inset_init(bContext *C, wmOperator *op, const bool is_modal) opdata->ob_store = MEM_malloc_arrayN(ob_store_len, sizeof(*opdata->ob_store), __func__); for (uint ob_index = 0; ob_index < ob_store_len; ob_index++) { Object *obedit = objects[ob_index]; - float scale = mat4_to_scale(obedit->obmat); + float scale = mat4_to_scale(obedit->object_to_world); opdata->max_obj_scale = max_ff(opdata->max_obj_scale, scale); BMEditMesh *em = BKE_editmesh_from_object(obedit); if (em->bm->totvertsel > 0) { diff --git a/source/blender/editors/mesh/editmesh_knife.c b/source/blender/editors/mesh/editmesh_knife.c index a147594b25b..369162e80a3 100644 --- a/source/blender/editors/mesh/editmesh_knife.c +++ b/source/blender/editors/mesh/editmesh_knife.c @@ -586,9 +586,9 @@ static void knifetool_draw_angle(const KnifeTool_OpData *kcd, float axis[3]; float arc_angle; - const float inverse_average_scale = 1 / - (kcd->curr.ob->obmat[0][0] + kcd->curr.ob->obmat[1][1] + - kcd->curr.ob->obmat[2][2]); + const float inverse_average_scale = 1 / (kcd->curr.ob->object_to_world[0][0] + + kcd->curr.ob->object_to_world[1][1] + + kcd->curr.ob->object_to_world[2][2]); const float px_scale = 3.0f * inverse_average_scale * @@ -1194,7 +1194,7 @@ static void knife_bm_tri_cagecos_get_worldspace(const KnifeTool_OpData *kcd, knife_bm_tri_cagecos_get(kcd, ob_index, tri_index, cos); const Object *ob = kcd->objects[ob_index]; for (int i = 0; i < 3; i++) { - mul_m4_v3(ob->obmat, cos[i]); + mul_m4_v3(ob->object_to_world, cos[i]); } } @@ -1744,7 +1744,7 @@ static KnifeVert *get_bm_knife_vert(KnifeTool_OpData *kcd, BMVert *v, Object *ob } float cageco_ws[3]; - mul_v3_m4v3(cageco_ws, ob->obmat, cageco); + mul_v3_m4v3(cageco_ws, ob->object_to_world, cageco); kfv = new_knife_vert(kcd, v->co, cageco_ws); kfv->v = v; @@ -2657,14 +2657,14 @@ static void calc_ortho_extent(KnifeTool_OpData *kcd) if (cagecos) { for (int i = 0; i < em->bm->totvert; i++) { copy_v3_v3(ws, cagecos[i]); - mul_m4_v3(ob->obmat, ws); + mul_m4_v3(ob->object_to_world, ws); minmax_v3v3_v3(min, max, ws); } } else { BM_ITER_MESH (v, &iter, em->bm, BM_VERTS_OF_MESH) { copy_v3_v3(ws, v->co); - mul_m4_v3(ob->obmat, ws); + mul_m4_v3(ob->object_to_world, ws); minmax_v3v3_v3(min, max, ws); } } @@ -5072,7 +5072,7 @@ void EDBM_mesh_knife(ViewContext *vc, BM_ITER_ELEM (f, &fiter, e, BM_FACES_OF_EDGE) { float cent[3], cent_ss[2]; BM_face_calc_point_in_face(f, cent); - mul_m4_v3(ob->obmat, cent); + mul_m4_v3(ob->object_to_world, cent); knife_project_v2(kcd, cent, cent_ss); if (edbm_mesh_knife_point_isect(polys, cent_ss)) { BM_elem_flag_enable(f, BM_ELEM_TAG); @@ -5113,7 +5113,7 @@ void EDBM_mesh_knife(ViewContext *vc, if (found) { float cent[3], cent_ss[2]; BM_face_calc_point_in_face(f, cent); - mul_m4_v3(ob->obmat, cent); + mul_m4_v3(ob->object_to_world, cent); knife_project_v2(kcd, cent, cent_ss); if ((kcd->cut_through || point_is_visible(kcd, cent, cent_ss, (BMElem *)f)) && edbm_mesh_knife_point_isect(polys, cent_ss)) { diff --git a/source/blender/editors/mesh/editmesh_loopcut.c b/source/blender/editors/mesh/editmesh_loopcut.c index 494e0ff4a27..9a91d7836fe 100644 --- a/source/blender/editors/mesh/editmesh_loopcut.c +++ b/source/blender/editors/mesh/editmesh_loopcut.c @@ -88,7 +88,7 @@ typedef struct RingSelOpData { static void ringsel_draw(const bContext *UNUSED(C), ARegion *UNUSED(region), void *arg) { RingSelOpData *lcd = arg; - EDBM_preselect_edgering_draw(lcd->presel_edgering, lcd->ob->obmat); + EDBM_preselect_edgering_draw(lcd->presel_edgering, lcd->ob->object_to_world); } static void edgering_select(RingSelOpData *lcd) diff --git a/source/blender/editors/mesh/editmesh_mask_extract.c b/source/blender/editors/mesh/editmesh_mask_extract.c index fdf4746ab09..070f748c78e 100644 --- a/source/blender/editors/mesh/editmesh_mask_extract.c +++ b/source/blender/editors/mesh/editmesh_mask_extract.c @@ -88,7 +88,7 @@ static int geometry_extract_apply(bContext *C, ED_object_sculptmode_exit(C, depsgraph); - BKE_sculpt_mask_layers_ensure(ob, NULL); + BKE_sculpt_mask_layers_ensure(depsgraph, bmain, ob, NULL); /* Ensures that deformation from sculpt mode is taken into account before duplicating the mesh to * extract the geometry. */ @@ -481,7 +481,7 @@ static int paint_mask_slice_exec(bContext *C, wmOperator *op) Object *ob = CTX_data_active_object(C); View3D *v3d = CTX_wm_view3d(C); - BKE_sculpt_mask_layers_ensure(ob, NULL); + BKE_sculpt_mask_layers_ensure(NULL, NULL, ob, NULL); Mesh *mesh = ob->data; Mesh *new_mesh = (Mesh *)BKE_id_copy(bmain, &mesh->id); diff --git a/source/blender/editors/mesh/editmesh_polybuild.c b/source/blender/editors/mesh/editmesh_polybuild.c index bf9664fa10d..63e37b18827 100644 --- a/source/blender/editors/mesh/editmesh_polybuild.c +++ b/source/blender/editors/mesh/editmesh_polybuild.c @@ -124,7 +124,7 @@ static int edbm_polybuild_transform_at_cursor_invoke(bContext *C, BMEditMesh *em = vc.em; BMesh *bm = em->bm; - invert_m4_m4(vc.obedit->imat, vc.obedit->obmat); + invert_m4_m4(vc.obedit->imat, vc.obedit->object_to_world); ED_view3d_init_mats_rv3d(vc.obedit, vc.rv3d); if (!ele_act) { @@ -192,7 +192,7 @@ static int edbm_polybuild_delete_at_cursor_invoke(bContext *C, BMEditMesh *em = vc.em; BMesh *bm = em->bm; - invert_m4_m4(vc.obedit->imat, vc.obedit->obmat); + invert_m4_m4(vc.obedit->imat, vc.obedit->object_to_world); ED_view3d_init_mats_rv3d(vc.obedit, vc.rv3d); if (!ele_act) { @@ -286,7 +286,7 @@ static int edbm_polybuild_face_at_cursor_invoke(bContext *C, wmOperator *op, con BMEditMesh *em = vc.em; BMesh *bm = em->bm; - invert_m4_m4(vc.obedit->imat, vc.obedit->obmat); + invert_m4_m4(vc.obedit->imat, vc.obedit->object_to_world); ED_view3d_init_mats_rv3d(vc.obedit, vc.rv3d); edbm_selectmode_ensure(vc.scene, vc.em, SCE_SELECT_VERTEX); @@ -294,7 +294,7 @@ static int edbm_polybuild_face_at_cursor_invoke(bContext *C, wmOperator *op, con if (ele_act == NULL || ele_act->head.htype == BM_FACE) { /* Just add vert */ copy_v3_v3(center, vc.scene->cursor.location); - mul_v3_m4v3(center, vc.obedit->obmat, center); + mul_v3_m4v3(center, vc.obedit->object_to_world, center); ED_view3d_win_to_3d_int(vc.v3d, vc.region, center, event->mval, center); mul_m4_v3(vc.obedit->imat, center); @@ -309,7 +309,7 @@ static int edbm_polybuild_face_at_cursor_invoke(bContext *C, wmOperator *op, con BMFace *f_reference = e_act->l ? e_act->l->f : NULL; mid_v3_v3v3(center, e_act->v1->co, e_act->v2->co); - mul_m4_v3(vc.obedit->obmat, center); + mul_m4_v3(vc.obedit->object_to_world, center); ED_view3d_win_to_3d_int(vc.v3d, vc.region, center, event->mval, center); mul_m4_v3(vc.obedit->imat, center); if (f_reference->len == 3 && RNA_boolean_get(op->ptr, "create_quads")) { @@ -364,7 +364,7 @@ static int edbm_polybuild_face_at_cursor_invoke(bContext *C, wmOperator *op, con BMFace *f_reference = e_pair[0]->l ? e_pair[0]->l->f : NULL; - mul_v3_m4v3(center, vc.obedit->obmat, v_act->co); + mul_v3_m4v3(center, vc.obedit->object_to_world, v_act->co); ED_view3d_win_to_3d_int(vc.v3d, vc.region, center, event->mval, center); mul_m4_v3(vc.obedit->imat, center); @@ -386,7 +386,7 @@ static int edbm_polybuild_face_at_cursor_invoke(bContext *C, wmOperator *op, con } else { /* Just add edge */ - mul_m4_v3(vc.obedit->obmat, center); + mul_m4_v3(vc.obedit->object_to_world, center); ED_view3d_win_to_3d_int(vc.v3d, vc.region, v_act->co, event->mval, center); mul_m4_v3(vc.obedit->imat, center); @@ -464,7 +464,7 @@ static int edbm_polybuild_split_at_cursor_invoke(bContext *C, BMEditMesh *em = vc.em; BMesh *bm = em->bm; - invert_m4_m4(vc.obedit->imat, vc.obedit->obmat); + invert_m4_m4(vc.obedit->imat, vc.obedit->object_to_world); ED_view3d_init_mats_rv3d(vc.obedit, vc.rv3d); edbm_selectmode_ensure(vc.scene, vc.em, SCE_SELECT_VERTEX); @@ -475,7 +475,7 @@ static int edbm_polybuild_split_at_cursor_invoke(bContext *C, if (ele_act->head.htype == BM_EDGE) { BMEdge *e_act = (BMEdge *)ele_act; mid_v3_v3v3(center, e_act->v1->co, e_act->v2->co); - mul_m4_v3(vc.obedit->obmat, center); + mul_m4_v3(vc.obedit->object_to_world, center); ED_view3d_win_to_3d_int(vc.v3d, vc.region, center, event->mval, center); mul_m4_v3(vc.obedit->imat, center); diff --git a/source/blender/editors/mesh/editmesh_preselect_elem.c b/source/blender/editors/mesh/editmesh_preselect_elem.c index cf73e579700..732f39e4123 100644 --- a/source/blender/editors/mesh/editmesh_preselect_elem.c +++ b/source/blender/editors/mesh/editmesh_preselect_elem.c @@ -243,7 +243,7 @@ static void view3d_preselect_update_preview_triangle_from_vert(struct EditMesh_P } if (e_pair[1] != NULL) { - mul_v3_m4v3(center, vc->obedit->obmat, v_act->co); + mul_v3_m4v3(center, vc->obedit->object_to_world, v_act->co); ED_view3d_win_to_3d_int(vc->v3d, vc->region, center, mval, center); mul_m4_v3(vc->obedit->imat, center); @@ -311,7 +311,7 @@ static void view3d_preselect_update_preview_triangle_from_edge(struct EditMesh_P psel->preview_tris = MEM_mallocN(sizeof(*psel->preview_tris), __func__); psel->preview_lines = MEM_mallocN(sizeof(*psel->preview_lines) * 3, __func__); mid_v3_v3v3(center, eed->v1->co, eed->v2->co); - mul_m4_v3(vc->obedit->obmat, center); + mul_m4_v3(vc->obedit->object_to_world, center); ED_view3d_win_to_3d_int(vc->v3d, vc->region, center, mval, center); mul_m4_v3(vc->obedit->imat, center); diff --git a/source/blender/editors/mesh/editmesh_select.cc b/source/blender/editors/mesh/editmesh_select.cc index 76d0bab8a52..2ef2772d404 100644 --- a/source/blender/editors/mesh/editmesh_select.cc +++ b/source/blender/editors/mesh/editmesh_select.cc @@ -1060,7 +1060,7 @@ bool EDBM_unified_findnearest_from_raycast(ViewContext *vc, float imat3[3][3]; ED_view3d_viewcontext_init_object(vc, obedit); - copy_m3_m4(imat3, obedit->obmat); + copy_m3_m4(imat3, obedit->object_to_world); invert_m3(imat3); const float(*coords)[3] = nullptr; @@ -1085,7 +1085,8 @@ bool EDBM_unified_findnearest_from_raycast(ViewContext *vc, for (uint j = 0; j < 2; j++) { BMVert *v = *((&e->v1) + j); float point[3]; - mul_v3_m4v3(point, obedit->obmat, coords ? coords[BM_elem_index_get(v)] : v->co); + mul_v3_m4v3( + point, obedit->object_to_world, coords ? coords[BM_elem_index_get(v)] : v->co); const float dist_sq_test = dist_squared_to_ray_v3_normalized( ray_origin, ray_direction, point); if (dist_sq_test < dist_sq_best_vert) { @@ -1114,7 +1115,7 @@ bool EDBM_unified_findnearest_from_raycast(ViewContext *vc, else { mid_v3_v3v3(point, e->v1->co, e->v2->co); } - mul_m4_v3(obedit->obmat, point); + mul_m4_v3(obedit->object_to_world, point); const float dist_sq_test = dist_squared_to_ray_v3_normalized( ray_origin, ray_direction, point); if (dist_sq_test < dist_sq_best_edge) { @@ -1139,7 +1140,8 @@ bool EDBM_unified_findnearest_from_raycast(ViewContext *vc, BM_ITER_MESH (v, &viter, bm, BM_VERTS_OF_MESH) { if (BM_elem_flag_test(v, BM_ELEM_HIDDEN) == false) { float point[3]; - mul_v3_m4v3(point, obedit->obmat, coords ? coords[BM_elem_index_get(v)] : v->co); + mul_v3_m4v3( + point, obedit->object_to_world, coords ? coords[BM_elem_index_get(v)] : v->co); const float dist_sq_test = dist_squared_to_ray_v3_normalized( ray_origin, ray_direction, point); if (dist_sq_test < dist_sq_best_vert) { @@ -1169,7 +1171,7 @@ bool EDBM_unified_findnearest_from_raycast(ViewContext *vc, else { mid_v3_v3v3(point, e->v1->co, e->v2->co); } - mul_m4_v3(obedit->obmat, point); + mul_m4_v3(obedit->object_to_world, point); const float dist_sq_test = dist_squared_to_ray_v3_normalized( ray_origin, ray_direction, point); if (dist_sq_test < dist_sq_best_edge) { @@ -1198,7 +1200,7 @@ bool EDBM_unified_findnearest_from_raycast(ViewContext *vc, else { BM_face_calc_center_median(f, point); } - mul_m4_v3(obedit->obmat, point); + mul_m4_v3(obedit->object_to_world, point); const float dist_sq_test = dist_squared_to_ray_v3_normalized( ray_origin, ray_direction, point); if (dist_sq_test < dist_sq_best_face) { @@ -4947,7 +4949,7 @@ static int edbm_select_axis_exec(bContext *C, wmOperator *op) { float vertex_world[3]; - mul_v3_m4v3(vertex_world, obedit->obmat, v_act->co); + mul_v3_m4v3(vertex_world, obedit->object_to_world, v_act->co); value = dot_v3v3(axis_vector, vertex_world); } @@ -4977,7 +4979,7 @@ static int edbm_select_axis_exec(bContext *C, wmOperator *op) BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) { if (!BM_elem_flag_test(v, BM_ELEM_HIDDEN | BM_ELEM_SELECT)) { float v_iter_world[3]; - mul_v3_m4v3(v_iter_world, obedit_iter->obmat, v->co); + mul_v3_m4v3(v_iter_world, obedit_iter->object_to_world, v->co); const float value_iter = dot_v3v3(axis_vector, v_iter_world); switch (sign) { case SELECT_AXIS_ALIGN: diff --git a/source/blender/editors/mesh/editmesh_select_similar.c b/source/blender/editors/mesh/editmesh_select_similar.c index 47c76b7709b..9469639718f 100644 --- a/source/blender/editors/mesh/editmesh_select_similar.c +++ b/source/blender/editors/mesh/editmesh_select_similar.c @@ -137,7 +137,7 @@ static void face_to_plane(const Object *ob, BMFace *face, float r_plane[4]) copy_v3_v3(normal, face->no); mul_transposed_mat3_m4_v3(ob->imat, normal); normalize_v3(normal); - mul_v3_m4v3(co, ob->obmat, BM_FACE_FIRST_LOOP(face)->v->co); + mul_v3_m4v3(co, ob->object_to_world, BM_FACE_FIRST_LOOP(face)->v->co); plane_from_point_normal_v3(r_plane, co, normal); } @@ -206,7 +206,7 @@ static int similar_face_select_exec(bContext *C, wmOperator *op) BMEditMesh *em = BKE_editmesh_from_object(ob); BMesh *bm = em->bm; Material ***material_array = NULL; - invert_m4_m4(ob->imat, ob->obmat); + invert_m4_m4(ob->imat, ob->object_to_world); int custom_data_offset = 0; if (bm->totfacesel == 0) { @@ -214,7 +214,7 @@ static int similar_face_select_exec(bContext *C, wmOperator *op) } float ob_m3[3][3]; - copy_m3_m4(ob_m3, ob->obmat); + copy_m3_m4(ob_m3, ob->object_to_world); switch (type) { case SIMFACE_MATERIAL: { @@ -335,7 +335,7 @@ static int similar_face_select_exec(bContext *C, wmOperator *op) int custom_data_offset; float ob_m3[3][3]; - copy_m3_m4(ob_m3, ob->obmat); + copy_m3_m4(ob_m3, ob->object_to_world); bool has_custom_data_layer = false; switch (type) { @@ -559,8 +559,8 @@ static void edge_pos_direction_worldspace_get(Object *ob, BMEdge *edge, float *r copy_v3_v3(v1, edge->v1->co); copy_v3_v3(v2, edge->v2->co); - mul_m4_v3(ob->obmat, v1); - mul_m4_v3(ob->obmat, v2); + mul_m4_v3(ob->object_to_world, v1); + mul_m4_v3(ob->object_to_world, v2); sub_v3_v3v3(r_dir, v1, v2); normalize_v3(r_dir); @@ -586,8 +586,8 @@ static float edge_length_squared_worldspace_get(Object *ob, BMEdge *edge) { float v1[3], v2[3]; - mul_v3_mat3_m4v3(v1, ob->obmat, edge->v1->co); - mul_v3_mat3_m4v3(v2, ob->obmat, edge->v2->co); + mul_v3_mat3_m4v3(v1, ob->object_to_world, edge->v1->co); + mul_v3_mat3_m4v3(v2, ob->object_to_world, edge->v2->co); return len_squared_v3v3(v1, v2); } @@ -705,7 +705,7 @@ static int similar_edge_select_exec(bContext *C, wmOperator *op) } float ob_m3[3][3], ob_m3_inv[3][3]; - copy_m3_m4(ob_m3, ob->obmat); + copy_m3_m4(ob_m3, ob->object_to_world); invert_m3_m3(ob_m3_inv, ob_m3); BMEdge *edge; /* Mesh edge. */ @@ -812,7 +812,7 @@ static int similar_edge_select_exec(bContext *C, wmOperator *op) } float ob_m3[3][3], ob_m3_inv[3][3]; - copy_m3_m4(ob_m3, ob->obmat); + copy_m3_m4(ob_m3, ob->object_to_world); invert_m3_m3(ob_m3_inv, ob_m3); BMEdge *edge; /* Mesh edge. */ @@ -1028,7 +1028,7 @@ static int similar_vert_select_exec(bContext *C, wmOperator *op) BLI_bitmap *defbase_selected = NULL; int defbase_len = 0; - invert_m4_m4(ob->imat, ob->obmat); + invert_m4_m4(ob->imat, ob->object_to_world); if (bm->totvertsel == 0) { continue; diff --git a/source/blender/editors/mesh/editmesh_tools.c b/source/blender/editors/mesh/editmesh_tools.c index 9f3ef8af17d..9f5c0d74ced 100644 --- a/source/blender/editors/mesh/editmesh_tools.c +++ b/source/blender/editors/mesh/editmesh_tools.c @@ -3356,7 +3356,7 @@ static bool merge_target(BMEditMesh *em, if (use_cursor) { vco = scene->cursor.location; copy_v3_v3(co, vco); - invert_m4_m4(ob->imat, ob->obmat); + invert_m4_m4(ob->imat, ob->object_to_world); mul_m4_v3(ob->imat, co); } else { @@ -6684,7 +6684,7 @@ static void sort_bmelem_flag(bContext *C, int coidx = (action == SRT_VIEW_ZAXIS) ? 2 : 0; /* Apply the view matrix to the object matrix. */ - mul_m4_m4m4(mat, rv3d->viewmat, ob->obmat); + mul_m4_m4m4(mat, rv3d->viewmat, ob->object_to_world); if (totelem[0]) { pb = pblock[0] = MEM_callocN(sizeof(char) * totelem[0], "sort_bmelem vert pblock"); @@ -6753,7 +6753,7 @@ static void sort_bmelem_flag(bContext *C, copy_v3_v3(cur, scene->cursor.location); - invert_m4_m4(mat, ob->obmat); + invert_m4_m4(mat, ob->object_to_world); mul_m4_v3(mat, cur); if (totelem[0]) { diff --git a/source/blender/editors/mesh/editmesh_utils.c b/source/blender/editors/mesh/editmesh_utils.c index 4fc44f01ea0..10acfc96ca8 100644 --- a/source/blender/editors/mesh/editmesh_utils.c +++ b/source/blender/editors/mesh/editmesh_utils.c @@ -1858,7 +1858,7 @@ bool BMBVH_EdgeVisible(struct BMBVHTree *tree, ED_view3d_win_to_segment_clipped(depsgraph, region, v3d, mval_f, origin, end, false); - invert_m4_m4(invmat, obedit->obmat); + invert_m4_m4(invmat, obedit->object_to_world); mul_m4_v3(invmat, origin); copy_v3_v3(co1, e->v1->co); diff --git a/source/blender/editors/mesh/mesh_data.cc b/source/blender/editors/mesh/mesh_data.cc index 122b8fa7d89..b468360ff9b 100644 --- a/source/blender/editors/mesh/mesh_data.cc +++ b/source/blender/editors/mesh/mesh_data.cc @@ -787,7 +787,7 @@ static int mesh_customdata_custom_splitnormals_add_exec(bContext *C, wmOperator if (me->edit_mesh) { /* Tag edges as sharp according to smooth threshold if needed, - * to preserve autosmooth shading. */ + * to preserve auto-smooth shading. */ if (me->flag & ME_AUTOSMOOTH) { BM_edges_sharp_from_angle_set(me->edit_mesh->bm, me->smoothresh); } @@ -796,7 +796,7 @@ static int mesh_customdata_custom_splitnormals_add_exec(bContext *C, wmOperator } else { /* Tag edges as sharp according to smooth threshold if needed, - * to preserve autosmooth shading. */ + * to preserve auto-smooth shading. */ if (me->flag & ME_AUTOSMOOTH) { const Span<MVert> verts = me->verts(); MutableSpan<MEdge> edges = me->edges_for_write(); diff --git a/source/blender/editors/mesh/meshtools.cc b/source/blender/editors/mesh/meshtools.cc index 4d75ab7f041..147c26e521f 100644 --- a/source/blender/editors/mesh/meshtools.cc +++ b/source/blender/editors/mesh/meshtools.cc @@ -132,7 +132,7 @@ static void join_mesh_single(Depsgraph *depsgraph, float cmat[4][4]; /* Watch this: switch matrix multiplication order really goes wrong. */ - mul_m4_m4m4(cmat, imat, ob_src->obmat); + mul_m4_m4m4(cmat, imat, ob_src->object_to_world); /* transform vertex coordinates into new space */ for (a = 0; a < me->totvert; a++, mvert++) { @@ -386,7 +386,7 @@ int ED_mesh_join_objects_exec(bContext *C, wmOperator *op) * NOTE: This doesn't apply recursive parenting. */ if (join_parent) { ob->parent = nullptr; - BKE_object_apply_mat4_ex(ob, ob->obmat, ob->parent, ob->parentinv, false); + BKE_object_apply_mat4_ex(ob, ob->object_to_world, ob->parent, ob->parentinv, false); } /* that way the active object is always selected */ @@ -594,7 +594,7 @@ int ED_mesh_join_objects_exec(bContext *C, wmOperator *op) /* Inverse transform for all selected meshes in this object, * See #object_join_exec for detailed comment on why the safe version is used. */ - invert_m4_m4_safe_ortho(imat, ob->obmat); + invert_m4_m4_safe_ortho(imat, ob->object_to_world); /* Add back active mesh first. * This allows to keep things similar as they were, as much as possible diff --git a/source/blender/editors/object/object_add.cc b/source/blender/editors/object/object_add.cc index 3ce39b695e0..6075e4250eb 100644 --- a/source/blender/editors/object/object_add.cc +++ b/source/blender/editors/object/object_add.cc @@ -322,7 +322,7 @@ void ED_object_base_init_transform_on_add(Object *object, const float loc[3], co copy_v3_v3(object->rot, rot); } - BKE_object_to_mat4(object, object->obmat); + BKE_object_to_mat4(object, object->object_to_world); } float ED_object_new_primitive_matrix(bContext *C, @@ -342,14 +342,14 @@ float ED_object_new_primitive_matrix(bContext *C, invert_m3(rmat); /* inverse transform for initial rotation and object */ - copy_m3_m4(mat, obedit->obmat); + copy_m3_m4(mat, obedit->object_to_world); mul_m3_m3m3(cmat, rmat, mat); invert_m3_m3(imat, cmat); copy_m4_m3(r_primmat, imat); /* center */ copy_v3_v3(r_primmat[3], loc); - sub_v3_v3v3(r_primmat[3], r_primmat[3], obedit->obmat[3]); + sub_v3_v3v3(r_primmat[3], r_primmat[3], obedit->object_to_world[3]); invert_m3_m3(imat, mat); mul_m3_v3(imat, r_primmat[3]); @@ -2084,7 +2084,7 @@ static int object_curves_empty_hair_add_exec(bContext *C, wmOperator *op) Object *curves_ob = ED_object_add_type( C, OB_CURVES, nullptr, nullptr, nullptr, false, local_view_bits); - BKE_object_apply_mat4(curves_ob, surface_ob->obmat, false, false); + BKE_object_apply_mat4(curves_ob, surface_ob->object_to_world, false, false); /* Set surface object. */ Curves *curves_id = static_cast<Curves *>(curves_ob->data); @@ -2561,8 +2561,8 @@ static void make_object_duplilist_real(bContext *C, id_us_min((ID *)ob_dst->instance_collection); ob_dst->instance_collection = nullptr; - copy_m4_m4(ob_dst->obmat, dob->mat); - BKE_object_apply_mat4(ob_dst, ob_dst->obmat, false, false); + copy_m4_m4(ob_dst->object_to_world, dob->mat); + BKE_object_apply_mat4(ob_dst, ob_dst->object_to_world, false, false); BLI_ghash_insert(dupli_gh, dob, ob_dst); if (parent_gh) { @@ -3017,7 +3017,7 @@ static int object_convert_exec(bContext *C, wmOperator *op) ushort local_view_bits = (v3d && v3d->localvd) ? v3d->local_view_uuid : 0; float loc[3], size[3], rot[3][3], eul[3]; float matrix[4][4]; - mat4_to_loc_rot_size(loc, rot, size, ob->obmat); + mat4_to_loc_rot_size(loc, rot, size, ob->object_to_world); mat3_to_eul(eul, rot); Object *ob_gpencil = ED_gpencil_add_object(C, loc, local_view_bits); @@ -3556,11 +3556,62 @@ void OBJECT_OT_convert(wmOperatorType *ot) /** \name Duplicate Object Operator * \{ */ +static void object_add_sync_base_collection( + Main *bmain, Scene *scene, ViewLayer *view_layer, Base *base_src, Object *object_new) +{ + if ((base_src != nullptr) && (base_src->flag & BASE_ENABLED_AND_MAYBE_VISIBLE_IN_VIEWPORT)) { + BKE_collection_object_add_from(bmain, scene, base_src->object, object_new); + } + else { + LayerCollection *layer_collection = BKE_layer_collection_get_active(view_layer); + BKE_collection_object_add(bmain, layer_collection->collection, object_new); + } +} + +static void object_add_sync_local_view(Base *base_src, Base *base_new) +{ + base_new->local_view_bits = base_src->local_view_bits; +} + +static void object_add_sync_rigid_body(Main *bmain, Object *object_src, Object *object_new) +{ + /* 1) duplis should end up in same collection as the original + * 2) Rigid Body sim participants MUST always be part of a collection... + */ + /* XXX: is 2) really a good measure here? */ + if (object_src->rigidbody_object || object_src->rigidbody_constraint) { + LISTBASE_FOREACH (Collection *, collection, &bmain->collections) { + if (BKE_collection_has_object(collection, object_src)) { + BKE_collection_object_add(bmain, collection, object_new); + } + } + } +} + /** * - Assumes `id.new` is correct. * - Leaves selection of base/object unaltered. * - Sets #ID.newid pointers. */ +static void object_add_duplicate_internal(Main *bmain, + Object *ob, + const eDupli_ID_Flags dupflag, + const eLibIDDuplicateFlags duplicate_options, + Object **r_ob_new) +{ + if (ob->mode & OB_MODE_POSE) { + return; + } + + Object *obn = static_cast<Object *>( + ID_NEW_SET(ob, BKE_object_duplicate(bmain, ob, dupflag, duplicate_options))); + if (r_ob_new) { + *r_ob_new = obn; + } + DEG_id_tag_update(&obn->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY); + return; +} + static Base *object_add_duplicate_internal(Main *bmain, Scene *scene, ViewLayer *view_layer, @@ -3569,49 +3620,25 @@ static Base *object_add_duplicate_internal(Main *bmain, const eLibIDDuplicateFlags duplicate_options, Object **r_ob_new) { - Base *base, *basen = nullptr; - Object *obn; - - if (ob->mode & OB_MODE_POSE) { - /* nothing? */ + Object *object_new = nullptr; + object_add_duplicate_internal(bmain, ob, dupflag, duplicate_options, &object_new); + if (r_ob_new) { + *r_ob_new = object_new; + } + if (object_new == nullptr) { + return nullptr; } - else { - obn = static_cast<Object *>( - ID_NEW_SET(ob, BKE_object_duplicate(bmain, ob, dupflag, duplicate_options))); - if (r_ob_new) { - *r_ob_new = obn; - } - DEG_id_tag_update(&obn->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY); - - BKE_view_layer_synced_ensure(scene, view_layer); - base = BKE_view_layer_base_find(view_layer, ob); - if ((base != nullptr) && (base->flag & BASE_ENABLED_AND_MAYBE_VISIBLE_IN_VIEWPORT)) { - BKE_collection_object_add_from(bmain, scene, ob, obn); - } - else { - LayerCollection *layer_collection = BKE_layer_collection_get_active(view_layer); - BKE_collection_object_add(bmain, layer_collection->collection, obn); - } - - BKE_view_layer_synced_ensure(scene, view_layer); - basen = BKE_view_layer_base_find(view_layer, obn); - if (base != nullptr && basen != nullptr) { - basen->local_view_bits = base->local_view_bits; - } - /* 1) duplis should end up in same collection as the original - * 2) Rigid Body sim participants MUST always be part of a collection... - */ - /* XXX: is 2) really a good measure here? */ - if (ob->rigidbody_object || ob->rigidbody_constraint) { - LISTBASE_FOREACH (Collection *, collection, &bmain->collections) { - if (BKE_collection_has_object(collection, ob)) { - BKE_collection_object_add(bmain, collection, obn); - } - } - } + BKE_view_layer_synced_ensure(scene, view_layer); + Base *base_src = BKE_view_layer_base_find(view_layer, ob); + object_add_sync_base_collection(bmain, scene, view_layer, base_src, object_new); + BKE_view_layer_synced_ensure(scene, view_layer); + Base *base_new = BKE_view_layer_base_find(view_layer, object_new); + if (base_src && base_new) { + object_add_sync_local_view(base_src, base_new); } - return basen; + object_add_sync_rigid_body(bmain, ob, object_new); + return base_new; } Base *ED_object_add_duplicate( @@ -3665,70 +3692,70 @@ static int duplicate_exec(bContext *C, wmOperator *op) * we also want to remap pointers between those... */ BKE_main_id_newptr_and_tag_clear(bmain); - /* Do not do collection re-syncs for each object; will do it once afterwards. - * However this means we can't get to new duplicated Base's immediately, will - * have to process them after the sync. */ - BKE_layer_collection_resync_forbid(); - /* Duplicate the selected objects, remember data needed to process - * after the sync (the base of the original object, and the copy of the - * original object). */ - blender::Vector<std::pair<Base *, Object *>> source_bases_new_objects; - Object *ob_new_active = nullptr; + * after the sync. */ + struct DuplicateObjectLink { + Base *base_src = nullptr; + Object *object_new = nullptr; + + DuplicateObjectLink(Base *base_src) : base_src(base_src) + { + } + }; + blender::Vector<DuplicateObjectLink> object_base_links; CTX_DATA_BEGIN (C, Base *, base, selected_bases) { - Object *ob_new = nullptr; + object_base_links.append(DuplicateObjectLink(base)); + } + CTX_DATA_END; + + bool new_objects_created = false; + for (DuplicateObjectLink &link : object_base_links) { object_add_duplicate_internal(bmain, - scene, - view_layer, - base->object, + link.base_src->object, dupflag, LIB_ID_DUPLICATE_IS_SUBPROCESS | LIB_ID_DUPLICATE_IS_ROOT_ID, - &ob_new); - if (ob_new == nullptr) { - continue; - } - source_bases_new_objects.append({base, ob_new}); - - /* note that this is safe to do with this context iterator, - * the list is made in advance */ - ED_object_base_select(base, BA_DESELECT); - - /* new object will become active */ - BKE_view_layer_synced_ensure(scene, view_layer); - if (BKE_view_layer_active_base_get(view_layer) == base) { - ob_new_active = ob_new; + &link.object_new); + if (link.object_new) { + new_objects_created = true; } } - CTX_DATA_END; - BKE_layer_collection_resync_allow(); - if (source_bases_new_objects.is_empty()) { + if (!new_objects_created) { return OPERATOR_CANCELLED; } - /* Sync the collection now, after everything is duplicated. */ - BKE_main_collection_sync(bmain); + /* Sync that could tag the view_layer out of sync. */ + for (DuplicateObjectLink &link : object_base_links) { + /* note that this is safe to do with this context iterator, + * the list is made in advance */ + ED_object_base_select(link.base_src, BA_DESELECT); + if (link.object_new) { + object_add_sync_base_collection(bmain, scene, view_layer, link.base_src, link.object_new); + object_add_sync_rigid_body(bmain, link.base_src->object, link.object_new); + } + } - /* After sync we can get to the new Base data, process it here. */ - for (const auto &item : source_bases_new_objects) { - Object *ob_new = item.second; - Base *base_source = item.first; - BKE_view_layer_synced_ensure(scene, view_layer); - Base *base_new = BKE_view_layer_base_find(view_layer, ob_new); - if (base_new == nullptr) { + /* Sync the view layer. Everything else should not tag the view_layer out of sync. */ + BKE_view_layer_synced_ensure(scene, view_layer); + const Base *active_base = BKE_view_layer_active_base_get(view_layer); + for (DuplicateObjectLink &link : object_base_links) { + if (!link.object_new) { continue; } + + Base *base_new = BKE_view_layer_base_find(view_layer, link.object_new); + BLI_assert(base_new); ED_object_base_select(base_new, BA_SELECT); - if (ob_new == ob_new_active) { + if (active_base == link.base_src) { ED_object_base_activate(C, base_new); } - if (base_new->object->data) { - DEG_id_tag_update(static_cast<ID *>(base_new->object->data), 0); + + if (link.object_new->data) { + DEG_id_tag_update(static_cast<ID *>(link.object_new->data), 0); } - /* #object_add_duplicate_internal will not have done this, since - * before the collection sync it would not have found the new base yet. */ - base_new->local_view_bits = base_source->local_view_bits; + + object_add_sync_local_view(link.base_src, base_new); } /* Note that this will also clear newid pointers and tags. */ @@ -3844,8 +3871,8 @@ static int object_add_named_exec(bContext *C, wmOperator *op) PropertyRNA *prop_matrix = RNA_struct_find_property(op->ptr, "matrix"); if (RNA_property_is_set(op->ptr, prop_matrix)) { Object *ob_add = basen->object; - RNA_property_float_get_array(op->ptr, prop_matrix, &ob_add->obmat[0][0]); - BKE_object_apply_mat4(ob_add, ob_add->obmat, true, true); + RNA_property_float_get_array(op->ptr, prop_matrix, &ob_add->object_to_world[0][0]); + BKE_object_apply_mat4(ob_add, ob_add->object_to_world, true, true); DEG_id_tag_update(&ob_add->id, ID_RECALC_TRANSFORM); } @@ -3942,7 +3969,7 @@ static int object_transform_to_mouse_exec(bContext *C, wmOperator *op) float mat_dst_unit[4][4]; float final_delta[4][4]; - normalize_m4_m4(mat_src_unit, ob->obmat); + normalize_m4_m4(mat_src_unit, ob->object_to_world); normalize_m4_m4(mat_dst_unit, matrix); invert_m4(mat_src_unit); mul_m4_m4m4(final_delta, mat_dst_unit, mat_src_unit); @@ -4097,7 +4124,7 @@ static int object_join_exec(bContext *C, wmOperator *op) * If the zero scale is removed, the data on this axis remains un-scaled * (something that wouldn't work for #invert_m4_m4_safe). */ float imat_test[4][4]; - if (!invert_m4_m4(imat_test, ob->obmat)) { + if (!invert_m4_m4(imat_test, ob->object_to_world)) { BKE_report(op->reports, RPT_WARNING, "Active object final transform has one or more zero scaled axes"); diff --git a/source/blender/editors/object/object_bake_api.c b/source/blender/editors/object/object_bake_api.c index 781866db6a0..d05badc8fee 100644 --- a/source/blender/editors/object/object_bake_api.c +++ b/source/blender/editors/object/object_bake_api.c @@ -1518,10 +1518,10 @@ static int bake(const BakeAPIRender *bkr, highpoly[i].me = BKE_mesh_new_from_object(NULL, highpoly[i].ob_eval, false, false); /* Low-poly to high-poly transformation matrix. */ - copy_m4_m4(highpoly[i].obmat, highpoly[i].ob->obmat); + copy_m4_m4(highpoly[i].obmat, highpoly[i].ob->object_to_world); invert_m4_m4(highpoly[i].imat, highpoly[i].obmat); - highpoly[i].is_flip_object = is_negative_m4(highpoly[i].ob->obmat); + highpoly[i].is_flip_object = is_negative_m4(highpoly[i].ob->object_to_world); i++; } @@ -1540,18 +1540,19 @@ static int bake(const BakeAPIRender *bkr, pixel_array_high = MEM_mallocN(sizeof(BakePixel) * targets.pixels_num, "bake pixels high poly"); - if (!RE_bake_pixels_populate_from_objects(me_low_eval, - pixel_array_low, - pixel_array_high, - highpoly, - tot_highpoly, - targets.pixels_num, - ob_cage != NULL, - bkr->cage_extrusion, - bkr->max_ray_distance, - ob_low_eval->obmat, - (ob_cage ? ob_cage->obmat : ob_low_eval->obmat), - me_cage_eval)) { + if (!RE_bake_pixels_populate_from_objects( + me_low_eval, + pixel_array_low, + pixel_array_high, + highpoly, + tot_highpoly, + targets.pixels_num, + ob_cage != NULL, + bkr->cage_extrusion, + bkr->max_ray_distance, + ob_low_eval->object_to_world, + (ob_cage ? ob_cage->object_to_world : ob_low_eval->object_to_world), + me_cage_eval)) { BKE_report(reports, RPT_ERROR, "Error handling selected objects"); goto cleanup; } @@ -1629,7 +1630,7 @@ static int bake(const BakeAPIRender *bkr, targets.result, me_low_eval, bkr->normal_swizzle, - ob_low_eval->obmat); + ob_low_eval->object_to_world); } else { /* From multi-resolution. */ @@ -1655,7 +1656,7 @@ static int bake(const BakeAPIRender *bkr, targets.result, (me_nores) ? me_nores : me_low_eval, bkr->normal_swizzle, - ob_low_eval->obmat); + ob_low_eval->object_to_world); if (md) { BKE_id_free(NULL, &me_nores->id); diff --git a/source/blender/editors/object/object_constraint.c b/source/blender/editors/object/object_constraint.c index fa9ded0f989..1386da5dbde 100644 --- a/source/blender/editors/object/object_constraint.c +++ b/source/blender/editors/object/object_constraint.c @@ -2327,14 +2327,14 @@ static bool get_new_constraint_target( /* Since by default, IK targets the tip of the last bone, * use the tip of the active PoseChannel if adding a target for an IK Constraint. */ if (con_type == CONSTRAINT_TYPE_KINEMATIC) { - mul_v3_m4v3(obt->loc, obact->obmat, pchanact->pose_tail); + mul_v3_m4v3(obt->loc, obact->object_to_world, pchanact->pose_tail); } else { - mul_v3_m4v3(obt->loc, obact->obmat, pchanact->pose_head); + mul_v3_m4v3(obt->loc, obact->object_to_world, pchanact->pose_head); } } else { - copy_v3_v3(obt->loc, obact->obmat[3]); + copy_v3_v3(obt->loc, obact->object_to_world[3]); } /* restore, BKE_object_add sets active */ diff --git a/source/blender/editors/object/object_hook.c b/source/blender/editors/object/object_hook.c index 27659042f50..63093692e43 100644 --- a/source/blender/editors/object/object_hook.c +++ b/source/blender/editors/object/object_hook.c @@ -535,7 +535,7 @@ static int add_hook_object(const bContext *C, ob = add_hook_object_new(bmain, scene, view_layer, v3d, obedit); /* transform cent to global coords for loc */ - mul_v3_m4v3(ob->loc, obedit->obmat, cent); + mul_v3_m4v3(ob->loc, obedit->object_to_world, cent); } md = obedit->modifiers.first; @@ -556,13 +556,13 @@ static int add_hook_object(const bContext *C, unit_m4(pose_mat); - invert_m4_m4(obedit->imat, obedit->obmat); + invert_m4_m4(obedit->imat, obedit->object_to_world); if (mode == OBJECT_ADDHOOK_NEWOB) { /* pass */ } else { /* may overwrite with pose-bone location, below */ - mul_v3_m4v3(cent, obedit->imat, ob->obmat[3]); + mul_v3_m4v3(cent, obedit->imat, ob->object_to_world[3]); } if (mode == OBJECT_ADDHOOK_SELOB_BONE) { @@ -576,7 +576,7 @@ static int add_hook_object(const bContext *C, pchan_act = BKE_pose_channel_active_if_layer_visible(ob); if (LIKELY(pchan_act)) { invert_m4_m4(pose_mat, pchan_act->pose_mat); - mul_v3_m4v3(cent, ob->obmat, pchan_act->pose_mat[3]); + mul_v3_m4v3(cent, ob->object_to_world, pchan_act->pose_mat[3]); mul_v3_m4v3(cent, obedit->imat, cent); } } @@ -588,16 +588,16 @@ static int add_hook_object(const bContext *C, copy_v3_v3(hmd->cent, cent); /* matrix calculus */ - /* vert x (obmat x hook->imat) x hook->obmat x ob->imat */ + /* vert x (obmat x hook->imat) x hook->object_to_world x ob->imat */ /* (parentinv ) */ Scene *scene_eval = DEG_get_evaluated_scene(depsgraph); Object *object_eval = DEG_get_evaluated_object(depsgraph, ob); BKE_object_transform_copy(object_eval, ob); BKE_object_where_is_calc(depsgraph, scene_eval, object_eval); - invert_m4_m4(object_eval->imat, object_eval->obmat); + invert_m4_m4(object_eval->imat, object_eval->object_to_world); /* apparently this call goes from right to left... */ - mul_m4_series(hmd->parentinv, pose_mat, object_eval->imat, obedit->obmat); + mul_m4_series(hmd->parentinv, pose_mat, object_eval->imat, obedit->object_to_world); DEG_relations_tag_update(bmain); @@ -834,10 +834,10 @@ static int object_hook_recenter_exec(bContext *C, wmOperator *op) } /* recenter functionality */ - copy_m3_m4(bmat, ob->obmat); + copy_m3_m4(bmat, ob->object_to_world); invert_m3_m3(imat, bmat); - sub_v3_v3v3(hmd->cent, scene->cursor.location, ob->obmat[3]); + sub_v3_v3v3(hmd->cent, scene->cursor.location, ob->object_to_world[3]); mul_m3_v3(imat, hmd->cent); DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); diff --git a/source/blender/editors/object/object_modifier.cc b/source/blender/editors/object/object_modifier.cc index c7995809438..85a35861329 100644 --- a/source/blender/editors/object/object_modifier.cc +++ b/source/blender/editors/object/object_modifier.cc @@ -218,7 +218,7 @@ ModifierData *ED_object_modifier_add( if (ob->mode & OB_MODE_SCULPT) { /* ensure that grid paint mask layer is created */ - BKE_sculpt_mask_layers_ensure(ob, (MultiresModifierData *)new_md); + BKE_sculpt_mask_layers_ensure(nullptr, nullptr, ob, (MultiresModifierData *)new_md); } } else if (type == eModifierType_Skin) { @@ -2041,7 +2041,8 @@ static int multires_subdivide_exec(bContext *C, wmOperator *op) if (object->mode & OB_MODE_SCULPT) { /* ensure that grid paint mask layer is created */ - BKE_sculpt_mask_layers_ensure(object, mmd); + BKE_sculpt_mask_layers_ensure( + CTX_data_ensure_evaluated_depsgraph(C), CTX_data_main(C), object, mmd); } return OPERATOR_FINISHED; diff --git a/source/blender/editors/object/object_relations.c b/source/blender/editors/object/object_relations.c index 5da19d76259..10068def991 100644 --- a/source/blender/editors/object/object_relations.c +++ b/source/blender/editors/object/object_relations.c @@ -272,7 +272,7 @@ static int vertex_parent_set_exec(bContext *C, wmOperator *op) /* inverse parent matrix */ BKE_object_workob_calc_parent(depsgraph, scene, ob, &workob); - invert_m4_m4(ob->parentinv, workob.obmat); + invert_m4_m4(ob->parentinv, workob.object_to_world); } else { ob->partype = PARVERT1; @@ -280,7 +280,7 @@ static int vertex_parent_set_exec(bContext *C, wmOperator *op) /* inverse parent matrix */ BKE_object_workob_calc_parent(depsgraph, scene, ob, &workob); - invert_m4_m4(ob->parentinv, workob.obmat); + invert_m4_m4(ob->parentinv, workob.object_to_world); } } } @@ -401,7 +401,7 @@ void ED_object_parent_clear(Object *ob, const int type) /* remove parent, and apply the parented transform * result as object's local transforms */ ob->parent = NULL; - BKE_object_apply_mat4(ob, ob->obmat, true, false); + BKE_object_apply_mat4(ob, ob->object_to_world, true, false); break; } case CLEAR_PARENT_INVERSE: { @@ -584,7 +584,7 @@ bool ED_object_parent_set(ReportList *reports, if (keep_transform) { /* Was removed because of bug T23577, * but this can be handy in some cases too T32616, so make optional. */ - BKE_object_apply_mat4(ob, ob->obmat, false, false); + BKE_object_apply_mat4(ob, ob->object_to_world, false, false); } /* Set the parent (except for follow-path constraint option). */ @@ -706,7 +706,7 @@ bool ED_object_parent_set(ReportList *reports, BKE_constraint_target_matrix_get( depsgraph, scene, con, 0, CONSTRAINT_OBTYPE_OBJECT, NULL, cmat, scene->r.cfra); - sub_v3_v3v3(vec, ob->obmat[3], cmat[3]); + sub_v3_v3v3(vec, ob->object_to_world[3], cmat[3]); copy_v3_v3(ob->loc, vec); } @@ -729,7 +729,7 @@ bool ED_object_parent_set(ReportList *reports, ob->partype = PAROBJECT; BKE_object_workob_calc_parent(depsgraph, scene, ob, &workob); - invert_m4_m4(ob->parentinv, workob.obmat); + invert_m4_m4(ob->parentinv, workob.object_to_world); } else if (is_armature_parent && (ob->type == OB_GPENCIL) && (par->type == OB_ARMATURE)) { if (partype == PAR_ARMATURE) { @@ -747,7 +747,7 @@ bool ED_object_parent_set(ReportList *reports, ob->partype = PAROBJECT; BKE_object_workob_calc_parent(depsgraph, scene, ob, &workob); - invert_m4_m4(ob->parentinv, workob.obmat); + invert_m4_m4(ob->parentinv, workob.object_to_world); } else if ((ob->type == OB_GPENCIL) && (par->type == OB_LATTICE)) { /* Add Lattice modifier */ @@ -758,12 +758,12 @@ bool ED_object_parent_set(ReportList *reports, ob->partype = PAROBJECT; BKE_object_workob_calc_parent(depsgraph, scene, ob, &workob); - invert_m4_m4(ob->parentinv, workob.obmat); + invert_m4_m4(ob->parentinv, workob.object_to_world); } else { /* calculate inverse parent matrix */ BKE_object_workob_calc_parent(depsgraph, scene, ob, &workob); - invert_m4_m4(ob->parentinv, workob.obmat); + invert_m4_m4(ob->parentinv, workob.object_to_world); } DEG_id_tag_update(&ob->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY); @@ -772,7 +772,7 @@ bool ED_object_parent_set(ReportList *reports, static void parent_set_vert_find(KDTree_3d *tree, Object *child, int vert_par[3], bool is_tri) { - const float *co_find = child->obmat[3]; + const float *co_find = child->object_to_world[3]; if (is_tri) { KDTreeNearest_3d nearest[3]; int tot; @@ -1186,7 +1186,7 @@ static int object_track_clear_exec(bContext *C, wmOperator *op) } if (type == CLEAR_TRACK_KEEP_TRANSFORM) { - BKE_object_apply_mat4(ob, ob->obmat, true, true); + BKE_object_apply_mat4(ob, ob->object_to_world, true, true); } } CTX_DATA_END; diff --git a/source/blender/editors/object/object_remesh.cc b/source/blender/editors/object/object_remesh.cc index 8358bf632d3..c653610d6fe 100644 --- a/source/blender/editors/object/object_remesh.cc +++ b/source/blender/editors/object/object_remesh.cc @@ -296,7 +296,7 @@ static void voxel_size_edit_draw(const bContext *C, ARegion * /*ar*/, void *arg) uint pos3d = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT); immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR); GPU_matrix_push(); - GPU_matrix_mul(cd->active_object->obmat); + GPU_matrix_mul(cd->active_object->object_to_world); /* Draw Rect */ immUniformColor4f(0.9f, 0.9f, 0.9f, 0.8f); @@ -494,7 +494,7 @@ static int voxel_size_edit_invoke(bContext *C, wmOperator *op, const wmEvent *ev float view_normal[3] = {0.0f, 0.0f, 1.0f}; /* Calculate the view normal. */ - invert_m4_m4(active_object->imat, active_object->obmat); + invert_m4_m4(active_object->imat, active_object->object_to_world); copy_m3_m4(mat, rv3d->viewinv); mul_m3_v3(mat, view_normal); copy_m3_m4(mat, active_object->imat); @@ -535,7 +535,7 @@ static int voxel_size_edit_invoke(bContext *C, wmOperator *op, const wmEvent *ev /* Project the selected face in the previous step of the Bounding Box. */ for (int i = 0; i < 4; i++) { float preview_plane_world_space[3]; - mul_v3_m4v3(preview_plane_world_space, active_object->obmat, cd->preview_plane[i]); + mul_v3_m4v3(preview_plane_world_space, active_object->object_to_world, cd->preview_plane[i]); ED_view3d_project_v2(region, preview_plane_world_space, preview_plane_proj[i]); } @@ -582,7 +582,7 @@ static int voxel_size_edit_invoke(bContext *C, wmOperator *op, const wmEvent *ev /* Invert object scale. */ float scale[3]; - mat4_to_size(scale, active_object->obmat); + mat4_to_size(scale, active_object->object_to_world); invert_v3(scale); size_to_mat4(scale_mat, scale); @@ -593,7 +593,7 @@ static int voxel_size_edit_invoke(bContext *C, wmOperator *op, const wmEvent *ev /* Scale the text to constant viewport size. */ float text_pos_word_space[3]; - mul_v3_m4v3(text_pos_word_space, active_object->obmat, text_pos); + mul_v3_m4v3(text_pos_word_space, active_object->object_to_world, text_pos); const float pixelsize = ED_view3d_pixel_size(rv3d, text_pos_word_space); scale_m4_fl(scale_mat, pixelsize * 0.5f); mul_m4_m4_post(cd->text_mat, scale_mat); diff --git a/source/blender/editors/object/object_transform.cc b/source/blender/editors/object/object_transform.cc index 6604e3da4d2..a863e9ac324 100644 --- a/source/blender/editors/object/object_transform.cc +++ b/source/blender/editors/object/object_transform.cc @@ -527,9 +527,9 @@ static void ignore_parent_tx(Main *bmain, Depsgraph *depsgraph, Scene *scene, Ob LISTBASE_FOREACH (Object *, ob_child, &bmain->objects) { if (ob_child->parent == ob) { Object *ob_child_eval = DEG_get_evaluated_object(depsgraph, ob_child); - BKE_object_apply_mat4(ob_child_eval, ob_child_eval->obmat, true, false); + BKE_object_apply_mat4(ob_child_eval, ob_child_eval->object_to_world, true, false); BKE_object_workob_calc_parent(depsgraph, scene, ob_child_eval, &workob); - invert_m4_m4(ob_child->parentinv, workob.obmat); + invert_m4_m4(ob_child->parentinv, workob.object_to_world); /* Copy result of BKE_object_apply_mat4(). */ BKE_object_transform_copy(ob_child, ob_child_eval); /* Make sure evaluated object is in a consistent state with the original one. @@ -660,11 +660,11 @@ static int apply_objects_internal(bContext *C, if (do_multi_user) { obact = CTX_data_active_object(C); - invert_m4_m4(obact_invmat, obact->obmat); + invert_m4_m4(obact_invmat, obact->object_to_world); Object workob; BKE_object_workob_calc_parent(depsgraph, scene, obact, &workob); - copy_m4_m4(obact_parent, workob.obmat); + copy_m4_m4(obact_parent, workob.object_to_world); copy_m4_m4(obact_parentinv, obact->parentinv); if (apply_objects_internal_need_single_user(C)) { @@ -989,7 +989,7 @@ static int apply_objects_internal(bContext *C, float _obmat[4][4], _iobmat[4][4]; float _mat[4][4]; - copy_m4_m4(_obmat, ob->obmat); + copy_m4_m4(_obmat, ob->object_to_world); invert_m4_m4(_iobmat, _obmat); copy_m4_m4(_mat, _obmat); @@ -1075,7 +1075,7 @@ static int visual_transform_apply_exec(bContext *C, wmOperator * /*op*/) CTX_DATA_BEGIN (C, Object *, ob, selected_editable_objects) { Object *ob_eval = DEG_get_evaluated_object(depsgraph, ob); BKE_object_where_is_calc(depsgraph, scene, ob_eval); - BKE_object_apply_mat4(ob_eval, ob_eval->obmat, true, true); + BKE_object_apply_mat4(ob_eval, ob_eval->object_to_world, true, true); BKE_object_transform_copy(ob, ob_eval); /* update for any children that may get moved */ @@ -1274,7 +1274,7 @@ static int object_origin_set_exec(bContext *C, wmOperator *op) if (centermode == ORIGIN_TO_CURSOR) { copy_v3_v3(cent, cursor); - invert_m4_m4(obedit->imat, obedit->obmat); + invert_m4_m4(obedit->imat, obedit->object_to_world); mul_m4_v3(obedit->imat, cent); } else { @@ -1342,7 +1342,7 @@ static int object_origin_set_exec(bContext *C, wmOperator *op) if (centermode == ORIGIN_TO_CURSOR) { copy_v3_v3(cent, cursor); - invert_m4_m4(ob->imat, ob->obmat); + invert_m4_m4(ob->imat, ob->object_to_world); mul_m4_v3(ob->imat, cent); } @@ -1363,7 +1363,7 @@ static int object_origin_set_exec(bContext *C, wmOperator *op) INIT_MINMAX(min, max); BKE_object_minmax_dupli(depsgraph, scene, ob, min, max, true); mid_v3_v3v3(cent, min, max); - invert_m4_m4(ob->imat, ob->obmat); + invert_m4_m4(ob->imat, ob->object_to_world); mul_m4_v3(ob->imat, cent); } @@ -1554,7 +1554,7 @@ static int object_origin_set_exec(bContext *C, wmOperator *op) if (centermode == ORIGIN_TO_GEOMETRY) { zero_v3(gpcenter); BKE_gpencil_centroid_3d(gpd, gpcenter); - add_v3_v3(gpcenter, ob->obmat[3]); + add_v3_v3(gpcenter, ob->object_to_world[3]); } if (centermode == ORIGIN_TO_CURSOR) { copy_v3_v3(gpcenter, cursor); @@ -1566,8 +1566,8 @@ static int object_origin_set_exec(bContext *C, wmOperator *op) float offset_local[3]; int i; - sub_v3_v3v3(offset_global, gpcenter, ob->obmat[3]); - copy_m3_m4(bmat, obact->obmat); + sub_v3_v3v3(offset_global, gpcenter, ob->object_to_world[3]); + copy_m3_m4(bmat, obact->object_to_world); invert_m3_m3(imat, bmat); mul_m3_v3(imat, offset_global); mul_v3_m3v3(offset_local, imat, offset_global); @@ -1699,7 +1699,7 @@ static int object_origin_set_exec(bContext *C, wmOperator *op) ob_other->flag |= OB_DONE; DEG_id_tag_update(&ob_other->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY); - mul_v3_mat3_m4v3(centn, ob_other->obmat, cent); /* omit translation part */ + mul_v3_mat3_m4v3(centn, ob_other->object_to_world, cent); /* omit translation part */ add_v3_v3(ob_other->loc, centn); Object *ob_other_eval = DEG_get_evaluated_object(depsgraph, ob_other); @@ -1873,9 +1873,9 @@ static void object_transform_axis_target_calc_depth_init(XFormAxisData *xfd, con int center_tot = 0; for (XFormAxisItem &item : xfd->object_data) { const Object *ob = item.ob; - const float *ob_co_a = ob->obmat[3]; + const float *ob_co_a = ob->object_to_world[3]; float ob_co_b[3]; - add_v3_v3v3(ob_co_b, ob->obmat[3], ob->obmat[2]); + add_v3_v3v3(ob_co_b, ob->object_to_world[3], ob->object_to_world[2]); float view_isect[3], ob_isect[3]; if (isect_line_line_v3(view_co_a, view_co_b, ob_co_a, ob_co_b, view_isect, ob_isect)) { add_v3_v3(center, view_isect); @@ -1946,7 +1946,7 @@ static void object_apply_location(Object *ob, const float loc[3]) /* quick but weak */ Object ob_prev = blender::dna::shallow_copy(*ob); float mat[4][4]; - copy_m4_m4(mat, ob->obmat); + copy_m4_m4(mat, ob->object_to_world); copy_v3_v3(mat[3], loc); BKE_object_apply_mat4(ob, mat, true, true); copy_v3_v3(mat[3], ob->loc); @@ -1961,7 +1961,7 @@ static bool object_orient_to_location(Object *ob, const bool z_flip) { float delta[3]; - sub_v3_v3v3(delta, ob->obmat[3], location); + sub_v3_v3v3(delta, ob->object_to_world[3], location); if (normalize_v3(delta) != 0.0f) { if (z_flip) { negate_v3(delta); @@ -2139,7 +2139,7 @@ static int object_transform_axis_target_modal(bContext *C, wmOperator *op, const float xform_rot_offset_inv_first[3][3]; for (const int i : xfd->object_data.index_range()) { XFormAxisItem &item = xfd->object_data[i]; - copy_m3_m4(item.xform_rot_offset, item.ob->obmat); + copy_m3_m4(item.xform_rot_offset, item.ob->object_to_world); normalize_m3(item.xform_rot_offset); if (i == 0) { @@ -2158,8 +2158,8 @@ static int object_transform_axis_target_modal(bContext *C, wmOperator *op, const XFormAxisItem &item = xfd->object_data[i]; if (is_translate_init) { float ob_axis[3]; - item.xform_dist = len_v3v3(item.ob->obmat[3], location_world); - normalize_v3_v3(ob_axis, item.ob->obmat[2]); + item.xform_dist = len_v3v3(item.ob->object_to_world[3], location_world); + normalize_v3_v3(ob_axis, item.ob->object_to_world[2]); /* Scale to avoid adding distance when moving between surfaces. */ if (normal_found) { float scale = fabsf(dot_v3v3(ob_axis, normal)); @@ -2173,7 +2173,7 @@ static int object_transform_axis_target_modal(bContext *C, wmOperator *op, const copy_v3_v3(target_normal, normal); } else { - normalize_v3_v3(target_normal, item.ob->obmat[2]); + normalize_v3_v3(target_normal, item.ob->object_to_world[2]); } #ifdef USE_RELATIVE_ROTATION @@ -2190,7 +2190,7 @@ static int object_transform_axis_target_modal(bContext *C, wmOperator *op, const madd_v3_v3fl(loc, target_normal, item.xform_dist); object_apply_location(item.ob, loc); /* so orient behaves as expected */ - copy_v3_v3(item.ob->obmat[3], loc); + copy_v3_v3(item.ob->object_to_world[3], loc); } object_orient_to_location( diff --git a/source/blender/editors/object/object_utils.c b/source/blender/editors/object/object_utils.c index 50ba5b8af5f..1387282357f 100644 --- a/source/blender/editors/object/object_utils.c +++ b/source/blender/editors/object/object_utils.c @@ -114,20 +114,20 @@ bool ED_object_calc_active_center(Object *ob, const bool select_only, float r_ce { if (ob->mode & OB_MODE_EDIT) { if (ED_object_calc_active_center_for_editmode(ob, select_only, r_center)) { - mul_m4_v3(ob->obmat, r_center); + mul_m4_v3(ob->object_to_world, r_center); return true; } return false; } if (ob->mode & OB_MODE_POSE) { if (ED_object_calc_active_center_for_posemode(ob, select_only, r_center)) { - mul_m4_v3(ob->obmat, r_center); + mul_m4_v3(ob->object_to_world, r_center); return true; } return false; } if (!select_only || (ob->base_flag & BASE_SELECTED)) { - copy_v3_v3(r_center, ob->obmat[3]); + copy_v3_v3(r_center, ob->object_to_world[3]); return true; } return false; @@ -245,11 +245,11 @@ void ED_object_xform_skip_child_container_item_ensure(struct XFormObjectSkipChil if (!BLI_ghash_ensure_p(xcs->obchild_in_obmode_map, ob, &xf_p)) { struct XFormObjectSkipChild *xf = MEM_mallocN(sizeof(*xf), __func__); copy_m4_m4(xf->parentinv_orig, ob->parentinv); - copy_m4_m4(xf->obmat_orig, ob->obmat); - copy_m4_m4(xf->parent_obmat_orig, ob->parent->obmat); - invert_m4_m4(xf->parent_obmat_inv_orig, ob->parent->obmat); + copy_m4_m4(xf->obmat_orig, ob->object_to_world); + copy_m4_m4(xf->parent_obmat_orig, ob->parent->object_to_world); + invert_m4_m4(xf->parent_obmat_inv_orig, ob->parent->object_to_world); if (ob_parent_recurse) { - copy_m4_m4(xf->parent_recurse_obmat_orig, ob_parent_recurse->obmat); + copy_m4_m4(xf->parent_recurse_obmat_orig, ob_parent_recurse->object_to_world); } xf->mode = mode; xf->ob_parent_recurse = ob_parent_recurse; @@ -274,14 +274,14 @@ void ED_object_xform_skip_child_container_update_all(struct XFormObjectSkipChild if (xf->mode == XFORM_OB_SKIP_CHILD_PARENT_IS_XFORM) { /* Parent is transformed, this isn't so compensate. */ Object *ob_parent_eval = DEG_get_evaluated_object(depsgraph, ob->parent); - mul_m4_m4m4(dmat, xf->parent_obmat_inv_orig, ob_parent_eval->obmat); + mul_m4_m4m4(dmat, xf->parent_obmat_inv_orig, ob_parent_eval->object_to_world); invert_m4(dmat); } else if (xf->mode == XFORM_OB_SKIP_CHILD_PARENT_IS_XFORM_INDIRECT) { /* Calculate parent matrix (from the root transform). */ Object *ob_parent_recurse_eval = DEG_get_evaluated_object(depsgraph, xf->ob_parent_recurse); float parent_recurse_obmat_inv[4][4]; - invert_m4_m4(parent_recurse_obmat_inv, ob_parent_recurse_eval->obmat); + invert_m4_m4(parent_recurse_obmat_inv, ob_parent_recurse_eval->object_to_world); mul_m4_m4m4(dmat, xf->parent_recurse_obmat_orig, parent_recurse_obmat_inv); invert_m4(dmat); float parent_obmat_calc[4][4]; @@ -296,7 +296,7 @@ void ED_object_xform_skip_child_container_update_all(struct XFormObjectSkipChild /* Transform this - without transform data. */ Object *ob_parent_recurse_eval = DEG_get_evaluated_object(depsgraph, xf->ob_parent_recurse); float parent_recurse_obmat_inv[4][4]; - invert_m4_m4(parent_recurse_obmat_inv, ob_parent_recurse_eval->obmat); + invert_m4_m4(parent_recurse_obmat_inv, ob_parent_recurse_eval->object_to_world); mul_m4_m4m4(dmat, xf->parent_recurse_obmat_orig, parent_recurse_obmat_inv); invert_m4(dmat); float obmat_calc[4][4]; @@ -350,7 +350,7 @@ void ED_object_data_xform_container_item_ensure(struct XFormObjectData_Container void **xf_p; if (!BLI_ghash_ensure_p(xds->obdata_in_obmode_map, ob->data, &xf_p)) { struct XFormObjectData_Extra *xf = MEM_mallocN(sizeof(*xf), __func__); - copy_m4_m4(xf->obmat_orig, ob->obmat); + copy_m4_m4(xf->obmat_orig, ob->object_to_world); xf->ob = ob; /* Result may be NULL, that's OK. */ xf->xod = ED_object_data_xform_create(ob->data); @@ -378,7 +378,7 @@ void ED_object_data_xform_container_update_all(struct XFormObjectData_Container Object *ob_eval = DEG_get_evaluated_object(depsgraph, xf->ob); float imat[4][4], dmat[4][4]; invert_m4_m4(imat, xf->obmat_orig); - mul_m4_m4m4(dmat, imat, ob_eval->obmat); + mul_m4_m4m4(dmat, imat, ob_eval->object_to_world); invert_m4(dmat); ED_object_data_xform_by_mat4(xf->xod, dmat); diff --git a/source/blender/editors/object/object_warp.c b/source/blender/editors/object/object_warp.c index a1d53cadd06..d1e6e7000d9 100644 --- a/source/blender/editors/object/object_warp.c +++ b/source/blender/editors/object/object_warp.c @@ -38,7 +38,7 @@ static void object_warp_calc_view_matrix(float r_mat_view[4][4], mul_m4_m4m4(viewmat_roll, mat_offset, viewmat); /* apply the view and the object matrix */ - mul_m4_m4m4(r_mat_view, viewmat_roll, obedit->obmat); + mul_m4_m4m4(r_mat_view, viewmat_roll, obedit->object_to_world); /* get the view-space cursor */ mul_v3_m4v3(r_center_view, viewmat_roll, center); diff --git a/source/blender/editors/physics/dynamicpaint_ops.c b/source/blender/editors/physics/dynamicpaint_ops.c index 1ce90849a88..41238eb171b 100644 --- a/source/blender/editors/physics/dynamicpaint_ops.c +++ b/source/blender/editors/physics/dynamicpaint_ops.c @@ -405,7 +405,7 @@ static void dynamicPaint_bakeImageSequence(DynamicPaintBakeJob *job) /* primary output layer */ if (surface->flags & MOD_DPAINT_OUT1) { /* set filepath */ - BLI_join_dirfile( + BLI_path_join( filepath, sizeof(filepath), surface->image_output_path, surface->output_name); BLI_path_frame(filepath, frame, 4); @@ -415,7 +415,7 @@ static void dynamicPaint_bakeImageSequence(DynamicPaintBakeJob *job) /* secondary output */ if (surface->flags & MOD_DPAINT_OUT2 && surface->type == MOD_DPAINT_SURFACE_T_PAINT) { /* set filepath */ - BLI_join_dirfile( + BLI_path_join( filepath, sizeof(filepath), surface->image_output_path, surface->output_name2); BLI_path_frame(filepath, frame, 4); diff --git a/source/blender/editors/physics/particle_edit.c b/source/blender/editors/physics/particle_edit.c index e6d0aca7902..6dc3860fdf2 100644 --- a/source/blender/editors/physics/particle_edit.c +++ b/source/blender/editors/physics/particle_edit.c @@ -3930,7 +3930,7 @@ static void brush_puff(PEData *data, int point_index, float mouse_distance) copy_v3_v3(co_root, co); copy_v3_v3(no_root, &edit->emitter_cosnos[point_index * 6 + 3]); - mul_mat3_m4_v3(data->ob->obmat, no_root); /* normal into global-space */ + mul_mat3_m4_v3(data->ob->object_to_world, no_root); /* normal into global-space */ normalize_v3(no_root); if (puff_volume) { @@ -4016,8 +4016,8 @@ static void brush_puff(PEData *data, int point_index, float mouse_distance) 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 world-space. */ - mul_mat3_m4_v3(imat, onor); /* World-space into particle-space. */ + mul_mat3_m4_v3(data->ob->object_to_world, onor); /* Normal into world-space. */ + mul_mat3_m4_v3(imat, onor); /* World-space into particle-space. */ normalize_v3(onor); } else { @@ -4412,7 +4412,7 @@ static int brush_add(const bContext *C, PEData *data, short number) short size = pset->brush[PE_BRUSH_ADD].size; RNG *rng; - invert_m4_m4(imat, ob->obmat); + invert_m4_m4(imat, ob->object_to_world); if (psys->flag & PSYS_GLOBAL_HAIR) { return 0; @@ -4797,7 +4797,7 @@ static void brush_edit_apply(bContext *C, wmOperator *op, PointerRNA *itemptr) data.combfac = 1.0f - data.combfac; } - invert_m4_m4(ob->imat, ob->obmat); + invert_m4_m4(ob->imat, ob->object_to_world); ED_view3d_win_to_delta(region, xy_delta, bedit->zfac, vec); data.dvec = vec; @@ -4865,7 +4865,7 @@ static void brush_edit_apply(bContext *C, wmOperator *op, PointerRNA *itemptr) } data.invert = (brush->invert ^ flip); - invert_m4_m4(ob->imat, ob->obmat); + invert_m4_m4(ob->imat, ob->object_to_world); foreach_mouse_hit_point(&data, brush_puff, selected); } @@ -4895,7 +4895,7 @@ static void brush_edit_apply(bContext *C, wmOperator *op, PointerRNA *itemptr) data.smoothfac = brush->strength; - invert_m4_m4(ob->imat, ob->obmat); + invert_m4_m4(ob->imat, ob->object_to_world); foreach_mouse_hit_key(&data, brush_smooth_get, selected); diff --git a/source/blender/editors/physics/particle_object.c b/source/blender/editors/physics/particle_object.c index 71ed32caede..852156f9403 100644 --- a/source/blender/editors/physics/particle_object.c +++ b/source/blender/editors/physics/particle_object.c @@ -726,8 +726,8 @@ static bool remap_hair_emitter(Depsgraph *depsgraph, edit_point = target_edit ? target_edit->points : NULL; - invert_m4_m4(from_ob_imat, ob->obmat); - invert_m4_m4(to_ob_imat, target_ob->obmat); + invert_m4_m4(from_ob_imat, ob->object_to_world); + invert_m4_m4(to_ob_imat, target_ob->object_to_world); invert_m4_m4(from_imat, from_mat); invert_m4_m4(to_imat, to_mat); @@ -843,7 +843,7 @@ static bool remap_hair_emitter(Depsgraph *depsgraph, float offset[3]; if (to_global) { - copy_m4_m4(imat, target_ob->obmat); + copy_m4_m4(imat, target_ob->object_to_world); } else { /* NOTE: using target_dm here, which is in target_ob object space and has full modifiers. @@ -923,8 +923,8 @@ static bool connect_hair(Depsgraph *depsgraph, Scene *scene, Object *ob, Particl ob, psys, psys->edit, - ob->obmat, - ob->obmat, + ob->object_to_world, + ob->object_to_world, psys->flag & PSYS_GLOBAL_HAIR, false); if (ok) { @@ -1174,8 +1174,8 @@ static bool copy_particle_systems_to_object(const bContext *C, to_mat = I; break; case PAR_COPY_SPACE_WORLD: - from_mat = ob_from->obmat; - to_mat = ob_to->obmat; + from_mat = ob_from->object_to_world; + to_mat = ob_to->object_to_world; break; default: /* should not happen */ @@ -1204,9 +1204,7 @@ static bool copy_particle_systems_to_object(const bContext *C, #undef PSYS_FROM_FIRST #undef PSYS_FROM_NEXT - if (duplicate_settings) { - DEG_relations_tag_update(bmain); - } + DEG_relations_tag_update(bmain); DEG_id_tag_update(&ob_to->id, ID_RECALC_GEOMETRY); WM_main_add_notifier(NC_OBJECT | ND_PARTICLE | NA_EDITED, ob_to); return true; @@ -1269,8 +1267,7 @@ static int copy_particle_systems_exec(bContext *C, wmOperator *op) CTX_DATA_END; if (changed_tot > 0) { - Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C); - DEG_graph_tag_relations_update(depsgraph); + DEG_relations_tag_update(CTX_data_main(C)); } if ((changed_tot == 0 && fail == 0) || fail) { diff --git a/source/blender/editors/physics/physics_fluid.c b/source/blender/editors/physics/physics_fluid.c index 07e8f5c5743..314796e96e4 100644 --- a/source/blender/editors/physics/physics_fluid.c +++ b/source/blender/editors/physics/physics_fluid.c @@ -368,7 +368,7 @@ static void fluid_bake_startjob(void *customdata, short *stop, short *do_update, BKE_spacedata_draw_locks(true); if (fluid_is_bake_noise(job) || fluid_is_bake_all(job)) { - BLI_path_join(temp_dir, sizeof(temp_dir), fds->cache_directory, FLUID_DOMAIN_DIR_NOISE, NULL); + BLI_path_join(temp_dir, sizeof(temp_dir), fds->cache_directory, FLUID_DOMAIN_DIR_NOISE); BLI_path_abs(temp_dir, relbase); BLI_dir_create_recursive(temp_dir); /* Create 'noise' subdir if it does not exist already */ fds->cache_flag &= ~(FLUID_DOMAIN_BAKED_NOISE | FLUID_DOMAIN_OUTDATED_NOISE); @@ -376,7 +376,7 @@ static void fluid_bake_startjob(void *customdata, short *stop, short *do_update, job->pause_frame = &fds->cache_frame_pause_noise; } if (fluid_is_bake_mesh(job) || fluid_is_bake_all(job)) { - BLI_path_join(temp_dir, sizeof(temp_dir), fds->cache_directory, FLUID_DOMAIN_DIR_MESH, NULL); + BLI_path_join(temp_dir, sizeof(temp_dir), fds->cache_directory, FLUID_DOMAIN_DIR_MESH); BLI_path_abs(temp_dir, relbase); BLI_dir_create_recursive(temp_dir); /* Create 'mesh' subdir if it does not exist already */ fds->cache_flag &= ~(FLUID_DOMAIN_BAKED_MESH | FLUID_DOMAIN_OUTDATED_MESH); @@ -384,8 +384,7 @@ static void fluid_bake_startjob(void *customdata, short *stop, short *do_update, job->pause_frame = &fds->cache_frame_pause_mesh; } if (fluid_is_bake_particle(job) || fluid_is_bake_all(job)) { - BLI_path_join( - temp_dir, sizeof(temp_dir), fds->cache_directory, FLUID_DOMAIN_DIR_PARTICLES, NULL); + BLI_path_join(temp_dir, sizeof(temp_dir), fds->cache_directory, FLUID_DOMAIN_DIR_PARTICLES); BLI_path_abs(temp_dir, relbase); /* Create 'particles' subdir if it does not exist already */ @@ -396,7 +395,7 @@ static void fluid_bake_startjob(void *customdata, short *stop, short *do_update, job->pause_frame = &fds->cache_frame_pause_particles; } if (fluid_is_bake_guiding(job) || fluid_is_bake_all(job)) { - BLI_path_join(temp_dir, sizeof(temp_dir), fds->cache_directory, FLUID_DOMAIN_DIR_GUIDE, NULL); + BLI_path_join(temp_dir, sizeof(temp_dir), fds->cache_directory, FLUID_DOMAIN_DIR_GUIDE); BLI_path_abs(temp_dir, relbase); BLI_dir_create_recursive(temp_dir); /* Create 'guiding' subdir if it does not exist already */ fds->cache_flag &= ~(FLUID_DOMAIN_BAKED_GUIDE | FLUID_DOMAIN_OUTDATED_GUIDE); @@ -404,11 +403,11 @@ static void fluid_bake_startjob(void *customdata, short *stop, short *do_update, job->pause_frame = &fds->cache_frame_pause_guide; } if (fluid_is_bake_data(job) || fluid_is_bake_all(job)) { - BLI_path_join(temp_dir, sizeof(temp_dir), fds->cache_directory, FLUID_DOMAIN_DIR_CONFIG, NULL); + BLI_path_join(temp_dir, sizeof(temp_dir), fds->cache_directory, FLUID_DOMAIN_DIR_CONFIG); BLI_path_abs(temp_dir, relbase); BLI_dir_create_recursive(temp_dir); /* Create 'config' subdir if it does not exist already */ - BLI_path_join(temp_dir, sizeof(temp_dir), fds->cache_directory, FLUID_DOMAIN_DIR_DATA, NULL); + BLI_path_join(temp_dir, sizeof(temp_dir), fds->cache_directory, FLUID_DOMAIN_DIR_DATA); BLI_path_abs(temp_dir, relbase); BLI_dir_create_recursive(temp_dir); /* Create 'data' subdir if it does not exist already */ fds->cache_flag &= ~(FLUID_DOMAIN_BAKED_DATA | FLUID_DOMAIN_OUTDATED_DATA); @@ -416,8 +415,7 @@ static void fluid_bake_startjob(void *customdata, short *stop, short *do_update, job->pause_frame = &fds->cache_frame_pause_data; if (fds->flags & FLUID_DOMAIN_EXPORT_MANTA_SCRIPT) { - BLI_path_join( - temp_dir, sizeof(temp_dir), fds->cache_directory, FLUID_DOMAIN_DIR_SCRIPT, NULL); + BLI_path_join(temp_dir, sizeof(temp_dir), fds->cache_directory, FLUID_DOMAIN_DIR_SCRIPT); BLI_path_abs(temp_dir, relbase); BLI_dir_create_recursive(temp_dir); /* Create 'script' subdir if it does not exist already */ } diff --git a/source/blender/editors/render/render_preview.cc b/source/blender/editors/render/render_preview.cc index ad24f46f923..5aae48b1138 100644 --- a/source/blender/editors/render/render_preview.cc +++ b/source/blender/editors/render/render_preview.cc @@ -785,7 +785,7 @@ static Object *object_preview_camera_create(Main *preview_main, float rotmat[3][3]; float dummyscale[3]; - mat4_to_loc_rot_size(camera->loc, rotmat, dummyscale, preview_object->obmat); + mat4_to_loc_rot_size(camera->loc, rotmat, dummyscale, preview_object->object_to_world); /* Camera is Y up, so needs additional rotations to obliquely face the front. */ float drotmat[3][3]; @@ -1325,7 +1325,7 @@ static ImBuf *icon_preview_imbuf_from_brush(Brush *brush) const char *brushicons_dir = BKE_appdir_folder_id(BLENDER_DATAFILES, "brushicons"); /* Expected to be found, but don't crash if it's not. */ if (brushicons_dir) { - BLI_join_dirfile(filepath, sizeof(filepath), brushicons_dir, brush->icon_filepath); + BLI_path_join(filepath, sizeof(filepath), brushicons_dir, brush->icon_filepath); /* Use default color spaces. */ brush->icon_imbuf = IMB_loadiffname(filepath, flags, nullptr); diff --git a/source/blender/editors/screen/area.c b/source/blender/editors/screen/area.c index 39e3c7a2f0a..a62e027ba03 100644 --- a/source/blender/editors/screen/area.c +++ b/source/blender/editors/screen/area.c @@ -147,7 +147,7 @@ void ED_region_do_listen(wmRegionListenerParams *params) } LISTBASE_FOREACH (uiBlock *, block, ®ion->uiblocks) { - UI_block_views_listen(block, params); + UI_block_listen(block, params); } LISTBASE_FOREACH (uiList *, list, ®ion->ui_lists) { @@ -187,7 +187,8 @@ static void area_draw_azone_fullscreen( min_ff(alpha, 0.75f), 0.0f, NULL, - false); + false, + UI_NO_ICON_OVERLAY_TEXT); } /** diff --git a/source/blender/editors/screen/workspace_edit.c b/source/blender/editors/screen/workspace_edit.c index 9a6bdc98d76..8cf11583b3a 100644 --- a/source/blender/editors/screen/workspace_edit.c +++ b/source/blender/editors/screen/workspace_edit.c @@ -405,7 +405,7 @@ static WorkspaceConfigFileData *workspace_config_file_read(const char *app_templ char startup_file_path[FILE_MAX] = {0}; if (cfgdir) { - BLI_join_dirfile(startup_file_path, sizeof(startup_file_path), cfgdir, BLENDER_STARTUP_FILE); + BLI_path_join(startup_file_path, sizeof(startup_file_path), cfgdir, BLENDER_STARTUP_FILE); } bool has_path = BLI_exists(startup_file_path); @@ -425,8 +425,7 @@ static WorkspaceConfigFileData *workspace_system_file_read(const char *app_templ } char startup_file_path[FILE_MAX]; - BLI_join_dirfile( - startup_file_path, sizeof(startup_file_path), template_dir, BLENDER_STARTUP_FILE); + BLI_path_join(startup_file_path, sizeof(startup_file_path), template_dir, BLENDER_STARTUP_FILE); bool has_path = BLI_exists(startup_file_path); return (has_path) ? BKE_blendfile_workspace_config_read(startup_file_path, NULL, 0, NULL) : NULL; diff --git a/source/blender/editors/sculpt_paint/curves_sculpt_brush.cc b/source/blender/editors/sculpt_paint/curves_sculpt_brush.cc index e276bae6697..8172eb8a5d7 100644 --- a/source/blender/editors/sculpt_paint/curves_sculpt_brush.cc +++ b/source/blender/editors/sculpt_paint/curves_sculpt_brush.cc @@ -185,7 +185,7 @@ std::optional<CurvesBrush3D> sample_curves_3d_brush(const Depsgraph &depsgraph, /* Shorten ray when the surface object is hit. */ if (surface_object_eval != nullptr) { - const float4x4 surface_to_world_mat = surface_object->obmat; + const float4x4 surface_to_world_mat = surface_object->object_to_world; const float4x4 world_to_surface_mat = surface_to_world_mat.inverted(); Mesh *surface_eval = BKE_object_get_evaluated_mesh(surface_object_eval); @@ -218,7 +218,7 @@ std::optional<CurvesBrush3D> sample_curves_3d_brush(const Depsgraph &depsgraph, } } - const float4x4 curves_to_world_mat = curves_object.obmat; + const float4x4 curves_to_world_mat = curves_object.object_to_world; const float4x4 world_to_curves_mat = curves_to_world_mat.inverted(); const float3 center_ray_start_cu = world_to_curves_mat * center_ray_start_wo; diff --git a/source/blender/editors/sculpt_paint/curves_sculpt_ops.cc b/source/blender/editors/sculpt_paint/curves_sculpt_ops.cc index 6366da310b6..df7dd871a94 100644 --- a/source/blender/editors/sculpt_paint/curves_sculpt_ops.cc +++ b/source/blender/editors/sculpt_paint/curves_sculpt_ops.cc @@ -220,8 +220,10 @@ static int sculpt_curves_stroke_invoke(bContext *C, wmOperator *op, const wmEven int return_value = op->type->modal(C, op, event); if (return_value == OPERATOR_FINISHED) { - paint_stroke_free(C, op, op_data->stroke); - MEM_delete(op_data); + if (op->customdata != nullptr) { + paint_stroke_free(C, op, op_data->stroke); + MEM_delete(op_data); + } return OPERATOR_FINISHED; } @@ -236,16 +238,19 @@ static int sculpt_curves_stroke_modal(bContext *C, wmOperator *op, const wmEvent int return_value = paint_stroke_modal(C, op, event, &op_data->stroke); if (ELEM(return_value, OPERATOR_FINISHED, OPERATOR_CANCELLED)) { MEM_delete(op_data); + op->customdata = nullptr; } return return_value; } static void sculpt_curves_stroke_cancel(bContext *C, wmOperator *op) { - SculptCurvesBrushStrokeData *op_data = static_cast<SculptCurvesBrushStrokeData *>( - op->customdata); - paint_stroke_cancel(C, op, op_data->stroke); - MEM_delete(op_data); + if (op->customdata != nullptr) { + SculptCurvesBrushStrokeData *op_data = static_cast<SculptCurvesBrushStrokeData *>( + op->customdata); + paint_stroke_cancel(C, op, op_data->stroke); + MEM_delete(op_data); + } } static void SCULPT_CURVES_OT_brush_stroke(struct wmOperatorType *ot) @@ -786,7 +791,7 @@ static void select_grow_invoke_per_curve(Curves &curves_id, }); }); - float4x4 curves_to_world_mat = curves_ob.obmat; + float4x4 curves_to_world_mat = curves_ob.object_to_world; float4x4 world_to_curves_mat = curves_to_world_mat.inverted(); float4x4 projection; diff --git a/source/blender/editors/sculpt_paint/paint_cursor.c b/source/blender/editors/sculpt_paint/paint_cursor.c index 71ec444098e..b85b878af7d 100644 --- a/source/blender/editors/sculpt_paint/paint_cursor.c +++ b/source/blender/editors/sculpt_paint/paint_cursor.c @@ -1071,7 +1071,7 @@ static void cursor_draw_tiling_preview(const uint gpuattr, for (int dim = 0; dim < 3; dim++) { location[dim] = cur[dim] * step[dim] + orgLoc[dim]; } - cursor_draw_point_screen_space(gpuattr, region, location, ob->obmat, 3); + cursor_draw_point_screen_space(gpuattr, region, location, ob->object_to_world, 3); } } } @@ -1092,7 +1092,7 @@ static void cursor_draw_point_with_symmetry(const uint gpuattr, /* Axis Symmetry. */ flip_v3_v3(location, true_location, (char)i); - cursor_draw_point_screen_space(gpuattr, region, location, ob->obmat, 3); + cursor_draw_point_screen_space(gpuattr, region, location, ob->object_to_world, 3); /* Tiling. */ cursor_draw_tiling_preview(gpuattr, region, location, sd, ob, radius); @@ -1107,7 +1107,7 @@ static void cursor_draw_point_with_symmetry(const uint gpuattr, mul_m4_v3(symm_rot_mat, location); cursor_draw_tiling_preview(gpuattr, region, location, sd, ob, radius); - cursor_draw_point_screen_space(gpuattr, region, location, ob->obmat, 3); + cursor_draw_point_screen_space(gpuattr, region, location, ob->object_to_world, 3); } } } @@ -1334,7 +1334,7 @@ static void paint_cursor_update_pixel_radius(PaintCursorContext *pcontext) } copy_v3_v3(pcontext->scene_space_location, pcontext->location); - mul_m4_v3(pcontext->vc.obact->obmat, pcontext->scene_space_location); + mul_m4_v3(pcontext->vc.obact->object_to_world, pcontext->scene_space_location); } else { Sculpt *sd = CTX_data_tool_settings(pcontext->C)->sculpt; @@ -1464,7 +1464,7 @@ static void paint_cursor_drawing_setup_cursor_space(PaintCursorContext *pcontext float cursor_trans[4][4], cursor_rot[4][4]; const float z_axis[4] = {0.0f, 0.0f, 1.0f, 0.0f}; float quat[4]; - copy_m4_m4(cursor_trans, pcontext->vc.obact->obmat); + copy_m4_m4(cursor_trans, pcontext->vc.obact->object_to_world); translate_m4(cursor_trans, pcontext->location[0], pcontext->location[1], pcontext->location[2]); rotation_between_vecs_to_quat(quat, z_axis, pcontext->normal); quat_to_mat4(cursor_rot, quat); @@ -1508,7 +1508,7 @@ static void paint_cursor_pose_brush_origins_draw(PaintCursorContext *pcontext) cursor_draw_point_screen_space(pcontext->pos, pcontext->region, ss->pose_ik_chain_preview->segments[i].initial_orig, - pcontext->vc.obact->obmat, + pcontext->vc.obact->object_to_world, 3); } } @@ -1526,7 +1526,7 @@ static void paint_cursor_preview_boundary_data_pivot_draw(PaintCursorContext *pc pcontext->pos, pcontext->region, SCULPT_vertex_co_get(pcontext->ss, pcontext->ss->boundary_preview->pivot_vertex), - pcontext->vc.obact->obmat, + pcontext->vc.obact->object_to_world, 3); } @@ -1634,7 +1634,7 @@ static void paint_cursor_draw_3d_view_brush_cursor_inactive(PaintCursorContext * pcontext->pos, pcontext->region, SCULPT_vertex_co_get(pcontext->ss, pcontext->ss->expand_cache->initial_active_vertex), - pcontext->vc.obact->obmat, + pcontext->vc.obact->object_to_world, 2); } @@ -1656,7 +1656,7 @@ static void paint_cursor_draw_3d_view_brush_cursor_inactive(PaintCursorContext * NULL); GPU_matrix_push(); - GPU_matrix_mul(pcontext->vc.obact->obmat); + GPU_matrix_mul(pcontext->vc.obact->object_to_world); /* Drawing Cursor overlays in 3D object space. */ if (is_brush_tool && brush->sculpt_tool == SCULPT_TOOL_GRAB && @@ -1747,7 +1747,7 @@ static void paint_cursor_cursor_draw_3d_view_brush_cursor_active(PaintCursorCont NULL, NULL); GPU_matrix_push(); - GPU_matrix_mul(pcontext->vc.obact->obmat); + GPU_matrix_mul(pcontext->vc.obact->object_to_world); /* Draw the special active cursors different tools may have. */ diff --git a/source/blender/editors/sculpt_paint/paint_curve.c b/source/blender/editors/sculpt_paint/paint_curve.c index 22d6626ab16..26f76d46f85 100644 --- a/source/blender/editors/sculpt_paint/paint_curve.c +++ b/source/blender/editors/sculpt_paint/paint_curve.c @@ -44,7 +44,7 @@ bool paint_curve_poll(bContext *C) RegionView3D *rv3d = CTX_wm_region_view3d(C); SpaceImage *sima; - if (rv3d && !(ob && ((ob->mode & OB_MODE_ALL_PAINT) != 0))) { + if (rv3d && !(ob && ((ob->mode & (OB_MODE_ALL_PAINT | OB_MODE_SCULPT_CURVES)) != 0))) { return false; } @@ -676,6 +676,9 @@ static int paintcurve_draw_exec(bContext *C, wmOperator *UNUSED(op)) case PAINT_MODE_SCULPT: name = "SCULPT_OT_brush_stroke"; break; + case PAINT_MODE_SCULPT_CURVES: + name = "SCULPT_CURVES_OT_brush_stroke"; + break; default: return OPERATOR_PASS_THROUGH; } diff --git a/source/blender/editors/sculpt_paint/paint_image_2d.c b/source/blender/editors/sculpt_paint/paint_image_2d.c index 79316361e53..b7ce4b2973c 100644 --- a/source/blender/editors/sculpt_paint/paint_image_2d.c +++ b/source/blender/editors/sculpt_paint/paint_image_2d.c @@ -402,7 +402,8 @@ static ImBuf *brush_painter_imbuf_new( if (is_texbrush) { brush_imbuf_tex_co(&tex_mapping, x, y, texco); - BKE_brush_sample_tex_3d(scene, brush, texco, rgba, thread, pool); + const MTex *mtex = &brush->mtex; + BKE_brush_sample_tex_3d(scene, brush, mtex, texco, rgba, thread, pool); /* TODO(sergey): Support texture paint color space. */ if (!use_float) { IMB_colormanagement_scene_linear_to_display_v3(rgba, display); @@ -446,6 +447,7 @@ static void brush_painter_imbuf_update(BrushPainter *painter, { Scene *scene = painter->scene; Brush *brush = painter->brush; + const MTex *mtex = &brush->mtex; BrushPainterCache *cache = &tile->cache; const char *display_device = scene->display_settings.display_device; @@ -485,7 +487,7 @@ static void brush_painter_imbuf_update(BrushPainter *painter, if (!use_texture_old) { if (is_texbrush) { brush_imbuf_tex_co(&tex_mapping, x, y, texco); - BKE_brush_sample_tex_3d(scene, brush, texco, rgba, thread, pool); + BKE_brush_sample_tex_3d(scene, brush, mtex, texco, rgba, thread, pool); /* TODO(sergey): Support texture paint color space. */ if (!use_float) { IMB_colormanagement_scene_linear_to_display_v3(rgba, display); diff --git a/source/blender/editors/sculpt_paint/paint_image_proj.c b/source/blender/editors/sculpt_paint/paint_image_proj.c index 41d5090b38c..ea33449f0dd 100644 --- a/source/blender/editors/sculpt_paint/paint_image_proj.c +++ b/source/blender/editors/sculpt_paint/paint_image_proj.c @@ -3684,7 +3684,7 @@ static void proj_paint_state_viewport_init(ProjPaintState *ps, const char symmet ps->viewDir[1] = 0.0f; ps->viewDir[2] = 1.0f; - copy_m4_m4(ps->obmat, ps->ob->obmat); + copy_m4_m4(ps->obmat, ps->ob->object_to_world); if (symmetry_flag) { int i; @@ -3742,7 +3742,7 @@ static void proj_paint_state_viewport_init(ProjPaintState *ps, const char symmet CameraParams params; /* viewmat & viewinv */ - copy_m4_m4(viewinv, cam_ob_eval->obmat); + copy_m4_m4(viewinv, cam_ob_eval->object_to_world); normalize_m4(viewinv); invert_m4_m4(viewmat, viewinv); @@ -4462,7 +4462,7 @@ static void project_paint_begin(const bContext *C, if (ps->source == PROJ_SRC_VIEW) { /* faster clipping lookups */ - ED_view3d_clipping_local(ps->rv3d, ps->ob->obmat); + ED_view3d_clipping_local(ps->rv3d, ps->ob->object_to_world); } ps->do_face_sel = ((((Mesh *)ps->ob->data)->editflag & ME_EDIT_PAINT_FACE_SEL) != 0); @@ -5370,7 +5370,7 @@ static void do_projectpaint_thread(TaskPool *__restrict UNUSED(pool), void *ph_v /* Color texture (alpha used as mask). */ if (ps->is_texbrush) { - MTex *mtex = &brush->mtex; + const MTex *mtex = BKE_brush_color_texture_get(brush, OB_MODE_TEXTURE_PAINT); float samplecos[3]; float texrgba[4]; @@ -5386,7 +5386,8 @@ static void do_projectpaint_thread(TaskPool *__restrict UNUSED(pool), void *ph_v /* NOTE: for clone and smear, * we only use the alpha, could be a special function */ - BKE_brush_sample_tex_3d(ps->scene, brush, samplecos, texrgba, thread_index, pool); + BKE_brush_sample_tex_3d( + ps->scene, brush, mtex, samplecos, texrgba, thread_index, pool); copy_v3_v3(texrgb, texrgba); custom_mask *= texrgba[3]; diff --git a/source/blender/editors/sculpt_paint/paint_mask.c b/source/blender/editors/sculpt_paint/paint_mask.c index e1fd731a4b7..c3e3109ac87 100644 --- a/source/blender/editors/sculpt_paint/paint_mask.c +++ b/source/blender/editors/sculpt_paint/paint_mask.c @@ -31,6 +31,7 @@ #include "BKE_multires.h" #include "BKE_paint.h" #include "BKE_pbvh.h" +#include "BKE_scene.h" #include "BKE_subsurf.h" #include "DEG_depsgraph.h" @@ -146,7 +147,7 @@ static int mask_flood_fill_exec(bContext *C, wmOperator *op) value = RNA_float_get(op->ptr, "value"); MultiresModifierData *mmd = BKE_sculpt_multires_active(scene, ob); - BKE_sculpt_mask_layers_ensure(ob, mmd); + BKE_sculpt_mask_layers_ensure(depsgraph, CTX_data_main(C), ob, mmd); BKE_sculpt_update_object_for_edit(depsgraph, ob, false, true, false); pbvh = ob->sculpt->pbvh; @@ -861,7 +862,9 @@ static void sculpt_gesture_mask_end(bContext *C, SculptGestureContext *sgcontext BKE_pbvh_update_vertex_data(sgcontext->ss->pbvh, PBVH_UpdateMask); } -static void sculpt_gesture_init_mask_properties(SculptGestureContext *sgcontext, wmOperator *op) +static void sculpt_gesture_init_mask_properties(bContext *C, + SculptGestureContext *sgcontext, + wmOperator *op) { sgcontext->operation = MEM_callocN(sizeof(SculptGestureMaskOperation), "Mask Operation"); @@ -869,7 +872,8 @@ static void sculpt_gesture_init_mask_properties(SculptGestureContext *sgcontext, Object *object = sgcontext->vc.obact; MultiresModifierData *mmd = BKE_sculpt_multires_active(sgcontext->vc.scene, object); - BKE_sculpt_mask_layers_ensure(sgcontext->vc.obact, mmd); + BKE_sculpt_mask_layers_ensure( + CTX_data_depsgraph_pointer(C), CTX_data_main(C), sgcontext->vc.obact, mmd); mask_operation->op.sculpt_gesture_begin = sculpt_gesture_mask_begin; mask_operation->op.sculpt_gesture_apply_for_symmetry_pass = @@ -1005,11 +1009,12 @@ static void sculpt_gesture_trim_shape_origin_normal_get(SculptGestureContext *sg copy_v3_v3(r_normal, sgcontext->world_space_view_normal); break; case SCULPT_GESTURE_TRIM_ORIENTATION_SURFACE: - mul_v3_m4v3(r_origin, sgcontext->vc.obact->obmat, sgcontext->ss->gesture_initial_location); + mul_v3_m4v3( + r_origin, sgcontext->vc.obact->object_to_world, sgcontext->ss->gesture_initial_location); /* Transforming the normal does not take non uniform scaling into account. Sculpt mode is not * expected to work on object with non uniform scaling. */ copy_v3_v3(r_normal, sgcontext->ss->gesture_initial_normal); - mul_mat3_m4_v3(sgcontext->vc.obact->obmat, r_normal); + mul_mat3_m4_v3(sgcontext->vc.obact->object_to_world, r_normal); break; } } @@ -1040,7 +1045,7 @@ static void sculpt_gesture_trim_calculate_depth(SculptGestureContext *sgcontext) * mesh, coordinates are first calculated in world space, then converted to object space to * store them. */ float world_space_vco[3]; - mul_v3_m4v3(world_space_vco, vc->obact->obmat, vco); + mul_v3_m4v3(world_space_vco, vc->obact->object_to_world, vco); const float dist = dist_signed_to_plane_v3(world_space_vco, shape_plane); trim_operation->depth_front = min_ff(dist, trim_operation->depth_front); trim_operation->depth_back = max_ff(dist, trim_operation->depth_back); @@ -1048,8 +1053,9 @@ static void sculpt_gesture_trim_calculate_depth(SculptGestureContext *sgcontext) if (trim_operation->use_cursor_depth) { float world_space_gesture_initial_location[3]; - mul_v3_m4v3( - world_space_gesture_initial_location, vc->obact->obmat, ss->gesture_initial_location); + mul_v3_m4v3(world_space_gesture_initial_location, + vc->obact->object_to_world, + ss->gesture_initial_location); float mid_point_depth; if (trim_operation->orientation == SCULPT_GESTURE_TRIM_ORIENTATION_VIEW) { @@ -1514,7 +1520,7 @@ static int paint_mask_gesture_box_exec(bContext *C, wmOperator *op) if (!sgcontext) { return OPERATOR_CANCELLED; } - sculpt_gesture_init_mask_properties(sgcontext, op); + sculpt_gesture_init_mask_properties(C, sgcontext, op); sculpt_gesture_apply(C, sgcontext, op); sculpt_gesture_context_free(sgcontext); return OPERATOR_FINISHED; @@ -1526,7 +1532,7 @@ static int paint_mask_gesture_lasso_exec(bContext *C, wmOperator *op) if (!sgcontext) { return OPERATOR_CANCELLED; } - sculpt_gesture_init_mask_properties(sgcontext, op); + sculpt_gesture_init_mask_properties(C, sgcontext, op); sculpt_gesture_apply(C, sgcontext, op); sculpt_gesture_context_free(sgcontext); return OPERATOR_FINISHED; @@ -1538,7 +1544,7 @@ static int paint_mask_gesture_line_exec(bContext *C, wmOperator *op) if (!sgcontext) { return OPERATOR_CANCELLED; } - sculpt_gesture_init_mask_properties(sgcontext, op); + sculpt_gesture_init_mask_properties(C, sgcontext, op); sculpt_gesture_apply(C, sgcontext, op); sculpt_gesture_context_free(sgcontext); return OPERATOR_FINISHED; diff --git a/source/blender/editors/sculpt_paint/paint_stroke.c b/source/blender/editors/sculpt_paint/paint_stroke.c index bc4c6dc4148..a70924b0626 100644 --- a/source/blender/editors/sculpt_paint/paint_stroke.c +++ b/source/blender/editors/sculpt_paint/paint_stroke.c @@ -564,7 +564,7 @@ static void paint_brush_stroke_add_step( if (SCULPT_stroke_get_location( C, world_space_position, stroke->last_mouse_position, stroke->original)) { copy_v3_v3(stroke->last_world_space_position, world_space_position); - mul_m4_v3(stroke->vc.obact->obmat, stroke->last_world_space_position); + mul_m4_v3(stroke->vc.obact->object_to_world, stroke->last_world_space_position); } else { add_v3_v3(stroke->last_world_space_position, stroke->last_scene_spacing_delta); @@ -825,7 +825,7 @@ static int paint_space_stroke(bContext *C, if (use_scene_spacing) { float world_space_position[3]; bool hit = SCULPT_stroke_get_location(C, world_space_position, final_mouse, stroke->original); - mul_m4_v3(stroke->vc.obact->obmat, world_space_position); + mul_m4_v3(stroke->vc.obact->object_to_world, world_space_position); if (hit && stroke->stroke_over_mesh) { sub_v3_v3v3(d_world_space_position, world_space_position, stroke->last_world_space_position); length = len_v3(d_world_space_position); @@ -1216,8 +1216,8 @@ static void paint_line_strokes_spacing(bContext *C, C, world_space_position_old, old_pos, stroke->original); bool hit_new = SCULPT_stroke_get_location( C, world_space_position_new, new_pos, stroke->original); - mul_m4_v3(stroke->vc.obact->obmat, world_space_position_old); - mul_m4_v3(stroke->vc.obact->obmat, world_space_position_new); + mul_m4_v3(stroke->vc.obact->object_to_world, world_space_position_old); + mul_m4_v3(stroke->vc.obact->object_to_world, world_space_position_new); if (hit_old && hit_new && stroke->stroke_over_mesh) { sub_v3_v3v3(d_world_space_position, world_space_position_new, world_space_position_old); length = len_v3(d_world_space_position); @@ -1360,7 +1360,7 @@ static bool paint_stroke_curve_end(bContext *C, wmOperator *op, PaintStroke *str if (paint_stroke_use_scene_spacing(br, BKE_paintmode_get_active_from_context(C))) { stroke->stroke_over_mesh = SCULPT_stroke_get_location( C, stroke->last_world_space_position, data + 2 * j, stroke->original); - mul_m4_v3(stroke->vc.obact->obmat, stroke->last_world_space_position); + mul_m4_v3(stroke->vc.obact->object_to_world, stroke->last_world_space_position); } stroke->stroke_started = stroke->test_start(C, op, stroke->last_mouse_position); @@ -1492,7 +1492,7 @@ int paint_stroke_modal(bContext *C, wmOperator *op, const wmEvent *event, PaintS if (paint_stroke_use_scene_spacing(br, mode)) { stroke->stroke_over_mesh = SCULPT_stroke_get_location( C, stroke->last_world_space_position, sample_average.mouse, stroke->original); - mul_m4_v3(stroke->vc.obact->obmat, stroke->last_world_space_position); + mul_m4_v3(stroke->vc.obact->object_to_world, stroke->last_world_space_position); } stroke->stroke_started = stroke->test_start(C, op, sample_average.mouse); BLI_assert((stroke->stroke_started & ~1) == 0); /* 0/1 */ diff --git a/source/blender/editors/sculpt_paint/paint_utils.c b/source/blender/editors/sculpt_paint/paint_utils.c index ce4a5151a20..f87ca073c82 100644 --- a/source/blender/editors/sculpt_paint/paint_utils.c +++ b/source/blender/editors/sculpt_paint/paint_utils.c @@ -135,12 +135,12 @@ float paint_calc_object_space_radius(ViewContext *vc, const float center[3], flo float delta[3], scale, loc[3]; const float xy_delta[2] = {pixel_radius, 0.0f}; - mul_v3_m4v3(loc, ob->obmat, center); + mul_v3_m4v3(loc, ob->object_to_world, center); const float zfac = ED_view3d_calc_zfac(vc->rv3d, loc); ED_view3d_win_to_delta(vc->region, xy_delta, zfac, delta); - scale = fabsf(mat4_to_scale(ob->obmat)); + scale = fabsf(mat4_to_scale(ob->object_to_world)); scale = (scale == 0.0f) ? 1.0f : scale; return len_v3(delta) / scale; @@ -297,7 +297,7 @@ static void imapaint_pick_uv( GPU_matrix_model_view_get(matrix); GPU_matrix_projection_get(proj); view[0] = view[1] = 0; - mul_m4_m4m4(matrix, matrix, ob_eval->obmat); + mul_m4_m4m4(matrix, matrix, ob_eval->object_to_world); mul_m4_m4m4(matrix, proj, matrix); minabsw = 1e10; diff --git a/source/blender/editors/sculpt_paint/paint_vertex.cc b/source/blender/editors/sculpt_paint/paint_vertex.cc index 6e3504332ed..ac5ad62c91f 100644 --- a/source/blender/editors/sculpt_paint/paint_vertex.cc +++ b/source/blender/editors/sculpt_paint/paint_vertex.cc @@ -433,9 +433,10 @@ static void paint_and_tex_color_alpha_intern(VPaint *vp, float r_rgba[4]) { const Brush *brush = BKE_paint_brush(&vp->paint); - BLI_assert(brush->mtex.tex != nullptr); - if (brush->mtex.brush_map_mode == MTEX_MAP_MODE_3D) { - BKE_brush_sample_tex_3d(vc->scene, brush, co, r_rgba, 0, nullptr); + const MTex *mtex = BKE_brush_mask_texture_get(brush, OB_MODE_SCULPT); + BLI_assert(mtex->tex != nullptr); + if (mtex->brush_map_mode == MTEX_MAP_MODE_3D) { + BKE_brush_sample_tex_3d(vc->scene, brush, mtex, co, r_rgba, 0, nullptr); } else { float co_ss[2]; /* screenspace */ @@ -445,7 +446,7 @@ static void paint_and_tex_color_alpha_intern(VPaint *vp, co_ss, (eV3DProjTest)(V3D_PROJ_TEST_CLIP_BB | V3D_PROJ_TEST_CLIP_NEAR)) == V3D_PROJ_RET_OK) { const float co_ss_3d[3] = {co_ss[0], co_ss[1], 0.0f}; /* we need a 3rd empty value */ - BKE_brush_sample_tex_3d(vc->scene, brush, co_ss_3d, r_rgba, 0, nullptr); + BKE_brush_sample_tex_3d(vc->scene, brush, mtex, co_ss_3d, r_rgba, 0, nullptr); } else { zero_v4(r_rgba); @@ -1646,7 +1647,7 @@ static void vwpaint_update_cache_invariants( /* cache projection matrix */ ED_view3d_ob_project_mat_get(cache->vc->rv3d, ob, cache->projection_mat); - invert_m4_m4(ob->imat, ob->obmat); + invert_m4_m4(ob->imat, ob->object_to_world); copy_m3_m4(mat, cache->vc->rv3d->viewinv); mul_m3_v3(mat, view_dir); copy_m3_m4(mat, ob->imat); @@ -2517,7 +2518,7 @@ static void wpaint_stroke_update_step(bContext *C, ED_view3d_init_mats_rv3d(ob, vc->rv3d); /* load projection matrix */ - mul_m4_m4m4(mat, vc->rv3d->persmat, ob->obmat); + mul_m4_m4m4(mat, vc->rv3d->persmat, ob->object_to_world); Mesh *mesh = static_cast<Mesh *>(ob->data); @@ -2555,7 +2556,7 @@ static void wpaint_stroke_update_step(bContext *C, /* Calculate pivot for rotation around selection if needed. * also needed for "Frame Selected" on last stroke. */ float loc_world[3]; - mul_v3_m4v3(loc_world, ob->obmat, ss->cache->true_location); + mul_v3_m4v3(loc_world, ob->object_to_world, ss->cache->true_location); paint_last_stroke_update(scene, loc_world); BKE_mesh_batch_cache_dirty_tag(mesh, BKE_MESH_BATCH_DIRTY_ALL); @@ -3846,7 +3847,7 @@ static void vpaint_stroke_update_step_intern(bContext *C, PaintStroke *stroke, P ED_view3d_init_mats_rv3d(ob, vc->rv3d); /* load projection matrix */ - mul_m4_m4m4(mat, vc->rv3d->persmat, ob->obmat); + mul_m4_m4m4(mat, vc->rv3d->persmat, ob->object_to_world); swap_m4m4(vc->rv3d->persmat, mat); @@ -3869,7 +3870,7 @@ static void vpaint_stroke_update_step_intern(bContext *C, PaintStroke *stroke, P /* Calculate pivot for rotation around selection if needed. * also needed for "Frame Selected" on last stroke. */ float loc_world[3]; - mul_v3_m4v3(loc_world, ob->obmat, ss->cache->true_location); + mul_v3_m4v3(loc_world, ob->object_to_world, ss->cache->true_location); paint_last_stroke_update(scene, loc_world); ED_region_tag_redraw(vc->region); diff --git a/source/blender/editors/sculpt_paint/sculpt.c b/source/blender/editors/sculpt_paint/sculpt.c index c46fd019725..24c6f1b0c3d 100644 --- a/source/blender/editors/sculpt_paint/sculpt.c +++ b/source/blender/editors/sculpt_paint/sculpt.c @@ -41,6 +41,7 @@ #include "BKE_paint.h" #include "BKE_pbvh.h" #include "BKE_report.h" +#include "BKE_scene.h" #include "BKE_subdiv_ccg.h" #include "BKE_subsurf.h" @@ -1120,8 +1121,8 @@ void SCULPT_tag_update_overlays(bContext *C) DEG_id_tag_update(&ob->id, ID_RECALC_SHADING); - View3D *v3d = CTX_wm_view3d(C); - if (!BKE_sculptsession_use_pbvh_draw(ob, v3d)) { + RegionView3D *rv3d = CTX_wm_region_view3d(C); + if (!BKE_sculptsession_use_pbvh_draw(ob, rv3d)) { DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); } } @@ -2457,7 +2458,7 @@ float SCULPT_brush_strength_factor(SculptSession *ss, { StrokeCache *cache = ss->cache; const Scene *scene = cache->vc->scene; - const MTex *mtex = &br->mtex; + const MTex *mtex = BKE_brush_mask_texture_get(br, OB_MODE_SCULPT); float avg = 1.0f; float rgba[4]; float point[3]; @@ -2469,7 +2470,7 @@ float SCULPT_brush_strength_factor(SculptSession *ss, } else if (mtex->brush_map_mode == MTEX_MAP_MODE_3D) { /* Get strength by feeding the vertex location directly into a texture. */ - avg = BKE_brush_sample_tex_3d(scene, br, point, rgba, 0, ss->tex_pool); + avg = BKE_brush_sample_tex_3d(scene, br, mtex, point, rgba, 0, ss->tex_pool); } else { float symm_point[3], point_2d[2]; @@ -2498,19 +2499,19 @@ float SCULPT_brush_strength_factor(SculptSession *ss, x = symm_point[0]; y = symm_point[1]; - x *= br->mtex.size[0]; - y *= br->mtex.size[1]; + x *= mtex->size[0]; + y *= mtex->size[1]; - x += br->mtex.ofs[0]; - y += br->mtex.ofs[1]; + x += mtex->ofs[0]; + y += mtex->ofs[1]; - avg = paint_get_tex_pixel(&br->mtex, x, y, ss->tex_pool, thread_id); + avg = paint_get_tex_pixel(mtex, x, y, ss->tex_pool, thread_id); avg += br->texture_sample_bias; } else { const float point_3d[3] = {point_2d[0], point_2d[1], 0.0f}; - avg = BKE_brush_sample_tex_3d(scene, br, point_3d, rgba, 0, ss->tex_pool); + avg = BKE_brush_sample_tex_3d(scene, br, mtex, point_3d, rgba, 0, ss->tex_pool); } } @@ -2792,7 +2793,7 @@ static void calc_brush_local_mat(const Brush *brush, Object *ob, float local_mat float up[3]; /* Ensure `ob->imat` is up to date. */ - invert_m4_m4(ob->imat, ob->obmat); + invert_m4_m4(ob->imat, ob->object_to_world); /* Initialize last column of matrix. */ mat[0][3] = 0.0f; @@ -2832,7 +2833,7 @@ void SCULPT_tilt_apply_to_normal(float r_normal[3], StrokeCache *cache, const fl return; } const float rot_max = M_PI_2 * tilt_strength * SCULPT_TILT_SENSITIVITY; - mul_v3_mat3_m4v3(r_normal, cache->vc->obact->obmat, r_normal); + mul_v3_mat3_m4v3(r_normal, cache->vc->obact->object_to_world, r_normal); float normal_tilt_y[3]; rotate_v3_v3v3fl(normal_tilt_y, r_normal, cache->vc->rv3d->viewinv[0], cache->y_tilt * rot_max); float normal_tilt_xy[3]; @@ -3283,7 +3284,7 @@ static void sculpt_topology_update(Sculpt *sd, /* Update average stroke position. */ copy_v3_v3(location, ss->cache->true_location); - mul_m4_v3(ob->obmat, location); + mul_m4_v3(ob->object_to_world, location); } static void do_brush_action_task_cb(void *__restrict userdata, @@ -3614,7 +3615,7 @@ static void do_brush_action(Sculpt *sd, /* Update average stroke position. */ copy_v3_v3(location, ss->cache->true_location); - mul_m4_v3(ob->obmat, location); + mul_m4_v3(ob->object_to_world, location); add_v3_v3(ups->average_stroke_accum, location); ups->average_stroke_counter++; @@ -4200,8 +4201,8 @@ static void sculpt_init_mirror_clipping(Object *ob, SculptSession *ss) /* Store matrix for mirror object clipping. */ if (mmd->mirror_ob) { float imtx_mirror_ob[4][4]; - invert_m4_m4(imtx_mirror_ob, mmd->mirror_ob->obmat); - mul_m4_m4m4(ss->cache->clip_mirror_mtx, imtx_mirror_ob, ob->obmat); + invert_m4_m4(imtx_mirror_ob, mmd->mirror_ob->object_to_world); + mul_m4_m4m4(ss->cache->clip_mirror_mtx, imtx_mirror_ob, ob->object_to_world); } } } @@ -4353,7 +4354,7 @@ static void sculpt_update_cache_invariants( /* Cache projection matrix. */ ED_view3d_ob_project_mat_get(cache->vc->rv3d, ob, cache->projection_mat); - invert_m4_m4(ob->imat, ob->obmat); + invert_m4_m4(ob->imat, ob->object_to_world); copy_m3_m4(mat, cache->vc->rv3d->viewinv); mul_m3_v3(mat, viewDir); copy_m3_m4(mat, ob->imat); @@ -4372,7 +4373,7 @@ static void sculpt_update_cache_invariants( if (sd->gravity_object) { Object *gravity_object = sd->gravity_object; - copy_v3_v3(cache->true_gravity_direction, gravity_object->obmat[2]); + copy_v3_v3(cache->true_gravity_direction, gravity_object->object_to_world[2]); } else { cache->true_gravity_direction[0] = cache->true_gravity_direction[1] = 0.0f; @@ -4526,27 +4527,27 @@ static void sculpt_update_brush_delta(UnifiedPaintSettings *ups, Object *ob, Bru } /* Compute 3d coordinate at same z from original location + mval. */ - mul_v3_m4v3(loc, ob->obmat, cache->orig_grab_location); + mul_v3_m4v3(loc, ob->object_to_world, cache->orig_grab_location); ED_view3d_win_to_3d(cache->vc->v3d, cache->vc->region, loc, mval, grab_location); /* Compute delta to move verts by. */ if (!SCULPT_stroke_is_first_brush_step_of_symmetry_pass(ss->cache)) { if (sculpt_needs_delta_from_anchored_origin(brush)) { sub_v3_v3v3(delta, grab_location, cache->old_grab_location); - invert_m4_m4(imat, ob->obmat); + invert_m4_m4(imat, ob->object_to_world); mul_mat3_m4_v3(imat, delta); add_v3_v3(cache->grab_delta, delta); } else if (sculpt_needs_delta_for_tip_orientation(brush)) { if (brush->flag & BRUSH_ANCHORED) { float orig[3]; - mul_v3_m4v3(orig, ob->obmat, cache->orig_grab_location); + mul_v3_m4v3(orig, ob->object_to_world, cache->orig_grab_location); sub_v3_v3v3(cache->grab_delta, grab_location, orig); } else { sub_v3_v3v3(cache->grab_delta, grab_location, cache->old_grab_location); } - invert_m4_m4(imat, ob->obmat); + invert_m4_m4(imat, ob->object_to_world); mul_mat3_m4_v3(imat, cache->grab_delta); } else { @@ -4591,7 +4592,7 @@ static void sculpt_update_brush_delta(UnifiedPaintSettings *ups, Object *ob, Bru /* Handle 'rake' */ cache->is_rake_rotation_valid = false; - invert_m4_m4(imat, ob->obmat); + invert_m4_m4(imat, ob->object_to_world); mul_mat3_m4_v3(imat, grab_location); if (SCULPT_stroke_is_first_brush_step_of_symmetry_pass(ss->cache)) { @@ -4812,12 +4813,12 @@ static bool sculpt_needs_connectivity_info(const Sculpt *sd, void SCULPT_stroke_modifiers_check(const bContext *C, Object *ob, const Brush *brush) { SculptSession *ss = ob->sculpt; - View3D *v3d = CTX_wm_view3d(C); + RegionView3D *rv3d = CTX_wm_region_view3d(C); Sculpt *sd = CTX_data_tool_settings(C)->sculpt; bool need_pmap = sculpt_needs_connectivity_info(sd, brush, ss, 0); if (ss->shapekey_active || ss->deform_modifiers_active || - (!BKE_sculptsession_use_pbvh_draw(ob, v3d) && need_pmap)) { + (!BKE_sculptsession_use_pbvh_draw(ob, rv3d) && need_pmap)) { Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C); BKE_sculpt_update_object_for_edit( depsgraph, ob, need_pmap, false, SCULPT_tool_is_paint(brush->sculpt_tool)); @@ -4912,7 +4913,7 @@ float SCULPT_raycast_init(ViewContext *vc, ED_view3d_win_to_segment_clipped( vc->depsgraph, vc->region, vc->v3d, mval, ray_start, ray_end, true); - invert_m4_m4(obimat, ob->obmat); + invert_m4_m4(obimat, ob->object_to_world); mul_m4_v3(obimat, ray_start); mul_m4_v3(obimat, ray_end); @@ -5020,7 +5021,7 @@ bool SCULPT_cursor_geometry_info_update(bContext *C, float radius; /* Update cursor data in SculptSession. */ - invert_m4_m4(ob->imat, ob->obmat); + invert_m4_m4(ob->imat, ob->object_to_world); copy_m3_m4(mat, vc.rv3d->viewinv); mul_m3_v3(mat, viewDir); copy_m3_m4(mat, ob->imat); @@ -5248,7 +5249,6 @@ void SCULPT_flush_update_step(bContext *C, SculptUpdateType update_flags) SculptSession *ss = ob->sculpt; ARegion *region = CTX_wm_region(C); MultiresModifierData *mmd = ss->multires.modifier; - View3D *v3d = CTX_wm_view3d(C); RegionView3D *rv3d = CTX_wm_region_view3d(C); if (rv3d) { @@ -5273,7 +5273,7 @@ void SCULPT_flush_update_step(bContext *C, SculptUpdateType update_flags) /* Only current viewport matters, slower update for all viewports will * be done in sculpt_flush_update_done. */ - if (!BKE_sculptsession_use_pbvh_draw(ob, v3d)) { + if (!BKE_sculptsession_use_pbvh_draw(ob, rv3d)) { /* Slow update with full dependency graph update and all that comes with it. * Needed when there are modifiers or full shading in the 3D viewport. */ DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); @@ -5315,16 +5315,15 @@ void SCULPT_flush_update_done(const bContext *C, Object *ob, SculptUpdateType up /* After we are done drawing the stroke, check if we need to do a more * expensive depsgraph tag to update geometry. */ wmWindowManager *wm = CTX_wm_manager(C); - View3D *current_v3d = CTX_wm_view3d(C); - RegionView3D *rv3d = CTX_wm_region_view3d(C); + RegionView3D *current_rv3d = CTX_wm_region_view3d(C); SculptSession *ss = ob->sculpt; Mesh *mesh = ob->data; /* Always needed for linked duplicates. */ bool need_tag = (ID_REAL_USERS(&mesh->id) > 1); - if (rv3d) { - rv3d->rflag &= ~RV3D_PAINTING; + if (current_rv3d) { + current_rv3d->rflag &= ~RV3D_PAINTING; } LISTBASE_FOREACH (wmWindow *, win, &wm->windows) { @@ -5334,16 +5333,17 @@ void SCULPT_flush_update_done(const bContext *C, Object *ob, SculptUpdateType up if (sl->spacetype != SPACE_VIEW3D) { continue; } - View3D *v3d = (View3D *)sl; - if (v3d != current_v3d) { - need_tag |= !BKE_sculptsession_use_pbvh_draw(ob, v3d); - } /* Tag all 3D viewports for redraw now that we are done. Others * viewports did not get a full redraw, and anti-aliasing for the * current viewport was deactivated. */ LISTBASE_FOREACH (ARegion *, region, &area->regionbase) { if (region->regiontype == RGN_TYPE_WINDOW) { + RegionView3D *rv3d = region->regiondata; + if (rv3d != current_rv3d) { + need_tag |= !BKE_sculptsession_use_pbvh_draw(ob, rv3d); + } + ED_region_tag_redraw(region); } } @@ -5377,15 +5377,17 @@ void SCULPT_flush_update_done(const bContext *C, Object *ob, SculptUpdateType up BKE_sculpt_attributes_destroy_temporary_stroke(ob); - if (BKE_pbvh_type(ss->pbvh) == PBVH_BMESH) { - BKE_pbvh_bmesh_after_stroke(ss->pbvh); - } + if (update_flags & SCULPT_UPDATE_COORDS) { + if (BKE_pbvh_type(ss->pbvh) == PBVH_BMESH) { + BKE_pbvh_bmesh_after_stroke(ss->pbvh); + } - /* Optimization: if there is locked key and active modifiers present in */ - /* the stack, keyblock is updating at each step. otherwise we could update */ - /* keyblock only when stroke is finished. */ - if (ss->shapekey_active && !ss->deform_modifiers_active) { - sculpt_update_keyblock(ob); + /* Optimization: if there is locked key and active modifiers present in */ + /* the stack, keyblock is updating at each step. otherwise we could update */ + /* keyblock only when stroke is finished. */ + if (ss->shapekey_active && !ss->deform_modifiers_active) { + sculpt_update_keyblock(ob); + } } if (need_tag) { @@ -5510,7 +5512,8 @@ static void sculpt_stroke_update_step(bContext *C, sculpt_restore_mesh(sd, ob); if (sd->flags & (SCULPT_DYNTOPO_DETAIL_CONSTANT | SCULPT_DYNTOPO_DETAIL_MANUAL)) { - float object_space_constant_detail = 1.0f / (sd->constant_detail * mat4_to_scale(ob->obmat)); + float object_space_constant_detail = 1.0f / (sd->constant_detail * + mat4_to_scale(ob->object_to_world)); BKE_pbvh_bmesh_detail_size_set(ss->pbvh, object_space_constant_detail); } else if (sd->flags & SCULPT_DYNTOPO_DETAIL_BRUSH) { @@ -5624,6 +5627,7 @@ static void sculpt_stroke_done(const bContext *C, struct PaintStroke *UNUSED(str } else { BKE_sculpt_attributes_destroy_temporary_stroke(ob); + SCULPT_flush_update_done(C, ob, SCULPT_UPDATE_COLOR); } } else { @@ -5666,7 +5670,7 @@ static int sculpt_brush_stroke_invoke(bContext *C, wmOperator *op, const wmEvent } if (SCULPT_tool_is_mask(brush->sculpt_tool)) { MultiresModifierData *mmd = BKE_sculpt_multires_active(ss->scene, ob); - BKE_sculpt_mask_layers_ensure(ob, mmd); + BKE_sculpt_mask_layers_ensure(CTX_data_depsgraph_pointer(C), CTX_data_main(C), ob, mmd); } if (SCULPT_tool_is_face_sets(brush->sculpt_tool)) { Mesh *mesh = BKE_object_get_original_mesh(ob); diff --git a/source/blender/editors/sculpt_paint/sculpt_cloth.c b/source/blender/editors/sculpt_paint/sculpt_cloth.c index b6bb4c185f9..cf7e1d027f7 100644 --- a/source/blender/editors/sculpt_paint/sculpt_cloth.c +++ b/source/blender/editors/sculpt_paint/sculpt_cloth.c @@ -667,15 +667,15 @@ static void cloth_brush_solve_collision(Object *object, BVHTreeRayHit hit; float obmat_inv[4][4]; - invert_m4_m4(obmat_inv, object->obmat); + invert_m4_m4(obmat_inv, object->object_to_world); for (collider_cache = cloth_sim->collider_list->first; collider_cache; collider_cache = collider_cache->next) { float ray_start[3], ray_normal[3]; float pos_world_space[3], prev_pos_world_space[3]; - mul_v3_m4v3(pos_world_space, object->obmat, cloth_sim->pos[i]); - mul_v3_m4v3(prev_pos_world_space, object->obmat, cloth_sim->last_iteration_pos[i]); + mul_v3_m4v3(pos_world_space, object->object_to_world, cloth_sim->pos[i]); + mul_v3_m4v3(prev_pos_world_space, object->object_to_world, cloth_sim->last_iteration_pos[i]); sub_v3_v3v3(ray_normal, pos_world_space, prev_pos_world_space); copy_v3_v3(ray_start, prev_pos_world_space); hit.index = -1; @@ -1419,7 +1419,7 @@ static void cloth_filter_apply_forces_task_cb(void *__restrict userdata, float sculpt_gravity[3] = {0.0f}; if (sd->gravity_object) { - copy_v3_v3(sculpt_gravity, sd->gravity_object->obmat[2]); + copy_v3_v3(sculpt_gravity, sd->gravity_object->object_to_world[2]); } else { sculpt_gravity[2] = -1.0f; diff --git a/source/blender/editors/sculpt_paint/sculpt_detail.c b/source/blender/editors/sculpt_paint/sculpt_detail.c index 6dd718d6a0c..0e46fd50f3b 100644 --- a/source/blender/editors/sculpt_paint/sculpt_detail.c +++ b/source/blender/editors/sculpt_paint/sculpt_detail.c @@ -102,7 +102,8 @@ static int sculpt_detail_flood_fill_exec(bContext *C, wmOperator *op) size = max_fff(dim[0], dim[1], dim[2]); /* Update topology size. */ - float object_space_constant_detail = 1.0f / (sd->constant_detail * mat4_to_scale(ob->obmat)); + float object_space_constant_detail = 1.0f / + (sd->constant_detail * mat4_to_scale(ob->object_to_world)); BKE_pbvh_bmesh_detail_size_set(ss->pbvh, object_space_constant_detail); SCULPT_undo_push_begin(ob, op); @@ -223,7 +224,7 @@ static void sample_detail_dyntopo(bContext *C, ViewContext *vc, const int mval[2 if (srd.hit && srd.edge_length > 0.0f) { /* Convert edge length to world space detail resolution. */ - sd->constant_detail = 1 / (srd.edge_length * mat4_to_scale(ob->obmat)); + sd->constant_detail = 1 / (srd.edge_length * mat4_to_scale(ob->object_to_world)); } } @@ -473,8 +474,8 @@ static void dyntopo_detail_size_parallel_lines_draw(uint pos3d, bool flip, const float angle) { - float object_space_constant_detail = 1.0f / - (cd->detail_size * mat4_to_scale(cd->active_object->obmat)); + float object_space_constant_detail = 1.0f / (cd->detail_size * + mat4_to_scale(cd->active_object->object_to_world)); /* The constant detail represents the maximum edge length allowed before subdividing it. If the * triangle grid preview is created with this value it will represent an ideal mesh density where @@ -592,7 +593,8 @@ static void dyntopo_detail_size_sample_from_surface(Object *ob, if (num_neighbors > 0) { const float avg_edge_len = len_accum / num_neighbors; /* Use 0.7 as the average of min and max dyntopo edge length. */ - const float detail_size = 0.7f / (avg_edge_len * mat4_to_scale(cd->active_object->obmat)); + const float detail_size = 0.7f / + (avg_edge_len * mat4_to_scale(cd->active_object->object_to_world)); cd->detail_size = clamp_f(detail_size, 1.0f, 500.0f); } } @@ -716,7 +718,7 @@ static int dyntopo_detail_size_edit_invoke(bContext *C, wmOperator *op, const wm float cursor_trans[4][4], cursor_rot[4][4]; const float z_axis[4] = {0.0f, 0.0f, 1.0f, 0.0f}; float quat[4]; - copy_m4_m4(cursor_trans, active_object->obmat); + copy_m4_m4(cursor_trans, active_object->object_to_world); translate_m4( cursor_trans, ss->cursor_location[0], ss->cursor_location[1], ss->cursor_location[2]); diff --git a/source/blender/editors/sculpt_paint/sculpt_expand.c b/source/blender/editors/sculpt_paint/sculpt_expand.c index 90279cb339c..3133bb2007e 100644 --- a/source/blender/editors/sculpt_paint/sculpt_expand.c +++ b/source/blender/editors/sculpt_paint/sculpt_expand.c @@ -27,6 +27,7 @@ #include "BKE_paint.h" #include "BKE_pbvh.h" #include "BKE_report.h" +#include "BKE_scene.h" #include "BKE_subdiv_ccg.h" #include "DEG_depsgraph.h" @@ -166,15 +167,16 @@ static float sculpt_expand_falloff_value_vertex_get(SculptSession *ss, if (expand_cache->texture_distortion_strength == 0.0f) { return expand_cache->vert_falloff[v_i]; } - - if (!expand_cache->brush->mtex.tex) { + const Brush *brush = expand_cache->brush; + const MTex *mtex = BKE_brush_mask_texture_get(brush, OB_MODE_SCULPT); + if (!mtex->tex) { return expand_cache->vert_falloff[v_i]; } float rgba[4]; const float *vertex_co = SCULPT_vertex_co_get(ss, v); const float avg = BKE_brush_sample_tex_3d( - expand_cache->scene, expand_cache->brush, vertex_co, rgba, 0, ss->tex_pool); + expand_cache->scene, brush, mtex, vertex_co, rgba, 0, ss->tex_pool); const float distortion = (avg - 0.5f) * expand_cache->texture_distortion_strength * expand_cache->max_vert_falloff; @@ -2107,6 +2109,11 @@ static int sculpt_expand_invoke(bContext *C, wmOperator *op, const wmEvent *even depsgraph = CTX_data_ensure_evaluated_depsgraph(C); } + if (ss->expand_cache->target == SCULPT_EXPAND_TARGET_MASK) { + MultiresModifierData *mmd = BKE_sculpt_multires_active(ss->scene, ob); + BKE_sculpt_mask_layers_ensure(depsgraph, CTX_data_main(C), ob, mmd); + } + BKE_sculpt_update_object_for_edit(depsgraph, ob, true, true, needs_colors); /* Do nothing when the mesh has 0 vertices. */ @@ -2121,11 +2128,6 @@ static int sculpt_expand_invoke(bContext *C, wmOperator *op, const wmEvent *even ss->face_sets = BKE_sculpt_face_sets_ensure(mesh); } - if (ss->expand_cache->target == SCULPT_EXPAND_TARGET_MASK) { - MultiresModifierData *mmd = BKE_sculpt_multires_active(ss->scene, ob); - BKE_sculpt_mask_layers_ensure(ob, mmd); - } - /* Face Set operations are not supported in dyntopo. */ if (ss->expand_cache->target == SCULPT_EXPAND_TARGET_FACE_SETS && BKE_pbvh_type(ss->pbvh) == PBVH_BMESH) { diff --git a/source/blender/editors/sculpt_paint/sculpt_face_set.cc b/source/blender/editors/sculpt_paint/sculpt_face_set.cc index 5f5a555b428..40835172be9 100644 --- a/source/blender/editors/sculpt_paint/sculpt_face_set.cc +++ b/source/blender/editors/sculpt_paint/sculpt_face_set.cc @@ -18,6 +18,7 @@ #include "BLI_math_vector.hh" #include "BLI_span.hh" #include "BLI_task.h" +#include "BLI_task.hh" #include "DNA_brush_types.h" #include "DNA_customdata_types.h" @@ -198,8 +199,8 @@ static void do_relax_face_sets_brush_task_cb_ex(void *__restrict userdata, const bool relax_face_sets = !(ss->cache->iteration_count % 3 == 0); /* This operations needs a strength tweak as the relax deformation is too weak by default. */ - if (relax_face_sets) { - bstrength *= 2.0f; + if (relax_face_sets && data->iteration < 2) { + bstrength *= 1.5f; } const int thread_id = BLI_task_parallel_thread_id(tls); @@ -261,6 +262,7 @@ void SCULPT_do_draw_face_sets_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, in if (ss->cache->alt_smooth) { SCULPT_boundary_info_ensure(ob); for (int i = 0; i < 4; i++) { + data.iteration = i; BLI_task_parallel_range(0, totnode, &data, do_relax_face_sets_brush_task_cb_ex, &settings); } } @@ -312,6 +314,7 @@ static EnumPropertyItem prop_sculpt_face_set_create_types[] = { static int sculpt_face_set_create_exec(bContext *C, wmOperator *op) { + using namespace blender; Object *ob = CTX_data_active_object(C); SculptSession *ss = ob->sculpt; Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C); @@ -395,25 +398,16 @@ static int sculpt_face_set_create_exec(bContext *C, wmOperator *op) } if (mode == SCULPT_FACE_SET_SELECTION) { - BMesh *bm; - const BMAllocTemplate allocsize = BMALLOC_TEMPLATE_FROM_ME(mesh); - BMeshCreateParams create_params{}; - create_params.use_toolflags = true; - bm = BM_mesh_create(&allocsize, &create_params); - - BMeshFromMeshParams convert_params{}; - convert_params.calc_vert_normal = true; - convert_params.calc_face_normal = true; - BM_mesh_bm_from_me(bm, mesh, &convert_params); - - BMIter iter; - BMFace *f; - BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) { - if (BM_elem_flag_test(f, BM_ELEM_SELECT)) { - ss->face_sets[BM_elem_index_get(f)] = next_face_set; + const bke::AttributeAccessor attributes = mesh->attributes(); + const VArraySpan<bool> select_poly = attributes.lookup_or_default<bool>( + ".select_poly", ATTR_DOMAIN_FACE, false); + threading::parallel_for(IndexRange(mesh->totvert), 4096, [&](const IndexRange range) { + for (const int i : range) { + if (select_poly[i]) { + ss->face_sets[i] = next_face_set; + } } - } - BM_mesh_free(bm); + }); } for (int i = 0; i < totnode; i++) { @@ -923,7 +917,7 @@ static int sculpt_face_sets_change_visibility_exec(bContext *C, wmOperator *op) UnifiedPaintSettings *ups = &CTX_data_tool_settings(C)->unified_paint_settings; float location[3]; copy_v3_v3(location, SCULPT_active_vertex_co_get(ss)); - mul_m4_v3(ob->obmat, location); + mul_m4_v3(ob->object_to_world, location); copy_v3_v3(ups->average_stroke_accum, location); ups->average_stroke_counter = 1; ups->last_stroke_valid = true; diff --git a/source/blender/editors/sculpt_paint/sculpt_filter_mask.c b/source/blender/editors/sculpt_paint/sculpt_filter_mask.c index 69eac9a6168..8e199a72858 100644 --- a/source/blender/editors/sculpt_paint/sculpt_filter_mask.c +++ b/source/blender/editors/sculpt_paint/sculpt_filter_mask.c @@ -16,6 +16,7 @@ #include "BKE_context.h" #include "BKE_paint.h" #include "BKE_pbvh.h" +#include "BKE_scene.h" #include "DEG_depsgraph.h" @@ -166,7 +167,7 @@ static int sculpt_mask_filter_exec(bContext *C, wmOperator *op) int filter_type = RNA_enum_get(op->ptr, "filter_type"); MultiresModifierData *mmd = BKE_sculpt_multires_active(scene, ob); - BKE_sculpt_mask_layers_ensure(ob, mmd); + BKE_sculpt_mask_layers_ensure(CTX_data_depsgraph_pointer(C), CTX_data_main(C), ob, mmd); BKE_sculpt_update_object_for_edit(depsgraph, ob, true, true, false); diff --git a/source/blender/editors/sculpt_paint/sculpt_filter_mesh.c b/source/blender/editors/sculpt_paint/sculpt_filter_mesh.c index 1fa53eaa006..078f0217416 100644 --- a/source/blender/editors/sculpt_paint/sculpt_filter_mesh.c +++ b/source/blender/editors/sculpt_paint/sculpt_filter_mesh.c @@ -146,8 +146,8 @@ void SCULPT_filter_cache_init(bContext *C, 0, ss->filter_cache->totnode, &data, filter_cache_init_task_cb, &settings); /* Setup orientation matrices. */ - copy_m4_m4(ss->filter_cache->obmat, ob->obmat); - invert_m4_m4(ss->filter_cache->obmat_inv, ob->obmat); + copy_m4_m4(ss->filter_cache->obmat, ob->object_to_world); + invert_m4_m4(ss->filter_cache->obmat_inv, ob->object_to_world); Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C); ViewContext vc; @@ -203,7 +203,7 @@ void SCULPT_filter_cache_init(bContext *C, /* Update last stroke location */ - mul_m4_v3(ob->obmat, co); + mul_m4_v3(ob->object_to_world, co); add_v3_v3(ups->average_stroke_accum, co); ups->average_stroke_counter++; @@ -221,7 +221,7 @@ void SCULPT_filter_cache_init(bContext *C, ED_view3d_ob_project_mat_get(vc.rv3d, ob, projection_mat); - invert_m4_m4(ob->imat, ob->obmat); + invert_m4_m4(ob->imat, ob->object_to_world); copy_m3_m4(mat, vc.rv3d->viewinv); mul_m3_v3(mat, viewDir); copy_m3_m4(mat, ob->imat); diff --git a/source/blender/editors/sculpt_paint/sculpt_intern.h b/source/blender/editors/sculpt_paint/sculpt_intern.h index edb681466b5..bf47b64d176 100644 --- a/source/blender/editors/sculpt_paint/sculpt_intern.h +++ b/source/blender/editors/sculpt_paint/sculpt_intern.h @@ -332,7 +332,7 @@ typedef struct SculptThreadedTaskData { int mask_init_seed; ThreadMutex mutex; - + int iteration; } SculptThreadedTaskData; /*************** Brush testing declarations ****************/ diff --git a/source/blender/editors/sculpt_paint/sculpt_mask_expand.c b/source/blender/editors/sculpt_paint/sculpt_mask_expand.c index 56ddb99fe28..1b8cc5347ac 100644 --- a/source/blender/editors/sculpt_paint/sculpt_mask_expand.c +++ b/source/blender/editors/sculpt_paint/sculpt_mask_expand.c @@ -14,6 +14,7 @@ #include "DNA_brush_types.h" #include "DNA_meshdata_types.h" +#include "DNA_modifier_types.h" #include "DNA_object_types.h" #include "BKE_ccg.h" @@ -331,6 +332,11 @@ static int sculpt_mask_expand_invoke(bContext *C, wmOperator *op, const wmEvent SculptCursorGeometryInfo sgi; const float mval_fl[2] = {UNPACK2(event->mval)}; + MultiresModifierData *mmd = BKE_sculpt_multires_active(CTX_data_scene(C), ob); + BKE_sculpt_mask_layers_ensure(depsgraph, CTX_data_main(C), ob, mmd); + + BKE_sculpt_update_object_for_edit(depsgraph, ob, true, true, false); + SCULPT_vertex_random_access_ensure(ss); op->customdata = MEM_mallocN(sizeof(float[2]), "initial mouse position"); @@ -338,8 +344,6 @@ static int sculpt_mask_expand_invoke(bContext *C, wmOperator *op, const wmEvent SCULPT_cursor_geometry_info_update(C, &sgi, mval_fl, false); - BKE_sculpt_update_object_for_edit(depsgraph, ob, true, true, false); - int vertex_count = SCULPT_vertex_count_get(ss); ss->filter_cache = MEM_callocN(sizeof(FilterCache), "filter cache"); diff --git a/source/blender/editors/sculpt_paint/sculpt_mask_init.c b/source/blender/editors/sculpt_paint/sculpt_mask_init.c index 5d7ef9aab15..99a7bb8a926 100644 --- a/source/blender/editors/sculpt_paint/sculpt_mask_init.c +++ b/source/blender/editors/sculpt_paint/sculpt_mask_init.c @@ -15,6 +15,7 @@ #include "DNA_brush_types.h" #include "DNA_meshdata_types.h" +#include "DNA_modifier_types.h" #include "DNA_object_types.h" #include "BKE_ccg.h" @@ -110,6 +111,9 @@ static int sculpt_mask_init_exec(bContext *C, wmOperator *op) const int mode = RNA_enum_get(op->ptr, "mode"); + MultiresModifierData *mmd = BKE_sculpt_multires_active(CTX_data_scene(C), ob); + BKE_sculpt_mask_layers_ensure(depsgraph, CTX_data_main(C), ob, mmd); + BKE_sculpt_update_object_for_edit(depsgraph, ob, true, true, false); PBVH *pbvh = ob->sculpt->pbvh; diff --git a/source/blender/editors/sculpt_paint/sculpt_ops.c b/source/blender/editors/sculpt_paint/sculpt_ops.c index 56a35ee1774..8affb0e9d53 100644 --- a/source/blender/editors/sculpt_paint/sculpt_ops.c +++ b/source/blender/editors/sculpt_paint/sculpt_ops.c @@ -21,6 +21,7 @@ #include "DNA_listBase.h" #include "DNA_mesh_types.h" #include "DNA_meshdata_types.h" +#include "DNA_modifier_types.h" #include "DNA_node_types.h" #include "DNA_object_types.h" #include "DNA_scene_types.h" @@ -322,7 +323,7 @@ void ED_object_sculptmode_enter_ex(Main *bmain, BKE_report( reports, RPT_WARNING, "Object has non-uniform scale, sculpting may be unpredictable"); } - else if (is_negative_m4(ob->obmat)) { + else if (is_negative_m4(ob->object_to_world)) { BKE_report(reports, RPT_WARNING, "Object has negative scale, sculpting may be unpredictable"); } @@ -1041,12 +1042,12 @@ static int sculpt_bake_cavity_exec(bContext *C, wmOperator *op) Sculpt *sd = CTX_data_tool_settings(C)->sculpt; Brush *brush = BKE_paint_brush(&sd->paint); + MultiresModifierData *mmd = BKE_sculpt_multires_active(CTX_data_scene(C), ob); + BKE_sculpt_mask_layers_ensure(depsgraph, CTX_data_main(C), ob, mmd); + BKE_sculpt_update_object_for_edit(depsgraph, ob, true, true, false); SCULPT_vertex_random_access_ensure(ss); - MultiresModifierData *mmd = BKE_sculpt_multires_active(CTX_data_scene(C), ob); - BKE_sculpt_mask_layers_ensure(ob, mmd); - SCULPT_undo_push_begin(ob, op); CavityBakeMixMode mode = RNA_enum_get(op->ptr, "mix_mode"); diff --git a/source/blender/editors/sculpt_paint/sculpt_undo.c b/source/blender/editors/sculpt_paint/sculpt_undo.c index 13e3dd64521..eb92c865f18 100644 --- a/source/blender/editors/sculpt_paint/sculpt_undo.c +++ b/source/blender/editors/sculpt_paint/sculpt_undo.c @@ -857,7 +857,7 @@ static void sculpt_undo_restore_list(bContext *C, Depsgraph *depsgraph, ListBase { Scene *scene = CTX_data_scene(C); ViewLayer *view_layer = CTX_data_view_layer(C); - View3D *v3d = CTX_wm_view3d(C); + RegionView3D *rv3d = CTX_wm_region_view3d(C); BKE_view_layer_synced_ensure(scene, view_layer); Object *ob = BKE_view_layer_active_object_get(view_layer); SculptSession *ss = ob->sculpt; @@ -911,7 +911,7 @@ static void sculpt_undo_restore_list(bContext *C, Depsgraph *depsgraph, ListBase } DEG_id_tag_update(&ob->id, ID_RECALC_SHADING); - if (!BKE_sculptsession_use_pbvh_draw(ob, v3d)) { + if (!BKE_sculptsession_use_pbvh_draw(ob, rv3d)) { DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); } @@ -1070,7 +1070,7 @@ static void sculpt_undo_restore_list(bContext *C, Depsgraph *depsgraph, ListBase } } - tag_update |= ID_REAL_USERS(ob->data) > 1 || !BKE_sculptsession_use_pbvh_draw(ob, v3d) || + tag_update |= ID_REAL_USERS(ob->data) > 1 || !BKE_sculptsession_use_pbvh_draw(ob, rv3d) || ss->shapekey_active || ss->deform_modifiers_active; if (tag_update) { diff --git a/source/blender/editors/space_action/action_draw.c b/source/blender/editors/space_action/action_draw.c index eb56c6c4b54..343975919e2 100644 --- a/source/blender/editors/space_action/action_draw.c +++ b/source/blender/editors/space_action/action_draw.c @@ -104,7 +104,7 @@ void draw_channel_names(bContext *C, bAnimContext *ac, ARegion *region) UI_block_draw(C, block); } - /* free tempolary channels */ + /* Free temporary channels. */ ANIM_animdata_freelist(&anim_data); } diff --git a/source/blender/editors/space_buttons/buttons_ops.c b/source/blender/editors/space_buttons/buttons_ops.c index a9ce9a3d723..9c8d46a41f9 100644 --- a/source/blender/editors/space_buttons/buttons_ops.c +++ b/source/blender/editors/space_buttons/buttons_ops.c @@ -41,7 +41,7 @@ /* -------------------------------------------------------------------- */ /** \name Start / Clear Search Filter Operators * - * \note Almost a duplicate of the file browser operator #FILE_OT_start_filter. + * \note Almost a duplicate of the file browser operator #FILE_OT_start_filter. * \{ */ static int buttons_start_filter_exec(bContext *C, wmOperator *UNUSED(op)) @@ -205,7 +205,7 @@ static int file_browse_exec(bContext *C, wmOperator *op) if (BLI_is_dir(path)) { /* Do this first so '//' isn't converted to '//\' on windows. */ - BLI_path_slash_ensure(path); + BLI_path_slash_ensure(path, sizeof(path)); if (is_relative) { BLI_path_rel(path, BKE_main_blendfile_path(bmain)); str_len = strlen(path); diff --git a/source/blender/editors/space_clip/clip_ops.c b/source/blender/editors/space_clip/clip_ops.c index a625c124dd3..486f9f9ccb0 100644 --- a/source/blender/editors/space_clip/clip_ops.c +++ b/source/blender/editors/space_clip/clip_ops.c @@ -201,7 +201,7 @@ static int open_exec(bContext *C, wmOperator *op) RNA_property_collection_lookup_int(op->ptr, prop, 0, &fileptr); RNA_string_get(&fileptr, "name", file_only); - BLI_join_dirfile(str, sizeof(str), dir_only, file_only); + BLI_path_join(str, sizeof(str), dir_only, file_only); } else { BKE_report(op->reports, RPT_ERROR, "No files selected to be opened"); diff --git a/source/blender/editors/space_file/file_draw.c b/source/blender/editors/space_file/file_draw.c index 554b628ba0f..240901318b5 100644 --- a/source/blender/editors/space_file/file_draw.c +++ b/source/blender/editors/space_file/file_draw.c @@ -410,8 +410,15 @@ static void file_draw_preview(const SpaceFile *sfile, } icon_x = xco + (ex / 2.0f) - (icon_size / 2.0f); icon_y = yco + (ey / 2.0f) - (icon_size * ((file->typeflag & FILE_TYPE_DIR) ? 0.78f : 0.75f)); - UI_icon_draw_ex( - icon_x, icon_y, icon, icon_aspect / U.dpi_fac, icon_opacity, 0.0f, icon_color, false); + UI_icon_draw_ex(icon_x, + icon_y, + icon, + icon_aspect / U.dpi_fac, + icon_opacity, + 0.0f, + icon_color, + false, + UI_NO_ICON_OVERLAY_TEXT); } if (is_link || is_offline) { @@ -424,8 +431,24 @@ static void file_draw_preview(const SpaceFile *sfile, /* At very bottom-left if preview style. */ const uchar dark[4] = {0, 0, 0, 255}; const uchar light[4] = {255, 255, 255, 255}; - UI_icon_draw_ex(icon_x + 1, icon_y - 1, arrow, 1.0f / U.dpi_fac, 0.2f, 0.0f, dark, false); - UI_icon_draw_ex(icon_x, icon_y, arrow, 1.0f / U.dpi_fac, 0.6f, 0.0f, light, false); + UI_icon_draw_ex(icon_x + 1, + icon_y - 1, + arrow, + 1.0f / U.dpi_fac, + 0.2f, + 0.0f, + dark, + false, + UI_NO_ICON_OVERLAY_TEXT); + UI_icon_draw_ex(icon_x, + icon_y, + arrow, + 1.0f / U.dpi_fac, + 0.6f, + 0.0f, + light, + false, + UI_NO_ICON_OVERLAY_TEXT); } else { /* Link to folder or non-previewed file. */ @@ -433,8 +456,15 @@ static void file_draw_preview(const SpaceFile *sfile, UI_GetThemeColor4ubv(TH_BACK, icon_color); icon_x = xco + ((file->typeflag & FILE_TYPE_DIR) ? 0.14f : 0.23f) * scaledx; icon_y = yco + ((file->typeflag & FILE_TYPE_DIR) ? 0.24f : 0.14f) * scaledy; - UI_icon_draw_ex( - icon_x, icon_y, arrow, icon_aspect / U.dpi_fac * 1.8, 0.3f, 0.0f, icon_color, false); + UI_icon_draw_ex(icon_x, + icon_y, + arrow, + icon_aspect / U.dpi_fac * 1.8, + 0.3f, + 0.0f, + icon_color, + false, + UI_NO_ICON_OVERLAY_TEXT); } } else if (icon && !is_icon && !(file->typeflag & FILE_TYPE_FTFONT)) { @@ -444,8 +474,17 @@ static void file_draw_preview(const SpaceFile *sfile, const uchar light[4] = {255, 255, 255, 255}; icon_x = xco + (2.0f * UI_DPI_FAC); icon_y = yco + (2.0f * UI_DPI_FAC); - UI_icon_draw_ex(icon_x + 1, icon_y - 1, icon, 1.0f / U.dpi_fac, 0.2f, 0.0f, dark, false); - UI_icon_draw_ex(icon_x, icon_y, icon, 1.0f / U.dpi_fac, 0.6f, 0.0f, light, false); + UI_icon_draw_ex(icon_x + 1, + icon_y - 1, + icon, + 1.0f / U.dpi_fac, + 0.2f, + 0.0f, + dark, + false, + UI_NO_ICON_OVERLAY_TEXT); + UI_icon_draw_ex( + icon_x, icon_y, icon, 1.0f / U.dpi_fac, 0.6f, 0.0f, light, false, UI_NO_ICON_OVERLAY_TEXT); } const bool is_current_main_data = filelist_file_get_id(file) != NULL; @@ -456,7 +495,15 @@ static void file_draw_preview(const SpaceFile *sfile, const uchar light[4] = {255, 255, 255, 255}; icon_x = xco + ex - UI_UNIT_X; icon_y = yco + ey - UI_UNIT_Y; - UI_icon_draw_ex(icon_x, icon_y, ICON_CURRENT_FILE, 1.0f / U.dpi_fac, 0.6f, 0.0f, light, false); + UI_icon_draw_ex(icon_x, + icon_y, + ICON_CURRENT_FILE, + 1.0f / U.dpi_fac, + 0.6f, + 0.0f, + light, + false, + UI_NO_ICON_OVERLAY_TEXT); } /* Contrasting outline around some preview types. */ @@ -544,10 +591,10 @@ static void renamebutton_cb(bContext *C, void *UNUSED(arg1), char *oldname) ARegion *region = CTX_wm_region(C); FileSelectParams *params = ED_fileselect_get_active_params(sfile); - BLI_join_dirfile(orgname, sizeof(orgname), params->dir, oldname); + BLI_path_join(orgname, sizeof(orgname), params->dir, oldname); BLI_strncpy(filename, params->renamefile, sizeof(filename)); BLI_filename_make_safe(filename); - BLI_join_dirfile(newname, sizeof(newname), params->dir, filename); + BLI_path_join(newname, sizeof(newname), params->dir, filename); if (!STREQ(orgname, newname)) { if (!BLI_exists(newname)) { @@ -952,7 +999,7 @@ void file_draw_list(const bContext *C, ARegion *region) file = filelist_file(files, i); file_selflag = filelist_entry_select_get(sfile->files, file, CHECK_ALL); - BLI_join_dirfile(path, sizeof(path), root, file->relpath); + BLI_path_join(path, sizeof(path), root, file->relpath); if (!(file_selflag & FILE_SEL_EDITING)) { if ((params->highlight_file == i) || (file_selflag & FILE_SEL_HIGHLIGHTED) || diff --git a/source/blender/editors/space_file/file_ops.c b/source/blender/editors/space_file/file_ops.c index f7fd910d6e9..f68d329329f 100644 --- a/source/blender/editors/space_file/file_ops.c +++ b/source/blender/editors/space_file/file_ops.c @@ -197,13 +197,12 @@ static FileSelect file_select_do(bContext *C, int selected_idx, bool do_diropen) } else if (file->redirection_path) { BLI_strncpy(params->dir, file->redirection_path, sizeof(params->dir)); - BLI_path_normalize_dir(BKE_main_blendfile_path(bmain), params->dir); - BLI_path_slash_ensure(params->dir); + BLI_path_normalize_dir(BKE_main_blendfile_path(bmain), params->dir, sizeof(params->dir)); + BLI_path_slash_ensure(params->dir, sizeof(params->dir)); } else { - BLI_path_normalize_dir(BKE_main_blendfile_path(bmain), params->dir); - strcat(params->dir, file->relpath); - BLI_path_slash_ensure(params->dir); + BLI_path_normalize_dir(BKE_main_blendfile_path(bmain), params->dir, sizeof(params->dir)); + BLI_path_append_dir(params->dir, sizeof(params->dir), file->relpath); } ED_file_change_dir(C); @@ -386,7 +385,7 @@ static bool fsmenu_write_file_and_refresh_or_report_error(struct FSMenu *fsmenu, } char filepath[FILE_MAX]; - BLI_join_dirfile(filepath, sizeof(filepath), cfgdir, BLENDER_BOOKMARK_FILE); + BLI_path_join(filepath, sizeof(filepath), cfgdir, BLENDER_BOOKMARK_FILE); if (UNLIKELY(!fsmenu_write_file(fsmenu, filepath))) { BKE_reportf(reports, RPT_ERROR, "Unable to open or write bookmark file \"%s\"", filepath); return false; @@ -1095,7 +1094,7 @@ static int bookmark_select_exec(bContext *C, wmOperator *op) RNA_property_string_get(op->ptr, prop, entry); BLI_strncpy(params->dir, entry, sizeof(params->dir)); - BLI_path_normalize_dir(BKE_main_blendfile_path(bmain), params->dir); + BLI_path_normalize_dir(BKE_main_blendfile_path(bmain), params->dir, sizeof(params->dir)); ED_file_change_dir(C); WM_event_add_notifier(C, NC_SPACE | ND_SPACE_FILE_LIST, NULL); @@ -1564,7 +1563,13 @@ void file_sfile_to_operator_ex( PropertyRNA *prop; /* XXX, not real length */ - BLI_join_dirfile(filepath, FILE_MAX, params->dir, params->file); + if (params->file[0]) { + BLI_path_join(filepath, FILE_MAX, params->dir, params->file); + } + else { + BLI_strncpy(filepath, params->dir, FILE_MAX); + BLI_path_slash_ensure(filepath, FILE_MAX); + } if ((prop = RNA_struct_find_property(op->ptr, "relative_path"))) { if (RNA_property_boolean_get(op->ptr, prop)) { @@ -1741,7 +1746,7 @@ bool file_draw_check_exists(SpaceFile *sfile) const FileSelectParams *params = ED_fileselect_get_active_params(sfile); if (params && (params->flag & FILE_CHECK_EXISTING)) { char filepath[FILE_MAX]; - BLI_join_dirfile(filepath, sizeof(filepath), params->dir, params->file); + BLI_path_join(filepath, sizeof(filepath), params->dir, params->file); if (BLI_is_file(filepath)) { return true; } @@ -1791,8 +1796,7 @@ static bool file_execute(bContext *C, SpaceFile *sfile) } else { BLI_path_normalize(BKE_main_blendfile_path(bmain), params->dir); - BLI_path_append(params->dir, sizeof(params->dir) - 1, file->relpath); - BLI_path_slash_ensure(params->dir); + BLI_path_append_dir(params->dir, sizeof(params->dir), file->relpath); } ED_file_change_dir(C); } @@ -1955,7 +1959,7 @@ static int file_parent_exec(bContext *C, wmOperator *UNUSED(unused)) if (params) { if (BLI_path_parent_dir(params->dir)) { - BLI_path_normalize_dir(BKE_main_blendfile_path(bmain), params->dir); + BLI_path_normalize_dir(BKE_main_blendfile_path(bmain), params->dir, sizeof(params->dir)); ED_file_change_dir(C); if (params->recursion_level > 1) { /* Disable 'dirtree' recursion when going up in tree. */ @@ -2311,13 +2315,13 @@ static bool new_folder_path(const char *parent, char folder[FILE_MAX], char name int len = 0; BLI_strncpy(name, "New Folder", FILE_MAXFILE); - BLI_join_dirfile(folder, FILE_MAX, parent, name); + BLI_path_join(folder, FILE_MAX, parent, name); /* check whether folder with the name already exists, in this case * add number to the name. Check length of generated name to avoid * crazy case of huge number of folders each named 'New Folder (x)' */ while (BLI_exists(folder) && (len < FILE_MAXFILE)) { len = BLI_snprintf(name, FILE_MAXFILE, "New Folder(%d)", i); - BLI_join_dirfile(folder, FILE_MAX, parent, name); + BLI_path_join(folder, FILE_MAX, parent, name); i++; } @@ -2457,8 +2461,7 @@ static void file_expand_directory(bContext *C) else if (params->dir[0] == '~') { char tmpstr[sizeof(params->dir) - 1]; BLI_strncpy(tmpstr, params->dir + 1, sizeof(tmpstr)); - BLI_path_join( - params->dir, sizeof(params->dir), BKE_appdir_folder_default_or_root(), tmpstr, NULL); + BLI_path_join(params->dir, sizeof(params->dir), BKE_appdir_folder_default_or_root(), tmpstr); } else if (params->dir[0] == '\0') @@ -2539,7 +2542,7 @@ void file_directory_enter_handle(bContext *C, void *UNUSED(arg_unused), void *UN } } - BLI_path_normalize_dir(BKE_main_blendfile_path(bmain), params->dir); + BLI_path_normalize_dir(BKE_main_blendfile_path(bmain), params->dir, sizeof(params->dir)); if (filelist_is_dir(sfile->files, params->dir)) { if (!STREQ(params->dir, old_dir)) { /* Avoids flickering when nothing's changed. */ @@ -2622,11 +2625,11 @@ void file_filename_enter_handle(bContext *C, void *UNUSED(arg_unused), void *arg } if (matches == 1) { - BLI_join_dirfile(filepath, sizeof(params->dir), params->dir, params->file); + BLI_path_join(filepath, sizeof(params->dir), params->dir, params->file); /* if directory, open it and empty filename field */ if (filelist_is_dir(sfile->files, filepath)) { - BLI_path_normalize_dir(BKE_main_blendfile_path(bmain), filepath); + BLI_path_normalize_dir(BKE_main_blendfile_path(bmain), filepath, sizeof(filepath)); BLI_strncpy(params->dir, filepath, sizeof(params->dir)); params->file[0] = '\0'; ED_file_change_dir(C); @@ -2850,7 +2853,7 @@ static bool file_delete_single(const FileSelectParams *params, const char **r_error_message) { char str[FILE_MAX]; - BLI_join_dirfile(str, sizeof(str), params->dir, file->relpath); + BLI_path_join(str, sizeof(str), params->dir, file->relpath); if (BLI_delete_soft(str, r_error_message) != 0 || BLI_exists(str)) { return false; } diff --git a/source/blender/editors/space_file/filelist.cc b/source/blender/editors/space_file/filelist.cc index c2dc8e9196d..3257534f94d 100644 --- a/source/blender/editors/space_file/filelist.cc +++ b/source/blender/editors/space_file/filelist.cc @@ -115,6 +115,9 @@ struct FileListInternEntry { * Owning pointer. */ AssetMetaData *imported_asset_data; + /* See #FILE_ENTRY_BLENDERLIB_NO_PREVIEW. */ + bool blenderlib_has_no_preview; + /** Defined in BLI_fileops.h */ eFileAttributes attributes; BLI_stat_t st; @@ -844,7 +847,7 @@ static bool is_filtered_lib_type(FileListInternEntry *file, { char path[FILE_MAX_LIBEXTRA], dir[FILE_MAX_LIBEXTRA], *group, *name; - BLI_join_dirfile(path, sizeof(path), root, file->relpath); + BLI_path_join(path, sizeof(path), root, file->relpath); if (BLO_library_path_explode(path, dir, &group, &name)) { return is_filtered_id_file_type(file, group, name, filter); @@ -1204,8 +1207,8 @@ static int filelist_geticon_ex(const FileDirEntry *file, target = file->redirection_path; } else if (root) { - BLI_join_dirfile(fullpath, sizeof(fullpath), root, file->relpath); - BLI_path_slash_ensure(fullpath); + BLI_path_join(fullpath, sizeof(fullpath), root, file->relpath); + BLI_path_slash_ensure(fullpath, sizeof(fullpath)); } for (; tfsm; tfsm = tfsm->next) { if (STREQ(tfsm->path, target)) { @@ -1575,6 +1578,14 @@ static void filelist_cache_previews_push(FileList *filelist, FileDirEntry *entry return; } + /* If we know this is an external ID without a preview, skip loading the preview. Can save quite + * some time in heavy files, because otherwise for each missing preview and for each preview + * reload, we'd reopen the .blend to look for the preview. */ + if ((entry->typeflag & FILE_TYPE_BLENDERLIB) && + (entry->flags & FILE_ENTRY_BLENDERLIB_NO_PREVIEW)) { + return; + } + FileListInternEntry *intern_entry = filelist->filelist_intern.filtered[index]; PreviewImage *preview_in_memory = intern_entry->local_data.preview_image; if (preview_in_memory && !BKE_previewimg_is_finished(preview_in_memory, ICON_SIZE_PREVIEW)) { @@ -1606,7 +1617,7 @@ static void filelist_cache_previews_push(FileList *filelist, FileDirEntry *entry BLI_strncpy(preview->filepath, entry->redirection_path, FILE_MAXDIR); } else { - BLI_join_dirfile( + BLI_path_join( preview->filepath, sizeof(preview->filepath), filelist->filelist.root, entry->relpath); } // printf("%s: %d - %s\n", __func__, preview->index, preview->filepath); @@ -1894,7 +1905,7 @@ static char *fileentry_uiname(const char *root, if (typeflag & FILE_TYPE_FTFONT && !(typeflag & FILE_TYPE_BLENDERLIB)) { char abspath[FILE_MAX_LIBEXTRA]; - BLI_join_dirfile(abspath, sizeof(abspath), root, relpath); + BLI_path_join(abspath, sizeof(abspath), root, relpath); name = BLF_display_name_from_file(abspath); if (name) { /* Allocated string, so no need to #BLI_strdup. */ @@ -1906,7 +1917,7 @@ static char *fileentry_uiname(const char *root, char abspath[FILE_MAX_LIBEXTRA]; char *group; - BLI_join_dirfile(abspath, sizeof(abspath), root, relpath); + BLI_path_join(abspath, sizeof(abspath), root, relpath); BLO_library_path_explode(abspath, buff, &group, &name); if (!name) { name = group; @@ -1941,7 +1952,7 @@ void filelist_setdir(struct FileList *filelist, char *r_dir) const bool allow_invalid = filelist->asset_library_ref != nullptr; BLI_assert(strlen(r_dir) < FILE_MAX_LIBEXTRA); - BLI_path_normalize_dir(BKE_main_blendfile_path_from_global(), r_dir); + BLI_path_normalize_dir(BKE_main_blendfile_path_from_global(), r_dir, FILE_MAX_LIBEXTRA); const bool is_valid_path = filelist->check_dir_fn(filelist, r_dir, !allow_invalid); BLI_assert(is_valid_path || allow_invalid); UNUSED_VARS_NDEBUG(is_valid_path); @@ -2042,6 +2053,9 @@ static FileDirEntry *filelist_file_create_entry(FileList *filelist, const int in ret->preview_icon_id = BKE_icon_imbuf_create(ibuf); } } + if (entry->blenderlib_has_no_preview) { + ret->flags |= FILE_ENTRY_BLENDERLIB_NO_PREVIEW; + } BLI_addtail(&cache->cached_entries, ret); return ret; } @@ -2887,7 +2901,7 @@ static int filelist_readjob_list_dir(const char *root, entry->relpath = static_cast<char *>(MEM_dupallocN(files[i].relname)); entry->st = files[i].s; - BLI_join_dirfile(full_path, FILE_MAX, root, entry->relpath); + BLI_path_join(full_path, FILE_MAX, root, entry->relpath); char *target = full_path; /* Set initial file type and attributes. */ @@ -2906,7 +2920,7 @@ static int filelist_readjob_list_dir(const char *root, if (BLI_file_alias_target(full_path, entry->redirection_path)) { if (BLI_is_dir(entry->redirection_path)) { entry->typeflag = FILE_TYPE_DIR; - BLI_path_slash_ensure(entry->redirection_path); + BLI_path_slash_ensure(entry->redirection_path, FILE_MAXDIR); } else { entry->typeflag = (eFileSel_File_Types)ED_path_extension_type(entry->redirection_path); @@ -2995,10 +3009,15 @@ static void filelist_readjob_list_lib_add_datablock(ListBase *entries, entry->relpath = BLI_strdup(datablock_info->name); } entry->typeflag |= FILE_TYPE_BLENDERLIB; - if (datablock_info && datablock_info->asset_data) { - entry->typeflag |= FILE_TYPE_ASSET; - /* Moves ownership! */ - entry->imported_asset_data = datablock_info->asset_data; + + if (datablock_info) { + entry->blenderlib_has_no_preview = datablock_info->no_preview_found; + + if (datablock_info->asset_data) { + entry->typeflag |= FILE_TYPE_ASSET; + /* Moves ownership! */ + entry->imported_asset_data = datablock_info->asset_data; + } } entry->blentype = idcode; BLI_addtail(entries, entry); @@ -3457,7 +3476,7 @@ static void filelist_readjob_recursive_dir_add_items(const bool do_lib, BLI_strncpy(dir, filelist->filelist.root, sizeof(dir)); BLI_strncpy(filter_glob, filelist->filter_data.filter_glob, sizeof(filter_glob)); - BLI_path_normalize_dir(job_params->main_name, dir); + BLI_path_normalize_dir(job_params->main_name, dir, sizeof(dir)); td_dir->dir = BLI_strdup(dir); /* Init the file indexer. */ @@ -3488,7 +3507,7 @@ static void filelist_readjob_recursive_dir_add_items(const bool do_lib, * Note that in the end, this means we 'cache' valid relative subdir once here, * this is actually better. */ BLI_strncpy(rel_subdir, subdir, sizeof(rel_subdir)); - BLI_path_normalize_dir(root, rel_subdir); + BLI_path_normalize_dir(root, rel_subdir, sizeof(rel_subdir)); BLI_path_rel(rel_subdir, root); bool is_lib = false; @@ -3525,7 +3544,7 @@ static void filelist_readjob_recursive_dir_add_items(const bool do_lib, /* When loading entries recursive, the rel_path should be relative from the root dir. * we combine the relative path to the subdir with the relative path of the entry. */ - BLI_join_dirfile(dir, sizeof(dir), rel_subdir, entry->relpath); + BLI_path_join(dir, sizeof(dir), rel_subdir, entry->relpath); MEM_freeN(entry->relpath); entry->relpath = BLI_strdup(dir + 2); /* + 2 to remove '//' * added by BLI_path_rel to rel_subdir. */ @@ -3535,8 +3554,8 @@ static void filelist_readjob_recursive_dir_add_items(const bool do_lib, if (filelist_readjob_should_recurse_into_entry( max_recursion, is_lib, recursion_level, entry)) { /* We have a directory we want to list, add it to todo list! */ - BLI_join_dirfile(dir, sizeof(dir), root, entry->relpath); - BLI_path_normalize_dir(job_params->main_name, dir); + BLI_path_join(dir, sizeof(dir), root, entry->relpath); + BLI_path_normalize_dir(job_params->main_name, dir, sizeof(dir)); td_dir = static_cast<TodoDir *>(BLI_stack_push_r(todo_dirs)); td_dir->level = recursion_level + 1; td_dir->dir = BLI_strdup(dir); diff --git a/source/blender/editors/space_file/filesel.c b/source/blender/editors/space_file/filesel.c index 9ebc4872544..af2c9d4e757 100644 --- a/source/blender/editors/space_file/filesel.c +++ b/source/blender/editors/space_file/filesel.c @@ -197,7 +197,7 @@ static FileSelectParams *fileselect_ensure_updated_file_params(SpaceFile *sfile) } if (params->dir[0]) { - BLI_path_normalize_dir(blendfile_path, params->dir); + BLI_path_normalize_dir(blendfile_path, params->dir, sizeof(params->dir)); BLI_path_abs(params->dir, blendfile_path); } @@ -1174,7 +1174,7 @@ int autocomplete_directory(struct bContext *C, char *str, void *UNUSED(arg_v)) char path[FILE_MAX]; BLI_stat_t status; - BLI_join_dirfile(path, sizeof(path), dirname, de->d_name); + BLI_path_join(path, sizeof(path), dirname, de->d_name); if (BLI_stat(path, &status) == 0) { if (S_ISDIR(status.st_mode)) { /* is subdir */ @@ -1187,7 +1187,7 @@ int autocomplete_directory(struct bContext *C, char *str, void *UNUSED(arg_v)) match = UI_autocomplete_end(autocpl, str); if (match == AUTOCOMPLETE_FULL_MATCH) { - BLI_path_slash_ensure(str); + BLI_path_slash_ensure(str, FILE_MAX); } } } diff --git a/source/blender/editors/space_file/fsmenu.c b/source/blender/editors/space_file/fsmenu.c index 35ce7ef364c..cea53908d4f 100644 --- a/source/blender/editors/space_file/fsmenu.c +++ b/source/blender/editors/space_file/fsmenu.c @@ -113,10 +113,10 @@ static GHash *fsmenu_xdg_user_dirs_parse(const char *home) char filepath[FILE_MAX]; const char *xdg_config_home = getenv("XDG_CONFIG_HOME"); if (xdg_config_home != NULL) { - BLI_path_join(filepath, sizeof(filepath), xdg_config_home, "user-dirs.dirs", NULL); + BLI_path_join(filepath, sizeof(filepath), xdg_config_home, "user-dirs.dirs"); } else { - BLI_path_join(filepath, sizeof(filepath), home, ".config", "user-dirs.dirs", NULL); + BLI_path_join(filepath, sizeof(filepath), home, ".config", "user-dirs.dirs"); } fp = BLI_fopen(filepath, "r"); if (!fp) { @@ -147,7 +147,7 @@ static GHash *fsmenu_xdg_user_dirs_parse(const char *home) * Based on the 'user-dirs.dirs' man page, * there is no need to resolve arbitrary environment variables. */ if (STRPREFIX(l_value, "$HOME" SEP_STR)) { - BLI_path_join(l_value_expanded, sizeof(l_value_expanded), home, l_value + 6, NULL); + BLI_path_join(l_value_expanded, sizeof(l_value_expanded), home, l_value + 6); l_value_final = l_value_expanded; } @@ -186,7 +186,7 @@ static void fsmenu_xdg_insert_entry(GHash *xdg_map, char xdg_path_buf[FILE_MAXDIR]; const char *xdg_path = xdg_map ? BLI_ghash_lookup(xdg_map, key) : NULL; if (xdg_path == NULL) { - BLI_path_join(xdg_path_buf, sizeof(xdg_path_buf), home, default_path, NULL); + BLI_path_join(xdg_path_buf, sizeof(xdg_path_buf), home, default_path); xdg_path = xdg_path_buf; } fsmenu_insert_entry( @@ -254,10 +254,10 @@ void ED_fsmenu_entry_set_path(struct FSMenuEntry *fsentry, const char *path) fsentry->path = (path && path[0]) ? BLI_strdup(path) : NULL; - BLI_join_dirfile(tmp_name, - sizeof(tmp_name), - BKE_appdir_folder_id_create(BLENDER_USER_CONFIG, NULL), - BLENDER_BOOKMARK_FILE); + BLI_path_join(tmp_name, + sizeof(tmp_name), + BKE_appdir_folder_id_create(BLENDER_USER_CONFIG, NULL), + BLENDER_BOOKMARK_FILE); fsmenu_write_file(ED_fsmenu_get(), tmp_name); } } @@ -318,10 +318,10 @@ void ED_fsmenu_entry_set_name(struct FSMenuEntry *fsentry, const char *name) BLI_strncpy(fsentry->name, name, sizeof(fsentry->name)); } - BLI_join_dirfile(tmp_name, - sizeof(tmp_name), - BKE_appdir_folder_id_create(BLENDER_USER_CONFIG, NULL), - BLENDER_BOOKMARK_FILE); + BLI_path_join(tmp_name, + sizeof(tmp_name), + BKE_appdir_folder_id_create(BLENDER_USER_CONFIG, NULL), + BLENDER_BOOKMARK_FILE); fsmenu_write_file(ED_fsmenu_get(), tmp_name); } } @@ -983,7 +983,7 @@ void fsmenu_read_system(struct FSMenu *fsmenu, int read_bookmarks) if (xdg_runtime_dir != NULL) { struct direntry *dirs; char name[FILE_MAX]; - BLI_join_dirfile(name, sizeof(name), xdg_runtime_dir, "gvfs/"); + BLI_path_join(name, sizeof(name), xdg_runtime_dir, "gvfs/"); const uint dirs_num = BLI_filelist_dir_contents(name, &dirs); for (uint i = 0; i < dirs_num; i++) { if (dirs[i].type & S_IFDIR) { diff --git a/source/blender/editors/space_file/space_file.c b/source/blender/editors/space_file/space_file.c index a3182222263..74f1b8e838a 100644 --- a/source/blender/editors/space_file/space_file.c +++ b/source/blender/editors/space_file/space_file.c @@ -1157,7 +1157,7 @@ void ED_file_read_bookmarks(void) if (cfgdir) { char name[FILE_MAX]; - BLI_join_dirfile(name, sizeof(name), cfgdir, BLENDER_BOOKMARK_FILE); + BLI_path_join(name, sizeof(name), cfgdir, BLENDER_BOOKMARK_FILE); fsmenu_read_bookmarks(ED_fsmenu_get(), name); } } diff --git a/source/blender/editors/space_graph/graph_draw.c b/source/blender/editors/space_graph/graph_draw.c index 41a8368152d..f8a0dff3a41 100644 --- a/source/blender/editors/space_graph/graph_draw.c +++ b/source/blender/editors/space_graph/graph_draw.c @@ -1446,7 +1446,7 @@ void graph_draw_channel_names(bContext *C, bAnimContext *ac, ARegion *region) GPU_blend(GPU_BLEND_NONE); } - /* free tempolary channels */ + /* Free temporary channels. */ ANIM_animdata_freelist(&anim_data); } diff --git a/source/blender/editors/space_image/image_sequence.c b/source/blender/editors/space_image/image_sequence.c index 7108c258665..d2725652979 100644 --- a/source/blender/editors/space_image/image_sequence.c +++ b/source/blender/editors/space_image/image_sequence.c @@ -62,14 +62,14 @@ static void image_sequence_get_frame_ranges(wmOperator *op, ListBase *ranges) STREQLEN(base_tail, tail, FILE_MAX)) { /* Set filepath to first frame in the range. */ if (frame->framenr < range_first_frame) { - BLI_join_dirfile(range->filepath, sizeof(range->filepath), dir, filename); + BLI_path_join(range->filepath, sizeof(range->filepath), dir, filename); range_first_frame = frame->framenr; } } else { /* start a new frame range */ range = MEM_callocN(sizeof(*range), __func__); - BLI_join_dirfile(range->filepath, sizeof(range->filepath), dir, filename); + BLI_path_join(range->filepath, sizeof(range->filepath), dir, filename); BLI_addtail(ranges, range); BLI_strncpy(base_head, head, sizeof(base_head)); diff --git a/source/blender/editors/space_info/textview.c b/source/blender/editors/space_info/textview.c index aee72860a0a..12ee6f45991 100644 --- a/source/blender/editors/space_info/textview.c +++ b/source/blender/editors/space_info/textview.c @@ -235,7 +235,8 @@ static bool textview_draw_string(TextViewDrawState *tds, 1.0f, 0.0f, icon_fg, - false); + false, + UI_NO_ICON_OVERLAY_TEXT); GPU_blend(GPU_BLEND_NONE); } diff --git a/source/blender/editors/space_nla/nla_draw.c b/source/blender/editors/space_nla/nla_draw.c index f57c9fead56..45bbe50eedd 100644 --- a/source/blender/editors/space_nla/nla_draw.c +++ b/source/blender/editors/space_nla/nla_draw.c @@ -905,7 +905,7 @@ void draw_nla_main_data(bAnimContext *ac, SpaceNla *snla, ARegion *region) } } - /* free tempolary channels */ + /* Free temporary channels. */ ANIM_animdata_freelist(&anim_data); } diff --git a/source/blender/editors/space_node/CMakeLists.txt b/source/blender/editors/space_node/CMakeLists.txt index d7eccbf0b68..ff9e5352d0a 100644 --- a/source/blender/editors/space_node/CMakeLists.txt +++ b/source/blender/editors/space_node/CMakeLists.txt @@ -29,6 +29,7 @@ set(INC set(SRC add_node_search.cc + add_menu_assets.cc drawnode.cc link_drag_search.cc node_add.cc diff --git a/source/blender/editors/space_node/add_menu_assets.cc b/source/blender/editors/space_node/add_menu_assets.cc new file mode 100644 index 00000000000..1ba1d67d854 --- /dev/null +++ b/source/blender/editors/space_node/add_menu_assets.cc @@ -0,0 +1,314 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +#include "BLI_multi_value_map.hh" + +#include "DNA_screen_types.h" +#include "DNA_space_types.h" + +#include "BKE_asset.h" +#include "BKE_asset_catalog.hh" +#include "BKE_asset_library.hh" +#include "BKE_idprop.h" +#include "BKE_screen.h" + +#include "BLT_translation.h" + +#include "RNA_access.h" +#include "RNA_prototypes.h" + +#include "ED_asset.h" +#include "ED_screen.h" + +#include "node_intern.hh" + +namespace blender::ed::space_node { + +static bool node_add_menu_poll(const bContext *C, MenuType * /*mt*/) +{ + return CTX_wm_space_node(C); +} + +static void node_add_menu_assets_listen_fn(const wmRegionListenerParams *params) +{ + const wmNotifier *wmn = params->notifier; + ARegion *region = params->region; + + switch (wmn->category) { + case NC_ASSET: + if (wmn->data == ND_ASSET_LIST_READING) { + ED_region_tag_refresh_ui(region); + } + break; + } +} + +struct LibraryAsset { + AssetLibraryReference library_ref; + AssetHandle handle; +}; + +struct LibraryCatalog { + bke::AssetLibrary *library; + const bke::AssetCatalog *catalog; +}; + +struct AssetItemTree { + bke::AssetCatalogTree catalogs; + MultiValueMap<bke::AssetCatalogPath, LibraryAsset> assets_per_path; + Map<const bke::AssetCatalogTreeItem *, bke::AssetCatalogPath> full_catalog_per_tree_item; +}; + +static bool all_loading_finished() +{ + for (const AssetLibraryReference &library : bke::all_valid_asset_library_refs()) { + if (!ED_assetlist_is_loaded(&library)) { + return false; + } + } + return true; +} + +static AssetItemTree build_catalog_tree(const bContext &C, const bNodeTree *node_tree) +{ + if (!node_tree) { + return {}; + } + const Main &bmain = *CTX_data_main(&C); + const Vector<AssetLibraryReference> all_libraries = bke::all_valid_asset_library_refs(); + + /* Merge catalogs from all libraries to deduplicate menu items. Also store the catalog and + * library for each asset ID in order to use them later when retrieving assets and removing + * empty catalogs. */ + Map<bke::CatalogID, LibraryCatalog> id_to_catalog_map; + bke::AssetCatalogTree catalogs_from_all_libraries; + for (const AssetLibraryReference &library_ref : all_libraries) { + if (bke::AssetLibrary *library = BKE_asset_library_load(&bmain, library_ref)) { + if (bke::AssetCatalogTree *tree = library->catalog_service->get_catalog_tree()) { + tree->foreach_item([&](bke::AssetCatalogTreeItem &item) { + const bke::CatalogID &id = item.get_catalog_id(); + bke::AssetCatalog *catalog = library->catalog_service->find_catalog(id); + catalogs_from_all_libraries.insert_item(*catalog); + id_to_catalog_map.add(item.get_catalog_id(), LibraryCatalog{library, catalog}); + }); + } + } + } + + /* Find all the matching node group assets for every catalog path. */ + MultiValueMap<bke::AssetCatalogPath, LibraryAsset> assets_per_path; + for (const AssetLibraryReference &library_ref : all_libraries) { + AssetFilterSettings type_filter{}; + type_filter.id_types = FILTER_ID_NT; + + ED_assetlist_storage_fetch(&library_ref, &C); + ED_assetlist_ensure_previews_job(&library_ref, &C); + ED_assetlist_iterate(library_ref, [&](AssetHandle asset) { + if (!ED_asset_filter_matches_asset(&type_filter, &asset)) { + return true; + } + const AssetMetaData &meta_data = *ED_asset_handle_get_metadata(&asset); + const IDProperty *tree_type = BKE_asset_metadata_idprop_find(&meta_data, "type"); + if (tree_type == nullptr || IDP_Int(tree_type) != node_tree->type) { + return true; + } + if (BLI_uuid_is_nil(meta_data.catalog_id)) { + return true; + } + const LibraryCatalog &library_catalog = id_to_catalog_map.lookup(meta_data.catalog_id); + assets_per_path.add(library_catalog.catalog->path, LibraryAsset{library_ref, asset}); + return true; + }); + } + + /* Build the final tree without any of the catalogs that don't have proper node group assets. */ + bke::AssetCatalogTree catalogs_with_node_assets; + catalogs_from_all_libraries.foreach_item([&](bke::AssetCatalogTreeItem &item) { + if (!assets_per_path.lookup(item.catalog_path()).is_empty()) { + const bke::CatalogID &id = item.get_catalog_id(); + const LibraryCatalog &library_catalog = id_to_catalog_map.lookup(id); + bke::AssetCatalog *catalog = library_catalog.library->catalog_service->find_catalog(id); + catalogs_with_node_assets.insert_item(*catalog); + } + }); + + /* Build another map storing full asset paths for each tree item, in order to have stable + * pointers to asset catalog paths to use for context pointers. This is necessary because + * #bke::AssetCatalogTreeItem doesn't store its full path directly. */ + Map<const bke::AssetCatalogTreeItem *, bke::AssetCatalogPath> full_catalog_per_tree_item; + catalogs_with_node_assets.foreach_item([&](bke::AssetCatalogTreeItem &item) { + full_catalog_per_tree_item.add_new(&item, item.catalog_path()); + }); + + return {std::move(catalogs_with_node_assets), + std::move(assets_per_path), + std::move(full_catalog_per_tree_item)}; +} + +static void node_add_catalog_assets_draw(const bContext *C, Menu *menu) +{ + bScreen &screen = *CTX_wm_screen(C); + const SpaceNode &snode = *CTX_wm_space_node(C); + if (!snode.runtime->assets_for_menu) { + BLI_assert_unreachable(); + return; + } + AssetItemTree &tree = *snode.runtime->assets_for_menu; + const bNodeTree *edit_tree = snode.edittree; + if (!edit_tree) { + return; + } + + const PointerRNA menu_path_ptr = CTX_data_pointer_get(C, "asset_catalog_path"); + if (RNA_pointer_is_null(&menu_path_ptr)) { + return; + } + const bke::AssetCatalogPath &menu_path = *static_cast<const bke::AssetCatalogPath *>( + menu_path_ptr.data); + + const Span<LibraryAsset> asset_items = tree.assets_per_path.lookup(menu_path); + bke::AssetCatalogTreeItem *catalog_item = tree.catalogs.find_item(menu_path); + BLI_assert(catalog_item != nullptr); + + if (asset_items.is_empty() && !catalog_item->has_children()) { + return; + } + + uiLayout *layout = menu->layout; + uiItemS(layout); + + for (const LibraryAsset &item : asset_items) { + uiLayout *col = uiLayoutColumn(layout, false); + PointerRNA file{ + &screen.id, &RNA_FileSelectEntry, const_cast<FileDirEntry *>(item.handle.file_data)}; + uiLayoutSetContextPointer(col, "active_file", &file); + + PointerRNA library_ptr{&screen.id, + &RNA_AssetLibraryReference, + const_cast<AssetLibraryReference *>(&item.library_ref)}; + uiLayoutSetContextPointer(col, "asset_library_ref", &library_ptr); + + uiItemO(col, ED_asset_handle_get_name(&item.handle), ICON_NONE, "NODE_OT_add_group_asset"); + } + + catalog_item->foreach_child([&](bke::AssetCatalogTreeItem &child_item) { + const bke::AssetCatalogPath &path = tree.full_catalog_per_tree_item.lookup(&child_item); + PointerRNA path_ptr{ + &screen.id, &RNA_AssetCatalogPath, const_cast<bke::AssetCatalogPath *>(&path)}; + uiLayout *col = uiLayoutColumn(layout, false); + uiLayoutSetContextPointer(col, "asset_catalog_path", &path_ptr); + uiItemM(col, "NODE_MT_node_add_catalog_assets", path.name().c_str(), ICON_NONE); + }); +} + +static void add_root_catalogs_draw(const bContext *C, Menu *menu) +{ + bScreen &screen = *CTX_wm_screen(C); + SpaceNode &snode = *CTX_wm_space_node(C); + const bNodeTree *edit_tree = snode.edittree; + uiLayout *layout = menu->layout; + + snode.runtime->assets_for_menu = std::make_shared<AssetItemTree>( + build_catalog_tree(*C, edit_tree)); + + const bool loading_finished = all_loading_finished(); + + AssetItemTree &tree = *snode.runtime->assets_for_menu; + if (tree.catalogs.is_empty() && loading_finished) { + return; + } + + uiItemS(layout); + + if (!loading_finished) { + uiItemL(layout, IFACE_("Loading Asset Libraries"), ICON_INFO); + } + + /* Avoid adding a separate root catalog when the assets have already been added to one of the + * builtin menus. + * TODO: The need to define the builtin menu labels here is completely non-ideal. We don't have + * any UI introspection that can do this though. This can be solved in the near future by + * removing the need to define the add menu completely, instead using a per-node-type path which + * can be merged with catalog tree. + */ + static Set<std::string> all_builtin_menus = []() { + Set<std::string> menus; + menus.add_new("Attribute"); + menus.add_new("Color"); + menus.add_new("Curve"); + menus.add_new("Curve Primitives"); + menus.add_new("Curve Topology"); + menus.add_new("Geometry"); + menus.add_new("Input"); + menus.add_new("Instances"); + menus.add_new("Material"); + menus.add_new("Mesh"); + menus.add_new("Mesh Primitives"); + menus.add_new("Mesh Topology"); + menus.add_new("Output"); + menus.add_new("Point"); + menus.add_new("Text"); + menus.add_new("Texture"); + menus.add_new("Utilities"); + menus.add_new("UV"); + menus.add_new("Vector"); + menus.add_new("Volume"); + menus.add_new("Group"); + menus.add_new("Layout"); + return menus; + }(); + + tree.catalogs.foreach_root_item([&](bke::AssetCatalogTreeItem &item) { + if (all_builtin_menus.contains(item.get_name())) { + return; + } + const bke::AssetCatalogPath &path = tree.full_catalog_per_tree_item.lookup(&item); + PointerRNA path_ptr{ + &screen.id, &RNA_AssetCatalogPath, const_cast<bke::AssetCatalogPath *>(&path)}; + uiLayout *col = uiLayoutColumn(layout, false); + uiLayoutSetContextPointer(col, "asset_catalog_path", &path_ptr); + uiItemM(col, "NODE_MT_node_add_catalog_assets", path.name().c_str(), ICON_NONE); + }); +} + +MenuType add_catalog_assets_menu_type() +{ + MenuType type{}; + BLI_strncpy(type.idname, "NODE_MT_node_add_catalog_assets", sizeof(type.idname)); + type.poll = node_add_menu_poll; + type.draw = node_add_catalog_assets_draw; + type.listener = node_add_menu_assets_listen_fn; + return type; +} + +MenuType add_root_catalogs_menu_type() +{ + MenuType type{}; + BLI_strncpy(type.idname, "NODE_MT_node_add_root_catalogs", sizeof(type.idname)); + type.poll = node_add_menu_poll; + type.draw = add_root_catalogs_draw; + type.listener = node_add_menu_assets_listen_fn; + return type; +} + +} // namespace blender::ed::space_node + +/* Note: This is only necessary because Python can't set an asset catalog path context item. */ +void uiTemplateNodeAssetMenuItems(uiLayout *layout, bContext *C, const char *catalog_path) +{ + using namespace blender; + using namespace blender::ed::space_node; + bScreen &screen = *CTX_wm_screen(C); + SpaceNode &snode = *CTX_wm_space_node(C); + AssetItemTree &tree = *snode.runtime->assets_for_menu; + const bke::AssetCatalogTreeItem *item = tree.catalogs.find_root_item(catalog_path); + if (!item) { + return; + } + const bke::AssetCatalogPath &path = tree.full_catalog_per_tree_item.lookup(item); + PointerRNA path_ptr{ + &screen.id, &RNA_AssetCatalogPath, const_cast<bke::AssetCatalogPath *>(&path)}; + uiItemS(layout); + uiLayout *col = uiLayoutColumn(layout, false); + uiLayoutSetContextPointer(col, "asset_catalog_path", &path_ptr); + uiItemMContents(col, "NODE_MT_node_add_catalog_assets"); +} diff --git a/source/blender/editors/space_node/node_add.cc b/source/blender/editors/space_node/node_add.cc index 07eecff320a..41f70a6d8cf 100644 --- a/source/blender/editors/space_node/node_add.cc +++ b/source/blender/editors/space_node/node_add.cc @@ -30,6 +30,7 @@ #include "DEG_depsgraph_build.h" +#include "ED_asset.h" #include "ED_node.h" /* own include */ #include "ED_render.h" #include "ED_screen.h" @@ -244,38 +245,36 @@ void NODE_OT_add_reroute(wmOperatorType *ot) /** \name Add Node Group Operator * \{ */ -static bNodeTree *node_add_group_get_and_poll_group_node_tree(Main *bmain, - wmOperator *op, - bNodeTree *ntree) +static bool node_group_add_poll(const bNodeTree &node_tree, + const bNodeTree &node_group, + ReportList &reports) { - bNodeTree *node_group = reinterpret_cast<bNodeTree *>( - WM_operator_properties_id_lookup_from_name_or_session_uuid(bmain, op->ptr, ID_NT)); - if (!node_group) { - return nullptr; + if (node_group.type != node_tree.type) { + return false; } const char *disabled_hint = nullptr; - if ((node_group->type != ntree->type) || !nodeGroupPoll(ntree, node_group, &disabled_hint)) { + if (!nodeGroupPoll(&node_tree, &node_group, &disabled_hint)) { if (disabled_hint) { - BKE_reportf(op->reports, + BKE_reportf(&reports, RPT_ERROR, "Can not add node group '%s' to '%s':\n %s", - node_group->id.name + 2, - ntree->id.name + 2, + node_group.id.name + 2, + node_tree.id.name + 2, disabled_hint); } else { - BKE_reportf(op->reports, + BKE_reportf(&reports, RPT_ERROR, "Can not add node group '%s' to '%s'", - node_group->id.name + 2, - ntree->id.name + 2); + node_group.id.name + 2, + node_tree.id.name + 2); } - return nullptr; + return false; } - return node_group; + return true; } static int node_add_group_exec(bContext *C, wmOperator *op) @@ -284,10 +283,14 @@ static int node_add_group_exec(bContext *C, wmOperator *op) SpaceNode *snode = CTX_wm_space_node(C); bNodeTree *ntree = snode->edittree; - bNodeTree *node_group = node_add_group_get_and_poll_group_node_tree(bmain, op, ntree); + bNodeTree *node_group = reinterpret_cast<bNodeTree *>( + WM_operator_properties_id_lookup_from_name_or_session_uuid(bmain, op->ptr, ID_NT)); if (!node_group) { return OPERATOR_CANCELLED; } + if (!node_group_add_poll(*ntree, *node_group, *op->reports)) { + return OPERATOR_CANCELLED; + } ED_preview_kill_jobs(CTX_wm_manager(C), CTX_data_main(C)); @@ -320,9 +323,8 @@ static bool node_add_group_poll(bContext *C) } const SpaceNode *snode = CTX_wm_space_node(C); if (snode->edittree->type == NTREE_CUSTOM) { - CTX_wm_operator_poll_msg_set(C, - "This node editor displays a custom (Python defined) node tree. " - "Dropping node groups isn't supported for this"); + CTX_wm_operator_poll_msg_set( + C, "Adding node groups isn't supported for custom (Python defined) node trees"); return false; } return true; @@ -367,6 +369,105 @@ void NODE_OT_add_group(wmOperatorType *ot) /** \} */ /* -------------------------------------------------------------------- */ +/** \name Add Node Group Asset Operator + * \{ */ + +static bool add_node_group_asset(const bContext &C, + const AssetLibraryReference &library_ref, + const AssetHandle asset, + ReportList &reports) +{ + Main &bmain = *CTX_data_main(&C); + SpaceNode &snode = *CTX_wm_space_node(&C); + bNodeTree &edit_tree = *snode.edittree; + + bNodeTree *node_group = reinterpret_cast<bNodeTree *>( + asset::get_local_id_from_asset_or_append_and_reuse(bmain, library_ref, asset)); + if (!node_group) { + return false; + } + if (!node_group_add_poll(edit_tree, *node_group, reports)) { + /* Remove the node group if it was newly appended but can't be added to the tree. */ + id_us_plus(&node_group->id); + BKE_id_free_us(&bmain, node_group); + return false; + } + + ED_preview_kill_jobs(CTX_wm_manager(&C), CTX_data_main(&C)); + + bNode *group_node = add_node( + C, ntreeTypeFind(node_group->idname)->group_idname, snode.runtime->cursor); + if (!group_node) { + BKE_report(&reports, RPT_WARNING, "Could not add node group"); + return false; + } + /* By default, don't show the data-block selector since it's not usually necessary for assets. */ + group_node->flag &= ~NODE_OPTIONS; + + group_node->id = &node_group->id; + id_us_plus(group_node->id); + BKE_ntree_update_tag_node_property(&edit_tree, group_node); + + nodeSetActive(&edit_tree, group_node); + ED_node_tree_propagate_change(&C, &bmain, nullptr); + DEG_relations_tag_update(&bmain); + + return true; +} + +static int node_add_group_asset_invoke(bContext *C, wmOperator *op, const wmEvent *event) +{ + ARegion ®ion = *CTX_wm_region(C); + SpaceNode &snode = *CTX_wm_space_node(C); + + const AssetLibraryReference *library_ref = CTX_wm_asset_library_ref(C); + if (!library_ref) { + return OPERATOR_CANCELLED; + } + bool is_valid; + const AssetHandle handle = CTX_wm_asset_handle(C, &is_valid); + if (!is_valid) { + return OPERATOR_CANCELLED; + } + + /* Convert mouse coordinates to v2d space. */ + UI_view2d_region_to_view(®ion.v2d, + event->mval[0], + event->mval[1], + &snode.runtime->cursor[0], + &snode.runtime->cursor[1]); + + snode.runtime->cursor /= UI_DPI_FAC; + + if (!add_node_group_asset(*C, *library_ref, handle, *op->reports)) { + return OPERATOR_CANCELLED; + } + + wmOperatorType *ot = WM_operatortype_find("NODE_OT_translate_attach_remove_on_cancel", true); + BLI_assert(ot); + PointerRNA ptr; + WM_operator_properties_create_ptr(&ptr, ot); + WM_operator_name_call_ptr(C, ot, WM_OP_INVOKE_DEFAULT, &ptr, nullptr); + WM_operator_properties_free(&ptr); + + return OPERATOR_FINISHED; +} + +void NODE_OT_add_group_asset(wmOperatorType *ot) +{ + ot->name = "Add Node Group Asset"; + ot->description = "Add a node group asset to the active node tree"; + ot->idname = "NODE_OT_add_group_asset"; + + ot->invoke = node_add_group_asset_invoke; + ot->poll = node_add_group_poll; + + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL; +} + +/** \} */ + +/* -------------------------------------------------------------------- */ /** \name Add Node Object Operator * \{ */ @@ -393,7 +494,7 @@ static int node_add_object_exec(bContext *C, wmOperator *op) bNodeSocket *sock = nodeFindSocket(object_node, SOCK_IN, "Object"); if (!sock) { - BKE_report(op->reports, RPT_WARNING, "Could not find node object socket"); + BLI_assert_unreachable(); return OPERATOR_CANCELLED; } diff --git a/source/blender/editors/space_node/node_draw.cc b/source/blender/editors/space_node/node_draw.cc index ee9ebd541a0..5ae6573df7c 100644 --- a/source/blender/editors/space_node/node_draw.cc +++ b/source/blender/editors/space_node/node_draw.cc @@ -2145,6 +2145,9 @@ static void node_draw_basis(const bContext &C, 0, ""); UI_but_func_set(but, node_toggle_button_cb, &node, (void *)"NODE_OT_group_edit"); + if (node.id) { + UI_but_icon_indicator_number_set(but, ID_REAL_USERS(node.id)); + } UI_block_emboss_set(&block, UI_EMBOSS); } if (node.type == NODE_CUSTOM && node.typeinfo->ui_icon != ICON_NONE) { diff --git a/source/blender/editors/space_node/node_edit.cc b/source/blender/editors/space_node/node_edit.cc index b01be5ff234..48b3d711bdf 100644 --- a/source/blender/editors/space_node/node_edit.cc +++ b/source/blender/editors/space_node/node_edit.cc @@ -2299,6 +2299,7 @@ static int node_clipboard_copy_exec(bContext *C, wmOperator * /*op*/) newlink->tosock = socket_map.lookup(link->tosock); newlink->fromnode = node_map.lookup(link->fromnode); newlink->fromsock = socket_map.lookup(link->fromsock); + newlink->multi_input_socket_index = link->multi_input_socket_index; BKE_node_clipboard_add_link(newlink); } @@ -2420,11 +2421,19 @@ static int node_clipboard_paste_exec(bContext *C, wmOperator *op) } LISTBASE_FOREACH (bNodeLink *, link, clipboard_links_lb) { - nodeAddLink(ntree, - node_map.lookup(link->fromnode), - socket_map.lookup(link->fromsock), - node_map.lookup(link->tonode), - socket_map.lookup(link->tosock)); + bNodeLink *new_link = nodeAddLink(ntree, + node_map.lookup(link->fromnode), + socket_map.lookup(link->fromsock), + node_map.lookup(link->tonode), + socket_map.lookup(link->tosock)); + new_link->multi_input_socket_index = link->multi_input_socket_index; + } + + ntree->ensure_topology_cache(); + + for (bNode *new_node : node_map.values()) { + /* Update multi input socket indices in case all connected nodes weren't copied. */ + update_multi_input_indices_for_removed_links(*new_node); } Main *bmain = CTX_data_main(C); diff --git a/source/blender/editors/space_node/node_intern.hh b/source/blender/editors/space_node/node_intern.hh index 50c03489027..88be9a52c61 100644 --- a/source/blender/editors/space_node/node_intern.hh +++ b/source/blender/editors/space_node/node_intern.hh @@ -38,6 +38,8 @@ extern const char *node_context_dir[]; namespace blender::ed::space_node { +struct AssetItemTree; + /** Temporary data used in node link drag modal operator. */ struct bNodeLinkDrag { /** Links dragged by the operator. */ @@ -96,6 +98,15 @@ struct SpaceNode_Runtime { /* 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; + + /** + * Temporary data for node add menu in order to provide longer-term storage for context pointers. + * Recreated every time the root menu is opened. In the future this will be replaced with an "all + * libraries" cache in the asset system itself. + * + * Stored with a shared pointer so that it can be forward declared. + */ + std::shared_ptr<AssetItemTree> assets_for_menu; }; enum NodeResizeDirection { @@ -253,6 +264,7 @@ bNode *add_static_node(const bContext &C, int type, const float2 &location); void NODE_OT_add_reroute(wmOperatorType *ot); void NODE_OT_add_search(wmOperatorType *ot); void NODE_OT_add_group(wmOperatorType *ot); +void NODE_OT_add_group_asset(wmOperatorType *ot); void NODE_OT_add_object(wmOperatorType *ot); void NODE_OT_add_collection(wmOperatorType *ot); void NODE_OT_add_file(wmOperatorType *ot); @@ -270,6 +282,8 @@ void NODE_OT_group_edit(wmOperatorType *ot); /* node_relationships.cc */ +void update_multi_input_indices_for_removed_links(bNode &node); + void NODE_OT_link(wmOperatorType *ot); void NODE_OT_link_make(wmOperatorType *ot); void NODE_OT_links_cut(wmOperatorType *ot); @@ -381,4 +395,9 @@ void invoke_node_link_drag_add_menu(bContext &C, void invoke_add_node_search_menu(bContext &C, const float2 &cursor, bool use_transform); +/* add_menu_assets.cc */ + +MenuType add_catalog_assets_menu_type(); +MenuType add_root_catalogs_menu_type(); + } // namespace blender::ed::space_node diff --git a/source/blender/editors/space_node/node_ops.cc b/source/blender/editors/space_node/node_ops.cc index d45c33a3c59..104d1acf3b4 100644 --- a/source/blender/editors/space_node/node_ops.cc +++ b/source/blender/editors/space_node/node_ops.cc @@ -78,6 +78,7 @@ void node_operatortypes() WM_operatortype_append(NODE_OT_add_search); WM_operatortype_append(NODE_OT_add_group); + WM_operatortype_append(NODE_OT_add_group_asset); WM_operatortype_append(NODE_OT_add_object); WM_operatortype_append(NODE_OT_add_collection); WM_operatortype_append(NODE_OT_add_file); diff --git a/source/blender/editors/space_node/node_relationships.cc b/source/blender/editors/space_node/node_relationships.cc index f53eaf0f2bd..637c795d4d7 100644 --- a/source/blender/editors/space_node/node_relationships.cc +++ b/source/blender/editors/space_node/node_relationships.cc @@ -75,8 +75,6 @@ static void clear_picking_highlight(ListBase *links) } } -void update_multi_input_indices_for_removed_links(bNode &node); - /* -------------------------------------------------------------------- */ /** \name Add Node * \{ */ @@ -817,7 +815,8 @@ static void draw_draglink_tooltip(const bContext * /*C*/, ARegion * /*region*/, nldrag->cursor[0]; const float y = nldrag->cursor[1] - 2.0f * UI_DPI_FAC; - UI_icon_draw_ex(x, y, ICON_ADD, U.inv_dpi_fac, 1.0f, 0.0f, text_col, false); + UI_icon_draw_ex( + x, y, ICON_ADD, U.inv_dpi_fac, 1.0f, 0.0f, text_col, false, UI_NO_ICON_OVERLAY_TEXT); } static void draw_draglink_tooltip_activate(const ARegion ®ion, bNodeLinkDrag &nldrag) diff --git a/source/blender/editors/space_node/space_node.cc b/source/blender/editors/space_node/space_node.cc index ac49115959c..5754e77399f 100644 --- a/source/blender/editors/space_node/space_node.cc +++ b/source/blender/editors/space_node/space_node.cc @@ -1170,5 +1170,8 @@ void ED_spacetype_node() art->draw = node_toolbar_region_draw; BLI_addhead(&st->regiontypes, art); + WM_menutype_add(MEM_new<MenuType>(__func__, add_catalog_assets_menu_type())); + WM_menutype_add(MEM_new<MenuType>(__func__, add_root_catalogs_menu_type())); + BKE_spacetype_register(st); } diff --git a/source/blender/editors/space_outliner/outliner_draw.cc b/source/blender/editors/space_outliner/outliner_draw.cc index 34d1e1bb546..699dd6d4844 100644 --- a/source/blender/editors/space_outliner/outliner_draw.cc +++ b/source/blender/editors/space_outliner/outliner_draw.cc @@ -2877,7 +2877,8 @@ static bool tselem_draw_icon(uiBlock *block, TreeStoreElem *tselem, TreeElement *te, float alpha, - const bool is_clickable) + const bool is_clickable, + const int num_elements) { TreeElementIcon data = tree_element_get_icon(tselem, te); if (data.icon == 0) { @@ -2885,6 +2886,8 @@ static bool tselem_draw_icon(uiBlock *block, } const bool is_collection = outliner_is_collection_tree_element(te); + IconTextOverlay text_overlay; + UI_icon_text_overlay_init_from_count(&text_overlay, num_elements); /* Collection colors and icons covered by restrict buttons. */ if (!is_clickable || x >= xmax || is_collection) { @@ -2904,7 +2907,8 @@ static bool tselem_draw_icon(uiBlock *block, alpha, 0.0f, btheme->collection_color[collection->color_tag].color, - true); + true, + &text_overlay); return true; } } @@ -2915,10 +2919,10 @@ static bool tselem_draw_icon(uiBlock *block, /* Restrict column clip. it has been coded by simply overdrawing, doesn't work for buttons. */ uchar color[4]; if (UI_icon_get_theme_color(data.icon, color)) { - UI_icon_draw_ex(x, y, data.icon, U.inv_dpi_fac, alpha, 0.0f, color, true); + UI_icon_draw_ex(x, y, data.icon, U.inv_dpi_fac, alpha, 0.0f, color, true, &text_overlay); } else { - UI_icon_draw_ex(x, y, data.icon, U.inv_dpi_fac, alpha, 0.0f, nullptr, false); + UI_icon_draw_ex(x, y, data.icon, U.inv_dpi_fac, alpha, 0.0f, nullptr, false, &text_overlay); } } else { @@ -2941,104 +2945,6 @@ static bool tselem_draw_icon(uiBlock *block, return true; } -static bool outliner_is_main_row(const ARegion *region, const int ys) -{ - int ystart; - - ystart = int(region->v2d.tot.ymax); - ystart = UI_UNIT_Y * (ystart / (UI_UNIT_Y)) - OL_Y_OFFSET; - - return ((ys - ystart) / UI_UNIT_Y) % 2; -} - -/** - * Get the expected row background color to use for the data-block counter - * - * This reproduces somes of the logic of outliner_draw_highlights. - * At the moment it doesn't implement the search match color since - * we don't draw the data-block counter in those cases. - */ -static void outliner_get_row_color(const ARegion *region, - const TreeElement *te, - int ys, - float r_color[4]) -{ - const TreeStoreElem *tselem = TREESTORE(te); - - if ((tselem->flag & TSE_ACTIVE) && (tselem->flag & TSE_SELECTED)) { - UI_GetThemeColor3fv(TH_ACTIVE, r_color); - } - else if (tselem->flag & TSE_SELECTED) { - UI_GetThemeColor3fv(TH_SELECT_HIGHLIGHT, r_color); - } - else if (outliner_is_main_row(region, ys)) { - UI_GetThemeColor3fv(TH_BACK, r_color); - } - else { - float color_alternating[4]; - UI_GetThemeColor4fv(TH_ROW_ALTERNATE, color_alternating); - UI_GetThemeColorBlend3f(TH_BACK, TH_ROW_ALTERNATE, color_alternating[3], r_color); - } - - if (tselem->flag & TSE_HIGHLIGHTED) { - const float color_highlight[4] = {1.0f, 1.0f, 1.0f, 0.13f}; - interp_v3_v3v3(r_color, r_color, color_highlight, color_highlight[3]); - } - r_color[3] = 1.0f; -} - -/** - * For icon-only children of a collapsed tree, - * Draw small number over the icon to show how many items of this type are displayed. - */ -static void outliner_draw_iconrow_number(const ARegion *region, - const uiFontStyle *fstyle, - int offsx, - int ys, - const TreeElement *te_visible, - const int num_elements) -{ - float color[4]; - outliner_get_row_color(region, te_visible, ys, color); - - float ufac = 0.25f * UI_UNIT_X; - float offset_x = float(offsx) + UI_UNIT_X * 0.35f; - rctf rect{}; - BLI_rctf_init(&rect, - offset_x + ufac, - offset_x + UI_UNIT_X - ufac, - float(ys) - UI_UNIT_Y * 0.2f + ufac, - float(ys) - UI_UNIT_Y * 0.2f + UI_UNIT_Y - ufac); - - UI_draw_roundbox_corner_set(UI_CNR_ALL); - UI_draw_roundbox_4fv_ex( - &rect, color, NULL, 1.0f, color, U.pixelsize, float(UI_UNIT_Y) / 2.0f - ufac); - - /* Now the numbers. */ - uchar text_col[4]; - - UI_GetThemeColor3ubv(TH_TEXT, text_col); - text_col[3] = 255; - - uiFontStyle fstyle_small = *fstyle; - fstyle_small.points *= 0.8f; - - /* We treat +99 as 4 digits to make sure the (eyeballed) alignment looks nice. */ - int num_digits = 4; - char number_text[4] = "+99"; - if (num_elements < 100) { - BLI_snprintf(number_text, sizeof(number_text), "%d", num_elements); - num_digits = num_elements < 10 ? 1 : 2; - } - UI_fontstyle_draw_simple(&fstyle_small, - (offset_x + ufac + UI_UNIT_X * (2 - num_digits) * 0.12f), - float(ys) - UI_UNIT_Y * 0.095f + ufac, - number_text, - text_col); - UI_fontstyle_set(fstyle); - GPU_blend(GPU_BLEND_ALPHA); /* Round-box and text drawing disables. */ -} - static void outliner_icon_background_colors(float icon_color[4], float icon_border[4]) { float text[4]; @@ -3069,11 +2975,8 @@ static void outliner_draw_active_indicator(const float minx, GPU_blend(GPU_BLEND_ALPHA); /* Round-box disables. */ } -static void outliner_draw_iconrow_doit(const ARegion *region, - uiBlock *block, - TreeElement *te_visible, +static void outliner_draw_iconrow_doit(uiBlock *block, TreeElement *te, - const uiFontStyle *fstyle, int xmax, int *offsx, int ys, @@ -3102,13 +3005,13 @@ static void outliner_draw_iconrow_doit(const ARegion *region, if (tselem->flag & TSE_HIGHLIGHTED_ICON) { alpha_fac += 0.5; } - tselem_draw_icon(block, xmax, float(*offsx), float(ys), tselem, te, alpha_fac, false); + tselem_draw_icon( + block, xmax, float(*offsx), float(ys), tselem, te, alpha_fac, false, num_elements); te->xs = *offsx; te->ys = ys; te->xend = short(*offsx) + UI_UNIT_X; if (num_elements > 1) { - outliner_draw_iconrow_number(region, fstyle, *offsx, ys, te_visible, num_elements); te->flag |= TE_ICONROW_MERGED; } else { @@ -3145,16 +3048,15 @@ static void outliner_draw_iconrow(bContext *C, const uiFontStyle *fstyle, const TreeViewContext *tvc, SpaceOutliner *space_outliner, - TreeElement *te_visible, ListBase *lb, int level, int xmax, int *offsx, int ys, float alpha_fac, + bool in_bone_hierarchy, MergedIconRow *merged) { - const ARegion *region = CTX_wm_region(C); eOLDrawState active = OL_DRAWSEL_NONE; LISTBASE_FOREACH (TreeElement *, te, lb) { @@ -3162,8 +3064,12 @@ static void outliner_draw_iconrow(bContext *C, te->flag &= ~(TE_ICONROW | TE_ICONROW_MERGED); /* object hierarchy always, further constrained on level */ + /* Bones are also hierarchies and get a merged count, but we only start recursing into them if + * an they are at the root level of a collapsed subtree (e.g. not "hidden" in a collapsed + * collection). */ + const bool is_bone = ELEM(tselem->type, TSE_BONE, TSE_EBONE, TSE_POSE_CHANNEL); if ((level < 1) || ((tselem->type == TSE_SOME_ID) && (te->idcode == ID_OB)) || - ELEM(tselem->type, TSE_BONE, TSE_EBONE, TSE_POSE_CHANNEL)) { + (in_bone_hierarchy && is_bone)) { /* active blocks get white circle */ if (tselem->type == TSE_SOME_ID) { if (te->idcode == ID_OB) { @@ -3194,8 +3100,7 @@ static void outliner_draw_iconrow(bContext *C, TSE_POSE_CHANNEL, TSE_POSEGRP, TSE_DEFGROUP)) { - outliner_draw_iconrow_doit( - region, block, te_visible, te, fstyle, xmax, offsx, ys, alpha_fac, active, 1); + outliner_draw_iconrow_doit(block, te, xmax, offsx, ys, alpha_fac, active, 1); } else { const int index = tree_element_id_type_to_index(te); @@ -3207,20 +3112,25 @@ static void outliner_draw_iconrow(bContext *C, } } - /* this tree element always has same amount of branches, so don't draw */ - if (tselem->type != TSE_R_LAYER) { + /* TSE_R_LAYER tree element always has same amount of branches, so don't draw. */ + /* Also only recurse into bone hierarchies if a direct child of the collapsed element to merge + * into. */ + const bool is_root_level_bone = is_bone && (level == 0); + in_bone_hierarchy |= is_root_level_bone; + if (!ELEM(tselem->type, TSE_R_LAYER, TSE_BONE, TSE_EBONE, TSE_POSE_CHANNEL) || + in_bone_hierarchy) { outliner_draw_iconrow(C, block, fstyle, tvc, space_outliner, - te, &te->subtree, level + 1, xmax, offsx, ys, alpha_fac, + in_bone_hierarchy, merged); } } @@ -3236,11 +3146,8 @@ static void outliner_draw_iconrow(bContext *C, for (int j = 0; j < num_subtypes; j++) { const int index = index_base + j; if (merged->num_elements[index] != 0) { - outliner_draw_iconrow_doit(region, - block, - te_visible, + outliner_draw_iconrow_doit(block, merged->tree_element[index], - fstyle, xmax, offsx, ys, @@ -3429,7 +3336,8 @@ static void outliner_draw_tree_element(bContext *C, tselem, te, (tselem->flag & TSE_HIGHLIGHTED_ICON) ? alpha_fac + 0.5f : alpha_fac, - true)) { + true, + 1)) { offsx += UI_UNIT_X + 4 * ufac; } else { @@ -3478,13 +3386,13 @@ static void outliner_draw_tree_element(bContext *C, fstyle, tvc, space_outliner, - te, &te->subtree, 0, xmax, &tempx, *starty, alpha_fac, + false, &merged); GPU_blend(GPU_BLEND_NONE); diff --git a/source/blender/editors/space_outliner/outliner_edit.cc b/source/blender/editors/space_outliner/outliner_edit.cc index 6eca6fffece..9a6a25fdbae 100644 --- a/source/blender/editors/space_outliner/outliner_edit.cc +++ b/source/blender/editors/space_outliner/outliner_edit.cc @@ -809,7 +809,7 @@ static int outliner_id_copy_exec(bContext *C, wmOperator *op) return OPERATOR_CANCELLED; } - BLI_join_dirfile(str, sizeof(str), BKE_tempdir_base(), "copybuffer.blend"); + BLI_path_join(str, sizeof(str), BKE_tempdir_base(), "copybuffer.blend"); BKE_copybuffer_copy_end(bmain, str, op->reports); BKE_reportf(op->reports, RPT_INFO, "Copied %d selected data-block(s)", num_ids); @@ -843,7 +843,7 @@ static int outliner_id_paste_exec(bContext *C, wmOperator *op) char str[FILE_MAX]; const short flag = FILE_AUTOSELECT | FILE_ACTIVE_COLLECTION; - BLI_join_dirfile(str, sizeof(str), BKE_tempdir_base(), "copybuffer.blend"); + BLI_path_join(str, sizeof(str), BKE_tempdir_base(), "copybuffer.blend"); const int num_pasted = BKE_copybuffer_paste(C, str, flag, op->reports, 0); if (num_pasted == 0) { diff --git a/source/blender/editors/space_sequencer/sequencer_add.c b/source/blender/editors/space_sequencer/sequencer_add.c index 6ef8d7fd108..b17d0bfac4e 100644 --- a/source/blender/editors/space_sequencer/sequencer_add.c +++ b/source/blender/editors/space_sequencer/sequencer_add.c @@ -274,7 +274,7 @@ static void load_data_init_from_operator(SeqLoadData *load_data, bContext *C, wm RNA_PROP_BEGIN (op->ptr, itemptr, prop) { char *filename = RNA_string_get_alloc(&itemptr, "name", NULL, 0, NULL); BLI_strncpy(load_data->name, filename, sizeof(load_data->name)); - BLI_join_dirfile(load_data->path, sizeof(load_data->path), directory, filename); + BLI_path_join(load_data->path, sizeof(load_data->path), directory, filename); MEM_freeN(filename); break; } @@ -834,7 +834,7 @@ static void sequencer_add_movie_multiple_strips(bContext *C, char file_only[FILE_MAX]; RNA_string_get(op->ptr, "directory", dir_only); RNA_string_get(&itemptr, "name", file_only); - BLI_join_dirfile(load_data->path, sizeof(load_data->path), dir_only, file_only); + BLI_path_join(load_data->path, sizeof(load_data->path), dir_only, file_only); BLI_strncpy(load_data->name, file_only, sizeof(load_data->name)); Sequence *seq_movie = NULL; Sequence *seq_sound = NULL; @@ -1082,7 +1082,7 @@ static void sequencer_add_sound_multiple_strips(bContext *C, char file_only[FILE_MAX]; RNA_string_get(op->ptr, "directory", dir_only); RNA_string_get(&itemptr, "name", file_only); - BLI_join_dirfile(load_data->path, sizeof(load_data->path), dir_only, file_only); + BLI_path_join(load_data->path, sizeof(load_data->path), dir_only, file_only); BLI_strncpy(load_data->name, file_only, sizeof(load_data->name)); Sequence *seq = SEQ_add_sound_strip(bmain, scene, ed->seqbasep, load_data); if (seq == NULL) { diff --git a/source/blender/editors/space_sequencer/sequencer_draw.c b/source/blender/editors/space_sequencer/sequencer_draw.c index 201425dafab..a6916f9d031 100644 --- a/source/blender/editors/space_sequencer/sequencer_draw.c +++ b/source/blender/editors/space_sequencer/sequencer_draw.c @@ -804,7 +804,7 @@ static void draw_seq_text_get_source(Sequence *seq, char *r_source, size_t sourc switch (seq->type) { case SEQ_TYPE_IMAGE: case SEQ_TYPE_MOVIE: { - BLI_join_dirfile(r_source, source_len, seq->strip->dir, seq->strip->stripdata->name); + BLI_path_join(r_source, source_len, seq->strip->dir, seq->strip->stripdata->name); break; } case SEQ_TYPE_SOUND_RAM: { diff --git a/source/blender/editors/space_sequencer/sequencer_edit.c b/source/blender/editors/space_sequencer/sequencer_edit.c index 2938513f130..c0c7782c60c 100644 --- a/source/blender/editors/space_sequencer/sequencer_edit.c +++ b/source/blender/editors/space_sequencer/sequencer_edit.c @@ -2939,7 +2939,7 @@ static int sequencer_change_path_invoke(bContext *C, wmOperator *op, const wmEve Sequence *seq = SEQ_select_active_get(scene); char filepath[FILE_MAX]; - BLI_join_dirfile(filepath, sizeof(filepath), seq->strip->dir, seq->strip->stripdata->name); + BLI_path_join(filepath, sizeof(filepath), seq->strip->dir, seq->strip->stripdata->name); RNA_string_set(op->ptr, "directory", seq->strip->dir); RNA_string_set(op->ptr, "filepath", filepath); diff --git a/source/blender/editors/space_sequencer/space_sequencer.c b/source/blender/editors/space_sequencer/space_sequencer.c index 8b6d37caa41..1d20926d16c 100644 --- a/source/blender/editors/space_sequencer/space_sequencer.c +++ b/source/blender/editors/space_sequencer/space_sequencer.c @@ -129,7 +129,6 @@ static SpaceLink *sequencer_create(const ScrArea *UNUSED(area), const Scene *sce region->regiontype = RGN_TYPE_TOOLS; region->alignment = RGN_ALIGN_LEFT; region->flag = RGN_FLAG_HIDDEN; - region->v2d.flag |= V2D_VIEWSYNC_AREA_VERTICAL; /* Channels. */ region = MEM_callocN(sizeof(ARegion), "channels for sequencer"); @@ -137,6 +136,7 @@ static SpaceLink *sequencer_create(const ScrArea *UNUSED(area), const Scene *sce BLI_addtail(&sseq->regionbase, region); region->regiontype = RGN_TYPE_CHANNELS; region->alignment = RGN_ALIGN_LEFT; + region->v2d.flag |= V2D_VIEWSYNC_AREA_VERTICAL; /* Preview region. */ /* NOTE: if you change values here, also change them in sequencer_init_preview_region. */ diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_column.cc b/source/blender/editors/space_spreadsheet/spreadsheet_column.cc index 46e98acb8e8..af41225f42a 100644 --- a/source/blender/editors/space_spreadsheet/spreadsheet_column.cc +++ b/source/blender/editors/space_spreadsheet/spreadsheet_column.cc @@ -12,6 +12,7 @@ #include "BLI_string_ref.hh" #include "BKE_geometry_set.hh" +#include "BKE_instances.hh" #include "spreadsheet_column.hh" #include "spreadsheet_column_values.hh" @@ -44,7 +45,7 @@ eSpreadsheetColumnValueType cpp_type_to_column_type(const CPPType &type) if (type.is<std::string>()) { return SPREADSHEET_VALUE_TYPE_STRING; } - if (type.is<InstanceReference>()) { + if (type.is<bke::InstanceReference>()) { return SPREADSHEET_VALUE_TYPE_INSTANCES; } if (type.is<ColorGeometry4b>()) { 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 b2f9cfc6395..59a8daf4f4a 100644 --- a/source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.cc +++ b/source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.cc @@ -10,6 +10,7 @@ #include "BKE_editmesh.h" #include "BKE_geometry_fields.hh" #include "BKE_global.h" +#include "BKE_instances.hh" #include "BKE_lib_id.h" #include "BKE_mesh.h" #include "BKE_mesh_wrapper.h" @@ -143,29 +144,31 @@ std::unique_ptr<ColumnValues> GeometryDataSource::get_column_values( } if (component_->type() == GEO_COMPONENT_TYPE_INSTANCES) { - const InstancesComponent &instances = static_cast<const InstancesComponent &>(*component_); - if (STREQ(column_id.name, "Name")) { - Span<int> reference_handles = instances.instance_reference_handles(); - Span<InstanceReference> references = instances.references(); - return std::make_unique<ColumnValues>( - column_id.name, - VArray<InstanceReference>::ForFunc(domain_num, - [reference_handles, references](int64_t index) { - return references[reference_handles[index]]; - })); - } - Span<float4x4> transforms = instances.instance_transforms(); - if (STREQ(column_id.name, "Rotation")) { - return std::make_unique<ColumnValues>( - column_id.name, VArray<float3>::ForFunc(domain_num, [transforms](int64_t index) { - return transforms[index].to_euler(); - })); - } - if (STREQ(column_id.name, "Scale")) { - return std::make_unique<ColumnValues>( - column_id.name, VArray<float3>::ForFunc(domain_num, [transforms](int64_t index) { - return transforms[index].scale(); - })); + if (const bke::Instances *instances = + static_cast<const InstancesComponent &>(*component_).get_for_read()) { + if (STREQ(column_id.name, "Name")) { + Span<int> reference_handles = instances->reference_handles(); + Span<bke::InstanceReference> references = instances->references(); + return std::make_unique<ColumnValues>( + column_id.name, + VArray<bke::InstanceReference>::ForFunc( + domain_num, [reference_handles, references](int64_t index) { + return references[reference_handles[index]]; + })); + } + Span<float4x4> transforms = instances->transforms(); + if (STREQ(column_id.name, "Rotation")) { + return std::make_unique<ColumnValues>( + column_id.name, VArray<float3>::ForFunc(domain_num, [transforms](int64_t index) { + return transforms[index].to_euler(); + })); + } + if (STREQ(column_id.name, "Scale")) { + return std::make_unique<ColumnValues>( + column_id.name, VArray<float3>::ForFunc(domain_num, [transforms](int64_t index) { + return transforms[index].scale(); + })); + } } } else if (G.debug_value == 4001 && component_->type() == GEO_COMPONENT_TYPE_MESH) { diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_layout.cc b/source/blender/editors/space_spreadsheet/spreadsheet_layout.cc index b4b8417c172..06eb338bd00 100644 --- a/source/blender/editors/space_spreadsheet/spreadsheet_layout.cc +++ b/source/blender/editors/space_spreadsheet/spreadsheet_layout.cc @@ -6,6 +6,7 @@ #include "BLI_math_vec_types.hh" #include "BKE_geometry_set.hh" +#include "BKE_instances.hh" #include "spreadsheet_column_values.hh" #include "spreadsheet_layout.hh" @@ -197,10 +198,10 @@ class SpreadsheetLayoutDrawer : public SpreadsheetDrawer { const ColorGeometry4b value = data.get<ColorGeometry4b>(real_index); this->draw_byte_color(params, value); } - else if (data.type().is<InstanceReference>()) { - const InstanceReference value = data.get<InstanceReference>(real_index); + else if (data.type().is<bke::InstanceReference>()) { + const bke::InstanceReference value = data.get<bke::InstanceReference>(real_index); switch (value.type()) { - case InstanceReference::Type::Object: { + case bke::InstanceReference::Type::Object: { const Object &object = value.object(); uiDefIconTextBut(params.block, UI_BTYPE_LABEL, @@ -219,7 +220,7 @@ class SpreadsheetLayoutDrawer : public SpreadsheetDrawer { nullptr); break; } - case InstanceReference::Type::Collection: { + case bke::InstanceReference::Type::Collection: { Collection &collection = value.collection(); uiDefIconTextBut(params.block, UI_BTYPE_LABEL, @@ -238,7 +239,7 @@ class SpreadsheetLayoutDrawer : public SpreadsheetDrawer { nullptr); break; } - case InstanceReference::Type::GeometrySet: { + case bke::InstanceReference::Type::GeometrySet: { uiDefIconTextBut(params.block, UI_BTYPE_LABEL, 0, @@ -256,7 +257,7 @@ class SpreadsheetLayoutDrawer : public SpreadsheetDrawer { nullptr); break; } - case InstanceReference::Type::None: { + case bke::InstanceReference::Type::None: { break; } } diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_row_filter.cc b/source/blender/editors/space_spreadsheet/spreadsheet_row_filter.cc index 96827692a25..3586389b00b 100644 --- a/source/blender/editors/space_spreadsheet/spreadsheet_row_filter.cc +++ b/source/blender/editors/space_spreadsheet/spreadsheet_row_filter.cc @@ -14,6 +14,8 @@ #include "RNA_access.h" +#include "BKE_instances.hh" + #include "spreadsheet_data_source_geometry.hh" #include "spreadsheet_intern.hh" #include "spreadsheet_layout.hh" @@ -280,22 +282,22 @@ static void apply_row_filter(const SpreadsheetRowFilter &row_filter, } } } - else if (column_data.type().is<InstanceReference>()) { + else if (column_data.type().is<bke::InstanceReference>()) { const StringRef value = row_filter.value_string; apply_filter_operation( - column_data.typed<InstanceReference>(), - [&](const InstanceReference cell) { + column_data.typed<bke::InstanceReference>(), + [&](const bke::InstanceReference cell) { switch (cell.type()) { - case InstanceReference::Type::Object: { + case bke::InstanceReference::Type::Object: { return value == (reinterpret_cast<ID &>(cell.object()).name + 2); } - case InstanceReference::Type::Collection: { + case bke::InstanceReference::Type::Collection: { return value == (reinterpret_cast<ID &>(cell.collection()).name + 2); } - case InstanceReference::Type::GeometrySet: { + case bke::InstanceReference::Type::GeometrySet: { return false; } - case InstanceReference::Type::None: { + case bke::InstanceReference::Type::None: { return false; } } diff --git a/source/blender/editors/space_view3d/space_view3d.cc b/source/blender/editors/space_view3d/space_view3d.cc index 635fbd75d74..05fb0c6a720 100644 --- a/source/blender/editors/space_view3d/space_view3d.cc +++ b/source/blender/editors/space_view3d/space_view3d.cc @@ -175,11 +175,11 @@ bool ED_view3d_area_user_region(const ScrArea *area, const View3D *v3d, ARegion void ED_view3d_init_mats_rv3d(const struct Object *ob, struct RegionView3D *rv3d) { /* local viewmat and persmat, to calculate projections */ - mul_m4_m4m4(rv3d->viewmatob, rv3d->viewmat, ob->obmat); - mul_m4_m4m4(rv3d->persmatob, rv3d->persmat, ob->obmat); + mul_m4_m4m4(rv3d->viewmatob, rv3d->viewmat, ob->object_to_world); + mul_m4_m4m4(rv3d->persmatob, rv3d->persmat, ob->object_to_world); /* initializes object space clipping, speeds up clip tests */ - ED_view3d_clipping_local(rv3d, ob->obmat); + ED_view3d_clipping_local(rv3d, ob->object_to_world); } void ED_view3d_init_mats_rv3d_gl(const struct Object *ob, struct RegionView3D *rv3d) @@ -189,7 +189,7 @@ void ED_view3d_init_mats_rv3d_gl(const struct Object *ob, struct RegionView3D *r /* We have to multiply instead of loading `viewmatob` to make * it work with duplis using display-lists, otherwise it will * override the dupli-matrix. */ - GPU_matrix_mul(ob->obmat); + GPU_matrix_mul(ob->object_to_world); } #ifdef DEBUG @@ -710,7 +710,7 @@ static void view3d_ob_drop_matrix_from_snap(V3DSnapCursorState *snap_state, copy_v3_v3(obmat_final[3], snap_data->loc); float scale[3]; - mat4_to_size(scale, ob->obmat); + mat4_to_size(scale, ob->object_to_world); rescale_m4(obmat_final, scale); const BoundBox *bb = BKE_object_boundbox_get(ob); diff --git a/source/blender/editors/space_view3d/view3d_buttons.c b/source/blender/editors/space_view3d/view3d_buttons.c index 4153f19f8be..83835535d49 100644 --- a/source/blender/editors/space_view3d/view3d_buttons.c +++ b/source/blender/editors/space_view3d/view3d_buttons.c @@ -474,7 +474,7 @@ static void v3d_editvertex_buts(uiLayout *layout, View3D *v3d, Object *ob, float /* Location, X/Y/Z */ mul_v3_fl(median_basis.generic.location, 1.0f / (float)tot); if (v3d->flag & V3D_GLOBAL_STATS) { - mul_m4_v3(ob->obmat, median_basis.generic.location); + mul_m4_v3(ob->object_to_world, median_basis.generic.location); } if (has_meshdata) { @@ -954,7 +954,7 @@ static void v3d_editvertex_buts(uiLayout *layout, View3D *v3d, Object *ob, float memcpy(&ve_median_basis, &tfp->ve_median, sizeof(tfp->ve_median)); if (v3d->flag & V3D_GLOBAL_STATS) { - invert_m4_m4(ob->imat, ob->obmat); + invert_m4_m4(ob->imat, ob->object_to_world); mul_m4_v3(ob->imat, median_basis.generic.location); mul_m4_v3(ob->imat, ve_median_basis.generic.location); } @@ -1215,7 +1215,7 @@ static void v3d_object_dimension_buts(bContext *C, uiLayout *layout, View3D *v3d BKE_object_dimensions_get(ob, tfp->ob_dims); copy_v3_v3(tfp->ob_dims_orig, tfp->ob_dims); copy_v3_v3(tfp->ob_scale_orig, ob->scale); - copy_m4_m4(tfp->ob_obmat_orig, ob->obmat); + copy_m4_m4(tfp->ob_obmat_orig, ob->object_to_world); uiDefBut(block, UI_BTYPE_LABEL, diff --git a/source/blender/editors/space_view3d/view3d_camera_control.c b/source/blender/editors/space_view3d/view3d_camera_control.c index b5962647278..299c8638b02 100644 --- a/source/blender/editors/space_view3d/view3d_camera_control.c +++ b/source/blender/editors/space_view3d/view3d_camera_control.c @@ -142,7 +142,7 @@ struct View3DCameraControl *ED_view3d_cameracontrol_acquire(Depsgraph *depsgraph vctrl->obtfm = BKE_object_tfm_backup(ob_back); BKE_object_where_is_calc(depsgraph, scene, v3d->camera); - negate_v3_v3(rv3d->ofs, v3d->camera->obmat[3]); + negate_v3_v3(rv3d->ofs, v3d->camera->object_to_world[3]); rv3d->dist = 0.0; } @@ -251,7 +251,7 @@ void ED_view3d_cameracontrol_update(View3DCameraControl *vctrl, invert_m4_m4(prev_view_imat, vctrl->view_mat_prev); mul_m4_m4m4(diff_mat, view_mat, prev_view_imat); - mul_m4_m4m4(parent_mat, diff_mat, vctrl->root_parent->obmat); + mul_m4_m4m4(parent_mat, diff_mat, vctrl->root_parent->object_to_world); if (object_apply_mat4_with_protect(vctrl->root_parent, parent_mat, false, rv3d, view_mat)) { /* Calculate again since the view locking changes the matrix. */ diff --git a/source/blender/editors/space_view3d/view3d_draw.cc b/source/blender/editors/space_view3d/view3d_draw.cc index 8a86889f2d0..31b26ba4cda 100644 --- a/source/blender/editors/space_view3d/view3d_draw.cc +++ b/source/blender/editors/space_view3d/view3d_draw.cc @@ -2066,7 +2066,7 @@ ImBuf *ED_view3d_draw_offscreen_imbuf_simple(Depsgraph *depsgraph, rv3d.persp = RV3D_CAMOB; - copy_m4_m4(rv3d.viewinv, v3d.camera->obmat); + copy_m4_m4(rv3d.viewinv, v3d.camera->object_to_world); normalize_m4(rv3d.viewinv); invert_m4_m4(rv3d.viewmat, rv3d.viewinv); diff --git a/source/blender/editors/space_view3d/view3d_gizmo_armature.c b/source/blender/editors/space_view3d/view3d_gizmo_armature.c index 4f73e2fada2..8a4301d1314 100644 --- a/source/blender/editors/space_view3d/view3d_gizmo_armature.c +++ b/source/blender/editors/space_view3d/view3d_gizmo_armature.c @@ -188,7 +188,7 @@ static void WIDGETGROUP_armature_spline_refresh(const bContext *C, wmGizmoGroup bspline_group->handles[i].index = i; float mat[4][4]; - mul_m4_m4m4(mat, ob->obmat, (i == 0) ? pchan->disp_mat : pchan->disp_tail_mat); + mul_m4_m4m4(mat, ob->object_to_world, (i == 0) ? pchan->disp_mat : pchan->disp_tail_mat); copy_m4_m4(gz->matrix_space, mat); /* need to set property here for undo. TODO: would prefer to do this in _init. */ diff --git a/source/blender/editors/space_view3d/view3d_gizmo_camera.c b/source/blender/editors/space_view3d/view3d_gizmo_camera.c index 952ef56710b..56a1f6212a0 100644 --- a/source/blender/editors/space_view3d/view3d_gizmo_camera.c +++ b/source/blender/editors/space_view3d/view3d_gizmo_camera.c @@ -85,7 +85,7 @@ static void WIDGETGROUP_camera_setup(const bContext *C, wmGizmoGroup *gzgroup) struct CameraWidgetGroup *cagzgroup = MEM_callocN(sizeof(struct CameraWidgetGroup), __func__); gzgroup->customdata = cagzgroup; - negate_v3_v3(dir, ob->obmat[2]); + negate_v3_v3(dir, ob->object_to_world[2]); /* dof distance */ { @@ -138,11 +138,11 @@ static void WIDGETGROUP_camera_refresh(const bContext *C, wmGizmoGroup *gzgroup) RNA_pointer_create(&ca->id, &RNA_Camera, ca, &camera_ptr); - negate_v3_v3(dir, ob->obmat[2]); + negate_v3_v3(dir, ob->object_to_world[2]); if ((ca->flag & CAM_SHOWLIMITS) && (v3d->gizmo_show_camera & V3D_GIZMO_SHOW_CAMERA_DOF_DIST)) { - WM_gizmo_set_matrix_location(cagzgroup->dop_dist, ob->obmat[3]); - WM_gizmo_set_matrix_rotation_from_yz_axis(cagzgroup->dop_dist, ob->obmat[1], dir); + WM_gizmo_set_matrix_location(cagzgroup->dop_dist, ob->object_to_world[3]); + WM_gizmo_set_matrix_rotation_from_yz_axis(cagzgroup->dop_dist, ob->object_to_world[1], dir); WM_gizmo_set_scale(cagzgroup->dop_dist, ca->drawsize); WM_gizmo_set_flag(cagzgroup->dop_dist, WM_GIZMO_HIDDEN, false); @@ -183,17 +183,17 @@ static void WIDGETGROUP_camera_refresh(const bContext *C, wmGizmoGroup *gzgroup) aspect[1] = (sensor_fit == CAMERA_SENSOR_FIT_HOR) ? aspy / aspx : 1.0f; unit_m4(widget->matrix_basis); - WM_gizmo_set_matrix_location(widget, ob->obmat[3]); - WM_gizmo_set_matrix_rotation_from_yz_axis(widget, ob->obmat[1], dir); + WM_gizmo_set_matrix_location(widget, ob->object_to_world[3]); + WM_gizmo_set_matrix_rotation_from_yz_axis(widget, ob->object_to_world[1], dir); if (is_ortho) { scale_matrix = ca->ortho_scale * 0.5f; } else { const float ob_scale_inv[3] = { - 1.0f / len_v3(ob->obmat[0]), - 1.0f / len_v3(ob->obmat[1]), - 1.0f / len_v3(ob->obmat[2]), + 1.0f / len_v3(ob->object_to_world[0]), + 1.0f / len_v3(ob->object_to_world[1]), + 1.0f / len_v3(ob->object_to_world[2]), }; const float ob_scale_uniform_inv = (ob_scale_inv[0] + ob_scale_inv[1] + ob_scale_inv[2]) / 3.0f; diff --git a/source/blender/editors/space_view3d/view3d_gizmo_empty.c b/source/blender/editors/space_view3d/view3d_gizmo_empty.c index 41a763192ce..03fc7328e39 100644 --- a/source/blender/editors/space_view3d/view3d_gizmo_empty.c +++ b/source/blender/editors/space_view3d/view3d_gizmo_empty.c @@ -139,7 +139,7 @@ static void WIDGETGROUP_empty_image_refresh(const bContext *C, wmGizmoGroup *gzg BKE_view_layer_synced_ensure(scene, view_layer); Object *ob = BKE_view_layer_active_object_get(view_layer); - copy_m4_m4(gz->matrix_basis, ob->obmat); + copy_m4_m4(gz->matrix_basis, ob->object_to_world); RNA_enum_set(gz->ptr, "transform", diff --git a/source/blender/editors/space_view3d/view3d_gizmo_forcefield.c b/source/blender/editors/space_view3d/view3d_gizmo_forcefield.c index 58b43301397..d194e2a6279 100644 --- a/source/blender/editors/space_view3d/view3d_gizmo_forcefield.c +++ b/source/blender/editors/space_view3d/view3d_gizmo_forcefield.c @@ -87,8 +87,8 @@ static void WIDGETGROUP_forcefield_refresh(const bContext *C, wmGizmoGroup *gzgr PointerRNA field_ptr; RNA_pointer_create(&ob->id, &RNA_FieldSettings, pd, &field_ptr); - WM_gizmo_set_matrix_location(gz, ob->obmat[3]); - WM_gizmo_set_matrix_rotation_from_z_axis(gz, ob->obmat[2]); + WM_gizmo_set_matrix_location(gz, ob->object_to_world[3]); + WM_gizmo_set_matrix_rotation_from_z_axis(gz, ob->object_to_world[2]); WM_gizmo_set_matrix_offset_location(gz, ofs); WM_gizmo_set_flag(gz, WM_GIZMO_HIDDEN, false); WM_gizmo_target_property_def_rna(gz, "offset", &field_ptr, "strength", -1); diff --git a/source/blender/editors/space_view3d/view3d_gizmo_light.c b/source/blender/editors/space_view3d/view3d_gizmo_light.c index 4401dbf7935..0b115bc0604 100644 --- a/source/blender/editors/space_view3d/view3d_gizmo_light.c +++ b/source/blender/editors/space_view3d/view3d_gizmo_light.c @@ -85,10 +85,10 @@ static void WIDGETGROUP_light_spot_refresh(const bContext *C, wmGizmoGroup *gzgr Light *la = ob->data; float dir[3]; - negate_v3_v3(dir, ob->obmat[2]); + negate_v3_v3(dir, ob->object_to_world[2]); WM_gizmo_set_matrix_rotation_from_z_axis(gz, dir); - WM_gizmo_set_matrix_location(gz, ob->obmat[3]); + WM_gizmo_set_matrix_location(gz, ob->object_to_world[3]); /* need to set property here for undo. TODO: would prefer to do this in _init. */ PointerRNA lamp_ptr; @@ -199,7 +199,7 @@ static void WIDGETGROUP_light_area_refresh(const bContext *C, wmGizmoGroup *gzgr Light *la = ob->data; wmGizmo *gz = wwrapper->gizmo; - copy_m4_m4(gz->matrix_basis, ob->obmat); + copy_m4_m4(gz->matrix_basis, ob->object_to_world); int flag = ED_GIZMO_CAGE2D_XFORM_FLAG_SCALE; if (ELEM(la->area_shape, LA_AREA_SQUARE, LA_AREA_DISK)) { @@ -296,7 +296,7 @@ static void WIDGETGROUP_light_target_draw_prepare(const bContext *C, wmGizmoGrou Object *ob = BKE_view_layer_active_object_get(view_layer); wmGizmo *gz = wwrapper->gizmo; - normalize_m4_m4(gz->matrix_basis, ob->obmat); + normalize_m4_m4(gz->matrix_basis, ob->object_to_world); unit_m4(gz->matrix_offset); if (ob->type == OB_LAMP) { diff --git a/source/blender/editors/space_view3d/view3d_gizmo_preselect_type.cc b/source/blender/editors/space_view3d/view3d_gizmo_preselect_type.cc index 793ada4f577..86aecfb6c34 100644 --- a/source/blender/editors/space_view3d/view3d_gizmo_preselect_type.cc +++ b/source/blender/editors/space_view3d/view3d_gizmo_preselect_type.cc @@ -97,7 +97,7 @@ static void gizmo_preselect_elem_draw(const bContext *C, wmGizmo *gz) MeshElemGizmo3D *gz_ele = (MeshElemGizmo3D *)gz; if (gz_ele->base_index != -1) { Object *ob = gz_ele->bases[gz_ele->base_index]->object; - EDBM_preselect_elem_draw(gz_ele->psel, ob->obmat); + EDBM_preselect_elem_draw(gz_ele->psel, ob->object_to_world); } } @@ -185,7 +185,7 @@ static int gizmo_preselect_elem_test_select(bContext *C, wmGizmo *gz, const int BMVert *vert = (BMVert *)eve_test; float vert_p_co[2], vert_co[3]; const float mval_f[2] = {float(vc.mval[0]), float(vc.mval[1])}; - mul_v3_m4v3(vert_co, gz_ele->bases[base_index_vert]->object->obmat, vert->co); + mul_v3_m4v3(vert_co, gz_ele->bases[base_index_vert]->object->object_to_world, vert->co); ED_view3d_project_v2(vc.region, vert_co, vert_p_co); float len = len_v2v2(vert_p_co, mval_f); if (len < 35) { @@ -330,7 +330,7 @@ static void gizmo_preselect_edgering_draw(const bContext *C, wmGizmo *gz) MeshEdgeRingGizmo3D *gz_ring = (MeshEdgeRingGizmo3D *)gz; if (gz_ring->base_index != -1) { Object *ob = gz_ring->bases[gz_ring->base_index]->object; - EDBM_preselect_edgering_draw(gz_ring->psel, ob->obmat); + EDBM_preselect_edgering_draw(gz_ring->psel, ob->object_to_world); } } diff --git a/source/blender/editors/space_view3d/view3d_iterators.cc b/source/blender/editors/space_view3d/view3d_iterators.cc index 932563863fe..aaa817ec00c 100644 --- a/source/blender/editors/space_view3d/view3d_iterators.cc +++ b/source/blender/editors/space_view3d/view3d_iterators.cc @@ -307,7 +307,7 @@ void meshobject_foreachScreenVert( &me->vdata, CD_PROP_BOOL, ".hide_vert"); if (clip_flag & V3D_PROJ_TEST_CLIP_BB) { - ED_view3d_clipping_local(vc->rv3d, vc->obact->obmat); + ED_view3d_clipping_local(vc->rv3d, vc->obact->object_to_world); } BKE_mesh_foreach_mapped_vert(me, meshobject_foreachScreenVert__mapFunc, &data, MESH_FOREACH_NOP); @@ -353,7 +353,8 @@ void mesh_foreachScreenVert( data.clip_flag = clip_flag; if (clip_flag & V3D_PROJ_TEST_CLIP_BB) { - ED_view3d_clipping_local(vc->rv3d, vc->obedit->obmat); /* for local clipping lookups */ + ED_view3d_clipping_local(vc->rv3d, + vc->obedit->object_to_world); /* for local clipping lookups */ } BM_mesh_elem_table_ensure(vc->em->bm, BM_VERT); @@ -422,7 +423,8 @@ void mesh_foreachScreenEdge(ViewContext *vc, data.clip_flag = clip_flag; if (clip_flag & V3D_PROJ_TEST_CLIP_BB) { - ED_view3d_clipping_local(vc->rv3d, vc->obedit->obmat); /* for local clipping lookups */ + ED_view3d_clipping_local(vc->rv3d, + vc->obedit->object_to_world); /* for local clipping lookups */ } if (clip_flag & V3D_PROJ_TEST_CLIP_CONTENT) { @@ -520,7 +522,8 @@ void mesh_foreachScreenEdge_clip_bb_segment(ViewContext *vc, BM_mesh_elem_table_ensure(vc->em->bm, BM_EDGE); if ((clip_flag & V3D_PROJ_TEST_CLIP_BB) && (vc->rv3d->clipbb != nullptr)) { - ED_view3d_clipping_local(vc->rv3d, vc->obedit->obmat); /* for local clipping lookups. */ + ED_view3d_clipping_local(vc->rv3d, + vc->obedit->object_to_world); /* for local clipping lookups. */ BKE_mesh_foreach_mapped_edge( me, vc->em->bm->totedge, mesh_foreachScreenEdge_clip_bb_segment__mapFunc, &data); } @@ -612,7 +615,8 @@ void nurbs_foreachScreenVert(ViewContext *vc, ED_view3d_check_mats_rv3d(vc->rv3d); if (clip_flag & V3D_PROJ_TEST_CLIP_BB) { - ED_view3d_clipping_local(vc->rv3d, vc->obedit->obmat); /* for local clipping lookups */ + ED_view3d_clipping_local(vc->rv3d, + vc->obedit->object_to_world); /* for local clipping lookups */ } LISTBASE_FOREACH (Nurb *, nu, nurbs) { @@ -732,7 +736,7 @@ void lattice_foreachScreenVert(ViewContext *vc, ED_view3d_check_mats_rv3d(vc->rv3d); if (clip_flag & V3D_PROJ_TEST_CLIP_BB) { - ED_view3d_clipping_local(vc->rv3d, obedit->obmat); /* for local clipping lookups */ + ED_view3d_clipping_local(vc->rv3d, obedit->object_to_world); /* for local clipping lookups */ } for (i = 0; i < N; i++, bp++, co += 3) { diff --git a/source/blender/editors/space_view3d/view3d_navigate.c b/source/blender/editors/space_view3d/view3d_navigate.c index 25073d02a7f..7d2beecd9a3 100644 --- a/source/blender/editors/space_view3d/view3d_navigate.c +++ b/source/blender/editors/space_view3d/view3d_navigate.c @@ -185,7 +185,7 @@ bool view3d_orbit_calc_center(bContext *C, float r_dyn_ofs[3]) copy_v3_v3(lastofs, stroke); } else { - copy_v3_v3(lastofs, ob_act_eval->obmat[3]); + copy_v3_v3(lastofs, ob_act_eval->object_to_world[3]); } is_set = true; } @@ -199,7 +199,7 @@ bool view3d_orbit_calc_center(bContext *C, float r_dyn_ofs[3]) } mul_v2_fl(lastofs, 1.0f / 4.0f); - mul_m4_v3(ob_act_eval->obmat, lastofs); + mul_m4_v3(ob_act_eval->object_to_world, lastofs); is_set = true; } @@ -219,11 +219,11 @@ bool view3d_orbit_calc_center(bContext *C, float r_dyn_ofs[3]) BKE_boundbox_calc_center_aabb(ob_eval->runtime.bb, cent); - mul_m4_v3(ob_eval->obmat, cent); + mul_m4_v3(ob_eval->object_to_world, cent); add_v3_v3(select_center, cent); } else { - add_v3_v3(select_center, ob_eval->obmat[3]); + add_v3_v3(select_center, ob_eval->object_to_world[3]); } tot++; } @@ -626,7 +626,7 @@ static void view3d_object_calc_minmax(Depsgraph *depsgraph, if (BKE_object_minmax_dupli(depsgraph, scene, ob_eval, min, max, false) == 0) { /* Use if duplis aren't found. */ if (only_center) { - minmax_v3v3_v3(min, max, ob_eval->obmat[3]); + minmax_v3v3_v3(min, max, ob_eval->object_to_world[3]); } else { BKE_object_minmax(ob_eval, min, max, false); @@ -934,8 +934,8 @@ static int viewselected_exec(bContext *C, wmOperator *op) CTX_DATA_END; if ((ob_eval) && (ok)) { - mul_m4_v3(ob_eval->obmat, min); - mul_m4_v3(ob_eval->obmat, max); + mul_m4_v3(ob_eval->object_to_world, min); + mul_m4_v3(ob_eval->object_to_world, max); } } else if (is_face_map) { diff --git a/source/blender/editors/space_view3d/view3d_navigate_smoothview.c b/source/blender/editors/space_view3d/view3d_navigate_smoothview.c index 6b150d1e771..a5eee436fdb 100644 --- a/source/blender/editors/space_view3d/view3d_navigate_smoothview.c +++ b/source/blender/editors/space_view3d/view3d_navigate_smoothview.c @@ -259,7 +259,7 @@ void ED_view3d_smooth_view_ex( Object *ob_camera_eval = DEG_get_evaluated_object(depsgraph, sview->camera); if (sview->ofs != NULL) { sms.dst.dist = ED_view3d_offset_distance( - ob_camera_eval->obmat, sview->ofs, VIEW3D_DIST_FALLBACK); + ob_camera_eval->object_to_world, sview->ofs, VIEW3D_DIST_FALLBACK); } ED_view3d_from_object(ob_camera_eval, sms.dst.ofs, sms.dst.quat, &sms.dst.dist, &sms.dst.lens); sms.to_camera = true; /* restore view3d values in end */ @@ -282,7 +282,8 @@ void ED_view3d_smooth_view_ex( if (sview->camera_old) { Object *ob_camera_old_eval = DEG_get_evaluated_object(depsgraph, sview->camera_old); if (sview->ofs != NULL) { - sms.src.dist = ED_view3d_offset_distance(ob_camera_old_eval->obmat, sview->ofs, 0.0f); + sms.src.dist = ED_view3d_offset_distance( + ob_camera_old_eval->object_to_world, sview->ofs, 0.0f); } ED_view3d_from_object( ob_camera_old_eval, sms.src.ofs, sms.src.quat, &sms.src.dist, &sms.src.lens); diff --git a/source/blender/editors/space_view3d/view3d_navigate_walk.c b/source/blender/editors/space_view3d/view3d_navigate_walk.c index 3e0ce892b5a..fcb4f549353 100644 --- a/source/blender/editors/space_view3d/view3d_navigate_walk.c +++ b/source/blender/editors/space_view3d/view3d_navigate_walk.c @@ -849,11 +849,15 @@ static void walkEvent(WalkInfo *walk, const wmEvent *event) if (ret) { WalkTeleport *teleport = &walk->teleport; + + /* Store the current navigation mode if we are not already teleporting. */ + if (teleport->state == WALK_TELEPORT_STATE_OFF) { + teleport->navigation_mode = walk->navigation_mode; + } teleport->state = WALK_TELEPORT_STATE_ON; teleport->initial_time = PIL_check_seconds_timer(); teleport->duration = U.walk_navigation.teleport_time; - teleport->navigation_mode = walk->navigation_mode; walk_navigation_mode_set(walk, WALK_MODE_FREE); copy_v3_v3(teleport->origin, walk->rv3d->viewinv[3]); @@ -864,9 +868,7 @@ static void walkEvent(WalkInfo *walk, const wmEvent *event) sub_v3_v3v3(teleport->direction, loc, teleport->origin); } - else { - walk->teleport.state = WALK_TELEPORT_STATE_OFF; - } + break; } @@ -1229,11 +1231,11 @@ static int walkApply(bContext *C, WalkInfo *walk, bool is_confirm) /* keep moving if we were moving */ copy_v2_v2(dvec, walk->teleport.direction); - z_cur = walk->rv3d->viewinv[3][2]; - z_new = walk->teleport.origin[2] - getFreeFallDistance(walk->gravity, t) * walk->grid; + z_cur = walk->rv3d->viewinv[3][2] / walk->grid; + z_new = (walk->teleport.origin[2] / walk->grid) - getFreeFallDistance(walk->gravity, t); /* jump */ - z_new += t * walk->speed_jump * walk->grid; + z_new += t * walk->speed_jump; /* duration is the jump duration */ if (t > walk->teleport.duration) { diff --git a/source/blender/editors/space_view3d/view3d_ops.c b/source/blender/editors/space_view3d/view3d_ops.c index 6fbd553e17b..ad12aef6d67 100644 --- a/source/blender/editors/space_view3d/view3d_ops.c +++ b/source/blender/editors/space_view3d/view3d_ops.c @@ -59,7 +59,7 @@ static int view3d_copybuffer_exec(bContext *C, wmOperator *op) } CTX_DATA_END; - BLI_join_dirfile(str, sizeof(str), BKE_tempdir_base(), "copybuffer.blend"); + BLI_path_join(str, sizeof(str), BKE_tempdir_base(), "copybuffer.blend"); BKE_copybuffer_copy_end(bmain, str, op->reports); BKE_reportf(op->reports, RPT_INFO, "Copied %d selected object(s)", num_copied); @@ -91,7 +91,7 @@ static int view3d_pastebuffer_exec(bContext *C, wmOperator *op) flag |= FILE_ACTIVE_COLLECTION; } - BLI_join_dirfile(str, sizeof(str), BKE_tempdir_base(), "copybuffer.blend"); + BLI_path_join(str, sizeof(str), BKE_tempdir_base(), "copybuffer.blend"); const int num_pasted = BKE_copybuffer_paste(C, str, flag, op->reports, FILTER_ID_OB); if (num_pasted == 0) { diff --git a/source/blender/editors/space_view3d/view3d_project.c b/source/blender/editors/space_view3d/view3d_project.c index c5f951bd64c..2718f14c855 100644 --- a/source/blender/editors/space_view3d/view3d_project.c +++ b/source/blender/editors/space_view3d/view3d_project.c @@ -80,7 +80,7 @@ eV3DProjStatus ED_view3d_project_base(const struct ARegion *region, float r_co[2]) { eV3DProjStatus ret = ED_view3d_project_float_global( - region, base->object->obmat[3], r_co, V3D_PROJ_TEST_CLIP_DEFAULT); + region, base->object->object_to_world[3], r_co, V3D_PROJ_TEST_CLIP_DEFAULT); /* Prevent uninitialized values when projection fails, * although the callers should check the return value. */ @@ -687,7 +687,7 @@ void ED_view3d_ob_project_mat_get(const RegionView3D *rv3d, const Object *ob, fl { float vmat[4][4]; - mul_m4_m4m4(vmat, rv3d->viewmat, ob->obmat); + mul_m4_m4m4(vmat, rv3d->viewmat, ob->object_to_world); mul_m4_m4m4(r_pmat, rv3d->winmat, vmat); } diff --git a/source/blender/editors/space_view3d/view3d_select.cc b/source/blender/editors/space_view3d/view3d_select.cc index cba85097071..9c450e85d23 100644 --- a/source/blender/editors/space_view3d/view3d_select.cc +++ b/source/blender/editors/space_view3d/view3d_select.cc @@ -2303,7 +2303,7 @@ static Base *mouse_select_object_center(ViewContext *vc, Base *startbase, const if (BASE_SELECTABLE(v3d, base)) { float screen_co[2]; if (ED_view3d_project_float_global( - region, base->object->obmat[3], screen_co, V3D_PROJ_TEST_CLIP_DEFAULT) == + region, base->object->object_to_world[3], screen_co, V3D_PROJ_TEST_CLIP_DEFAULT) == V3D_PROJ_RET_OK) { float dist_test = len_manhattan_v2v2(mval_fl, screen_co); if (base == oldbasact) { @@ -2704,7 +2704,10 @@ static bool ed_object_select_pick(bContext *C, /* When there is no `baseact` this will have operated on `oldbasact`, * allowing #SelectPick_Params.deselect_all work in pose-mode. * In this case no object operations are needed. */ - if (basact != nullptr) { + if (basact == nullptr) { + handled = true; + } + else { /* By convention the armature-object is selected when in pose-mode. * While leaving it unselected will work, leaving pose-mode would leave the object * active + unselected which isn't ideal when performing other actions on the object. */ @@ -4725,9 +4728,10 @@ static bool object_circle_select(ViewContext *vc, LISTBASE_FOREACH (Base *, base, BKE_view_layer_object_bases_get(view_layer)) { if (BASE_SELECTABLE(v3d, base) && ((base->flag & BASE_SELECTED) != select_flag)) { float screen_co[2]; - if (ED_view3d_project_float_global( - vc->region, base->object->obmat[3], screen_co, V3D_PROJ_TEST_CLIP_DEFAULT) == - V3D_PROJ_RET_OK) { + if (ED_view3d_project_float_global(vc->region, + base->object->object_to_world[3], + screen_co, + V3D_PROJ_TEST_CLIP_DEFAULT) == V3D_PROJ_RET_OK) { if (len_squared_v2v2(mval_fl, screen_co) <= radius_squared) { ED_object_base_select(base, select ? BA_SELECT : BA_DESELECT); changed = true; diff --git a/source/blender/editors/space_view3d/view3d_snap.c b/source/blender/editors/space_view3d/view3d_snap.c index ee6b1886dc2..f2b952c4f46 100644 --- a/source/blender/editors/space_view3d/view3d_snap.c +++ b/source/blender/editors/space_view3d/view3d_snap.c @@ -86,18 +86,18 @@ static int snap_sel_to_grid_exec(bContext *C, wmOperator *UNUSED(op)) } if (tvs.transverts_tot != 0) { - copy_m3_m4(bmat, obedit->obmat); + copy_m3_m4(bmat, obedit->object_to_world); invert_m3_m3(imat, bmat); tv = tvs.transverts; for (a = 0; a < tvs.transverts_tot; a++, tv++) { copy_v3_v3(vec, tv->loc); mul_m3_v3(bmat, vec); - add_v3_v3(vec, obedit->obmat[3]); + add_v3_v3(vec, obedit->object_to_world[3]); vec[0] = gridf * floorf(0.5f + vec[0] / gridf); vec[1] = gridf * floorf(0.5f + vec[1] / gridf); vec[2] = gridf * floorf(0.5f + vec[2] / gridf); - sub_v3_v3(vec, obedit->obmat[3]); + sub_v3_v3(vec, obedit->object_to_world[3]); mul_m3_v3(imat, vec); copy_v3_v3(tv->loc, vec); @@ -118,7 +118,7 @@ static int snap_sel_to_grid_exec(bContext *C, wmOperator *UNUSED(op)) bPoseChannel *pchan_eval; bArmature *arm_eval = ob_eval->data; - invert_m4_m4(ob_eval->imat, ob_eval->obmat); + invert_m4_m4(ob_eval->imat, ob_eval->object_to_world); for (pchan_eval = ob_eval->pose->chanbase.first; pchan_eval; pchan_eval = pchan_eval->next) { if (pchan_eval->bone->flag & BONE_SELECTED) { @@ -129,7 +129,7 @@ static int snap_sel_to_grid_exec(bContext *C, wmOperator *UNUSED(op)) /* get nearest grid point to snap to */ copy_v3_v3(nLoc, pchan_eval->pose_mat[3]); /* We must operate in world space! */ - mul_m4_v3(ob_eval->obmat, nLoc); + mul_m4_v3(ob_eval->object_to_world, nLoc); vec[0] = gridf * floorf(0.5f + nLoc[0] / gridf); vec[1] = gridf * floorf(0.5f + nLoc[1] / gridf); vec[2] = gridf * floorf(0.5f + nLoc[2] / gridf); @@ -214,9 +214,12 @@ static int snap_sel_to_grid_exec(bContext *C, wmOperator *UNUSED(op)) for (int ob_index = 0; ob_index < objects_eval_len; ob_index++) { Object *ob_eval = objects_eval[ob_index]; Object *ob = DEG_get_original_object(ob_eval); - vec[0] = -ob_eval->obmat[3][0] + gridf * floorf(0.5f + ob_eval->obmat[3][0] / gridf); - vec[1] = -ob_eval->obmat[3][1] + gridf * floorf(0.5f + ob_eval->obmat[3][1] / gridf); - vec[2] = -ob_eval->obmat[3][2] + gridf * floorf(0.5f + ob_eval->obmat[3][2] / gridf); + vec[0] = -ob_eval->object_to_world[3][0] + + gridf * floorf(0.5f + ob_eval->object_to_world[3][0] / gridf); + vec[1] = -ob_eval->object_to_world[3][1] + + gridf * floorf(0.5f + ob_eval->object_to_world[3][1] / gridf); + vec[2] = -ob_eval->object_to_world[3][2] + + gridf * floorf(0.5f + ob_eval->object_to_world[3][2] / gridf); if (ob->parent) { float originmat[3][3]; @@ -343,11 +346,11 @@ static bool snap_selected_to_location(bContext *C, } if (tvs.transverts_tot != 0) { - copy_m3_m4(bmat, obedit->obmat); + copy_m3_m4(bmat, obedit->object_to_world); invert_m3_m3(imat, bmat); /* get the cursor in object space */ - sub_v3_v3v3(snap_target_local, snap_target_global, obedit->obmat[3]); + sub_v3_v3v3(snap_target_local, snap_target_global, obedit->object_to_world[3]); mul_m3_v3(imat, snap_target_local); if (use_offset) { @@ -384,7 +387,7 @@ static bool snap_selected_to_location(bContext *C, bArmature *arm = ob->data; float snap_target_local[3]; - invert_m4_m4(ob->imat, ob->obmat); + invert_m4_m4(ob->imat, ob->object_to_world); mul_v3_m4v3(snap_target_local, ob->imat, snap_target_global); for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) { @@ -409,7 +412,7 @@ static bool snap_selected_to_location(bContext *C, float cursor_pose[3]; if (use_offset) { - mul_v3_m4v3(cursor_pose, ob->obmat, pchan->pose_mat[3]); + mul_v3_m4v3(cursor_pose, ob->object_to_world, pchan->pose_mat[3]); add_v3_v3(cursor_pose, offset_global); mul_m4_v3(ob->imat, cursor_pose); @@ -510,13 +513,13 @@ static bool snap_selected_to_location(bContext *C, float cursor_parent[3]; /* parent-relative */ if (use_offset) { - add_v3_v3v3(cursor_parent, ob->obmat[3], offset_global); + add_v3_v3v3(cursor_parent, ob->object_to_world[3], offset_global); } else { copy_v3_v3(cursor_parent, snap_target_global); } - sub_v3_v3(cursor_parent, ob->obmat[3]); + sub_v3_v3(cursor_parent, ob->object_to_world[3]); if (ob->parent) { float originmat[3][3], parentmat[4][4]; @@ -730,7 +733,7 @@ static void bundle_midpoint(Scene *scene, Object *ob, float r_vec[3]) tracking = &clip->tracking; - copy_m4_m4(cammat, ob->obmat); + copy_m4_m4(cammat, ob->object_to_world); BKE_tracking_get_camera_object_matrix(ob, mat); @@ -809,13 +812,13 @@ static bool snap_curs_to_sel_ex(bContext *C, const int pivot_point, float r_curs count += tvs.transverts_tot; if (tvs.transverts_tot != 0) { Object *obedit_eval = DEG_get_evaluated_object(depsgraph, obedit); - copy_m3_m4(bmat, obedit_eval->obmat); + copy_m3_m4(bmat, obedit_eval->object_to_world); tv = tvs.transverts; for (int i = 0; i < tvs.transverts_tot; i++, tv++) { copy_v3_v3(vec, tv->loc); mul_m3_v3(bmat, vec); - add_v3_v3(vec, obedit_eval->obmat[3]); + add_v3_v3(vec, obedit_eval->object_to_world[3]); add_v3_v3(centroid, vec); minmax_v3v3_v3(min, max, vec); } @@ -835,7 +838,7 @@ static bool snap_curs_to_sel_ex(bContext *C, const int pivot_point, float r_curs if (arm->layer & pchan->bone->layer) { if (pchan->bone->flag & BONE_SELECTED) { copy_v3_v3(vec, pchan->pose_head); - mul_m4_v3(obact_eval->obmat, vec); + mul_m4_v3(obact_eval->object_to_world, vec); add_v3_v3(centroid, vec); minmax_v3v3_v3(min, max, vec); count++; @@ -845,7 +848,7 @@ static bool snap_curs_to_sel_ex(bContext *C, const int pivot_point, float r_curs } else { FOREACH_SELECTED_OBJECT_BEGIN (view_layer_eval, v3d, ob_eval) { - copy_v3_v3(vec, ob_eval->obmat[3]); + copy_v3_v3(vec, ob_eval->object_to_world[3]); /* special case for camera -- snap to bundles */ if (ob_eval->type == OB_CAMERA) { @@ -1008,7 +1011,7 @@ bool ED_view3d_minmax_verts(Object *obedit, float r_min[3], float r_max[3]) float ob_min[3], ob_max[3]; bool changed; - changed = BKE_mball_minmax_ex(obedit->data, ob_min, ob_max, obedit->obmat, SELECT); + changed = BKE_mball_minmax_ex(obedit->data, ob_min, ob_max, obedit->object_to_world, SELECT); if (changed) { minmax_v3v3_v3(r_min, r_max, ob_min); minmax_v3v3_v3(r_min, r_max, ob_max); @@ -1024,13 +1027,13 @@ bool ED_view3d_minmax_verts(Object *obedit, float r_min[3], float r_max[3]) return false; } - copy_m3_m4(bmat, obedit->obmat); + copy_m3_m4(bmat, obedit->object_to_world); tv = tvs.transverts; for (int a = 0; a < tvs.transverts_tot; a++, tv++) { copy_v3_v3(vec, (tv->flag & TX_VERT_USE_MAPLOC) ? tv->maploc : tv->loc); mul_m3_v3(bmat, vec); - add_v3_v3(vec, obedit->obmat[3]); + add_v3_v3(vec, obedit->object_to_world[3]); add_v3_v3(centroid, vec); minmax_v3v3_v3(r_min, r_max, vec); } diff --git a/source/blender/editors/space_view3d/view3d_utils.c b/source/blender/editors/space_view3d/view3d_utils.c index 1fc16939f3f..fc26e6b4a06 100644 --- a/source/blender/editors/space_view3d/view3d_utils.c +++ b/source/blender/editors/space_view3d/view3d_utils.c @@ -281,7 +281,7 @@ void ED_view3d_clipping_calc( /* optionally transform to object space */ if (ob) { float imat[4][4]; - invert_m4_m4(imat, ob->obmat); + invert_m4_m4(imat, ob->object_to_world); for (int val = 0; val < 8; val++) { mul_m4_v3(imat, bb->vec[val]); @@ -291,7 +291,7 @@ void ED_view3d_clipping_calc( /* verify if we have negative scale. doing the transform before cross * product flips the sign of the vector compared to doing cross product * before transform then, so we correct for that. */ - int flip_sign = (ob) ? is_negative_m4(ob->obmat) : false; + int flip_sign = (ob) ? is_negative_m4(ob->object_to_world) : false; ED_view3d_clipping_calc_from_boundbox(planes, bb, flip_sign); } @@ -466,7 +466,8 @@ void ED_view3d_persp_switch_from_camera(const Depsgraph *depsgraph, if (v3d->camera) { Object *ob_camera_eval = DEG_get_evaluated_object(depsgraph, v3d->camera); - rv3d->dist = ED_view3d_offset_distance(ob_camera_eval->obmat, rv3d->ofs, VIEW3D_DIST_FALLBACK); + rv3d->dist = ED_view3d_offset_distance( + ob_camera_eval->object_to_world, rv3d->ofs, VIEW3D_DIST_FALLBACK); ED_view3d_from_object(ob_camera_eval, rv3d->ofs, rv3d->viewquat, &rv3d->dist, NULL); } @@ -558,7 +559,7 @@ void ED_view3d_camera_lock_init_ex(const Depsgraph *depsgraph, if (calc_dist) { /* using a fallback dist is OK here since ED_view3d_from_object() compensates for it */ rv3d->dist = ED_view3d_offset_distance( - ob_camera_eval->obmat, rv3d->ofs, VIEW3D_DIST_FALLBACK); + ob_camera_eval->object_to_world, rv3d->ofs, VIEW3D_DIST_FALLBACK); } ED_view3d_from_object(ob_camera_eval, rv3d->ofs, rv3d->viewquat, &rv3d->dist, NULL); } @@ -592,12 +593,12 @@ bool ED_view3d_camera_lock_sync(const Depsgraph *depsgraph, View3D *v3d, RegionV ED_view3d_to_m4(view_mat, rv3d->ofs, rv3d->viewquat, rv3d->dist); - normalize_m4_m4(tmat, ob_camera_eval->obmat); + normalize_m4_m4(tmat, ob_camera_eval->object_to_world); invert_m4_m4(imat, tmat); mul_m4_m4m4(diff_mat, view_mat, imat); - mul_m4_m4m4(parent_mat, diff_mat, root_parent_eval->obmat); + mul_m4_m4m4(parent_mat, diff_mat, root_parent_eval->object_to_world); BKE_object_tfm_protected_backup(root_parent, &obtfm); BKE_object_apply_mat4(root_parent, parent_mat, true, false); @@ -1508,7 +1509,7 @@ void ED_view3d_to_m4(float mat[4][4], const float ofs[3], const float quat[4], c void ED_view3d_from_object(const Object *ob, float ofs[3], float quat[4], float *dist, float *lens) { - ED_view3d_from_m4(ob->obmat, ofs, quat, dist); + ED_view3d_from_m4(ob->object_to_world, ofs, quat, dist); if (lens) { CameraParams params; @@ -1555,7 +1556,7 @@ static bool view3d_camera_to_view_selected_impl(struct Main *bmain, is_ortho_camera = true; } - copy_m4_m4(obmat_new, camera_ob_eval->obmat); + copy_m4_m4(obmat_new, camera_ob_eval->object_to_world); copy_v3_v3(obmat_new[3], co); /* only touch location */ diff --git a/source/blender/editors/space_view3d/view3d_view.c b/source/blender/editors/space_view3d/view3d_view.c index d0db4de0c47..c630a1a5653 100644 --- a/source/blender/editors/space_view3d/view3d_view.c +++ b/source/blender/editors/space_view3d/view3d_view.c @@ -365,7 +365,7 @@ static void obmat_to_viewmat(RegionView3D *rv3d, Object *ob) rv3d->view = RV3D_VIEW_USER; /* don't show the grid */ - normalize_m4_m4(bmat, ob->obmat); + normalize_m4_m4(bmat, ob->object_to_world); invert_m4_m4(rv3d->viewmat, bmat); /* view quat calculation, needed for add object */ @@ -404,12 +404,12 @@ void view3d_viewmatrix_set(Depsgraph *depsgraph, Object *ob_eval = DEG_get_evaluated_object(depsgraph, v3d->ob_center); float vec[3]; - copy_v3_v3(vec, ob_eval->obmat[3]); + copy_v3_v3(vec, ob_eval->object_to_world[3]); if (ob_eval->type == OB_ARMATURE && v3d->ob_center_bone[0]) { bPoseChannel *pchan = BKE_pose_channel_find_name(ob_eval->pose, v3d->ob_center_bone); if (pchan) { copy_v3_v3(vec, pchan->pose_mat[3]); - mul_m4_v3(ob_eval->obmat, vec); + mul_m4_v3(ob_eval->object_to_world, vec); } } translate_m4(rv3d->viewmat, -vec[0], -vec[1], -vec[2]); diff --git a/source/blender/editors/transform/transform.c b/source/blender/editors/transform/transform.c index 93e99f97387..ad6ab625438 100644 --- a/source/blender/editors/transform/transform.c +++ b/source/blender/editors/transform/transform.c @@ -60,8 +60,6 @@ * and being able to set it to zero is handy. */ /* #define USE_NUM_NO_ZERO */ -static void initSnapSpatial(TransInfo *t, float r_snap[2]); - bool transdata_check_local_islands(TransInfo *t, short around) { if (t->options & (CTX_CURSOR | CTX_TEXTURE_SPACE)) { @@ -1596,9 +1594,9 @@ void saveTransform(bContext *C, TransInfo *t, wmOperator *op) RNA_enum_set(op->ptr, "snap_target", t->tsnap.source_select); eSnapTargetSelect target = t->tsnap.target_select; - RNA_boolean_set(op->ptr, "use_snap_self", (target & SCE_SNAP_TARGET_NOT_ACTIVE) != 0); - RNA_boolean_set(op->ptr, "use_snap_edit", (target & SCE_SNAP_TARGET_NOT_EDITED) != 0); - RNA_boolean_set(op->ptr, "use_snap_nonedit", (target & SCE_SNAP_TARGET_NOT_NONEDITED) != 0); + RNA_boolean_set(op->ptr, "use_snap_self", (target & SCE_SNAP_TARGET_NOT_ACTIVE) == 0); + RNA_boolean_set(op->ptr, "use_snap_edit", (target & SCE_SNAP_TARGET_NOT_EDITED) == 0); + RNA_boolean_set(op->ptr, "use_snap_nonedit", (target & SCE_SNAP_TARGET_NOT_NONEDITED) == 0); RNA_boolean_set( op->ptr, "use_snap_selectable", (target & SCE_SNAP_TARGET_ONLY_SELECTABLE) != 0); } @@ -1723,13 +1721,18 @@ void saveTransform(bContext *C, TransInfo *t, wmOperator *op) } } -static void initSnapSpatial(TransInfo *t, float r_snap[2]) +static void initSnapSpatial(TransInfo *t, float r_snap[3], float *r_snap_precision) { + /* Default values. */ + r_snap[0] = r_snap[1] = 1.0f; + r_snap[2] = 0.0f; + *r_snap_precision = 0.1f; + if (t->spacetype == SPACE_VIEW3D) { if (t->region->regiondata) { View3D *v3d = t->area->spacedata.first; - r_snap[0] = ED_view3d_grid_view_scale(t->scene, v3d, t->region, NULL) * 1.0f; - r_snap[1] = r_snap[0] * 0.1f; + r_snap[0] = r_snap[1] = r_snap[2] = ED_view3d_grid_view_scale( + t->scene, v3d, t->region, NULL); } } else if (t->spacetype == SPACE_IMAGE) { @@ -1737,33 +1740,22 @@ static void initSnapSpatial(TransInfo *t, float r_snap[2]) View2D *v2d = &t->region->v2d; int grid_size = SI_GRID_STEPS_LEN; float zoom_factor = ED_space_image_zoom_level(v2d, grid_size); - float grid_steps[SI_GRID_STEPS_LEN]; + float grid_steps_x[SI_GRID_STEPS_LEN]; float grid_steps_y[SI_GRID_STEPS_LEN]; - ED_space_image_grid_steps(sima, grid_steps, grid_steps_y, grid_size); + ED_space_image_grid_steps(sima, grid_steps_x, grid_steps_y, grid_size); /* Snapping value based on what type of grid is used (adaptive-subdividing or custom-grid). */ - r_snap[0] = ED_space_image_increment_snap_value(grid_size, grid_steps, zoom_factor); - r_snap[1] = r_snap[0] / 2.0f; - - /* TODO: Implement snapping for custom grid sizes with `grid_steps[0] != grid_steps_y[0]`. - * r_snap_y[0] = ED_space_image_increment_snap_value(grid_size, grid_steps_y, zoom_factor); - * r_snap_y[1] = r_snap_y[0] / 2.0f; - */ + r_snap[0] = ED_space_image_increment_snap_value(grid_size, grid_steps_x, zoom_factor); + r_snap[1] = ED_space_image_increment_snap_value(grid_size, grid_steps_y, zoom_factor); + *r_snap_precision = 0.5f; } else if (t->spacetype == SPACE_CLIP) { - r_snap[0] = 0.125f; - r_snap[1] = 0.0625f; + r_snap[0] = r_snap[1] = 0.125f; + *r_snap_precision = 0.5f; } else if (t->spacetype == SPACE_NODE) { r_snap[0] = r_snap[1] = ED_node_grid_size(); } - else if (t->spacetype == SPACE_GRAPH) { - r_snap[0] = 1.0; - r_snap[1] = 0.1f; - } - else { - r_snap[0] = r_snap[1] = 1.0f; - } } bool initTransform(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *event, int mode) @@ -1903,7 +1895,7 @@ bool initTransform(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve initSnapping(t, op); /* Initialize snapping data AFTER mode flags */ - initSnapSpatial(t, t->snap_spatial); + initSnapSpatial(t, t->snap_spatial, &t->snap_spatial_precision); /* EVIL! posemode code can switch translation to rotate when 1 bone is selected. * will be removed (ton) */ diff --git a/source/blender/editors/transform/transform.h b/source/blender/editors/transform/transform.h index e2bab378cad..1e260ecd292 100644 --- a/source/blender/editors/transform/transform.h +++ b/source/blender/editors/transform/transform.h @@ -469,7 +469,8 @@ typedef struct TransDataContainer { /** * Store matrix, this avoids having to have duplicate check all over - * Typically: 'obedit->obmat' or 'poseobj->obmat', but may be used elsewhere too. + * Typically: 'obedit->object_to_world' or 'poseobj->object_to_world', but may be used elsewhere + * too. */ bool use_local_mat; @@ -555,7 +556,12 @@ typedef struct TransInfo { /** Snapping Gears. */ float snap[2]; /** Spatial snapping gears(even when rotating, scaling... etc). */ - float snap_spatial[2]; + float snap_spatial[3]; + /** + * Precision factor that is multiplied to snap_spatial when precision + * modifier is enabled for snap to grid or incremental snap. + */ + float snap_spatial_precision; /** Mouse side of the current frame, 'L', 'R' or 'B' */ char frame_side; diff --git a/source/blender/editors/transform/transform_constraints.c b/source/blender/editors/transform/transform_constraints.c index fa56456d8e7..7abf0e5c00c 100644 --- a/source/blender/editors/transform/transform_constraints.c +++ b/source/blender/editors/transform/transform_constraints.c @@ -404,9 +404,11 @@ static void applyAxisConstraintVec(const TransInfo *t, } } + /* Fallback for when axes are aligned. */ + mul_m3_v3(t->con.pmtx, out); + if (is_snap_to_point) { - /* With snap points, a projection is alright, no adjustments needed. */ - mul_m3_v3(t->con.pmtx, out); + /* Pass. With snap points, a projection is alright, no adjustments needed. */ } else { const int dims = getConstraintSpaceDimension(t); @@ -422,14 +424,9 @@ static void applyAxisConstraintVec(const TransInfo *t, /* Disabled, as it has not proven to be really useful. (See T82386). */ // constraint_snap_plane_to_face(t, plane, out); } - else { + else if (!isPlaneProjectionViewAligned(t, plane)) { /* View alignment correction. */ - if (!isPlaneProjectionViewAligned(t, plane)) { - planeProjection(t, plane, in, out); - } - else { - mul_m3_v3(t->con.pmtx, out); - } + planeProjection(t, plane, in, out); } } } diff --git a/source/blender/editors/transform/transform_convert.c b/source/blender/editors/transform/transform_convert.c index 7a68ee1bfbf..a5b2442f11c 100644 --- a/source/blender/editors/transform/transform_convert.c +++ b/source/blender/editors/transform/transform_convert.c @@ -981,7 +981,7 @@ static void init_TransDataContainers(TransInfo *t, if (tc->use_local_mat) { BLI_assert((t->flag & T_2D_EDIT) == 0); - copy_m4_m4(tc->mat, objects[i]->obmat); + copy_m4_m4(tc->mat, objects[i]->object_to_world); copy_m3_m4(tc->mat3, tc->mat); /* for non-invertible scale matrices, invert_m4_m4_fallback() * can still provide a valid pivot */ @@ -1235,8 +1235,8 @@ void transform_convert_clip_mirror_modifier_apply(TransDataContainer *tc) if (mmd->mirror_ob) { float obinv[4][4]; - invert_m4_m4(obinv, mmd->mirror_ob->obmat); - mul_m4_m4m4(mtx, obinv, ob->obmat); + invert_m4_m4(obinv, mmd->mirror_ob->object_to_world); + mul_m4_m4m4(mtx, obinv, ob->object_to_world); invert_m4_m4(imtx, mtx); } diff --git a/source/blender/editors/transform/transform_convert.h b/source/blender/editors/transform/transform_convert.h index 8466fd88e1d..4798d666d70 100644 --- a/source/blender/editors/transform/transform_convert.h +++ b/source/blender/editors/transform/transform_convert.h @@ -226,8 +226,6 @@ void transform_convert_mesh_crazyspace_transdata_set(const float mtx[3][3], struct TransData *r_td); void transform_convert_mesh_crazyspace_free(struct TransMeshDataCrazySpace *r_crazyspace_data); -void special_aftertrans_update__mesh(bContext *C, TransInfo *t); - /* transform_convert_mesh_edge.c */ extern TransConvertTypeInfo TransConvertType_MeshEdge; diff --git a/source/blender/editors/transform/transform_convert_armature.c b/source/blender/editors/transform/transform_convert_armature.c index 4b79625fa66..2e37f6b7c34 100644 --- a/source/blender/editors/transform/transform_convert_armature.c +++ b/source/blender/editors/transform/transform_convert_armature.c @@ -306,8 +306,9 @@ static short pose_grab_with_ik_add(bPoseChannel *pchan) * just make things obey standard rotation locks too */ if (data->rootbone == 0) { for (bPoseChannel *pchan_iter = pchan; pchan_iter; pchan_iter = pchan_iter->parent) { - /* here, we set ik-settings for bone from pchan->protectflag */ - /* XXX: careful with quats/axis-angle rotations where we're locking 4d components. */ + /* Here, we set IK-settings for bone from `pchan->protectflag`. */ + /* XXX: careful with quaternion/axis-angle rotations + * where we're locking 4d components. */ if (pchan_iter->protectflag & OB_LOCK_ROTX) { pchan_iter->ikflag |= BONE_IK_NO_XDOF_TEMP; } @@ -592,7 +593,7 @@ static void add_pose_transdata(TransInfo *t, bPoseChannel *pchan, Object *ob, Tr td->ext->rotOrder = pchan->rotmode; /* proper way to get parent transform + own transform + constraints transform */ - copy_m3_m4(omat, ob->obmat); + copy_m3_m4(omat, ob->object_to_world); /* New code, using "generic" BKE_bone_parent_transform_calc_from_pchan(). */ { @@ -954,7 +955,7 @@ static void createTransArmatureVerts(bContext *UNUSED(C), TransInfo *t) bool mirror = ((arm->flag & ARM_MIRROR_EDIT) != 0); BoneInitData *bid = tc->custom.type.data; - copy_m3_m4(mtx, tc->obedit->obmat); + copy_m3_m4(mtx, tc->obedit->object_to_world); pseudoinverse_m3_m3(smtx, mtx, PSEUDOINVERSE_EPSILON); td = tc->data = MEM_callocN(tc->data_len * sizeof(TransData), "TransEditBone"); diff --git a/source/blender/editors/transform/transform_convert_curve.c b/source/blender/editors/transform/transform_convert_curve.c index 404b1293208..13ba28ec3d0 100644 --- a/source/blender/editors/transform/transform_convert_curve.c +++ b/source/blender/editors/transform/transform_convert_curve.c @@ -174,7 +174,7 @@ static void createTransCurveVerts(bContext *UNUSED(C), TransInfo *t) transform_mode_use_local_origins(t)); float mtx[3][3], smtx[3][3]; - copy_m3_m4(mtx, tc->obedit->obmat); + copy_m3_m4(mtx, tc->obedit->object_to_world); pseudoinverse_m3_m3(smtx, mtx, PSEUDOINVERSE_EPSILON); TransData *td = tc->data; diff --git a/source/blender/editors/transform/transform_convert_lattice.c b/source/blender/editors/transform/transform_convert_lattice.c index b77538dc249..e9b3401974b 100644 --- a/source/blender/editors/transform/transform_convert_lattice.c +++ b/source/blender/editors/transform/transform_convert_lattice.c @@ -66,7 +66,7 @@ static void createTransLatticeVerts(bContext *UNUSED(C), TransInfo *t) } tc->data = MEM_callocN(tc->data_len * sizeof(TransData), "TransObData(Lattice EditMode)"); - copy_m3_m4(mtx, tc->obedit->obmat); + copy_m3_m4(mtx, tc->obedit->object_to_world); pseudoinverse_m3_m3(smtx, mtx, PSEUDOINVERSE_EPSILON); td = tc->data; diff --git a/source/blender/editors/transform/transform_convert_mball.c b/source/blender/editors/transform/transform_convert_mball.c index 7ae93524d0b..c90052e9e8c 100644 --- a/source/blender/editors/transform/transform_convert_mball.c +++ b/source/blender/editors/transform/transform_convert_mball.c @@ -61,7 +61,7 @@ static void createTransMBallVerts(bContext *UNUSED(C), TransInfo *t) tx = tc->data_ext = MEM_callocN(tc->data_len * sizeof(TransDataExtension), "MetaElement_TransExtension"); - copy_m3_m4(mtx, tc->obedit->obmat); + copy_m3_m4(mtx, tc->obedit->object_to_world); pseudoinverse_m3_m3(smtx, mtx, PSEUDOINVERSE_EPSILON); for (ml = mb->editelems->first; ml; ml = ml->next) { diff --git a/source/blender/editors/transform/transform_convert_mesh.c b/source/blender/editors/transform/transform_convert_mesh.c index af7982f862a..3192b1b6786 100644 --- a/source/blender/editors/transform/transform_convert_mesh.c +++ b/source/blender/editors/transform/transform_convert_mesh.c @@ -1527,7 +1527,7 @@ static void createTransEditVerts(bContext *UNUSED(C), TransInfo *t) em, calc_single_islands, calc_island_center, calc_island_axismtx, &island_data); } - copy_m3_m4(mtx, tc->obedit->obmat); + copy_m3_m4(mtx, tc->obedit->object_to_world); /* we use a pseudo-inverse so that when one of the axes is scaled to 0, * matrix inversion still works and we can still moving along the other */ pseudoinverse_m3_m3(smtx, mtx, PSEUDOINVERSE_EPSILON); @@ -2068,7 +2068,7 @@ static void recalcData_mesh(TransInfo *t) /** \name Special After Transform Mesh * \{ */ -void special_aftertrans_update__mesh(bContext *UNUSED(C), TransInfo *t) +static void special_aftertrans_update__mesh(bContext *UNUSED(C), TransInfo *t) { const bool is_canceling = (t->state == TRANS_CANCEL); const bool use_automerge = !is_canceling && (t->flag & (T_AUTOMERGE | T_AUTOSPLIT)) != 0; diff --git a/source/blender/editors/transform/transform_convert_mesh_edge.c b/source/blender/editors/transform/transform_convert_mesh_edge.c index 7f26029850b..fd62b199345 100644 --- a/source/blender/editors/transform/transform_convert_mesh_edge.c +++ b/source/blender/editors/transform/transform_convert_mesh_edge.c @@ -62,7 +62,7 @@ static void createTransEdge(bContext *UNUSED(C), TransInfo *t) td = tc->data = MEM_callocN(tc->data_len * sizeof(TransData), "TransCrease"); - copy_m3_m4(mtx, tc->obedit->obmat); + copy_m3_m4(mtx, tc->obedit->object_to_world); pseudoinverse_m3_m3(smtx, mtx, PSEUDOINVERSE_EPSILON); /* create data we need */ @@ -125,5 +125,5 @@ TransConvertTypeInfo TransConvertType_MeshEdge = { /* flags */ T_EDIT, /* createTransData */ createTransEdge, /* recalcData */ recalcData_mesh_edge, - /* special_aftertrans_update */ special_aftertrans_update__mesh, + /* special_aftertrans_update */ NULL, }; diff --git a/source/blender/editors/transform/transform_convert_mesh_skin.c b/source/blender/editors/transform/transform_convert_mesh_skin.c index 376e559181e..cb6108a4c45 100644 --- a/source/blender/editors/transform/transform_convert_mesh_skin.c +++ b/source/blender/editors/transform/transform_convert_mesh_skin.c @@ -130,7 +130,7 @@ static void createTransMeshSkin(bContext *UNUSED(C), TransInfo *t) em, calc_single_islands, calc_island_center, calc_island_axismtx, &island_data); } - copy_m3_m4(mtx, tc->obedit->obmat); + copy_m3_m4(mtx, tc->obedit->object_to_world); /* we use a pseudo-inverse so that when one of the axes is scaled to 0, * matrix inversion still works and we can still moving along the other */ pseudoinverse_m3_m3(smtx, mtx, PSEUDOINVERSE_EPSILON); diff --git a/source/blender/editors/transform/transform_convert_mesh_vert_cdata.c b/source/blender/editors/transform/transform_convert_mesh_vert_cdata.c index 59836180166..d253261f458 100644 --- a/source/blender/editors/transform/transform_convert_mesh_vert_cdata.c +++ b/source/blender/editors/transform/transform_convert_mesh_vert_cdata.c @@ -131,7 +131,7 @@ static void createTransMeshVertCData(bContext *UNUSED(C), TransInfo *t) em, calc_single_islands, calc_island_center, calc_island_axismtx, &island_data); } - copy_m3_m4(mtx, tc->obedit->obmat); + copy_m3_m4(mtx, tc->obedit->object_to_world); /* we use a pseudo-inverse so that when one of the axes is scaled to 0, * matrix inversion still works and we can still moving along the other */ pseudoinverse_m3_m3(smtx, mtx, PSEUDOINVERSE_EPSILON); diff --git a/source/blender/editors/transform/transform_convert_nla.c b/source/blender/editors/transform/transform_convert_nla.c index af5a51cbff6..830094ebe83 100644 --- a/source/blender/editors/transform/transform_convert_nla.c +++ b/source/blender/editors/transform/transform_convert_nla.c @@ -60,9 +60,9 @@ typedef struct TransDataNla { * \{ */ /** - * \brief Applies a translation to the given NlaStrip. - * \param strip_rna_ptr The RNA pointer of the NLA strip to modify. - * \param transdata The transformation info structure. + * \brief Applies a translation to the given #NlaStrip. + * \param strip_rna_ptr: The RNA pointer of the NLA strip to modify. + * \param transdata: The transformation info structure. */ static void applyTransformNLA_translation(PointerRNA *strip_rna_ptr, const TransDataNla *transdata) { diff --git a/source/blender/editors/transform/transform_convert_node.cc b/source/blender/editors/transform/transform_convert_node.cc index eb5eb822d69..6ab0e1fe701 100644 --- a/source/blender/editors/transform/transform_convert_node.cc +++ b/source/blender/editors/transform/transform_convert_node.cc @@ -155,9 +155,52 @@ static void createTransNodeData(bContext * /*C*/, TransInfo *t) /** \} */ /* -------------------------------------------------------------------- */ -/** \name Node Transform Creation +/** \name Flush Transform Nodes * \{ */ +static void node_snap_grid_apply(TransInfo *t) +{ + int i; + + if (!(activeSnap(t) && (t->tsnap.mode & (SCE_SNAP_MODE_INCREMENT | SCE_SNAP_MODE_GRID)))) { + return; + } + + float grid_size[2]; + copy_v2_v2(grid_size, t->snap_spatial); + if (t->modifiers & MOD_PRECISION) { + mul_v2_fl(grid_size, t->snap_spatial_precision); + } + + /* Early exit on unusable grid size. */ + if (is_zero_v2(grid_size)) { + return; + } + + FOREACH_TRANS_DATA_CONTAINER (t, tc) { + TransData *td; + + for (i = 0, td = tc->data; i < tc->data_len; i++, td++) { + float iloc[2], loc[2], tvec[2]; + if (td->flag & TD_SKIP) { + continue; + } + + if ((t->flag & T_PROP_EDIT) && (td->factor == 0.0f)) { + continue; + } + + copy_v2_v2(iloc, td->loc); + + loc[0] = roundf(iloc[0] / grid_size[0]) * grid_size[0]; + loc[1] = roundf(iloc[1] / grid_size[1]) * grid_size[1]; + + sub_v2_v2v2(tvec, loc, iloc); + add_v2_v2(td->loc, tvec); + } + } +} + static void flushTransNodes(TransInfo *t) { using namespace blender::ed; @@ -191,7 +234,7 @@ static void flushTransNodes(TransInfo *t) } FOREACH_TRANS_DATA_CONTAINER (t, tc) { - applyGridAbsolute(t); + node_snap_grid_apply(t); /* flush to 2d vector from internally used 3d vector */ for (int i = 0; i < tc->data_len; i++) { diff --git a/source/blender/editors/transform/transform_convert_object.c b/source/blender/editors/transform/transform_convert_object.c index 0dcfd7206ad..55f7cd9b23d 100644 --- a/source/blender/editors/transform/transform_convert_object.c +++ b/source/blender/editors/transform/transform_convert_object.c @@ -158,14 +158,14 @@ static void ObjectToTransData(TransInfo *t, TransData *td, Object *ob) copy_qt_qt(td->ext->oquat, ob->quat); } /* update object's loc/rot to get current rigid body transform */ - mat4_to_loc_rot_size(ob->loc, rot, scale, ob->obmat); + mat4_to_loc_rot_size(ob->loc, rot, scale, ob->object_to_world); sub_v3_v3(ob->loc, ob->dloc); BKE_object_mat3_to_rot(ob, rot, false); /* drot is already corrected here */ } } /* axismtx has the real orientation */ - transform_orientations_create_from_axis(td->axismtx, UNPACK3(ob->obmat)); + transform_orientations_create_from_axis(td->axismtx, UNPACK3(ob->object_to_world)); 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); @@ -192,7 +192,7 @@ static void ObjectToTransData(TransInfo *t, TransData *td, Object *ob) * More proper solution would be to make a shallow copy of the object and * evaluate that, and access matrix of that evaluated copy of the object. * Might be more tricky than it sounds, if some logic later on accesses the - * object matrix via td->ob->obmat. */ + * object matrix via td->ob->object_to_world. */ Object *object_eval = DEG_get_evaluated_object(t->depsgraph, ob); if (skip_invert == false && constinv == false) { object_eval->transflag |= OB_NO_CONSTRAINTS; /* BKE_object_where_is_calc checks this */ @@ -208,7 +208,7 @@ static void ObjectToTransData(TransInfo *t, TransData *td, Object *ob) } /* Copy newly evaluated fields to the original object, similar to how * active dependency graph will do it. */ - copy_m4_m4(ob->obmat, object_eval->obmat); + copy_m4_m4(ob->object_to_world, object_eval->object_to_world); /* Only copy negative scale flag, this is the only flag which is modified by * the BKE_object_where_is_calc(). The rest of the flags we need to keep, * otherwise we might lose dupli flags (see T61787). */ @@ -258,9 +258,9 @@ static void ObjectToTransData(TransInfo *t, TransData *td, Object *ob) copy_v3_v3(td->ext->isize, ob->scale); copy_v3_v3(td->ext->dscale, ob->dscale); - copy_v3_v3(td->center, ob->obmat[3]); + copy_v3_v3(td->center, ob->object_to_world[3]); - copy_m4_m4(td->ext->obmat, ob->obmat); + copy_m4_m4(td->ext->obmat, ob->object_to_world); /* is there a need to set the global<->data space conversion matrices? */ if (ob->parent || constinv) { @@ -271,7 +271,7 @@ static void ObjectToTransData(TransInfo *t, TransData *td, Object *ob) * done, as it doesn't work well. */ BKE_object_to_mat3(ob, obmtx); - copy_m3_m4(totmat, ob->obmat); + copy_m3_m4(totmat, ob->object_to_world); /* If the object scale is zero on any axis, this might result in a zero matrix. * In this case, the transformation would not do anything, see: T50103. */ diff --git a/source/blender/editors/transform/transform_convert_object_texspace.c b/source/blender/editors/transform/transform_convert_object_texspace.c index 839bf6b77b3..b4c1c134d49 100644 --- a/source/blender/editors/transform/transform_convert_object_texspace.c +++ b/source/blender/editors/transform/transform_convert_object_texspace.c @@ -67,8 +67,8 @@ static void createTransTexspace(bContext *UNUSED(C), TransInfo *t) td->flag = TD_SELECTED; td->ob = ob; - copy_m3_m4(td->mtx, ob->obmat); - copy_m3_m4(td->axismtx, ob->obmat); + copy_m3_m4(td->mtx, ob->object_to_world); + copy_m3_m4(td->axismtx, ob->object_to_world); normalize_m3(td->axismtx); pseudoinverse_m3_m3(td->smtx, td->mtx, PSEUDOINVERSE_EPSILON); diff --git a/source/blender/editors/transform/transform_convert_particle.c b/source/blender/editors/transform/transform_convert_particle.c index 3e056b6a048..f212f042773 100644 --- a/source/blender/editors/transform/transform_convert_particle.c +++ b/source/blender/editors/transform/transform_convert_particle.c @@ -95,7 +95,7 @@ static void createTransParticleVerts(bContext *UNUSED(C), TransInfo *t) unit_m4(mat); - invert_m4_m4(ob->imat, ob->obmat); + invert_m4_m4(ob->imat, ob->object_to_world); for (i = 0, point = edit->points; i < edit->totpoint; i++, point++) { TransData *head, *tail; diff --git a/source/blender/editors/transform/transform_convert_sculpt.c b/source/blender/editors/transform/transform_convert_sculpt.c index f4f2e2a1c6e..cdbf497c584 100644 --- a/source/blender/editors/transform/transform_convert_sculpt.c +++ b/source/blender/editors/transform/transform_convert_sculpt.c @@ -49,7 +49,7 @@ static void createTransSculpt(bContext *C, TransInfo *t) td->flag = TD_SELECTED; copy_v3_v3(td->center, ss->pivot_pos); - mul_m4_v3(ob->obmat, td->center); + mul_m4_v3(ob->object_to_world, td->center); td->ob = ob; td->loc = ss->pivot_pos; @@ -60,16 +60,16 @@ static void createTransSculpt(bContext *C, TransInfo *t) } float obmat_inv[3][3]; - copy_m3_m4(obmat_inv, ob->obmat); + copy_m3_m4(obmat_inv, ob->object_to_world); invert_m3(obmat_inv); td->ext->rot = NULL; td->ext->rotAxis = NULL; td->ext->rotAngle = NULL; td->ext->quat = ss->pivot_rot; - copy_m4_m4(td->ext->obmat, ob->obmat); + copy_m4_m4(td->ext->obmat, ob->object_to_world); copy_m3_m3(td->ext->l_smtx, obmat_inv); - copy_m3_m4(td->ext->r_mtx, ob->obmat); + copy_m3_m4(td->ext->r_mtx, ob->object_to_world); copy_m3_m3(td->ext->r_smtx, obmat_inv); copy_qt_qt(td->ext->iquat, ss->pivot_rot); @@ -83,8 +83,8 @@ static void createTransSculpt(bContext *C, TransInfo *t) copy_v3_v3(td->ext->isize, ss->init_pivot_scale); copy_m3_m3(td->smtx, obmat_inv); - copy_m3_m4(td->mtx, ob->obmat); - copy_m3_m4(td->axismtx, ob->obmat); + copy_m3_m4(td->mtx, ob->object_to_world); + copy_m3_m4(td->axismtx, ob->object_to_world); BLI_assert(!(t->options & CTX_PAINT_CURVE)); ED_sculpt_init_transform(C, ob, t->mval, t->undo_name); diff --git a/source/blender/editors/transform/transform_generics.c b/source/blender/editors/transform/transform_generics.c index 301eac4536e..e1f93bf881b 100644 --- a/source/blender/editors/transform/transform_generics.c +++ b/source/blender/editors/transform/transform_generics.c @@ -1063,7 +1063,7 @@ bool calculateCenterActive(TransInfo *t, bool select_only, float r_center[3]) } if (tc->obedit) { if (ED_object_calc_active_center_for_editmode(tc->obedit, select_only, r_center)) { - mul_m4_v3(tc->obedit->obmat, r_center); + mul_m4_v3(tc->obedit->object_to_world, r_center); return true; } } @@ -1071,7 +1071,7 @@ bool calculateCenterActive(TransInfo *t, bool select_only, float r_center[3]) BKE_view_layer_synced_ensure(t->scene, t->view_layer); Object *ob = BKE_view_layer_active_object_get(t->view_layer); if (ED_object_calc_active_center_for_posemode(ob, select_only, r_center)) { - mul_m4_v3(ob->obmat, r_center); + mul_m4_v3(ob->object_to_world, r_center); return true; } } @@ -1088,7 +1088,7 @@ bool calculateCenterActive(TransInfo *t, bool select_only, float r_center[3]) BKE_view_layer_synced_ensure(t->scene, t->view_layer); Base *base = BKE_view_layer_active_base_get(t->view_layer); if (base && ((!select_only) || ((base->flag & BASE_SELECTED) != 0))) { - copy_v3_v3(r_center, base->object->obmat[3]); + copy_v3_v3(r_center, base->object->object_to_world[3]); return true; } } diff --git a/source/blender/editors/transform/transform_gizmo_3d.c b/source/blender/editors/transform/transform_gizmo_3d.c index f3d17559a63..2be210d24e7 100644 --- a/source/blender/editors/transform/transform_gizmo_3d.c +++ b/source/blender/editors/transform/transform_gizmo_3d.c @@ -581,12 +581,12 @@ bool gimbal_axis_pose(Object *ob, const bPoseChannel *pchan, float gmat[3][3]) mul_m3_m3m3(mat, parent_mat, tmat); /* needed if object transformation isn't identity */ - copy_m3_m4(obmat, ob->obmat); + copy_m3_m4(obmat, ob->object_to_world); mul_m3_m3m3(gmat, obmat, mat); } else { /* needed if object transformation isn't identity */ - copy_m3_m4(obmat, ob->obmat); + copy_m3_m4(obmat, ob->object_to_world); mul_m3_m3m3(gmat, obmat, tmat); } @@ -608,7 +608,7 @@ bool gimbal_axis_object(Object *ob, float gmat[3][3]) if (ob->parent) { float parent_mat[3][3]; - copy_m3_m4(parent_mat, ob->parent->obmat); + copy_m3_m4(parent_mat, ob->parent->object_to_world); normalize_m3(parent_mat); mul_m3_m3m3(gmat, parent_mat, gmat); } @@ -675,14 +675,14 @@ int ED_transform_calc_gizmo_stats(const bContext *C, copy_m3_m4(tbounds->axis, rv3d->twmat); if (params->use_local_axis && (ob && ob->mode & (OB_MODE_EDIT | OB_MODE_POSE))) { float diff_mat[3][3]; - copy_m3_m4(diff_mat, ob->obmat); + copy_m3_m4(diff_mat, ob->object_to_world); normalize_m3(diff_mat); invert_m3(diff_mat); mul_m3_m3m3(tbounds->axis, tbounds->axis, diff_mat); normalize_m3(tbounds->axis); tbounds->use_matrix_space = true; - copy_m4_m4(tbounds->matrix_space, ob->obmat); + copy_m4_m4(tbounds->matrix_space, ob->object_to_world); } if (is_gp_edit) { @@ -751,7 +751,7 @@ int ED_transform_calc_gizmo_stats(const bContext *C, #define FOREACH_EDIT_OBJECT_BEGIN(ob_iter, use_mat_local) \ { \ - invert_m4_m4(obedit->imat, obedit->obmat); \ + invert_m4_m4(obedit->imat, obedit->object_to_world); \ uint objects_len = 0; \ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode( \ scene, view_layer, CTX_wm_view3d(C), &objects_len); \ @@ -780,7 +780,7 @@ int ED_transform_calc_gizmo_stats(const bContext *C, float mat_local[4][4]; if (use_mat_local) { - mul_m4_m4m4(mat_local, obedit->imat, ob_iter->obmat); + mul_m4_m4m4(mat_local, obedit->imat, ob_iter->object_to_world); } BM_ITER_MESH (eve, &iter, bm, BM_VERTS_OF_MESH) { @@ -800,7 +800,7 @@ int ED_transform_calc_gizmo_stats(const bContext *C, float mat_local[4][4]; if (use_mat_local) { - mul_m4_m4m4(mat_local, obedit->imat, ob_iter->obmat); + mul_m4_m4m4(mat_local, obedit->imat, ob_iter->object_to_world); } LISTBASE_FOREACH (EditBone *, ebo, arm->edbo) { if (EBONE_VISIBLE(arm, ebo)) { @@ -833,7 +833,7 @@ int ED_transform_calc_gizmo_stats(const bContext *C, float mat_local[4][4]; if (use_mat_local) { - mul_m4_m4m4(mat_local, obedit->imat, ob_iter->obmat); + mul_m4_m4m4(mat_local, obedit->imat, ob_iter->object_to_world); } nu = nurbs->first; @@ -893,7 +893,7 @@ int ED_transform_calc_gizmo_stats(const bContext *C, float mat_local[4][4]; if (use_mat_local) { - mul_m4_m4m4(mat_local, obedit->imat, ob_iter->obmat); + mul_m4_m4m4(mat_local, obedit->imat, ob_iter->object_to_world); } LISTBASE_FOREACH (MetaElem *, ml, mb->editelems) { @@ -913,7 +913,7 @@ int ED_transform_calc_gizmo_stats(const bContext *C, float mat_local[4][4]; if (use_mat_local) { - mul_m4_m4m4(mat_local, obedit->imat, ob_iter->obmat); + mul_m4_m4m4(mat_local, obedit->imat, ob_iter->object_to_world); } while (a--) { @@ -933,13 +933,13 @@ int ED_transform_calc_gizmo_stats(const bContext *C, /* selection center */ if (totsel) { mul_v3_fl(tbounds->center, 1.0f / (float)totsel); /* centroid! */ - mul_m4_v3(obedit->obmat, tbounds->center); - mul_m4_v3(obedit->obmat, tbounds->min); - mul_m4_v3(obedit->obmat, tbounds->max); + mul_m4_v3(obedit->object_to_world, tbounds->center); + mul_m4_v3(obedit->object_to_world, tbounds->min); + mul_m4_v3(obedit->object_to_world, tbounds->max); } } else if (ob && (ob->mode & OB_MODE_POSE)) { - invert_m4_m4(ob->imat, ob->obmat); + invert_m4_m4(ob->imat, ob->object_to_world); uint objects_len = 0; Object **objects = BKE_object_pose_array_get(scene, view_layer, v3d, &objects_len); @@ -954,7 +954,7 @@ int ED_transform_calc_gizmo_stats(const bContext *C, float mat_local[4][4]; if (use_mat_local) { - mul_m4_m4m4(mat_local, ob->imat, ob_iter->obmat); + mul_m4_m4m4(mat_local, ob->imat, ob_iter->object_to_world); } /* Use channels to get stats. */ @@ -971,18 +971,18 @@ int ED_transform_calc_gizmo_stats(const bContext *C, if (totsel) { mul_v3_fl(tbounds->center, 1.0f / (float)totsel); /* centroid! */ - mul_m4_v3(ob->obmat, tbounds->center); - mul_m4_v3(ob->obmat, tbounds->min); - mul_m4_v3(ob->obmat, tbounds->max); + mul_m4_v3(ob->object_to_world, tbounds->center); + mul_m4_v3(ob->object_to_world, tbounds->min); + mul_m4_v3(ob->object_to_world, tbounds->max); } } else if (ob && (ob->mode & OB_MODE_ALL_PAINT)) { if (ob->mode & OB_MODE_SCULPT) { totsel = 1; - calc_tw_center_with_matrix(tbounds, ob->sculpt->pivot_pos, false, ob->obmat); - mul_m4_v3(ob->obmat, tbounds->center); - mul_m4_v3(ob->obmat, tbounds->min); - mul_m4_v3(ob->obmat, tbounds->max); + calc_tw_center_with_matrix(tbounds, ob->sculpt->pivot_pos, false, ob->object_to_world); + mul_m4_v3(ob->object_to_world, tbounds->center); + mul_m4_v3(ob->object_to_world, tbounds->min); + mul_m4_v3(ob->object_to_world, tbounds->max); } } else if (ob && ob->mode & OB_MODE_PARTICLE_EDIT) { @@ -1037,12 +1037,12 @@ int ED_transform_calc_gizmo_stats(const bContext *C, } if (params->use_only_center || (bb == NULL)) { - calc_tw_center(tbounds, base->object->obmat[3]); + calc_tw_center(tbounds, base->object->object_to_world[3]); } else { for (uint j = 0; j < 8; j++) { float co[3]; - mul_v3_m4v3(co, base->object->obmat, bb->vec[j]); + mul_v3_m4v3(co, base->object->object_to_world, bb->vec[j]); calc_tw_center(tbounds, co); } } diff --git a/source/blender/editors/transform/transform_mode.c b/source/blender/editors/transform/transform_mode.c index 2eaeaf92c86..aeceedf0690 100644 --- a/source/blender/editors/transform/transform_mode.c +++ b/source/blender/editors/transform/transform_mode.c @@ -1041,7 +1041,7 @@ void ElementResize(const TransInfo *t, if (t->options & CTX_POSE_BONE) { /* Without this, the resulting location of scaled bones aren't correct, * especially noticeable scaling root or disconnected bones around the cursor, see T92515. */ - mul_mat3_m4_v3(tc->poseobj->obmat, vec); + mul_mat3_m4_v3(tc->poseobj->object_to_world, vec); } mul_m3_v3(td->smtx, vec); } diff --git a/source/blender/editors/transform/transform_mode_curveshrinkfatten.c b/source/blender/editors/transform/transform_mode_curveshrinkfatten.c index f7f9e14b8ac..0b87b45679a 100644 --- a/source/blender/editors/transform/transform_mode_curveshrinkfatten.c +++ b/source/blender/editors/transform/transform_mode_curveshrinkfatten.c @@ -8,6 +8,7 @@ #include <stdlib.h> #include "BLI_math.h" +#include "BLI_math_bits.h" #include "BLI_string.h" #include "BKE_context.h" @@ -62,7 +63,14 @@ static void applyCurveShrinkFatten(TransInfo *t, const int UNUSED(mval[2])) } if (td->val) { - *td->val = td->ival * ratio; + if (td->ival == 0.0f && ratio > 1.0f) { + /* Allow Shrink/Fatten for zero radius. */ + *td->val = (ratio - 1.0f) * uint_as_float(POINTER_AS_UINT(t->custom.mode.data)); + } + else { + *td->val = td->ival * ratio; + } + /* apply PET */ *td->val = interpf(*td->val, td->ival, td->factor); CLAMP_MIN(*td->val, 0.0f); @@ -92,6 +100,18 @@ void initCurveShrinkFatten(TransInfo *t) t->num.unit_type[0] = B_UNIT_NONE; t->flag |= T_NO_CONSTRAINT; + + float scale_factor = 0.0f; + if (((t->spacetype == SPACE_VIEW3D) && (t->region->regiontype == RGN_TYPE_WINDOW) && + (t->data_len_all == 1)) || + (t->data_len_all == 3 && TRANS_DATA_CONTAINER_FIRST_OK(t)->data[0].val == NULL)) { + /* For cases where only one point on the curve is being transformed and the radius of that + * point is zero, use the factor to multiply the offset of the ratio and allow scaling. + * Note that for bezier curves, 3 TransData equals 1 point in most cases. */ + RegionView3D *rv3d = t->region->regiondata; + scale_factor = rv3d->pixsize * t->mouse.factor * t->zfac; + } + t->custom.mode.data = POINTER_FROM_UINT(float_as_uint(scale_factor)); } /** \} */ diff --git a/source/blender/editors/transform/transform_mode_edge_slide.c b/source/blender/editors/transform/transform_mode_edge_slide.c index 5baf06006d9..5cdb4d3bf61 100644 --- a/source/blender/editors/transform/transform_mode_edge_slide.c +++ b/source/blender/editors/transform/transform_mode_edge_slide.c @@ -1149,7 +1149,7 @@ void drawEdgeSlide(TransInfo *t) GPU_blend(GPU_BLEND_ALPHA); GPU_matrix_push(); - GPU_matrix_mul(TRANS_DATA_CONTAINER_FIRST_OK(t)->obedit->obmat); + GPU_matrix_mul(TRANS_DATA_CONTAINER_FIRST_OK(t)->obedit->object_to_world); uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT); diff --git a/source/blender/editors/transform/transform_mode_translate.c b/source/blender/editors/transform/transform_mode_translate.c index 8f6ec7bd98f..59d34c3918b 100644 --- a/source/blender/editors/transform/transform_mode_translate.c +++ b/source/blender/editors/transform/transform_mode_translate.c @@ -170,7 +170,7 @@ static void transdata_elem_translate_fn(void *__restrict iter_data_v, /** \} */ /* -------------------------------------------------------------------- */ -/** \name Transform (Translation) +/** \name Transform (Translation) Header * \{ */ static void translate_dist_to_str(char *r_str, @@ -341,6 +341,96 @@ static void headerTranslation(TransInfo *t, const float vec[3], char str[UI_MAX_ } } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Transform (Translation) Snapping + * \{ */ + +static void translate_snap_target_grid_ensure(TransInfo *t) +{ + /* Only need to calculate once. */ + if ((t->tsnap.status & TARGET_GRID_INIT) == 0) { + if (t->data_type == &TransConvertType_Cursor3D) { + /* Use a fallback when transforming the cursor. + * In this case the center is _not_ derived from the cursor which is being transformed. */ + copy_v3_v3(t->tsnap.snapTargetGrid, TRANS_DATA_CONTAINER_FIRST_SINGLE(t)->data->iloc); + } + else if (t->around == V3D_AROUND_CURSOR) { + /* Use a fallback for cursor selection, + * this isn't useful as a global center for absolute grid snapping + * since its not based on the position of the selection. */ + tranform_snap_target_median_calc(t, t->tsnap.snapTargetGrid); + } + else { + copy_v3_v3(t->tsnap.snapTargetGrid, t->center_global); + } + t->tsnap.status |= TARGET_GRID_INIT; + } +} + +static void translate_snap_grid_apply(TransInfo *t, + const int max_index, + const float grid_dist[3], + const float loc[3], + float r_out[3]) +{ + BLI_assert(max_index <= 2); + translate_snap_target_grid_ensure(t); + const float *center_global = t->tsnap.snapTargetGrid; + const float *asp = t->aspect; + + float in[3]; + if (t->con.mode & CON_APPLY) { + BLI_assert(t->tsnap.snapElem == SCE_SNAP_MODE_NONE); + t->con.applyVec(t, NULL, NULL, loc, in); + } + else { + copy_v3_v3(in, loc); + } + + for (int i = 0; i <= max_index; i++) { + const float iter_fac = grid_dist[i] * asp[i]; + r_out[i] = iter_fac * roundf((in[i] + center_global[i]) / iter_fac) - center_global[i]; + } +} + +static bool translate_snap_grid(TransInfo *t, float *val) +{ + if (!activeSnap(t)) { + return false; + } + + if (!(t->tsnap.mode & SCE_SNAP_MODE_GRID) || validSnap(t)) { + /* Don't do grid snapping if there is a valid snap point. */ + return false; + } + + /* Don't do grid snapping if not in 3D viewport or UV editor */ + if (!ELEM(t->spacetype, SPACE_VIEW3D, SPACE_IMAGE)) { + return false; + } + + if (t->mode != TFM_TRANSLATION) { + return false; + } + + float grid_dist[3]; + copy_v3_v3(grid_dist, t->snap_spatial); + if (t->modifiers & MOD_PRECISION) { + mul_v3_fl(grid_dist, t->snap_spatial_precision); + } + + /* Early bailing out if no need to snap */ + if (is_zero_v3(grid_dist)) { + return false; + } + + translate_snap_grid_apply(t, t->idx_max, grid_dist, val, val); + t->tsnap.snapElem = SCE_SNAP_MODE_GRID; + return true; +} + static void ApplySnapTranslation(TransInfo *t, float vec[3]) { float point[3]; @@ -372,6 +462,12 @@ static void ApplySnapTranslation(TransInfo *t, float vec[3]) } } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Transform (Translation) + * \{ */ + static void applyTranslationValue(TransInfo *t, const float vec[3]) { struct TranslateCustomData *custom_data = t->custom.mode.data; @@ -514,7 +610,7 @@ static void applyTranslation(TransInfo *t, const int UNUSED(mval[2])) t->tsnap.snapElem = SCE_SNAP_MODE_NONE; applySnappingAsGroup(t, global_dir); - transform_snap_grid(t, global_dir); + translate_snap_grid(t, global_dir); if (t->con.mode & CON_APPLY) { float in[3]; @@ -590,7 +686,8 @@ void initTranslation(TransInfo *t) t->num.flag = 0; t->num.idx_max = t->idx_max; - copy_v2_v2(t->snap, t->snap_spatial); + t->snap[0] = t->snap_spatial[0]; + t->snap[1] = t->snap_spatial[0] * t->snap_spatial_precision; copy_v3_fl(t->num.val_inc, t->snap[0]); t->num.unit_sys = t->scene->unit.system; diff --git a/source/blender/editors/transform/transform_mode_vert_slide.c b/source/blender/editors/transform/transform_mode_vert_slide.c index d7c4d862b23..cc1ea188fbc 100644 --- a/source/blender/editors/transform/transform_mode_vert_slide.c +++ b/source/blender/editors/transform/transform_mode_vert_slide.c @@ -167,7 +167,7 @@ static void calcVertSlideMouseActiveEdges(struct TransInfo *t, const int mval[2] float dir_dot; sub_v3_v3v3(tdir, sv->co_orig_3d, sv->co_link_orig_3d[j]); - mul_mat3_m4_v3(TRANS_DATA_CONTAINER_FIRST_OK(t)->obedit->obmat, tdir); + mul_mat3_m4_v3(TRANS_DATA_CONTAINER_FIRST_OK(t)->obedit->object_to_world, tdir); project_plane_v3_v3v3(tdir, tdir, t->viewinv[2]); normalize_v3(tdir); @@ -382,7 +382,7 @@ void drawVertSlide(TransInfo *t) GPU_blend(GPU_BLEND_ALPHA); GPU_matrix_push(); - GPU_matrix_mul(TRANS_DATA_CONTAINER_FIRST_OK(t)->obedit->obmat); + GPU_matrix_mul(TRANS_DATA_CONTAINER_FIRST_OK(t)->obedit->object_to_world); GPU_line_width(line_size); @@ -437,14 +437,15 @@ void drawVertSlide(TransInfo *t) xy_delta[0] = t->mval[0] - t->mouse.imval[0]; xy_delta[1] = t->mval[1] - t->mouse.imval[1]; - mul_v3_m4v3( - co_orig_3d, TRANS_DATA_CONTAINER_FIRST_OK(t)->obedit->obmat, curr_sv->co_orig_3d); + mul_v3_m4v3(co_orig_3d, + TRANS_DATA_CONTAINER_FIRST_OK(t)->obedit->object_to_world, + curr_sv->co_orig_3d); zfac = ED_view3d_calc_zfac(t->region->regiondata, co_orig_3d); ED_view3d_win_to_delta(t->region, xy_delta, zfac, co_dest_3d); invert_m4_m4(TRANS_DATA_CONTAINER_FIRST_OK(t)->obedit->imat, - TRANS_DATA_CONTAINER_FIRST_OK(t)->obedit->obmat); + TRANS_DATA_CONTAINER_FIRST_OK(t)->obedit->object_to_world); mul_mat3_m4_v3(TRANS_DATA_CONTAINER_FIRST_OK(t)->obedit->imat, co_dest_3d); add_v3_v3(co_dest_3d, curr_sv->co_orig_3d); diff --git a/source/blender/editors/transform/transform_orientations.c b/source/blender/editors/transform/transform_orientations.c index 212df5978e4..66fee01f864 100644 --- a/source/blender/editors/transform/transform_orientations.c +++ b/source/blender/editors/transform/transform_orientations.c @@ -126,7 +126,7 @@ static TransformOrientation *createObjectSpace(bContext *C, ob = base->object; - copy_m3_m4(mat, ob->obmat); + copy_m3_m4(mat, ob->object_to_world); normalize_m3(mat); /* use object name if no name is given */ @@ -532,7 +532,7 @@ short ED_transform_calc_orientation_from_type_ex(const Scene *scene, ED_getTransformOrientationMatrix(scene, view_layer, v3d, ob, obedit, pivot_point, r_mat); } else { - transform_orientations_create_from_axis(r_mat, UNPACK3(ob->obmat)); + transform_orientations_create_from_axis(r_mat, UNPACK3(ob->object_to_world)); } break; } @@ -764,7 +764,7 @@ int getTransformOrientation_ex(const Scene *scene, float imat[3][3], mat[3][3]; /* we need the transpose of the inverse for a normal... */ - copy_m3_m4(imat, ob->obmat); + copy_m3_m4(imat, ob->object_to_world); invert_m3_m3(mat, imat); transpose_m3(mat); @@ -1192,8 +1192,8 @@ int getTransformOrientation_ex(const Scene *scene, if (result == ORIENTATION_EDGE) { float tvec[3]; - mul_mat3_m4_v3(ob->obmat, normal); - mul_mat3_m4_v3(ob->obmat, plane); + mul_mat3_m4_v3(ob->object_to_world, normal); + mul_mat3_m4_v3(ob->object_to_world, plane); /* align normal to edge direction (so normal is perpendicular to the plane). * 'ORIENTATION_EDGE' will do the other way around. @@ -1235,7 +1235,7 @@ int getTransformOrientation_ex(const Scene *scene, /* use for both active & all */ if (ok) { /* we need the transpose of the inverse for a normal... */ - copy_m3_m4(imat, ob->obmat); + copy_m3_m4(imat, ob->object_to_world); invert_m3_m3(mat, imat); transpose_m3(mat); @@ -1267,8 +1267,8 @@ int getTransformOrientation_ex(const Scene *scene, } if (ok) { - copy_v3_v3(normal, ob->obmat[2]); - copy_v3_v3(plane, ob->obmat[1]); + copy_v3_v3(normal, ob->object_to_world[2]); + copy_v3_v3(plane, ob->object_to_world[1]); } } result = ORIENTATION_NORMAL; diff --git a/source/blender/editors/transform/transform_snap.c b/source/blender/editors/transform/transform_snap.c index 3f9cca55138..11cb57dc911 100644 --- a/source/blender/editors/transform/transform_snap.c +++ b/source/blender/editors/transform/transform_snap.c @@ -372,7 +372,7 @@ static bool applyFaceProject(TransInfo *t, TransDataContainer *tc, TransData *td } else if (t->options & CTX_OBJECT) { BKE_object_eval_transform_all(t->depsgraph, t->scene, td->ob); - copy_v3_v3(iloc, td->ob->obmat[3]); + copy_v3_v3(iloc, td->ob->object_to_world[3]); } if (ED_view3d_project_float_global(t->region, iloc, mval_fl, V3D_PROJ_TEST_NOP) != @@ -444,7 +444,7 @@ static void applyFaceNearest(TransInfo *t, TransDataContainer *tc, TransData *td } else if (t->options & CTX_OBJECT) { BKE_object_eval_transform_all(t->depsgraph, t->scene, td->ob); - copy_v3_v3(init_loc, td->ob->obmat[3]); + copy_v3_v3(init_loc, td->ob->object_to_world[3]); } eSnapMode hit = ED_transform_snap_object_project_view3d( @@ -511,56 +511,6 @@ void applySnappingIndividual(TransInfo *t) } } -void applyGridAbsolute(TransInfo *t) -{ - int i; - - if (!(activeSnap(t) && (t->tsnap.mode & (SCE_SNAP_MODE_INCREMENT | SCE_SNAP_MODE_GRID)))) { - return; - } - - float grid_size = (t->modifiers & MOD_PRECISION) ? t->snap_spatial[1] : t->snap_spatial[0]; - - /* early exit on unusable grid size */ - if (grid_size == 0.0f) { - return; - } - - FOREACH_TRANS_DATA_CONTAINER (t, tc) { - TransData *td; - - for (i = 0, td = tc->data; i < tc->data_len; i++, td++) { - float iloc[3], loc[3], tvec[3]; - if (td->flag & TD_SKIP) { - continue; - } - - if ((t->flag & T_PROP_EDIT) && (td->factor == 0.0f)) { - continue; - } - - copy_v3_v3(iloc, td->loc); - if (tc->use_local_mat) { - mul_m4_v3(tc->mat, iloc); - } - else if (t->options & CTX_OBJECT) { - BKE_object_eval_transform_all(t->depsgraph, t->scene, td->ob); - copy_v3_v3(iloc, td->ob->obmat[3]); - } - - mul_v3_v3fl(loc, iloc, 1.0f / grid_size); - loc[0] = roundf(loc[0]); - loc[1] = roundf(loc[1]); - loc[2] = roundf(loc[2]); - mul_v3_fl(loc, grid_size); - - sub_v3_v3v3(tvec, loc, iloc); - mul_m3_v3(td->smtx, tvec); - add_v3_v3(td->loc, tvec); - } - } -} - void applySnappingAsGroup(TransInfo *t, float *vec) { if (!activeSnap_SnappingAsGroup(t)) { @@ -1187,7 +1137,7 @@ static void snap_calc_sequencer_fn(TransInfo *t, float *UNUSED(vec)) /** \name Target * \{ */ -static void snap_target_median_impl(TransInfo *t, float r_median[3]) +void tranform_snap_target_median_calc(const TransInfo *t, float r_median[3]) { int i_accum = 0; @@ -1223,28 +1173,6 @@ static void snap_target_median_impl(TransInfo *t, float r_median[3]) // TargetSnapOffset(t, NULL); } -static void snap_target_grid_ensure(TransInfo *t) -{ - /* Only need to calculate once. */ - if ((t->tsnap.status & TARGET_GRID_INIT) == 0) { - if (t->data_type == &TransConvertType_Cursor3D) { - /* Use a fallback when transforming the cursor. - * In this case the center is _not_ derived from the cursor which is being transformed. */ - copy_v3_v3(t->tsnap.snapTargetGrid, TRANS_DATA_CONTAINER_FIRST_SINGLE(t)->data->iloc); - } - else if (t->around == V3D_AROUND_CURSOR) { - /* Use a fallback for cursor selection, - * this isn't useful as a global center for absolute grid snapping - * since its not based on the position of the selection. */ - snap_target_median_impl(t, t->tsnap.snapTargetGrid); - } - else { - copy_v3_v3(t->tsnap.snapTargetGrid, t->center_global); - } - t->tsnap.status |= TARGET_GRID_INIT; - } -} - static void TargetSnapOffset(TransInfo *t, TransData *td) { if (t->spacetype == SPACE_NODE && td != NULL) { @@ -1316,7 +1244,7 @@ static void TargetSnapMedian(TransInfo *t) { /* Only need to calculate once. */ if ((t->tsnap.status & TARGET_INIT) == 0) { - snap_target_median_impl(t, t->tsnap.snapTarget); + tranform_snap_target_median_calc(t, t->tsnap.snapTarget); t->tsnap.status |= TARGET_INIT; } } @@ -1654,61 +1582,6 @@ bool snapNodesTransform( /** \name snap Grid * \{ */ -static void snap_grid_apply( - TransInfo *t, const int max_index, const float grid_dist, const float loc[3], float r_out[3]) -{ - BLI_assert(max_index <= 2); - snap_target_grid_ensure(t); - const float *center_global = t->tsnap.snapTargetGrid; - const float *asp = t->aspect; - - float in[3]; - if (t->con.mode & CON_APPLY) { - BLI_assert(t->tsnap.snapElem == SCE_SNAP_MODE_NONE); - t->con.applyVec(t, NULL, NULL, loc, in); - } - else { - copy_v3_v3(in, loc); - } - - for (int i = 0; i <= max_index; i++) { - const float iter_fac = grid_dist * asp[i]; - r_out[i] = iter_fac * roundf((in[i] + center_global[i]) / iter_fac) - center_global[i]; - } -} - -bool transform_snap_grid(TransInfo *t, float *val) -{ - if (!activeSnap(t)) { - return false; - } - - if (!(t->tsnap.mode & SCE_SNAP_MODE_GRID) || validSnap(t)) { - /* Don't do grid snapping if there is a valid snap point. */ - return false; - } - - /* Don't do grid snapping if not in 3D viewport or UV editor */ - if (!ELEM(t->spacetype, SPACE_VIEW3D, SPACE_IMAGE)) { - return false; - } - - if (t->mode != TFM_TRANSLATION) { - return false; - } - - float grid_dist = (t->modifiers & MOD_PRECISION) ? t->snap[1] : t->snap[0]; - - /* Early bailing out if no need to snap */ - if (grid_dist == 0.0f) { - return false; - } - - snap_grid_apply(t, t->idx_max, grid_dist, val, val); - t->tsnap.snapElem = SCE_SNAP_MODE_GRID; - return true; -} - static void snap_increment_apply_ex(const TransInfo *UNUSED(t), const int max_index, const float increment_val, diff --git a/source/blender/editors/transform/transform_snap.h b/source/blender/editors/transform/transform_snap.h index 2b78c554ad8..16d9062e978 100644 --- a/source/blender/editors/transform/transform_snap.h +++ b/source/blender/editors/transform/transform_snap.h @@ -38,10 +38,10 @@ bool snapNodesTransform(struct TransInfo *t, bool transformModeUseSnap(const TransInfo *t); +void tranform_snap_target_median_calc(const TransInfo *t, float r_median[3]); bool transform_snap_increment_ex(const TransInfo *t, bool use_local_space, float *r_val); bool transform_snap_increment(const TransInfo *t, float *val); float transform_snap_increment_get(const TransInfo *t); -bool transform_snap_grid(TransInfo *t, float *val); bool activeSnap(const TransInfo *t); bool activeSnap_SnappingIndividual(const TransInfo *t); @@ -52,7 +52,6 @@ bool validSnap(const TransInfo *t); void initSnapping(struct TransInfo *t, struct wmOperator *op); void freeSnapping(struct TransInfo *t); void applySnappingIndividual(TransInfo *t); -void applyGridAbsolute(TransInfo *t); void applySnappingAsGroup(TransInfo *t, float *vec); void resetSnapping(TransInfo *t); eRedrawFlag handleSnapping(TransInfo *t, const struct wmEvent *event); diff --git a/source/blender/editors/transform/transform_snap_object.cc b/source/blender/editors/transform/transform_snap_object.cc index 7971e1ca9af..24d76a50117 100644 --- a/source/blender/editors/transform/transform_snap_object.cc +++ b/source/blender/editors/transform/transform_snap_object.cc @@ -565,7 +565,7 @@ static void iter_snap_objects(SnapObjectContext *sctx, free_object_duplilist(lb); } - sob_callback(sctx, params, obj_eval, obj_eval->obmat, is_object_active, data); + sob_callback(sctx, params, obj_eval, obj_eval->object_to_world, is_object_active, data); } } @@ -1145,7 +1145,7 @@ static void raycast_obj_fn(SnapObjectContext *sctx, * \param r_index: Hit index or -1 when no valid index is found. * (currently only set to the polygon index when using `snap_to == SCE_SNAP_MODE_FACE_RAYCAST`). * \param r_ob: Hit object. - * \param r_obmat: Object matrix (may not be #Object.obmat with dupli-instances). + * \param r_obmat: Object matrix (may not be #Object.object_to_world with dupli-instances). * \param r_hit_list: List of #SnapObjectHitDepth (caller must free). */ static bool raycastObjects(SnapObjectContext *sctx, @@ -1483,7 +1483,7 @@ static void nearest_world_object_fn(SnapObjectContext *sctx, * \param r_no: Normal of nearest point on target surface. * \param r_index: Index of nearest polygon on target surface. * \param r_ob: Nearest target object. - * \param r_obmat: Nearest target matrix (may not be #Object.obmat with dupli-instances). + * \param r_obmat: Nearest target matrix (may not be #Object.object_to_world with dupli-instances). */ static bool nearestWorldObjects(SnapObjectContext *sctx, const struct SnapObjectParams *params, @@ -3177,7 +3177,7 @@ static void snap_obj_fn(SnapObjectContext *sctx, * \param r_index: Hit index or -1 when no valid index is found. * (currently only set to the polygon index when using `snap_to == SCE_SNAP_MODE_FACE_RAYCAST`). * \param r_ob: Hit object. - * \param r_obmat: Object matrix (may not be #Object.obmat with dupli-instances). + * \param r_obmat: Object matrix (may not be #Object.object_to_world with dupli-instances). */ static eSnapMode snapObjectsRay(SnapObjectContext *sctx, const SnapObjectParams *params, diff --git a/source/blender/editors/util/ed_util.c b/source/blender/editors/util/ed_util.c index 12e77c6ef00..92d65688bf1 100644 --- a/source/blender/editors/util/ed_util.c +++ b/source/blender/editors/util/ed_util.c @@ -374,7 +374,7 @@ void unpack_menu(bContext *C, char local_name[FILE_MAXDIR + FILE_MAX], fi[FILE_MAX]; BLI_split_file_part(abs_name, fi, sizeof(fi)); - BLI_path_join(local_name, sizeof(local_name), "//", folder, fi, NULL); + BLI_path_join(local_name, sizeof(local_name), "//", folder, fi); if (!STREQ(abs_name, local_name)) { switch (BKE_packedfile_compare_to_file(blendfile_path, local_name, pf)) { case PF_CMP_NOFILE: diff --git a/source/blender/editors/util/ed_viewer_path.cc b/source/blender/editors/util/ed_viewer_path.cc index 5c03367cba8..4da1559b726 100644 --- a/source/blender/editors/util/ed_viewer_path.cc +++ b/source/blender/editors/util/ed_viewer_path.cc @@ -249,6 +249,9 @@ bool is_active_geometry_nodes_viewer(const bContext &C, if (md->type != eModifierType_Nodes) { return false; } + if ((md->mode & eModifierMode_Realtime) == 0) { + return false; + } modifier = reinterpret_cast<const NodesModifierData *>(md); break; } diff --git a/source/blender/editors/uvedit/uvedit_islands.cc b/source/blender/editors/uvedit/uvedit_islands.cc index bdd05b06d94..92745667505 100644 --- a/source/blender/editors/uvedit/uvedit_islands.cc +++ b/source/blender/editors/uvedit/uvedit_islands.cc @@ -600,6 +600,22 @@ static BoxPack *pack_islands_params(const blender::Vector<FaceIsland *> &island_ return box_array; } +static bool island_has_pins(FaceIsland *island) +{ + BMLoop *l; + BMIter iter; + const int cd_loop_uv_offset = island->cd_loop_uv_offset; + for (int i = 0; i < island->faces_len; i++) { + BM_ITER_ELEM (l, &iter, island->faces[i], BM_LOOPS_OF_FACE) { + MLoopUV *luv = static_cast<MLoopUV *>(BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset)); + if (luv->flag & MLOOPUV_PINNED) { + return true; + } + } + } + return false; +} + /* -------------------------------------------------------------------- */ /** \name Public UV Island Packing * @@ -651,8 +667,14 @@ void ED_uvedit_pack_islands_multi(const Scene *scene, aspect_y, cd_loop_uv_offset); - int index; - LISTBASE_FOREACH_INDEX (struct FaceIsland *, island, &island_list, index) { + /* Remove from linked list and append to blender::Vector. */ + LISTBASE_FOREACH_MUTABLE (struct FaceIsland *, island, &island_list) { + BLI_remlink(&island_list, island); + if (params->ignore_pinned && island_has_pins(island)) { + MEM_freeN(island->faces); + MEM_freeN(island); + continue; + } island_vector.append(island); } } diff --git a/source/blender/editors/uvedit/uvedit_ops.c b/source/blender/editors/uvedit/uvedit_ops.c index 5e2d9097abd..b65f4889347 100644 --- a/source/blender/editors/uvedit/uvedit_ops.c +++ b/source/blender/editors/uvedit/uvedit_ops.c @@ -37,6 +37,7 @@ #include "BKE_node.h" #include "DEG_depsgraph.h" +#include "DEG_depsgraph_query.h" #include "ED_image.h" #include "ED_mesh.h" @@ -113,7 +114,8 @@ bool ED_object_get_active_image(Object *ob, bNode **r_node, bNodeTree **r_ntree) { - Material *ma = BKE_object_material_get(ob, mat_nr); + Material *ma = DEG_is_evaluated_object(ob) ? BKE_object_material_get_eval(ob, mat_nr) : + BKE_object_material_get(ob, mat_nr); bNodeTree *ntree = (ma && ma->use_nodes) ? ma->nodetree : NULL; bNode *node = (ntree) ? nodeGetActiveTexture(ntree) : NULL; diff --git a/source/blender/editors/uvedit/uvedit_select.c b/source/blender/editors/uvedit/uvedit_select.c index 7dd223a9252..777cc1d97e4 100644 --- a/source/blender/editors/uvedit/uvedit_select.c +++ b/source/blender/editors/uvedit/uvedit_select.c @@ -4705,7 +4705,7 @@ static int uv_select_similar_vert_exec(bContext *C, wmOperator *op) const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV); float ob_m3[3][3]; - copy_m3_m4(ob_m3, ob->obmat); + copy_m3_m4(ob_m3, ob->object_to_world); BMFace *face; BMIter iter; @@ -4742,7 +4742,7 @@ static int uv_select_similar_vert_exec(bContext *C, wmOperator *op) bool changed = false; const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV); float ob_m3[3][3]; - copy_m3_m4(ob_m3, ob->obmat); + copy_m3_m4(ob_m3, ob->object_to_world); BMFace *face; BMIter iter; @@ -4818,7 +4818,7 @@ static int uv_select_similar_edge_exec(bContext *C, wmOperator *op) const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV); float ob_m3[3][3]; - copy_m3_m4(ob_m3, ob->obmat); + copy_m3_m4(ob_m3, ob->object_to_world); BMFace *face; BMIter iter; @@ -4859,7 +4859,7 @@ static int uv_select_similar_edge_exec(bContext *C, wmOperator *op) bool changed = false; const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV); float ob_m3[3][3]; - copy_m3_m4(ob_m3, ob->obmat); + copy_m3_m4(ob_m3, ob->object_to_world); BMFace *face; BMIter iter; @@ -4927,7 +4927,7 @@ static int uv_select_similar_face_exec(bContext *C, wmOperator *op) BMesh *bm = em->bm; float ob_m3[3][3]; - copy_m3_m4(ob_m3, ob->obmat); + copy_m3_m4(ob_m3, ob->object_to_world); const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV); @@ -4963,7 +4963,7 @@ static int uv_select_similar_face_exec(bContext *C, wmOperator *op) const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV); float ob_m3[3][3]; - copy_m3_m4(ob_m3, ob->obmat); + copy_m3_m4(ob_m3, ob->object_to_world); BMFace *face; BMIter iter; @@ -5053,7 +5053,7 @@ static int uv_select_similar_island_exec(bContext *C, wmOperator *op) } float ob_m3[3][3]; - copy_m3_m4(ob_m3, obedit->obmat); + copy_m3_m4(ob_m3, obedit->object_to_world); int index; LISTBASE_FOREACH_INDEX (struct FaceIsland *, island, &island_list_ptr[ob_index], index) { @@ -5082,7 +5082,7 @@ static int uv_select_similar_island_exec(bContext *C, wmOperator *op) continue; } float ob_m3[3][3]; - copy_m3_m4(ob_m3, obedit->obmat); + copy_m3_m4(ob_m3, obedit->object_to_world); bool changed = false; int index; diff --git a/source/blender/editors/uvedit/uvedit_unwrap_ops.c b/source/blender/editors/uvedit/uvedit_unwrap_ops.c index 2c977552e72..de1c88fe896 100644 --- a/source/blender/editors/uvedit/uvedit_unwrap_ops.c +++ b/source/blender/editors/uvedit/uvedit_unwrap_ops.c @@ -1050,31 +1050,6 @@ void UV_OT_minimize_stretch(wmOperatorType *ot) /** \name Pack UV Islands Operator * \{ */ -/** - * \warning Since this uses #ParamHandle it doesn't work with non-manifold meshes (see T82637). - * Use #ED_uvedit_pack_islands_multi for a more general solution. - * - * TODO: remove this function, in favor of #ED_uvedit_pack_islands_multi. - */ -static void uvedit_pack_islands_multi(const Scene *scene, - Object **objects, - const uint objects_len, - const UnwrapOptions *options, - bool rotate, - bool ignore_pinned) -{ - ParamHandle *handle = construct_param_handle_multi(scene, objects, objects_len, options); - GEO_uv_parametrizer_pack(handle, scene->toolsettings->uvcalc_margin, rotate, ignore_pinned); - GEO_uv_parametrizer_flush(handle); - GEO_uv_parametrizer_delete(handle); - - for (uint ob_index = 0; ob_index < objects_len; ob_index++) { - Object *obedit = objects[ob_index]; - DEG_id_tag_update(obedit->data, ID_RECALC_GEOMETRY); - WM_main_add_notifier(NC_GEOM | ND_DATA, obedit->data); - } -} - /* Packing targets. */ enum { PACK_UDIM_SRC_CLOSEST = 0, @@ -1119,16 +1094,22 @@ static int pack_islands_exec(bContext *C, wmOperator *op) const bool use_udim_params = ED_uvedit_udim_params_from_image_space( sima, use_active, &udim_params); - struct UVPackIsland_Params params = { + const struct UVPackIsland_Params pack_island_params = { .rotate = RNA_boolean_get(op->ptr, "rotate"), - .only_selected_uvs = true, - .only_selected_faces = true, - .correct_aspect = true, + .only_selected_uvs = options.only_selected_uvs, + .only_selected_faces = options.only_selected_faces, + .use_seams = !options.topology_from_uvs || options.topology_from_uvs_use_seams, + .correct_aspect = options.correct_aspect, + .ignore_pinned = false, .margin_method = RNA_enum_get(op->ptr, "margin_method"), .margin = RNA_float_get(op->ptr, "margin"), }; - ED_uvedit_pack_islands_multi( - scene, objects, objects_len, NULL, use_udim_params ? &udim_params : NULL, ¶ms); + ED_uvedit_pack_islands_multi(scene, + objects, + objects_len, + NULL, + use_udim_params ? &udim_params : NULL, + &pack_island_params); MEM_freeN(objects); return OPERATOR_FINISHED; @@ -1407,7 +1388,7 @@ static void uv_map_transform_center(const Scene *scene, } case V3D_AROUND_CURSOR: /* cursor center */ { - invert_m4_m4(ob->imat, ob->obmat); + invert_m4_m4(ob->imat, ob->object_to_world); mul_v3_m4v3(r_center, ob->imat, scene->cursor.location); break; } @@ -1458,7 +1439,7 @@ static void uv_map_rotation_matrix_ex(float result[4][4], zero_v3(viewmatrix[3]); /* get rotation of the current object matrix */ - copy_m4_m4(rotobj, ob->obmat); + copy_m4_m4(rotobj, ob->object_to_world); zero_v3(rotobj[3]); /* but shifting */ @@ -1793,8 +1774,8 @@ static void uv_map_clip_correct(const Scene *scene, dy = 1.0f / dy; } - if (dx == 1.0f && dy == 1.0f) { - /* Scaling by 1.0 has no effect. */ + if (dx == 1.0f && dy == 1.0f && min[0] == 0.0f && min[1] == 0.0f) { + /* Scaling by 1.0, without translating, has no effect. */ return; } @@ -1889,12 +1870,19 @@ void ED_uvedit_live_unwrap(const Scene *scene, Object **objects, int objects_len .fill_holes = (scene->toolsettings->uvcalc_flag & UVCALC_FILLHOLES) != 0, .correct_aspect = (scene->toolsettings->uvcalc_flag & UVCALC_NO_ASPECT_CORRECT) == 0, }; - - bool rotate = true; - bool ignore_pinned = true; - uvedit_unwrap_multi(scene, objects, objects_len, &options, NULL); - uvedit_pack_islands_multi(scene, objects, objects_len, &options, rotate, ignore_pinned); + + const struct UVPackIsland_Params pack_island_params = { + .rotate = true, + .only_selected_uvs = options.only_selected_uvs, + .only_selected_faces = options.only_selected_faces, + .use_seams = !options.topology_from_uvs || options.topology_from_uvs_use_seams, + .correct_aspect = options.correct_aspect, + .ignore_pinned = true, + .margin_method = ED_UVPACK_MARGIN_SCALED, + .margin = scene->toolsettings->uvcalc_margin, + }; + ED_uvedit_pack_islands_multi(scene, objects, objects_len, NULL, NULL, &pack_island_params); } } @@ -1926,8 +1914,6 @@ static int unwrap_exec(bContext *C, wmOperator *op) .correct_aspect = RNA_boolean_get(op->ptr, "correct_aspect"), }; - bool rotate = true; - bool ignore_pinned = true; if (CTX_wm_space_image(C)) { /* Inside the UV Editor, only unwrap selected UVs. */ options.only_selected_uvs = true; @@ -1962,7 +1948,7 @@ static int unwrap_exec(bContext *C, wmOperator *op) continue; } - mat4_to_size(obsize, obedit->obmat); + mat4_to_size(obsize, obedit->object_to_world); if (!(fabsf(obsize[0] - obsize[1]) < 1e-4f && fabsf(obsize[1] - obsize[2]) < 1e-4f)) { if ((reported_errors & UNWRAP_ERROR_NONUNIFORM) == 0) { BKE_report(op->reports, @@ -1972,7 +1958,7 @@ static int unwrap_exec(bContext *C, wmOperator *op) reported_errors |= UNWRAP_ERROR_NONUNIFORM; } } - else if (is_negative_m4(obedit->obmat)) { + else if (is_negative_m4(obedit->object_to_world)) { if ((reported_errors & UNWRAP_ERROR_NEGATIVE) == 0) { BKE_report( op->reports, @@ -2032,7 +2018,18 @@ static int unwrap_exec(bContext *C, wmOperator *op) .count_failed = 0, }; uvedit_unwrap_multi(scene, objects, objects_len, &options, &result_info); - uvedit_pack_islands_multi(scene, objects, objects_len, &options, rotate, ignore_pinned); + + const struct UVPackIsland_Params pack_island_params = { + .rotate = true, + .only_selected_uvs = options.only_selected_uvs, + .only_selected_faces = options.only_selected_faces, + .use_seams = !options.topology_from_uvs || options.topology_from_uvs_use_seams, + .correct_aspect = options.correct_aspect, + .ignore_pinned = true, + .margin_method = RNA_enum_get(op->ptr, "margin_method"), + .margin = RNA_float_get(op->ptr, "margin"), + }; + ED_uvedit_pack_islands_multi(scene, objects, objects_len, NULL, NULL, &pack_island_params); MEM_freeN(objects); @@ -2541,7 +2538,7 @@ static int uv_from_view_exec(bContext *C, wmOperator *op) float objects_pos_avg[4] = {0}; for (uint ob_index = 0; ob_index < objects_len; ob_index++) { - add_v4_v4(objects_pos_avg, objects[ob_index]->obmat[3]); + add_v4_v4(objects_pos_avg, objects[ob_index]->object_to_world[3]); } mul_v4_fl(objects_pos_avg, 1.0f / objects_len); @@ -2579,7 +2576,7 @@ static int uv_from_view_exec(bContext *C, wmOperator *op) const bool camera_bounds = RNA_boolean_get(op->ptr, "camera_bounds"); struct ProjCameraInfo *uci = BLI_uvproject_camera_info( v3d->camera, - obedit->obmat, + obedit->object_to_world, camera_bounds ? (scene->r.xsch * scene->r.xasp) : 1.0f, camera_bounds ? (scene->r.ysch * scene->r.yasp) : 1.0f); @@ -2600,7 +2597,7 @@ static int uv_from_view_exec(bContext *C, wmOperator *op) } } else { - copy_m4_m4(rotmat, obedit->obmat); + copy_m4_m4(rotmat, obedit->object_to_world); BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { if (!BM_elem_flag_test(efa, BM_ELEM_SELECT)) { diff --git a/source/blender/freestyle/intern/blender_interface/BlenderFileLoader.cpp b/source/blender/freestyle/intern/blender_interface/BlenderFileLoader.cpp index 19589491bc4..53c2b1d235b 100644 --- a/source/blender/freestyle/intern/blender_interface/BlenderFileLoader.cpp +++ b/source/blender/freestyle/intern/blender_interface/BlenderFileLoader.cpp @@ -73,7 +73,8 @@ NodeGroup *BlenderFileLoader::Load() break; } - if (ob->base_flag & (BASE_HOLDOUT | BASE_INDIRECT_ONLY)) { + if ((ob->base_flag & (BASE_HOLDOUT | BASE_INDIRECT_ONLY)) || + (ob->visibility_flag & OB_HOLDOUT)) { continue; } @@ -430,7 +431,7 @@ void BlenderFileLoader::insertShapeNode(Object *ob, Mesh *me, int id) // Compute matrix including camera transform float obmat[4][4], nmat[4][4]; - mul_m4_m4m4(obmat, viewmat, ob->obmat); + mul_m4_m4m4(obmat, viewmat, ob->object_to_world); invert_m4_m4(nmat, obmat); transpose_m4(nmat); diff --git a/source/blender/freestyle/intern/geometry/FitCurve.cpp b/source/blender/freestyle/intern/geometry/FitCurve.cpp index ad9b7dfa5ed..0d47665c6d3 100644 --- a/source/blender/freestyle/intern/geometry/FitCurve.cpp +++ b/source/blender/freestyle/intern/geometry/FitCurve.cpp @@ -12,6 +12,8 @@ #include "FitCurve.h" +#include "BLI_sys_types.h" + using namespace std; namespace Freestyle { diff --git a/source/blender/freestyle/intern/geometry/GeomCleaner.cpp b/source/blender/freestyle/intern/geometry/GeomCleaner.cpp index c17fb92a58c..db6816bf045 100644 --- a/source/blender/freestyle/intern/geometry/GeomCleaner.cpp +++ b/source/blender/freestyle/intern/geometry/GeomCleaner.cpp @@ -25,6 +25,8 @@ #include "BKE_global.h" +#include "BLI_sys_types.h" + using namespace std; namespace Freestyle { diff --git a/source/blender/freestyle/intern/geometry/GeomUtils.cpp b/source/blender/freestyle/intern/geometry/GeomUtils.cpp index f1e4297ab5e..b8beeed5880 100644 --- a/source/blender/freestyle/intern/geometry/GeomUtils.cpp +++ b/source/blender/freestyle/intern/geometry/GeomUtils.cpp @@ -7,6 +7,8 @@ #include "GeomUtils.h" +#include "BLI_sys_types.h" + namespace Freestyle::GeomUtils { // This internal procedure is defined below. diff --git a/source/blender/freestyle/intern/geometry/HashGrid.cpp b/source/blender/freestyle/intern/geometry/HashGrid.cpp index 51c87757645..46ce9184951 100644 --- a/source/blender/freestyle/intern/geometry/HashGrid.cpp +++ b/source/blender/freestyle/intern/geometry/HashGrid.cpp @@ -7,6 +7,8 @@ #include "HashGrid.h" +#include "BLI_sys_types.h" + namespace Freestyle { void HashGrid::clear() diff --git a/source/blender/freestyle/intern/geometry/Noise.cpp b/source/blender/freestyle/intern/geometry/Noise.cpp index 306913e6297..04e271f7a5b 100644 --- a/source/blender/freestyle/intern/geometry/Noise.cpp +++ b/source/blender/freestyle/intern/geometry/Noise.cpp @@ -12,6 +12,7 @@ #include "BLI_compiler_attrs.h" #include "BLI_rand.h" +#include "BLI_sys_types.h" #include "Noise.h" diff --git a/source/blender/freestyle/intern/image/ImagePyramid.cpp b/source/blender/freestyle/intern/image/ImagePyramid.cpp index 95afa4dda48..bc68d17a1f9 100644 --- a/source/blender/freestyle/intern/image/ImagePyramid.cpp +++ b/source/blender/freestyle/intern/image/ImagePyramid.cpp @@ -11,6 +11,8 @@ #include "Image.h" #include "ImagePyramid.h" +#include "BLI_sys_types.h" + using namespace std; namespace Freestyle { diff --git a/source/blender/freestyle/intern/python/BPy_ContextFunctions.cpp b/source/blender/freestyle/intern/python/BPy_ContextFunctions.cpp index 114fafea55b..d79c2f4d9b0 100644 --- a/source/blender/freestyle/intern/python/BPy_ContextFunctions.cpp +++ b/source/blender/freestyle/intern/python/BPy_ContextFunctions.cpp @@ -9,6 +9,8 @@ #include "../stroke/ContextFunctions.h" +#include "BLI_sys_types.h" + using namespace Freestyle; #ifdef __cplusplus diff --git a/source/blender/freestyle/intern/python/BPy_Freestyle.cpp b/source/blender/freestyle/intern/python/BPy_Freestyle.cpp index 96887f7a83b..237f1802026 100644 --- a/source/blender/freestyle/intern/python/BPy_Freestyle.cpp +++ b/source/blender/freestyle/intern/python/BPy_Freestyle.cpp @@ -531,7 +531,7 @@ PyObject *Freestyle_Init(void) const char *const path = BKE_appdir_folder_id(BLENDER_SYSTEM_SCRIPTS, "freestyle"); if (path) { char modpath[FILE_MAX]; - BLI_join_dirfile(modpath, sizeof(modpath), path, "modules"); + BLI_path_join(modpath, sizeof(modpath), path, "modules"); PyObject *sys_path = PySys_GetObject("path"); /* borrow */ PyObject *py_modpath = PyUnicode_FromString(modpath); PyList_Append(sys_path, py_modpath); diff --git a/source/blender/freestyle/intern/python/BPy_FrsNoise.cpp b/source/blender/freestyle/intern/python/BPy_FrsNoise.cpp index 097fdb6a16b..684edb26a97 100644 --- a/source/blender/freestyle/intern/python/BPy_FrsNoise.cpp +++ b/source/blender/freestyle/intern/python/BPy_FrsNoise.cpp @@ -9,6 +9,8 @@ #include "../system/RandGen.h" +#include "BLI_sys_types.h" + #include <sstream> #ifdef __cplusplus diff --git a/source/blender/freestyle/intern/python/BPy_IntegrationType.cpp b/source/blender/freestyle/intern/python/BPy_IntegrationType.cpp index d88d3edecc0..711cf9c6bab 100644 --- a/source/blender/freestyle/intern/python/BPy_IntegrationType.cpp +++ b/source/blender/freestyle/intern/python/BPy_IntegrationType.cpp @@ -12,6 +12,8 @@ #include "UnaryFunction0D/BPy_UnaryFunction0DFloat.h" #include "UnaryFunction0D/BPy_UnaryFunction0DUnsigned.h" +#include "BLI_sys_types.h" + #ifdef __cplusplus extern "C" { #endif diff --git a/source/blender/freestyle/intern/python/BPy_Operators.cpp b/source/blender/freestyle/intern/python/BPy_Operators.cpp index 1c5e90474ab..860573016f2 100644 --- a/source/blender/freestyle/intern/python/BPy_Operators.cpp +++ b/source/blender/freestyle/intern/python/BPy_Operators.cpp @@ -16,6 +16,8 @@ #include "UnaryFunction0D/BPy_UnaryFunction0DDouble.h" #include "UnaryFunction1D/BPy_UnaryFunction1DVoid.h" +#include "BLI_sys_types.h" + #include <sstream> #ifdef __cplusplus diff --git a/source/blender/freestyle/intern/python/BPy_SShape.cpp b/source/blender/freestyle/intern/python/BPy_SShape.cpp index 7fb647119e6..92867e36479 100644 --- a/source/blender/freestyle/intern/python/BPy_SShape.cpp +++ b/source/blender/freestyle/intern/python/BPy_SShape.cpp @@ -12,6 +12,8 @@ #include "Interface0D/BPy_SVertex.h" #include "Interface1D/BPy_FEdge.h" +#include "BLI_sys_types.h" + #ifdef __cplusplus extern "C" { #endif diff --git a/source/blender/freestyle/intern/python/BPy_ViewShape.cpp b/source/blender/freestyle/intern/python/BPy_ViewShape.cpp index 77c3c708103..130526ac309 100644 --- a/source/blender/freestyle/intern/python/BPy_ViewShape.cpp +++ b/source/blender/freestyle/intern/python/BPy_ViewShape.cpp @@ -11,6 +11,8 @@ #include "Interface0D/BPy_ViewVertex.h" #include "Interface1D/BPy_ViewEdge.h" +#include "BLI_sys_types.h" + #ifdef __cplusplus extern "C" { #endif diff --git a/source/blender/freestyle/intern/python/Director.cpp b/source/blender/freestyle/intern/python/Director.cpp index ad54787ad05..40df2033221 100644 --- a/source/blender/freestyle/intern/python/Director.cpp +++ b/source/blender/freestyle/intern/python/Director.cpp @@ -42,6 +42,8 @@ #include "UnaryFunction1D/BPy_UnaryFunction1DVec3f.h" #include "UnaryFunction1D/BPy_UnaryFunction1DVectorViewShape.h" +#include "BLI_sys_types.h" + using namespace Freestyle; // BinaryPredicate0D: __call__ diff --git a/source/blender/freestyle/intern/python/Interface0D/BPy_SVertex.cpp b/source/blender/freestyle/intern/python/Interface0D/BPy_SVertex.cpp index cb84b7e82ba..55faebc509c 100644 --- a/source/blender/freestyle/intern/python/Interface0D/BPy_SVertex.cpp +++ b/source/blender/freestyle/intern/python/Interface0D/BPy_SVertex.cpp @@ -10,6 +10,8 @@ #include "../BPy_Id.h" #include "../Interface1D/BPy_FEdge.h" +#include "BLI_sys_types.h" + #ifdef __cplusplus extern "C" { #endif diff --git a/source/blender/freestyle/intern/python/Interface1D/BPy_Stroke.cpp b/source/blender/freestyle/intern/python/Interface1D/BPy_Stroke.cpp index e9dcedef34e..6f90406d74d 100644 --- a/source/blender/freestyle/intern/python/Interface1D/BPy_Stroke.cpp +++ b/source/blender/freestyle/intern/python/Interface1D/BPy_Stroke.cpp @@ -13,6 +13,8 @@ #include "../Interface0D/CurvePoint/BPy_StrokeVertex.h" #include "../Iterator/BPy_StrokeVertexIterator.h" +#include "BLI_sys_types.h" + #ifdef __cplusplus extern "C" { #endif diff --git a/source/blender/freestyle/intern/python/Interface1D/FEdge/BPy_FEdgeSharp.cpp b/source/blender/freestyle/intern/python/Interface1D/FEdge/BPy_FEdgeSharp.cpp index 0a4d1a5d32c..aae8d5514c9 100644 --- a/source/blender/freestyle/intern/python/Interface1D/FEdge/BPy_FEdgeSharp.cpp +++ b/source/blender/freestyle/intern/python/Interface1D/FEdge/BPy_FEdgeSharp.cpp @@ -9,6 +9,8 @@ #include "../../BPy_Convert.h" #include "../../Interface0D/BPy_SVertex.h" +#include "BLI_sys_types.h" + #ifdef __cplusplus extern "C" { #endif diff --git a/source/blender/freestyle/intern/python/Interface1D/FEdge/BPy_FEdgeSmooth.cpp b/source/blender/freestyle/intern/python/Interface1D/FEdge/BPy_FEdgeSmooth.cpp index 51ae9334f37..6516ad8af9c 100644 --- a/source/blender/freestyle/intern/python/Interface1D/FEdge/BPy_FEdgeSmooth.cpp +++ b/source/blender/freestyle/intern/python/Interface1D/FEdge/BPy_FEdgeSmooth.cpp @@ -9,6 +9,8 @@ #include "../../BPy_Convert.h" #include "../../Interface0D/BPy_SVertex.h" +#include "BLI_sys_types.h" + #ifdef __cplusplus extern "C" { #endif diff --git a/source/blender/freestyle/intern/python/UnaryFunction0D/BPy_UnaryFunction0DUnsigned.cpp b/source/blender/freestyle/intern/python/UnaryFunction0D/BPy_UnaryFunction0DUnsigned.cpp index 29e1a1d3525..8faefd085d6 100644 --- a/source/blender/freestyle/intern/python/UnaryFunction0D/BPy_UnaryFunction0DUnsigned.cpp +++ b/source/blender/freestyle/intern/python/UnaryFunction0D/BPy_UnaryFunction0DUnsigned.cpp @@ -11,6 +11,8 @@ #include "UnaryFunction0D_unsigned_int/BPy_QuantitativeInvisibilityF0D.h" +#include "BLI_sys_types.h" + #ifdef __cplusplus extern "C" { #endif diff --git a/source/blender/freestyle/intern/python/UnaryFunction0D/BPy_UnaryFunction0DVectorViewShape.cpp b/source/blender/freestyle/intern/python/UnaryFunction0D/BPy_UnaryFunction0DVectorViewShape.cpp index e0aa5af2adb..7f5b98da223 100644 --- a/source/blender/freestyle/intern/python/UnaryFunction0D/BPy_UnaryFunction0DVectorViewShape.cpp +++ b/source/blender/freestyle/intern/python/UnaryFunction0D/BPy_UnaryFunction0DVectorViewShape.cpp @@ -11,6 +11,8 @@ #include "UnaryFunction0D_vector_ViewShape/BPy_GetOccludersF0D.h" +#include "BLI_sys_types.h" + #ifdef __cplusplus extern "C" { #endif diff --git a/source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_float/BPy_ReadSteerableViewMapPixelF0D.cpp b/source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_float/BPy_ReadSteerableViewMapPixelF0D.cpp index 3a2c9868014..82362704119 100644 --- a/source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_float/BPy_ReadSteerableViewMapPixelF0D.cpp +++ b/source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_float/BPy_ReadSteerableViewMapPixelF0D.cpp @@ -8,6 +8,8 @@ #include "../../../stroke/AdvancedFunctions0D.h" +#include "BLI_sys_types.h" + #ifdef __cplusplus extern "C" { #endif diff --git a/source/blender/freestyle/intern/python/UnaryFunction1D/BPy_UnaryFunction1DUnsigned.cpp b/source/blender/freestyle/intern/python/UnaryFunction1D/BPy_UnaryFunction1DUnsigned.cpp index 41bc3199271..800a5da1978 100644 --- a/source/blender/freestyle/intern/python/UnaryFunction1D/BPy_UnaryFunction1DUnsigned.cpp +++ b/source/blender/freestyle/intern/python/UnaryFunction1D/BPy_UnaryFunction1DUnsigned.cpp @@ -12,6 +12,8 @@ #include "UnaryFunction1D_unsigned_int/BPy_QuantitativeInvisibilityF1D.h" +#include "BLI_sys_types.h" + #ifdef __cplusplus extern "C" { #endif diff --git a/source/blender/freestyle/intern/python/UnaryFunction1D/BPy_UnaryFunction1DVectorViewShape.cpp b/source/blender/freestyle/intern/python/UnaryFunction1D/BPy_UnaryFunction1DVectorViewShape.cpp index 242f4a141bc..fa15983f0d3 100644 --- a/source/blender/freestyle/intern/python/UnaryFunction1D/BPy_UnaryFunction1DVectorViewShape.cpp +++ b/source/blender/freestyle/intern/python/UnaryFunction1D/BPy_UnaryFunction1DVectorViewShape.cpp @@ -14,6 +14,8 @@ #include "UnaryFunction1D_vector_ViewShape/BPy_GetOccludersF1D.h" #include "UnaryFunction1D_vector_ViewShape/BPy_GetShapeF1D.h" +#include "BLI_sys_types.h" + #ifdef __cplusplus extern "C" { #endif diff --git a/source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_double/BPy_GetDirectionalViewMapDensityF1D.cpp b/source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_double/BPy_GetDirectionalViewMapDensityF1D.cpp index b513686524e..d1479f27935 100644 --- a/source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_double/BPy_GetDirectionalViewMapDensityF1D.cpp +++ b/source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_double/BPy_GetDirectionalViewMapDensityF1D.cpp @@ -10,6 +10,8 @@ #include "../../BPy_Convert.h" #include "../../BPy_IntegrationType.h" +#include "BLI_sys_types.h" + #ifdef __cplusplus extern "C" { #endif diff --git a/source/blender/freestyle/intern/python/UnaryPredicate1D/BPy_EqualToChainingTimeStampUP1D.cpp b/source/blender/freestyle/intern/python/UnaryPredicate1D/BPy_EqualToChainingTimeStampUP1D.cpp index ecf95e189d8..99c688985f5 100644 --- a/source/blender/freestyle/intern/python/UnaryPredicate1D/BPy_EqualToChainingTimeStampUP1D.cpp +++ b/source/blender/freestyle/intern/python/UnaryPredicate1D/BPy_EqualToChainingTimeStampUP1D.cpp @@ -6,6 +6,8 @@ #include "BPy_EqualToChainingTimeStampUP1D.h" +#include "BLI_sys_types.h" + #ifdef __cplusplus extern "C" { #endif diff --git a/source/blender/freestyle/intern/python/UnaryPredicate1D/BPy_EqualToTimeStampUP1D.cpp b/source/blender/freestyle/intern/python/UnaryPredicate1D/BPy_EqualToTimeStampUP1D.cpp index b75e45cb132..48365507d1a 100644 --- a/source/blender/freestyle/intern/python/UnaryPredicate1D/BPy_EqualToTimeStampUP1D.cpp +++ b/source/blender/freestyle/intern/python/UnaryPredicate1D/BPy_EqualToTimeStampUP1D.cpp @@ -6,6 +6,8 @@ #include "BPy_EqualToTimeStampUP1D.h" +#include "BLI_sys_types.h" + #ifdef __cplusplus extern "C" { #endif diff --git a/source/blender/freestyle/intern/python/UnaryPredicate1D/BPy_ShapeUP1D.cpp b/source/blender/freestyle/intern/python/UnaryPredicate1D/BPy_ShapeUP1D.cpp index ad8aba9eb29..b410ee14831 100644 --- a/source/blender/freestyle/intern/python/UnaryPredicate1D/BPy_ShapeUP1D.cpp +++ b/source/blender/freestyle/intern/python/UnaryPredicate1D/BPy_ShapeUP1D.cpp @@ -6,6 +6,8 @@ #include "BPy_ShapeUP1D.h" +#include "BLI_sys_types.h" + #ifdef __cplusplus extern "C" { #endif diff --git a/source/blender/freestyle/intern/scene_graph/IndexedFaceSet.cpp b/source/blender/freestyle/intern/scene_graph/IndexedFaceSet.cpp index 3962ac0aa35..39dbf4b87a9 100644 --- a/source/blender/freestyle/intern/scene_graph/IndexedFaceSet.cpp +++ b/source/blender/freestyle/intern/scene_graph/IndexedFaceSet.cpp @@ -7,6 +7,8 @@ #include "IndexedFaceSet.h" +#include "BLI_sys_types.h" + namespace Freestyle { IndexedFaceSet::IndexedFaceSet() diff --git a/source/blender/freestyle/intern/scene_graph/NodeTransform.cpp b/source/blender/freestyle/intern/scene_graph/NodeTransform.cpp index 97fa07df4c9..0089f68ce2d 100644 --- a/source/blender/freestyle/intern/scene_graph/NodeTransform.cpp +++ b/source/blender/freestyle/intern/scene_graph/NodeTransform.cpp @@ -9,6 +9,7 @@ #include "NodeTransform.h" #include "BLI_math.h" +#include "BLI_sys_types.h" namespace Freestyle { diff --git a/source/blender/freestyle/intern/scene_graph/SceneHash.cpp b/source/blender/freestyle/intern/scene_graph/SceneHash.cpp index a4ef70722d0..0ab83003514 100644 --- a/source/blender/freestyle/intern/scene_graph/SceneHash.cpp +++ b/source/blender/freestyle/intern/scene_graph/SceneHash.cpp @@ -6,6 +6,8 @@ #include "SceneHash.h" +#include "BLI_sys_types.h" + #include <sstream> namespace Freestyle { diff --git a/source/blender/freestyle/intern/scene_graph/ScenePrettyPrinter.cpp b/source/blender/freestyle/intern/scene_graph/ScenePrettyPrinter.cpp index cc5d8ef6ed4..4a2b6979985 100644 --- a/source/blender/freestyle/intern/scene_graph/ScenePrettyPrinter.cpp +++ b/source/blender/freestyle/intern/scene_graph/ScenePrettyPrinter.cpp @@ -10,6 +10,8 @@ #include "IndexedFaceSet.h" #include "ScenePrettyPrinter.h" +#include "BLI_sys_types.h" + namespace Freestyle { #define VISIT(CLASS) \ diff --git a/source/blender/freestyle/intern/stroke/AdvancedFunctions1D.cpp b/source/blender/freestyle/intern/stroke/AdvancedFunctions1D.cpp index 79825b626d5..a221e0e8bbd 100644 --- a/source/blender/freestyle/intern/stroke/AdvancedFunctions1D.cpp +++ b/source/blender/freestyle/intern/stroke/AdvancedFunctions1D.cpp @@ -10,6 +10,8 @@ #include "../view_map/SteerableViewMap.h" +#include "BLI_sys_types.h" + namespace Freestyle::Functions1D { int GetSteerableViewMapDensityF1D::operator()(Interface1D &inter) diff --git a/source/blender/freestyle/intern/stroke/AdvancedFunctions1D.h b/source/blender/freestyle/intern/stroke/AdvancedFunctions1D.h index c19ac31ae4a..e5009f2b4f8 100644 --- a/source/blender/freestyle/intern/stroke/AdvancedFunctions1D.h +++ b/source/blender/freestyle/intern/stroke/AdvancedFunctions1D.h @@ -33,7 +33,7 @@ class DensityF1D : public UnaryFunction1D<double> { public: /** Builds the functor. * \param sigma: - * Thesigma used in DensityF0D and determining the window size used in each density query. + * The sigma used in DensityF0D and determining the window size used in each density query. * \param iType: * The integration method used to compute a single value from a set of values. * \param sampling: diff --git a/source/blender/freestyle/intern/stroke/AdvancedStrokeShaders.cpp b/source/blender/freestyle/intern/stroke/AdvancedStrokeShaders.cpp index 4ff00dd0a08..6508c95f2b4 100644 --- a/source/blender/freestyle/intern/stroke/AdvancedStrokeShaders.cpp +++ b/source/blender/freestyle/intern/stroke/AdvancedStrokeShaders.cpp @@ -11,6 +11,8 @@ #include "../system/PseudoNoise.h" #include "../system/RandGen.h" +#include "BLI_sys_types.h" + namespace Freestyle { ///////////////////////////////////////// diff --git a/source/blender/freestyle/intern/stroke/BasicStrokeShaders.cpp b/source/blender/freestyle/intern/stroke/BasicStrokeShaders.cpp index 4df0bd7b089..e77ba63f3d6 100644 --- a/source/blender/freestyle/intern/stroke/BasicStrokeShaders.cpp +++ b/source/blender/freestyle/intern/stroke/BasicStrokeShaders.cpp @@ -23,6 +23,8 @@ #include "BKE_global.h" +#include "BLI_sys_types.h" + #include "IMB_imbuf.h" #include "IMB_imbuf_types.h" diff --git a/source/blender/freestyle/intern/stroke/Canvas.cpp b/source/blender/freestyle/intern/stroke/Canvas.cpp index af79a8eb4eb..741fad592cf 100644 --- a/source/blender/freestyle/intern/stroke/Canvas.cpp +++ b/source/blender/freestyle/intern/stroke/Canvas.cpp @@ -22,6 +22,8 @@ #include "../view_map/SteerableViewMap.h" +#include "BLI_sys_types.h" + #include "BKE_global.h" // soc #include <qimage.h> diff --git a/source/blender/freestyle/intern/stroke/ContextFunctions.cpp b/source/blender/freestyle/intern/stroke/ContextFunctions.cpp index 879ea49b43a..cd37a5f893d 100644 --- a/source/blender/freestyle/intern/stroke/ContextFunctions.cpp +++ b/source/blender/freestyle/intern/stroke/ContextFunctions.cpp @@ -12,6 +12,8 @@ #include "../system/TimeStamp.h" +#include "BLI_sys_types.h" + namespace Freestyle::ContextFunctions { uint GetTimeStampCF() diff --git a/source/blender/freestyle/intern/stroke/Operators.cpp b/source/blender/freestyle/intern/stroke/Operators.cpp index b45e3218a13..93524e6ebe5 100644 --- a/source/blender/freestyle/intern/stroke/Operators.cpp +++ b/source/blender/freestyle/intern/stroke/Operators.cpp @@ -14,6 +14,8 @@ #include "Stroke.h" #include "StrokeIterators.h" +#include "BLI_sys_types.h" + #include "BKE_global.h" namespace Freestyle { diff --git a/source/blender/freestyle/intern/stroke/StrokeRenderer.cpp b/source/blender/freestyle/intern/stroke/StrokeRenderer.cpp index 30dacb7f7df..095cb74d607 100644 --- a/source/blender/freestyle/intern/stroke/StrokeRenderer.cpp +++ b/source/blender/freestyle/intern/stroke/StrokeRenderer.cpp @@ -9,6 +9,8 @@ #include "../geometry/GeomUtils.h" +#include "BLI_sys_types.h" + using namespace std; namespace Freestyle { diff --git a/source/blender/freestyle/intern/system/StringUtils.cpp b/source/blender/freestyle/intern/system/StringUtils.cpp index 79b2cea0446..fbd85815da1 100644 --- a/source/blender/freestyle/intern/system/StringUtils.cpp +++ b/source/blender/freestyle/intern/system/StringUtils.cpp @@ -10,6 +10,8 @@ #include "StringUtils.h" #include "FreestyleConfig.h" +#include "BLI_sys_types.h" + namespace Freestyle::StringUtils { void getPathName(const string &path, const string &base, vector<string> &pathnames) diff --git a/source/blender/freestyle/intern/view_map/ArbitraryGridDensityProvider.cpp b/source/blender/freestyle/intern/view_map/ArbitraryGridDensityProvider.cpp index 7fa4f52506d..f4619e6e85f 100644 --- a/source/blender/freestyle/intern/view_map/ArbitraryGridDensityProvider.cpp +++ b/source/blender/freestyle/intern/view_map/ArbitraryGridDensityProvider.cpp @@ -7,6 +7,8 @@ #include "ArbitraryGridDensityProvider.h" +#include "BLI_sys_types.h" + #include "BKE_global.h" namespace Freestyle { diff --git a/source/blender/freestyle/intern/view_map/AverageAreaGridDensityProvider.cpp b/source/blender/freestyle/intern/view_map/AverageAreaGridDensityProvider.cpp index 11ba5933ce0..b984d5dba29 100644 --- a/source/blender/freestyle/intern/view_map/AverageAreaGridDensityProvider.cpp +++ b/source/blender/freestyle/intern/view_map/AverageAreaGridDensityProvider.cpp @@ -7,6 +7,8 @@ #include "AverageAreaGridDensityProvider.h" +#include "BLI_sys_types.h" + #include "BKE_global.h" namespace Freestyle { diff --git a/source/blender/freestyle/intern/view_map/BoxGrid.cpp b/source/blender/freestyle/intern/view_map/BoxGrid.cpp index 36afb0119a2..4464aab6419 100644 --- a/source/blender/freestyle/intern/view_map/BoxGrid.cpp +++ b/source/blender/freestyle/intern/view_map/BoxGrid.cpp @@ -10,6 +10,8 @@ #include "BoxGrid.h" +#include "BLI_sys_types.h" + #include "BKE_global.h" using namespace std; diff --git a/source/blender/freestyle/intern/view_map/CulledOccluderSource.cpp b/source/blender/freestyle/intern/view_map/CulledOccluderSource.cpp index e2886370800..c1afb6de881 100644 --- a/source/blender/freestyle/intern/view_map/CulledOccluderSource.cpp +++ b/source/blender/freestyle/intern/view_map/CulledOccluderSource.cpp @@ -9,6 +9,8 @@ #include "../geometry/GridHelpers.h" +#include "BLI_sys_types.h" + #include "BKE_global.h" namespace Freestyle { diff --git a/source/blender/freestyle/intern/view_map/FEdgeXDetector.cpp b/source/blender/freestyle/intern/view_map/FEdgeXDetector.cpp index e455011f187..b7e805f8767 100644 --- a/source/blender/freestyle/intern/view_map/FEdgeXDetector.cpp +++ b/source/blender/freestyle/intern/view_map/FEdgeXDetector.cpp @@ -12,6 +12,8 @@ #include "../geometry/GeomUtils.h" #include "../geometry/normal_cycle.h" +#include "BLI_sys_types.h" + #include "BKE_global.h" namespace Freestyle { diff --git a/source/blender/freestyle/intern/view_map/Functions0D.cpp b/source/blender/freestyle/intern/view_map/Functions0D.cpp index 2157c533986..aaafc5c884a 100644 --- a/source/blender/freestyle/intern/view_map/Functions0D.cpp +++ b/source/blender/freestyle/intern/view_map/Functions0D.cpp @@ -8,6 +8,8 @@ #include "Functions0D.h" #include "ViewMap.h" +#include "BLI_sys_types.h" + #include "BKE_global.h" using namespace std; diff --git a/source/blender/freestyle/intern/view_map/HeuristicGridDensityProviderFactory.cpp b/source/blender/freestyle/intern/view_map/HeuristicGridDensityProviderFactory.cpp index 7e4f673e2fb..40fa8387637 100644 --- a/source/blender/freestyle/intern/view_map/HeuristicGridDensityProviderFactory.cpp +++ b/source/blender/freestyle/intern/view_map/HeuristicGridDensityProviderFactory.cpp @@ -7,6 +7,8 @@ #include "HeuristicGridDensityProviderFactory.h" +#include "BLI_sys_types.h" + namespace Freestyle { HeuristicGridDensityProviderFactory::HeuristicGridDensityProviderFactory(real sizeFactor, diff --git a/source/blender/freestyle/intern/view_map/OccluderSource.cpp b/source/blender/freestyle/intern/view_map/OccluderSource.cpp index 54c30661de9..7ac5de9abbc 100644 --- a/source/blender/freestyle/intern/view_map/OccluderSource.cpp +++ b/source/blender/freestyle/intern/view_map/OccluderSource.cpp @@ -9,6 +9,8 @@ #include "OccluderSource.h" +#include "BLI_sys_types.h" + #include "BKE_global.h" namespace Freestyle { diff --git a/source/blender/freestyle/intern/view_map/Pow23GridDensityProvider.cpp b/source/blender/freestyle/intern/view_map/Pow23GridDensityProvider.cpp index 43809f83dc4..af6924eea6e 100644 --- a/source/blender/freestyle/intern/view_map/Pow23GridDensityProvider.cpp +++ b/source/blender/freestyle/intern/view_map/Pow23GridDensityProvider.cpp @@ -7,6 +7,8 @@ #include "Pow23GridDensityProvider.h" +#include "BLI_sys_types.h" + #include "BKE_global.h" namespace Freestyle { diff --git a/source/blender/freestyle/intern/view_map/SilhouetteGeomEngine.cpp b/source/blender/freestyle/intern/view_map/SilhouetteGeomEngine.cpp index 7d9d871f586..ce4c8fcd453 100644 --- a/source/blender/freestyle/intern/view_map/SilhouetteGeomEngine.cpp +++ b/source/blender/freestyle/intern/view_map/SilhouetteGeomEngine.cpp @@ -14,6 +14,8 @@ #include "../geometry/GeomUtils.h" +#include "BLI_sys_types.h" + #include "BKE_global.h" using namespace std; diff --git a/source/blender/freestyle/intern/view_map/SphericalGrid.cpp b/source/blender/freestyle/intern/view_map/SphericalGrid.cpp index 6d800d13b3b..bb4dbd17f70 100644 --- a/source/blender/freestyle/intern/view_map/SphericalGrid.cpp +++ b/source/blender/freestyle/intern/view_map/SphericalGrid.cpp @@ -10,6 +10,8 @@ #include "SphericalGrid.h" +#include "BLI_sys_types.h" + #include "BKE_global.h" using namespace std; diff --git a/source/blender/freestyle/intern/view_map/SteerableViewMap.cpp b/source/blender/freestyle/intern/view_map/SteerableViewMap.cpp index ba37dc434f4..20472599835 100644 --- a/source/blender/freestyle/intern/view_map/SteerableViewMap.cpp +++ b/source/blender/freestyle/intern/view_map/SteerableViewMap.cpp @@ -16,8 +16,10 @@ #include "../image/Image.h" #include "../image/ImagePyramid.h" -#include "BKE_global.h" #include "BLI_math.h" +#include "BLI_sys_types.h" + +#include "BKE_global.h" #include "IMB_imbuf.h" #include "IMB_imbuf_types.h" diff --git a/source/blender/freestyle/intern/view_map/ViewEdgeXBuilder.cpp b/source/blender/freestyle/intern/view_map/ViewEdgeXBuilder.cpp index 277334d13fd..fcb157a4e60 100644 --- a/source/blender/freestyle/intern/view_map/ViewEdgeXBuilder.cpp +++ b/source/blender/freestyle/intern/view_map/ViewEdgeXBuilder.cpp @@ -13,6 +13,8 @@ #include "../winged_edge/WXEdge.h" +#include "BLI_sys_types.h" + using namespace std; namespace Freestyle { diff --git a/source/blender/freestyle/intern/view_map/ViewMap.cpp b/source/blender/freestyle/intern/view_map/ViewMap.cpp index 0ba4850eed5..09432aa4ac7 100644 --- a/source/blender/freestyle/intern/view_map/ViewMap.cpp +++ b/source/blender/freestyle/intern/view_map/ViewMap.cpp @@ -13,6 +13,8 @@ #include "../geometry/GeomUtils.h" +#include "BLI_sys_types.h" + namespace Freestyle { /**********************************/ diff --git a/source/blender/freestyle/intern/view_map/ViewMapBuilder.cpp b/source/blender/freestyle/intern/view_map/ViewMapBuilder.cpp index 4ef06c0ac96..9c2919b0ca8 100644 --- a/source/blender/freestyle/intern/view_map/ViewMapBuilder.cpp +++ b/source/blender/freestyle/intern/view_map/ViewMapBuilder.cpp @@ -24,6 +24,8 @@ #include "../winged_edge/WFillGrid.h" +#include "BLI_sys_types.h" + #include "BKE_global.h" namespace Freestyle { diff --git a/source/blender/freestyle/intern/view_map/ViewMapTesselator.h b/source/blender/freestyle/intern/view_map/ViewMapTesselator.h index 2da95d47912..c666e548884 100644 --- a/source/blender/freestyle/intern/view_map/ViewMapTesselator.h +++ b/source/blender/freestyle/intern/view_map/ViewMapTesselator.h @@ -89,7 +89,7 @@ class ViewMapTesselator { #endif }; -/** Class to tesselate the 2D projected silhouette */ +/** Class to tessellate the 2D projected silhouette */ class ViewMapTesselator2D : public ViewMapTesselator { public: inline ViewMapTesselator2D() : ViewMapTesselator() @@ -110,7 +110,7 @@ class ViewMapTesselator2D : public ViewMapTesselator { #endif }; -/** Class to tesselate the 3D silhouette */ +/** Class to tessellate the 3D silhouette */ class ViewMapTesselator3D : public ViewMapTesselator { public: inline ViewMapTesselator3D() : ViewMapTesselator() diff --git a/source/blender/freestyle/intern/winged_edge/WEdge.cpp b/source/blender/freestyle/intern/winged_edge/WEdge.cpp index 33f72cc0c9f..3082988bd36 100644 --- a/source/blender/freestyle/intern/winged_edge/WEdge.cpp +++ b/source/blender/freestyle/intern/winged_edge/WEdge.cpp @@ -9,6 +9,8 @@ #include "WEdge.h" +#include "BLI_sys_types.h" + namespace Freestyle { /** Temporary structures */ diff --git a/source/blender/freestyle/intern/winged_edge/WXEdge.cpp b/source/blender/freestyle/intern/winged_edge/WXEdge.cpp index 2c107a01d13..6838060b44e 100644 --- a/source/blender/freestyle/intern/winged_edge/WXEdge.cpp +++ b/source/blender/freestyle/intern/winged_edge/WXEdge.cpp @@ -6,6 +6,9 @@ */ #include "WXEdge.h" + +#include "BLI_sys_types.h" + #include "BKE_global.h" namespace Freestyle { diff --git a/source/blender/freestyle/intern/winged_edge/WXEdgeBuilder.cpp b/source/blender/freestyle/intern/winged_edge/WXEdgeBuilder.cpp index 929e9b7e4dd..e22de505472 100644 --- a/source/blender/freestyle/intern/winged_edge/WXEdgeBuilder.cpp +++ b/source/blender/freestyle/intern/winged_edge/WXEdgeBuilder.cpp @@ -9,6 +9,8 @@ #include "WXEdgeBuilder.h" #include "WXEdge.h" +#include "BLI_sys_types.h" + namespace Freestyle { void WXEdgeBuilder::visitIndexedFaceSet(IndexedFaceSet &ifs) diff --git a/source/blender/freestyle/intern/winged_edge/WingedEdgeBuilder.cpp b/source/blender/freestyle/intern/winged_edge/WingedEdgeBuilder.cpp index e8095d89ee1..ce6054830f3 100644 --- a/source/blender/freestyle/intern/winged_edge/WingedEdgeBuilder.cpp +++ b/source/blender/freestyle/intern/winged_edge/WingedEdgeBuilder.cpp @@ -14,6 +14,8 @@ #include "../scene_graph/NodeShape.h" +#include "BLI_sys_types.h" + using namespace std; namespace Freestyle { diff --git a/source/blender/geometry/intern/fillet_curves.cc b/source/blender/geometry/intern/fillet_curves.cc index 1bbbee6edef..2479458f88d 100644 --- a/source/blender/geometry/intern/fillet_curves.cc +++ b/source/blender/geometry/intern/fillet_curves.cc @@ -148,12 +148,14 @@ static float limit_radius(const float3 &position_prev, const float displacement_prev = radius_prev * std::tan(angle_prev / 2.0f); const float segment_length_prev = math::distance(position, position_prev); const float total_displacement_prev = displacement_prev + displacement; - const float factor_prev = std::clamp(segment_length_prev / total_displacement_prev, 0.0f, 1.0f); + const float factor_prev = std::clamp( + safe_divide(segment_length_prev, total_displacement_prev), 0.0f, 1.0f); const float displacement_next = radius_next * std::tan(angle_next / 2.0f); const float segment_length_next = math::distance(position, position_next); const float total_displacement_next = displacement_next + displacement; - const float factor_next = std::clamp(segment_length_next / total_displacement_next, 0.0f, 1.0f); + const float factor_next = std::clamp( + safe_divide(segment_length_next, total_displacement_next), 0.0f, 1.0f); return radius * std::min(factor_prev, factor_next); } diff --git a/source/blender/geometry/intern/realize_instances.cc b/source/blender/geometry/intern/realize_instances.cc index 7b3c307cf37..2d9c23df348 100644 --- a/source/blender/geometry/intern/realize_instances.cc +++ b/source/blender/geometry/intern/realize_instances.cc @@ -17,6 +17,7 @@ #include "BKE_curves.hh" #include "BKE_deform.h" #include "BKE_geometry_set_instances.hh" +#include "BKE_instances.hh" #include "BKE_material.h" #include "BKE_mesh.h" #include "BKE_pointcloud.h" @@ -30,6 +31,8 @@ using blender::bke::AttributeMetaData; using blender::bke::custom_data_type_to_cpp_type; using blender::bke::CustomDataAttributes; using blender::bke::GSpanAttributeWriter; +using blender::bke::InstanceReference; +using blender::bke::Instances; using blender::bke::object_get_evaluated_geometry_set; using blender::bke::SpanAttributeWriter; @@ -370,11 +373,11 @@ static void gather_realize_tasks_recursive(GatherTasksInfo &gather_info, */ static Vector<std::pair<int, GSpan>> prepare_attribute_fallbacks( GatherTasksInfo &gather_info, - const InstancesComponent &instances_component, + const Instances &instances, const OrderedAttributes &ordered_attributes) { Vector<std::pair<int, GSpan>> attributes_to_override; - const CustomDataAttributes &attributes = instances_component.instance_attributes(); + const CustomDataAttributes &attributes = instances.custom_data_attributes(); attributes.foreach_attribute( [&](const AttributeIDRef &attribute_id, const AttributeMetaData &meta_data) { const int attribute_index = ordered_attributes.ids.index_of_try(attribute_id); @@ -394,7 +397,7 @@ static Vector<std::pair<int, GSpan>> prepare_attribute_fallbacks( } /* Convert the attribute on the instances component to the expected attribute type. */ std::unique_ptr<GArray<>> temporary_array = std::make_unique<GArray<>>( - to_type, instances_component.instances_num()); + to_type, instances.instances_num()); conversions.convert_to_initialized_n(span, temporary_array->as_mutable_span()); span = temporary_array->as_span(); gather_info.r_temporary_arrays.append(std::move(temporary_array)); @@ -430,7 +433,7 @@ static void foreach_geometry_in_reference( int index = 0; FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN (&collection, object) { const GeometrySet object_geometry_set = object_get_evaluated_geometry_set(*object); - const float4x4 matrix = base_transform * offset_matrix * object->obmat; + const float4x4 matrix = base_transform * offset_matrix * object->object_to_world; const int sub_id = noise::hash(id, index); fn(object_geometry_set, matrix, sub_id); index++; @@ -450,17 +453,17 @@ static void foreach_geometry_in_reference( } static void gather_realize_tasks_for_instances(GatherTasksInfo &gather_info, - const InstancesComponent &instances_component, + const Instances &instances, const float4x4 &base_transform, const InstanceContext &base_instance_context) { - const Span<InstanceReference> references = instances_component.references(); - const Span<int> handles = instances_component.instance_reference_handles(); - const Span<float4x4> transforms = instances_component.instance_transforms(); + const Span<InstanceReference> references = instances.references(); + const Span<int> handles = instances.reference_handles(); + const Span<float4x4> transforms = instances.transforms(); Span<int> stored_instance_ids; if (gather_info.create_id_attribute_on_any_component) { - std::optional<GSpan> ids = instances_component.instance_attributes().get_for_read("id"); + std::optional<GSpan> ids = instances.custom_data_attributes().get_for_read("id"); if (ids.has_value()) { stored_instance_ids = ids->typed<int>(); } @@ -469,11 +472,11 @@ static void gather_realize_tasks_for_instances(GatherTasksInfo &gather_info, /* Prepare attribute fallbacks. */ InstanceContext instance_context = base_instance_context; Vector<std::pair<int, GSpan>> pointcloud_attributes_to_override = prepare_attribute_fallbacks( - gather_info, instances_component, gather_info.pointclouds.attributes); + gather_info, instances, gather_info.pointclouds.attributes); Vector<std::pair<int, GSpan>> mesh_attributes_to_override = prepare_attribute_fallbacks( - gather_info, instances_component, gather_info.meshes.attributes); + gather_info, instances, gather_info.meshes.attributes); Vector<std::pair<int, GSpan>> curve_attributes_to_override = prepare_attribute_fallbacks( - gather_info, instances_component, gather_info.curves.attributes); + gather_info, instances, gather_info.curves.attributes); for (const int i : transforms.index_range()) { const int handle = handles[i]; @@ -584,8 +587,11 @@ static void gather_realize_tasks_recursive(GatherTasksInfo &gather_info, case GEO_COMPONENT_TYPE_INSTANCES: { const InstancesComponent &instances_component = *static_cast<const InstancesComponent *>( component); - gather_realize_tasks_for_instances( - gather_info, instances_component, base_transform, base_instance_context); + const Instances *instances = instances_component.get_for_read(); + if (instances != nullptr && instances->instances_num() > 0) { + gather_realize_tasks_for_instances( + gather_info, *instances, base_transform, base_instance_context); + } break; } case GEO_COMPONENT_TYPE_VOLUME: { @@ -645,8 +651,7 @@ static void gather_pointclouds_to_realize(const GeometrySet &geometry_set, r_pointclouds.add(pointcloud); } } - if (const InstancesComponent *instances = - geometry_set.get_component_for_read<InstancesComponent>()) { + if (const Instances *instances = geometry_set.get_instances_for_read()) { instances->foreach_referenced_geometry([&](const GeometrySet &instance_geometry_set) { gather_pointclouds_to_realize(instance_geometry_set, r_pointclouds); }); @@ -827,8 +832,7 @@ static void gather_meshes_to_realize(const GeometrySet &geometry_set, r_meshes.add(mesh); } } - if (const InstancesComponent *instances = - geometry_set.get_component_for_read<InstancesComponent>()) { + if (const Instances *instances = geometry_set.get_instances_for_read()) { instances->foreach_referenced_geometry([&](const GeometrySet &instance_geometry_set) { gather_meshes_to_realize(instance_geometry_set, r_meshes); }); @@ -855,6 +859,7 @@ static AllMeshesInfo preprocess_meshes(const GeometrySet &geometry_set, } } } + info.create_material_index_attribute |= info.materials.size() > 1; info.realize_info.reinitialize(info.order.size()); for (const int mesh_index : info.realize_info.index_range()) { MeshRealizeInfo &mesh_info = info.realize_info[mesh_index]; @@ -1148,8 +1153,7 @@ static void gather_curves_to_realize(const GeometrySet &geometry_set, r_curves.add(curves); } } - if (const InstancesComponent *instances = - geometry_set.get_component_for_read<InstancesComponent>()) { + if (const Instances *instances = geometry_set.get_instances_for_read()) { instances->foreach_referenced_geometry([&](const GeometrySet &instance_geometry_set) { gather_curves_to_realize(instance_geometry_set, r_curves); }); @@ -1415,9 +1419,8 @@ static void execute_realize_curve_tasks(const RealizeInstancesOptions &options, static void remove_id_attribute_from_instances(GeometrySet &geometry_set) { geometry_set.modify_geometry_sets([&](GeometrySet &sub_geometry) { - if (sub_geometry.has<InstancesComponent>()) { - InstancesComponent &component = sub_geometry.get_component_for_write<InstancesComponent>(); - component.instance_attributes().remove("id"); + if (Instances *instances = sub_geometry.get_instances_for_write()) { + instances->custom_data_attributes().remove("id"); } }); } diff --git a/source/blender/geometry/intern/resample_curves.cc b/source/blender/geometry/intern/resample_curves.cc index a7f6ac16f8d..3be850ec097 100644 --- a/source/blender/geometry/intern/resample_curves.cc +++ b/source/blender/geometry/intern/resample_curves.cc @@ -139,6 +139,9 @@ static void gather_point_attributes_to_interpolate( if (meta_data.domain != ATTR_DOMAIN_POINT) { return true; } + if (meta_data.data_type == CD_PROP_STRING) { + return true; + } if (!interpolate_attribute_to_curves(id, dst_curves.curve_type_counts())) { return true; } diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilarray.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilarray.c index 8bb61136cc2..e51fe8832f0 100644 --- a/source/blender/gpencil_modifiers/intern/MOD_gpencilarray.c +++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilarray.c @@ -104,9 +104,9 @@ static void BKE_gpencil_instance_modifier_instance_tfm(Object *ob, if (mmd->flag & GP_ARRAY_USE_OFFSET) { add_v3_v3(mat_offset[3], mmd->offset); } - invert_m4_m4(obinv, ob->obmat); + invert_m4_m4(obinv, ob->object_to_world); - mul_m4_series(r_offset, mat_offset, obinv, mmd->object->obmat); + mul_m4_series(r_offset, mat_offset, obinv, mmd->object->object_to_world); copy_m4_m4(mat_offset, r_offset); /* clear r_mat locations to avoid double transform */ diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilbuild.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilbuild.c index 3c971ec6af0..49ac3275c82 100644 --- a/source/blender/gpencil_modifiers/intern/MOD_gpencilbuild.c +++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilbuild.c @@ -303,8 +303,8 @@ static void build_sequential(Object *ob, /* Compute distance to control object if set, and build according to that order. */ if (mmd->object) { float sv1[3], sv2[3]; - mul_v3_m4v3(sv1, ob->obmat, &gps->points[0].x); - mul_v3_m4v3(sv2, ob->obmat, &gps->points[gps->totpoints - 1].x); + mul_v3_m4v3(sv1, ob->object_to_world, &gps->points[0].x); + mul_v3_m4v3(sv2, ob->object_to_world, &gps->points[gps->totpoints - 1].x); float dist_l = len_v3v3(sv1, mmd->object->loc); float dist_r = len_v3v3(sv2, mmd->object->loc); if (dist_r < dist_l) { diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilhook.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilhook.c index 1a2bfebdc55..6e31fffd11d 100644 --- a/source/blender/gpencil_modifiers/intern/MOD_gpencilhook.c +++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilhook.c @@ -234,13 +234,13 @@ static void deformStroke(GpencilModifierData *md, /* get world-space matrix of target, corrected for the space the verts are in */ if (mmd->subtarget[0] && pchan) { /* bone target if there's a matching pose-channel */ - mul_m4_m4m4(dmat, mmd->object->obmat, pchan->pose_mat); + mul_m4_m4m4(dmat, mmd->object->object_to_world, pchan->pose_mat); } else { /* just object target */ - copy_m4_m4(dmat, mmd->object->obmat); + copy_m4_m4(dmat, mmd->object->object_to_world); } - invert_m4_m4(ob->imat, ob->obmat); + invert_m4_m4(ob->imat, ob->object_to_world); mul_m4_series(tData.mat, ob->imat, dmat, mmd->parentinv); /* loop points and apply deform */ diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilmirror.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilmirror.c index 326e86091c5..bc91094e80e 100644 --- a/source/blender/gpencil_modifiers/intern/MOD_gpencilmirror.c +++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilmirror.c @@ -81,8 +81,8 @@ static void update_mirror_object(Object *ob, float tmp[4][4]; float itmp[4][4]; - invert_m4_m4(tmp, mmd->object->obmat); - mul_m4_m4m4(tmp, tmp, ob->obmat); + invert_m4_m4(tmp, mmd->object->object_to_world); + mul_m4_m4m4(tmp, tmp, ob->object_to_world); invert_m4_m4(itmp, tmp); mul_m4_series(mtx, itmp, mtx, tmp); diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilmultiply.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilmultiply.c index 1cf11a694ac..cb4a7893080 100644 --- a/source/blender/gpencil_modifiers/intern/MOD_gpencilmultiply.c +++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilmultiply.c @@ -109,7 +109,7 @@ static void duplicateStroke(Object *ob, float opacity_factor; /* Apply object scale to offset distance. */ - offset *= mat4_to_scale(ob->obmat); + offset *= mat4_to_scale(ob->object_to_world); BKE_gpencil_stroke_normal(gps, stroke_normal); if (len_v3(stroke_normal) < FLT_EPSILON) { diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpenciloutline.c b/source/blender/gpencil_modifiers/intern/MOD_gpenciloutline.c index 387e3c2d5ce..455d8b0b528 100644 --- a/source/blender/gpencil_modifiers/intern/MOD_gpenciloutline.c +++ b/source/blender/gpencil_modifiers/intern/MOD_gpenciloutline.c @@ -116,7 +116,7 @@ static void convert_stroke(GpencilModifierData *md, /* Apply layer thickness change. */ gps_duplicate->thickness += gpl->line_change; /* Apply object scale to thickness. */ - gps_duplicate->thickness *= mat4_to_scale(ob->obmat); + gps_duplicate->thickness *= mat4_to_scale(ob->object_to_world); CLAMP_MIN(gps_duplicate->thickness, 1.0f); /* Stroke. */ @@ -197,7 +197,7 @@ static void generateStrokes(GpencilModifierData *md, Depsgraph *depsgraph, Objec } Object *cam_ob = scene->camera; float viewmat[4][4]; - invert_m4_m4(viewmat, cam_ob->obmat); + invert_m4_m4(viewmat, cam_ob->object_to_world); LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) { bGPDframe *gpf = BKE_gpencil_frame_retime_get(depsgraph, scene, ob, gpl); @@ -240,7 +240,7 @@ static void bakeModifier(Main *UNUSED(bmain), BKE_scene_graph_update_for_newframe(depsgraph); /* Ensure the camera is the right one. */ BKE_scene_camera_switch_update(scene); - invert_m4_m4(viewmat, cam_ob->obmat); + invert_m4_m4(viewmat, cam_ob->object_to_world); /* Prepare transform matrix. */ float diff_mat[4][4]; diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpenciltint.c b/source/blender/gpencil_modifiers/intern/MOD_gpenciltint.c index 94d8cb98290..7add5c7b84e 100644 --- a/source/blender/gpencil_modifiers/intern/MOD_gpenciltint.c +++ b/source/blender/gpencil_modifiers/intern/MOD_gpenciltint.c @@ -144,7 +144,7 @@ static void deformStroke(GpencilModifierData *md, float coba_res[4]; float matrix[4][4]; if (is_gradient) { - mul_m4_m4m4(matrix, mmd->object->imat, ob->obmat); + mul_m4_m4m4(matrix, mmd->object->imat, ob->object_to_world); } /* loop points and apply color. */ diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilweight_angle.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilweight_angle.c index 3ecff4bf447..e9761732614 100644 --- a/source/blender/gpencil_modifiers/intern/MOD_gpencilweight_angle.c +++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilweight_angle.c @@ -97,7 +97,7 @@ static void deformStroke(GpencilModifierData *md, /* Apply the rotation of the object. */ if (mmd->space == GP_SPACE_LOCAL) { - mul_mat3_m4_v3(ob->obmat, vec_ref); + mul_mat3_m4_v3(ob->object_to_world, vec_ref); } /* Ensure there is a vertex group. */ @@ -122,8 +122,8 @@ static void deformStroke(GpencilModifierData *md, bGPDspoint *pt1 = (i > 0) ? &gps->points[i] : &gps->points[i + 1]; bGPDspoint *pt2 = (i > 0) ? &gps->points[i - 1] : &gps->points[i]; float fpt1[3], fpt2[3]; - mul_v3_m4v3(fpt1, ob->obmat, &pt1->x); - mul_v3_m4v3(fpt2, ob->obmat, &pt2->x); + mul_v3_m4v3(fpt1, ob->object_to_world, &pt1->x); + mul_v3_m4v3(fpt2, ob->object_to_world, &pt2->x); float vec[3]; sub_v3_v3v3(vec, fpt1, fpt2); diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilweight_proximity.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilweight_proximity.c index f64c83443d8..ddf852bcd11 100644 --- a/source/blender/gpencil_modifiers/intern/MOD_gpencilweight_proximity.c +++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilweight_proximity.c @@ -64,8 +64,8 @@ static float calc_point_weight_by_distance(Object *ob, { float weight; float gvert[3]; - mul_v3_m4v3(gvert, ob->obmat, &pt->x); - float dist = len_v3v3(mmd->object->obmat[3], gvert); + mul_v3_m4v3(gvert, ob->object_to_world, &pt->x); + float dist = len_v3v3(mmd->object->object_to_world[3], gvert); if (dist > dist_max) { weight = 1.0f; diff --git a/source/blender/gpencil_modifiers/intern/lineart/lineart_cpp_bridge.cc b/source/blender/gpencil_modifiers/intern/lineart/lineart_cpp_bridge.cc index 5e741ccbd55..85f158d42e6 100644 --- a/source/blender/gpencil_modifiers/intern/lineart/lineart_cpp_bridge.cc +++ b/source/blender/gpencil_modifiers/intern/lineart/lineart_cpp_bridge.cc @@ -9,17 +9,15 @@ #include "MOD_lineart.h" #include "lineart_intern.h" -static bool cmp_adjacent_items(const LineartAdjacentEdge &p1, const LineartAdjacentEdge &p2) -{ - int a = p1.v1 - p2.v1; - int b = p1.v2 - p2.v2; - /* parallel_sort() requires cmp() to return true when the first element needs to appear before - * the second element in the sorted array, false otherwise (strict weak ordering), see - * https://en.cppreference.com/w/cpp/named_req/Compare. */ - return a < 0 ? true : (a == 0 ? b < 0 : false); -} - void lineart_sort_adjacent_items(LineartAdjacentEdge *ai, int length) { - blender::parallel_sort(ai, ai + length, cmp_adjacent_items); + blender::parallel_sort( + ai, ai + length, [](const LineartAdjacentEdge &p1, const LineartAdjacentEdge &p2) { + int a = p1.v1 - p2.v1; + int b = p1.v2 - p2.v2; + /* parallel_sort() requires cmp() to return true when the first element needs to appear + * before the second element in the sorted array, false otherwise (strict weak ordering), + * see https://en.cppreference.com/w/cpp/named_req/Compare. */ + return a < 0 ? true : (a == 0 ? b < 0 : false); + }); } diff --git a/source/blender/gpencil_modifiers/intern/lineart/lineart_cpu.c b/source/blender/gpencil_modifiers/intern/lineart/lineart_cpu.c index c1e71bde254..4b5c40c0e38 100644 --- a/source/blender/gpencil_modifiers/intern/lineart/lineart_cpu.c +++ b/source/blender/gpencil_modifiers/intern/lineart/lineart_cpu.c @@ -2633,7 +2633,7 @@ void lineart_main_load_geometries(Depsgraph *depsgraph, scene, eval_ob, eval_ob, - eval_ob->obmat, + eval_ob->object_to_world, is_render, olti, thread_count, @@ -3589,11 +3589,11 @@ static LineartData *lineart_create_render_buffer(Scene *scene, clipping_offset = 0.0001; } - copy_v3db_v3fl(ld->conf.camera_pos, camera->obmat[3]); + copy_v3db_v3fl(ld->conf.camera_pos, camera->object_to_world[3]); if (active_camera) { - copy_v3db_v3fl(ld->conf.active_camera_pos, active_camera->obmat[3]); + copy_v3db_v3fl(ld->conf.active_camera_pos, active_camera->object_to_world[3]); } - copy_m4_m4(ld->conf.cam_obmat, camera->obmat); + copy_m4_m4(ld->conf.cam_obmat, camera->object_to_world); ld->conf.cam_is_persp = (c->type == CAM_PERSP); ld->conf.near_clip = c->clip_start + clipping_offset; @@ -3620,8 +3620,8 @@ static LineartData *lineart_create_render_buffer(Scene *scene, if (lmd->light_contour_object) { Object *light_obj = lmd->light_contour_object; - copy_v3db_v3fl(ld->conf.camera_pos_secondary, light_obj->obmat[3]); - copy_m4_m4(ld->conf.cam_obmat_secondary, light_obj->obmat); + copy_v3db_v3fl(ld->conf.camera_pos_secondary, light_obj->object_to_world[3]); + copy_m4_m4(ld->conf.cam_obmat_secondary, light_obj->object_to_world); ld->conf.light_reference_available = true; if (light_obj->type == OB_LAMP) { ld->conf.cam_is_persp_secondary = ((Light *)light_obj->data)->type != LA_SUN; @@ -5418,7 +5418,7 @@ void MOD_lineart_gpencil_generate(LineartCache *cache, } float gp_obmat_inverse[4][4]; - invert_m4_m4(gp_obmat_inverse, ob->obmat); + invert_m4_m4(gp_obmat_inverse, ob->object_to_world); lineart_gpencil_generate(cache, depsgraph, ob, diff --git a/source/blender/gpencil_modifiers/intern/lineart/lineart_shadow.c b/source/blender/gpencil_modifiers/intern/lineart/lineart_shadow.c index e34e6fc43ea..edea052e728 100644 --- a/source/blender/gpencil_modifiers/intern/lineart/lineart_shadow.c +++ b/source/blender/gpencil_modifiers/intern/lineart/lineart_shadow.c @@ -1167,7 +1167,7 @@ bool lineart_main_try_generate_shadow(Depsgraph *depsgraph, copy_v3_v3_db(ld->conf.camera_pos_secondary, ld->conf.camera_pos); copy_m4_m4(ld->conf.cam_obmat_secondary, ld->conf.cam_obmat); - copy_m4_m4(ld->conf.cam_obmat, lmd->light_contour_object->obmat); + copy_m4_m4(ld->conf.cam_obmat, lmd->light_contour_object->object_to_world); copy_v3db_v3fl(ld->conf.camera_pos, ld->conf.cam_obmat[3]); ld->conf.cam_is_persp_secondary = ld->conf.cam_is_persp; ld->conf.cam_is_persp = is_persp; diff --git a/source/blender/gpu/CMakeLists.txt b/source/blender/gpu/CMakeLists.txt index f387a4588b6..bfbbf1be225 100644 --- a/source/blender/gpu/CMakeLists.txt +++ b/source/blender/gpu/CMakeLists.txt @@ -12,6 +12,7 @@ endif() set(INC . intern + vulkan metal opengl ../blenkernel @@ -184,11 +185,41 @@ set(OPENGL_SRC opengl/gl_vertex_buffer.hh ) +set(VULKAN_SRC + vulkan/vk_backend.cc + vulkan/vk_batch.cc + vulkan/vk_context.cc + vulkan/vk_drawlist.cc + vulkan/vk_framebuffer.cc + vulkan/vk_index_buffer.cc + vulkan/vk_query.cc + vulkan/vk_shader.cc + vulkan/vk_storage_buffer.cc + vulkan/vk_texture.cc + vulkan/vk_uniform_buffer.cc + vulkan/vk_vertex_buffer.cc + + vulkan/vk_backend.hh + vulkan/vk_batch.hh + vulkan/vk_context.hh + vulkan/vk_drawlist.hh + vulkan/vk_framebuffer.hh + vulkan/vk_index_buffer.hh + vulkan/vk_query.hh + vulkan/vk_shader.hh + vulkan/vk_storage_buffer.hh + vulkan/vk_texture.hh + vulkan/vk_uniform_buffer.hh + vulkan/vk_vertex_buffer.hh +) + set(METAL_SRC metal/mtl_backend.mm + metal/mtl_batch.mm metal/mtl_command_buffer.mm metal/mtl_context.mm metal/mtl_debug.mm + metal/mtl_drawlist.mm metal/mtl_framebuffer.mm metal/mtl_immediate.mm metal/mtl_index_buffer.mm @@ -233,6 +264,10 @@ if(WITH_OPENGL) list(APPEND SRC ${OPENGL_SRC}) endif() +if(WITH_VULKAN_BACKEND) + list(APPEND SRC ${VULKAN_SRC}) +endif() + if(WITH_METAL_BACKEND) list(APPEND SRC ${METAL_SRC}) endif() @@ -280,6 +315,8 @@ set(GLSL_SRC shaders/gpu_shader_2D_image_vert.glsl shaders/gpu_shader_2D_image_rect_vert.glsl shaders/gpu_shader_2D_image_multi_rect_vert.glsl + shaders/gpu_shader_icon_frag.glsl + shaders/gpu_shader_icon_vert.glsl shaders/gpu_shader_image_frag.glsl shaders/gpu_shader_image_desaturate_frag.glsl shaders/gpu_shader_image_overlays_merge_frag.glsl @@ -347,6 +384,7 @@ set(GLSL_SRC shaders/compositor/compositor_morphological_distance_feather.glsl shaders/compositor/compositor_morphological_distance_threshold.glsl shaders/compositor/compositor_morphological_step.glsl + shaders/compositor/compositor_normalize.glsl shaders/compositor/compositor_parallel_reduction.glsl shaders/compositor/compositor_projector_lens_distortion.glsl shaders/compositor/compositor_realize_on_domain.glsl @@ -355,6 +393,8 @@ set(GLSL_SRC shaders/compositor/compositor_split_viewer.glsl shaders/compositor/compositor_symmetric_blur.glsl shaders/compositor/compositor_symmetric_separable_blur.glsl + shaders/compositor/compositor_tone_map_photoreceptor.glsl + shaders/compositor/compositor_tone_map_simple.glsl shaders/compositor/library/gpu_shader_compositor_alpha_over.glsl shaders/compositor/library/gpu_shader_compositor_blur_common.glsl @@ -604,6 +644,7 @@ set(SRC_SHADER_CREATE_INFOS shaders/infos/gpu_shader_3D_smooth_color_info.hh shaders/infos/gpu_shader_3D_uniform_color_info.hh shaders/infos/gpu_shader_gpencil_stroke_info.hh + shaders/infos/gpu_shader_icon_info.hh shaders/infos/gpu_shader_instance_varying_color_varying_size_info.hh shaders/infos/gpu_shader_keyframe_shape_info.hh shaders/infos/gpu_shader_line_dashed_uniform_color_info.hh @@ -629,6 +670,7 @@ set(SRC_SHADER_CREATE_INFOS shaders/compositor/infos/compositor_morphological_distance_info.hh shaders/compositor/infos/compositor_morphological_distance_threshold_info.hh shaders/compositor/infos/compositor_morphological_step_info.hh + shaders/compositor/infos/compositor_normalize_info.hh shaders/compositor/infos/compositor_parallel_reduction_info.hh shaders/compositor/infos/compositor_projector_lens_distortion_info.hh shaders/compositor/infos/compositor_realize_on_domain_info.hh @@ -637,6 +679,8 @@ set(SRC_SHADER_CREATE_INFOS shaders/compositor/infos/compositor_split_viewer_info.hh shaders/compositor/infos/compositor_symmetric_blur_info.hh shaders/compositor/infos/compositor_symmetric_separable_blur_info.hh + shaders/compositor/infos/compositor_tone_map_photoreceptor_info.hh + shaders/compositor/infos/compositor_tone_map_simple_info.hh ) set(SRC_SHADER_CREATE_INFOS_MTL diff --git a/source/blender/gpu/GPU_context.h b/source/blender/gpu/GPU_context.h index b59ea9e55d2..ac82774039a 100644 --- a/source/blender/gpu/GPU_context.h +++ b/source/blender/gpu/GPU_context.h @@ -21,6 +21,8 @@ extern "C" { * automatically initializes the back-end, and #GPU_context_discard frees it when there * are no more contexts. */ bool GPU_backend_supported(void); +void GPU_backend_type_selection_set(const eGPUBackendType backend); +eGPUBackendType GPU_backend_type_selection_get(void); eGPUBackendType GPU_backend_get_type(void); /** Opaque type hiding blender::gpu::Context. */ diff --git a/source/blender/gpu/GPU_framebuffer.h b/source/blender/gpu/GPU_framebuffer.h index bdb384c16f1..917407eece3 100644 --- a/source/blender/gpu/GPU_framebuffer.h +++ b/source/blender/gpu/GPU_framebuffer.h @@ -47,6 +47,9 @@ typedef struct GPUOffScreen GPUOffScreen; GPUFrameBuffer *GPU_framebuffer_create(const char *name); void GPU_framebuffer_free(GPUFrameBuffer *fb); void GPU_framebuffer_bind(GPUFrameBuffer *fb); + +const char *GPU_framebuffer_get_name(GPUFrameBuffer *fb); + /** * Workaround for binding a SRGB frame-buffer without doing the SRGB transform. */ diff --git a/source/blender/gpu/GPU_platform.h b/source/blender/gpu/GPU_platform.h index b63fe4c0580..657b45df1a5 100644 --- a/source/blender/gpu/GPU_platform.h +++ b/source/blender/gpu/GPU_platform.h @@ -16,6 +16,7 @@ typedef enum eGPUBackendType { GPU_BACKEND_NONE = 0, GPU_BACKEND_OPENGL = 1 << 0, GPU_BACKEND_METAL = 1 << 1, + GPU_BACKEND_VULKAN = 1 << 3, GPU_BACKEND_ANY = 0xFFFFFFFFu } eGPUBackendType; diff --git a/source/blender/gpu/GPU_shader.h b/source/blender/gpu/GPU_shader.h index 3f35db42eb9..1148207fc57 100644 --- a/source/blender/gpu/GPU_shader.h +++ b/source/blender/gpu/GPU_shader.h @@ -209,6 +209,10 @@ typedef enum eGPUBuiltinShader { GPU_SHADER_KEYFRAME_SHAPE, GPU_SHADER_SIMPLE_LIGHTING, /** + * Draw an icon, leaving a semi-transparent rectangle on top of the icon. + */ + GPU_SHADER_ICON, + /** * Take a 2D position and color for each vertex with linear interpolation in window space. * * \param color: in vec4 diff --git a/source/blender/gpu/intern/gpu_context.cc b/source/blender/gpu/intern/gpu_context.cc index 48d7b2019c5..7e94538892a 100644 --- a/source/blender/gpu/intern/gpu_context.cc +++ b/source/blender/gpu/intern/gpu_context.cc @@ -33,6 +33,9 @@ # include "gl_backend.hh" # include "gl_context.hh" #endif +#ifdef WITH_VULKAN_BACKEND +# include "vk_backend.hh" +#endif #ifdef WITH_METAL_BACKEND # include "mtl_backend.hh" #endif @@ -223,9 +226,19 @@ void GPU_render_step() /* NOTE: To enable Metal API, we need to temporarily change this to `GPU_BACKEND_METAL`. * Until a global switch is added, Metal also needs to be enabled in GHOST_ContextCGL: * `m_useMetalForRendering = true`. */ -static const eGPUBackendType g_backend_type = GPU_BACKEND_OPENGL; +static eGPUBackendType g_backend_type = GPU_BACKEND_OPENGL; static GPUBackend *g_backend = nullptr; +void GPU_backend_type_selection_set(const eGPUBackendType backend) +{ + g_backend_type = backend; +} + +eGPUBackendType GPU_backend_type_selection_get() +{ + return g_backend_type; +} + bool GPU_backend_supported(void) { switch (g_backend_type) { @@ -235,6 +248,12 @@ bool GPU_backend_supported(void) #else return false; #endif + case GPU_BACKEND_VULKAN: +#ifdef WITH_VULKAN_BACKEND + return true; +#else + return false; +#endif case GPU_BACKEND_METAL: #ifdef WITH_METAL_BACKEND return MTLBackend::metal_is_supported(); @@ -258,6 +277,11 @@ static void gpu_backend_create() g_backend = new GLBackend; break; #endif +#ifdef WITH_VULKAN_BACKEND + case GPU_BACKEND_VULKAN: + g_backend = new VKBackend; + break; +#endif #ifdef WITH_METAL_BACKEND case GPU_BACKEND_METAL: g_backend = new MTLBackend; diff --git a/source/blender/gpu/intern/gpu_framebuffer.cc b/source/blender/gpu/intern/gpu_framebuffer.cc index 6528f39d4ec..5b50fd66196 100644 --- a/source/blender/gpu/intern/gpu_framebuffer.cc +++ b/source/blender/gpu/intern/gpu_framebuffer.cc @@ -238,6 +238,11 @@ void GPU_framebuffer_free(GPUFrameBuffer *gpu_fb) delete unwrap(gpu_fb); } +const char *GPU_framebuffer_get_name(GPUFrameBuffer *gpu_fb) +{ + return unwrap(gpu_fb)->name_get(); +} + /* ---------- Binding ----------- */ void GPU_framebuffer_bind(GPUFrameBuffer *gpu_fb) diff --git a/source/blender/gpu/intern/gpu_framebuffer_private.hh b/source/blender/gpu/intern/gpu_framebuffer_private.hh index 76e816e7f65..cb7fd62445c 100644 --- a/source/blender/gpu/intern/gpu_framebuffer_private.hh +++ b/source/blender/gpu/intern/gpu_framebuffer_private.hh @@ -95,11 +95,6 @@ class FrameBuffer { #endif public: - /* Reference of a pointer that needs to be cleaned when deallocating the frame-buffer. - * Points to #BPyGPUFrameBuffer::fb */ - void **ref = nullptr; - - public: FrameBuffer(const char *name); virtual ~FrameBuffer(); @@ -209,6 +204,11 @@ class FrameBuffer { { return attachments_[GPU_FB_COLOR_ATTACHMENT0 + slot].tex; }; + + inline const char *const name_get() const + { + return name_; + }; }; /* Syntactic sugar. */ diff --git a/source/blender/gpu/intern/gpu_immediate.cc b/source/blender/gpu/intern/gpu_immediate.cc index 3b4accf9cc5..81c0a65bb7c 100644 --- a/source/blender/gpu/intern/gpu_immediate.cc +++ b/source/blender/gpu/intern/gpu_immediate.cc @@ -45,7 +45,7 @@ void immBindShader(GPUShader *shader) BLI_assert(imm->shader == nullptr); imm->shader = shader; - imm->builtin_shader_bound = GPU_SHADER_TEXT; /* Default value. */ + imm->builtin_shader_bound = std::nullopt; if (!imm->vertex_format.packed) { VertexFormat_pack(&imm->vertex_format); @@ -125,9 +125,12 @@ static void wide_line_workaround_start(GPUPrimType prim_type) /* No need to change the shader. */ return; } + if (!imm->builtin_shader_bound) { + return; + } eGPUBuiltinShader polyline_sh; - switch (imm->builtin_shader_bound) { + switch (*imm->builtin_shader_bound) { case GPU_SHADER_3D_CLIPPED_UNIFORM_COLOR: polyline_sh = GPU_SHADER_3D_POLYLINE_CLIPPED_UNIFORM_COLOR; break; @@ -180,8 +183,8 @@ static void wide_line_workaround_end() } immUnbindProgram(); - immBindBuiltinProgram(imm->prev_builtin_shader); - imm->prev_builtin_shader = GPU_SHADER_TEXT; + immBindBuiltinProgram(*imm->prev_builtin_shader); + imm->prev_builtin_shader = std::nullopt; } } diff --git a/source/blender/gpu/intern/gpu_immediate_private.hh b/source/blender/gpu/intern/gpu_immediate_private.hh index 74ebbdc7ae3..c4e11e7082b 100644 --- a/source/blender/gpu/intern/gpu_immediate_private.hh +++ b/source/blender/gpu/intern/gpu_immediate_private.hh @@ -9,6 +9,8 @@ #pragma once +#include <optional> + #include "GPU_batch.h" #include "GPU_primitive.h" #include "GPU_shader.h" @@ -42,9 +44,9 @@ class Immediate { /** Wide Line workaround. */ /** Previously bound shader to restore after drawing. */ - eGPUBuiltinShader prev_builtin_shader = GPU_SHADER_TEXT; - /** Builtin shader index. Used to test if the workaround can be done. */ - eGPUBuiltinShader builtin_shader_bound = GPU_SHADER_TEXT; + std::optional<eGPUBuiltinShader> prev_builtin_shader; + /** Builtin shader index. Used to test if the line width workaround can be done. */ + std::optional<eGPUBuiltinShader> builtin_shader_bound; /** Uniform color: Kept here to update the wide-line shader just before #immBegin. */ float uniform_color[4]; diff --git a/source/blender/gpu/intern/gpu_shader_builder.cc b/source/blender/gpu/intern/gpu_shader_builder.cc index 3aa2963ecd0..abb45ca074a 100644 --- a/source/blender/gpu/intern/gpu_shader_builder.cc +++ b/source/blender/gpu/intern/gpu_shader_builder.cc @@ -15,6 +15,8 @@ #include "GPU_init_exit.h" #include "gpu_shader_create_info_private.hh" +#include "BLI_vector.hh" + #include "CLG_log.h" namespace blender::gpu::shader_builder { @@ -41,6 +43,22 @@ void ShaderBuilder::init() CLG_init(); GHOST_GLSettings glSettings = {0}; + switch (GPU_backend_type_selection_get()) { + case GPU_BACKEND_OPENGL: + glSettings.context_type = GHOST_kDrawingContextTypeOpenGL; + break; + +#ifdef WITH_METAL_BACKEND + case GPU_BACKEND_METAL: + glSettings.context_type = GHOST_kDrawingContextTypeMetal; + break; +#endif + + default: + BLI_assert_unreachable(); + break; + } + ghost_system_ = GHOST_CreateSystem(); ghost_context_ = GHOST_CreateOpenGLContext(ghost_system_, glSettings); GHOST_ActivateOpenGLContext(ghost_context_); @@ -73,13 +91,32 @@ int main(int argc, const char *argv[]) int exit_code = 0; - blender::gpu::shader_builder::ShaderBuilder builder; - builder.init(); - if (!builder.bake_create_infos()) { - exit_code = 1; + struct NamedBackend { + std::string name; + eGPUBackendType backend; + }; + + blender::Vector<NamedBackend> backends_to_validate; + backends_to_validate.append({"OpenGL", GPU_BACKEND_OPENGL}); +#ifdef WITH_METAL_BACKEND + backends_to_validate.append({"Metal", GPU_BACKEND_METAL}); +#endif + for (NamedBackend &backend : backends_to_validate) { + GPU_backend_type_selection_set(backend.backend); + if (!GPU_backend_supported()) { + printf("%s isn't supported on this platform. Shader compilation is skipped\n", + backend.name.c_str()); + continue; + } + blender::gpu::shader_builder::ShaderBuilder builder; + builder.init(); + if (!builder.bake_create_infos()) { + printf("Shader compilation failed for %s backend\n", backend.name.c_str()); + exit_code = 1; + } + builder.exit(); } - builder.exit(); - exit(exit_code); + exit(exit_code); return exit_code; } diff --git a/source/blender/gpu/intern/gpu_shader_builder_stubs.cc b/source/blender/gpu/intern/gpu_shader_builder_stubs.cc index 7a06ede5c6d..65bda7ba858 100644 --- a/source/blender/gpu/intern/gpu_shader_builder_stubs.cc +++ b/source/blender/gpu/intern/gpu_shader_builder_stubs.cc @@ -46,6 +46,15 @@ void IMB_freeImBuf(ImBuf * /*ibuf*/) BLI_assert_unreachable(); } +struct ImBuf *IMB_allocImBuf(unsigned int /*x*/, + unsigned int /*y*/, + unsigned char /*planes*/, + unsigned int /*flags*/) +{ + BLI_assert_unreachable(); + return nullptr; +} + /** \} */ /* -------------------------------------------------------------------- */ diff --git a/source/blender/gpu/intern/gpu_shader_builtin.c b/source/blender/gpu/intern/gpu_shader_builtin.c index 8a6586e06f6..470643ba863 100644 --- a/source/blender/gpu/intern/gpu_shader_builtin.c +++ b/source/blender/gpu/intern/gpu_shader_builtin.c @@ -153,6 +153,11 @@ static const GPUShaderStages builtin_shader_stages[GPU_SHADER_BUILTIN_LEN] = { .create_info = "gpu_shader_2D_diag_stripes", }, + [GPU_SHADER_ICON] = + { + .name = "GPU_SHADER_ICON", + .create_info = "gpu_shader_icon", + }, [GPU_SHADER_2D_IMAGE_OVERLAYS_MERGE] = { .name = "GPU_SHADER_2D_IMAGE_OVERLAYS_MERGE", diff --git a/source/blender/gpu/intern/gpu_texture_private.hh b/source/blender/gpu/intern/gpu_texture_private.hh index b96a9b870e5..124b1751b96 100644 --- a/source/blender/gpu/intern/gpu_texture_private.hh +++ b/source/blender/gpu/intern/gpu_texture_private.hh @@ -431,15 +431,16 @@ inline bool validate_data_format(eGPUTextureFormat tex_format, eGPUDataFormat da case GPU_DEPTH_COMPONENT24: case GPU_DEPTH_COMPONENT16: case GPU_DEPTH_COMPONENT32F: - return data_format == GPU_DATA_FLOAT; + return ELEM(data_format, GPU_DATA_FLOAT, GPU_DATA_UINT); case GPU_DEPTH24_STENCIL8: case GPU_DEPTH32F_STENCIL8: - return data_format == GPU_DATA_UINT_24_8; + return ELEM(data_format, GPU_DATA_UINT_24_8, GPU_DATA_UINT); case GPU_R8UI: case GPU_R16UI: case GPU_RG16UI: case GPU_R32UI: return data_format == GPU_DATA_UINT; + case GPU_R32I: case GPU_RG16I: case GPU_R16I: return data_format == GPU_DATA_INT; @@ -453,6 +454,8 @@ inline bool validate_data_format(eGPUTextureFormat tex_format, eGPUDataFormat da return ELEM(data_format, GPU_DATA_2_10_10_10_REV, GPU_DATA_FLOAT); case GPU_R11F_G11F_B10F: return ELEM(data_format, GPU_DATA_10_11_11_REV, GPU_DATA_FLOAT); + case GPU_RGBA16F: + return ELEM(data_format, GPU_DATA_HALF_FLOAT, GPU_DATA_FLOAT); default: return data_format == GPU_DATA_FLOAT; } @@ -585,7 +588,7 @@ inline eGPUFrameBufferBits to_framebuffer_bits(eGPUTextureFormat tex_format) static inline eGPUTextureFormat to_texture_format(const GPUVertFormat *format) { - if (format->attr_len > 1 || format->attr_len == 0) { + if (format->attr_len == 0) { BLI_assert_msg(0, "Incorrect vertex format for buffer texture"); return GPU_DEPTH_COMPONENT24; } diff --git a/source/blender/gpu/intern/gpu_vertex_format.cc b/source/blender/gpu/intern/gpu_vertex_format.cc index b30e3c358c8..76d95ac1b55 100644 --- a/source/blender/gpu/intern/gpu_vertex_format.cc +++ b/source/blender/gpu/intern/gpu_vertex_format.cc @@ -361,8 +361,12 @@ void VertexFormat_texture_buffer_pack(GPUVertFormat *format) * minimum per-vertex stride, which mandates 4-byte alignment in Metal. * This additional alignment padding caused smaller data types, e.g. U16, * to mis-align. */ - BLI_assert_msg(format->attr_len == 1, - "Texture buffer mode should only use a single vertex attribute."); + for (int i = 0; i < format->attr_len; i++) { + /* The buffer texture setup uses the first attribute for type and size. + * Make sure all attributes use the same size. */ + BLI_assert_msg(format->attrs[i].size == format->attrs[0].size, + "Texture buffer mode should only use a attributes with the same size."); + } /* Pack vertex format without minimum stride, as this is not required by texture buffers. */ VertexFormat_pack_impl(format, 1); diff --git a/source/blender/gpu/intern/gpu_viewport.c b/source/blender/gpu/intern/gpu_viewport.c index 71bdf9e336b..e267d5a2f12 100644 --- a/source/blender/gpu/intern/gpu_viewport.c +++ b/source/blender/gpu/intern/gpu_viewport.c @@ -147,6 +147,10 @@ static void gpu_viewport_textures_create(GPUViewport *viewport) if (viewport->depth_tx == NULL) { viewport->depth_tx = GPU_texture_create_2d( "dtxl_depth", UNPACK2(size), 1, GPU_DEPTH24_STENCIL8, NULL); + if (GPU_clear_viewport_workaround()) { + static int depth_clear = 0; + GPU_texture_clear(viewport->depth_tx, GPU_DATA_UINT_24_8, &depth_clear); + } } if (!viewport->depth_tx || !viewport->color_render_tx[0] || !viewport->color_overlay_tx[0]) { diff --git a/source/blender/gpu/metal/mtl_backend.mm b/source/blender/gpu/metal/mtl_backend.mm index 2ca1fd3f3d0..240951c1ebd 100644 --- a/source/blender/gpu/metal/mtl_backend.mm +++ b/source/blender/gpu/metal/mtl_backend.mm @@ -47,13 +47,11 @@ Context *MTLBackend::context_alloc(void *ghost_window, void *ghost_context) Batch *MTLBackend::batch_alloc() { - /* TODO(Metal): Full MTLBatch implementation. */ return new MTLBatch(); }; DrawList *MTLBackend::drawlist_alloc(int list_length) { - /* TODO(Metal): Full MTLDrawList implementation. */ return new MTLDrawList(list_length); }; @@ -420,6 +418,7 @@ void MTLBackend::capabilities_init(MTLContext *ctx) GCaps.depth_blitting_workaround = false; GCaps.use_main_context_workaround = false; GCaps.broken_amd_driver = false; + GCaps.clear_viewport_workaround = true; /* Metal related workarounds. */ /* Minimum per-vertex stride is 4 bytes in Metal. diff --git a/source/blender/gpu/metal/mtl_batch.hh b/source/blender/gpu/metal/mtl_batch.hh index 236367bf5a4..9e179e662b5 100644 --- a/source/blender/gpu/metal/mtl_batch.hh +++ b/source/blender/gpu/metal/mtl_batch.hh @@ -10,31 +10,126 @@ #pragma once #include "MEM_guardedalloc.h" - #include "gpu_batch_private.hh" +#include "mtl_index_buffer.hh" +#include "mtl_primitive.hh" +#include "mtl_shader.hh" +#include "mtl_vertex_buffer.hh" + +namespace blender::gpu { + +class MTLContext; +class MTLShaderInterface; + +#define GPU_VAO_STATIC_LEN 64 -namespace blender { -namespace gpu { +struct VertexBufferID { + uint32_t id : 16; + uint32_t is_instance : 15; + uint32_t used : 1; +}; -/* Pass-through MTLBatch. TODO(Metal): Implement. */ class MTLBatch : public Batch { + + /* Vertex Bind-state Caching for a given shader interface used with the Batch. */ + struct VertexDescriptorShaderInterfacePair { + MTLVertexDescriptor vertex_descriptor{}; + const ShaderInterface *interface = nullptr; + uint16_t attr_mask{}; + int num_buffers{}; + VertexBufferID bufferIds[GPU_BATCH_VBO_MAX_LEN] = {}; + /* Cache life index compares a cache entry with the active MTLBatch state. + * This is initially set to the cache life index of MTLBatch. If the batch has been modified, + * this index is incremented to cheaply invalidate existing cache entries. */ + uint32_t cache_life_index = 0; + }; + + class MTLVertexDescriptorCache { + + private: + MTLBatch *batch_; + + VertexDescriptorShaderInterfacePair cache_[GPU_VAO_STATIC_LEN] = {}; + MTLContext *cache_context_ = nullptr; + uint32_t cache_life_index_ = 0; + + public: + MTLVertexDescriptorCache(MTLBatch *batch) : batch_(batch){}; + VertexDescriptorShaderInterfacePair *find(const ShaderInterface *interface); + bool insert(VertexDescriptorShaderInterfacePair &data); + + private: + void vertex_descriptor_cache_init(MTLContext *ctx); + void vertex_descriptor_cache_clear(); + void vertex_descriptor_cache_ensure(); + }; + + private: + MTLShader *active_shader_ = nullptr; + bool shader_in_use_ = false; + MTLVertexDescriptorCache vao_cache = {this}; + + /* Topology emulation. */ + gpu::MTLBuffer *emulated_topology_buffer_ = nullptr; + GPUPrimType emulated_topology_type_; + uint32_t topology_buffer_input_v_count_ = 0; + uint32_t topology_buffer_output_v_count_ = 0; + public: - void draw(int v_first, int v_count, int i_first, int i_count) override - { - } + MTLBatch(){}; + ~MTLBatch(){}; + void draw(int v_first, int v_count, int i_first, int i_count) override; void draw_indirect(GPUStorageBuf *indirect_buf, intptr_t offset) override { + /* TODO(Metal): Support indirect draw commands. */ } - void multi_draw_indirect(GPUStorageBuf *indirect_buf, int count, intptr_t offset, intptr_t stride) override { + /* TODO(Metal): Support indirect draw commands. */ + } + + /* Returns an initialized RenderComandEncoder for drawing if all is good. + * Otherwise, nil. */ + id<MTLRenderCommandEncoder> bind(uint v_first, uint v_count, uint i_first, uint i_count); + void unbind(); + + /* Convenience getters. */ + MTLIndexBuf *elem_() const + { + return static_cast<MTLIndexBuf *>(unwrap(elem)); + } + MTLVertBuf *verts_(const int index) const + { + return static_cast<MTLVertBuf *>(unwrap(verts[index])); } + MTLVertBuf *inst_(const int index) const + { + return static_cast<MTLVertBuf *>(unwrap(inst[index])); + } + MTLShader *active_shader_get() const + { + return active_shader_; + } + + private: + void shader_bind(); + void draw_advanced(int v_first, int v_count, int i_first, int i_count); + int prepare_vertex_binding(MTLVertBuf *verts, + MTLRenderPipelineStateDescriptor &desc, + const MTLShaderInterface *interface, + uint16_t &attr_mask, + bool instanced); + + id<MTLBuffer> get_emulated_toplogy_buffer(GPUPrimType &in_out_prim_type, uint32_t &v_count); + + void prepare_vertex_descriptor_and_bindings( + MTLVertBuf **buffers, int &num_buffers, int v_first, int v_count, int i_first, int i_count); + MEM_CXX_CLASS_ALLOC_FUNCS("MTLBatch"); }; -} // namespace gpu -} // namespace blender +} // namespace blender::gpu diff --git a/source/blender/gpu/metal/mtl_batch.mm b/source/blender/gpu/metal/mtl_batch.mm new file mode 100644 index 00000000000..988fb9b793b --- /dev/null +++ b/source/blender/gpu/metal/mtl_batch.mm @@ -0,0 +1,998 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +/** \file + * \ingroup gpu + * + * Metal implementation of GPUBatch. + */ + +#include "BLI_assert.h" +#include "BLI_span.hh" + +#include "BKE_global.h" + +#include "GPU_common.h" +#include "gpu_batch_private.hh" +#include "gpu_shader_private.hh" + +#include "mtl_batch.hh" +#include "mtl_context.hh" +#include "mtl_debug.hh" +#include "mtl_index_buffer.hh" +#include "mtl_shader.hh" +#include "mtl_vertex_buffer.hh" + +#include <string> + +namespace blender::gpu { + +/* -------------------------------------------------------------------- */ +/** \name Creation & Deletion + * \{ */ +void MTLBatch::draw(int v_first, int v_count, int i_first, int i_count) +{ + if (this->flag & GPU_BATCH_INVALID) { + this->shader_in_use_ = false; + } + this->draw_advanced(v_first, v_count, i_first, i_count); +} + +void MTLBatch::shader_bind() +{ + if (active_shader_ && active_shader_->is_valid()) { + active_shader_->bind(); + shader_in_use_ = true; + } +} + +void MTLBatch::MTLVertexDescriptorCache::vertex_descriptor_cache_init(MTLContext *ctx) +{ + BLI_assert(ctx != nullptr); + this->vertex_descriptor_cache_clear(); + cache_context_ = ctx; +} + +void MTLBatch::MTLVertexDescriptorCache::vertex_descriptor_cache_clear() +{ + cache_life_index_++; + cache_context_ = nullptr; +} + +void MTLBatch::MTLVertexDescriptorCache::vertex_descriptor_cache_ensure() +{ + if (this->cache_context_ != nullptr) { + + /* Invalidate vertex descriptor bindings cache if batch has changed. */ + if (batch_->flag & GPU_BATCH_DIRTY) { + batch_->flag &= ~GPU_BATCH_DIRTY; + this->vertex_descriptor_cache_clear(); + } + } + + /* Initialize cache if not ready. */ + if (cache_context_ == nullptr) { + this->vertex_descriptor_cache_init(MTLContext::get()); + } +} + +MTLBatch::VertexDescriptorShaderInterfacePair *MTLBatch::MTLVertexDescriptorCache::find( + const ShaderInterface *interface) +{ + this->vertex_descriptor_cache_ensure(); + for (int i = 0; i < GPU_VAO_STATIC_LEN; ++i) { + if (cache_[i].interface == interface && cache_[i].cache_life_index == cache_life_index_) { + return &cache_[i]; + } + } + return nullptr; +} + +bool MTLBatch::MTLVertexDescriptorCache::insert( + MTLBatch::VertexDescriptorShaderInterfacePair &data) +{ + vertex_descriptor_cache_ensure(); + for (int i = 0; i < GPU_VAO_STATIC_LEN; ++i) { + if (cache_[i].interface == nullptr || cache_[i].cache_life_index != cache_life_index_) { + cache_[i] = data; + cache_[i].cache_life_index = cache_life_index_; + return true; + } + } + return false; +} + +int MTLBatch::prepare_vertex_binding(MTLVertBuf *verts, + MTLRenderPipelineStateDescriptor &desc, + const MTLShaderInterface *interface, + uint16_t &attr_mask, + bool instanced) +{ + + const GPUVertFormat *format = &verts->format; + /* Whether the current vertex buffer has been added to the buffer layout descriptor. */ + bool buffer_added = false; + /* Per-vertex stride of current vertex buffer. */ + int buffer_stride = format->stride; + /* Buffer binding index of the vertex buffer once added to the buffer layout descriptor. */ + int buffer_index = -1; + int attribute_offset = 0; + + if (!active_shader_->get_uses_ssbo_vertex_fetch()) { + BLI_assert( + buffer_stride >= 4 && + "In Metal, Vertex buffer stride should be 4. SSBO Vertex fetch is not affected by this"); + } + + /* Iterate over GPUVertBuf vertex format and find attributes matching those in the active + * shader's interface. */ + for (uint32_t a_idx = 0; a_idx < format->attr_len; a_idx++) { + const GPUVertAttr *a = &format->attrs[a_idx]; + + if (format->deinterleaved) { + attribute_offset += ((a_idx == 0) ? 0 : format->attrs[a_idx - 1].size) * verts->vertex_len; + buffer_stride = a->size; + } + else { + attribute_offset = a->offset; + } + + /* Find attribute with the matching name. Attributes may have multiple compatible + * name aliases. */ + for (uint32_t n_idx = 0; n_idx < a->name_len; n_idx++) { + const char *name = GPU_vertformat_attr_name_get(format, a, n_idx); + const ShaderInput *input = interface->attr_get(name); + + if (input == nullptr || input->location == -1) { + /* Vertex/instance buffers provided have attribute data for attributes which are not needed + * by this particular shader. This shader only needs binding information for the attributes + * has in the shader interface. */ + MTL_LOG_WARNING( + "MTLBatch: Could not find attribute with name '%s' (defined in active vertex format) " + "in the shader interface for shader '%s'\n", + name, + interface->get_name()); + continue; + } + + /* Fetch metal attribute information. */ + const MTLShaderInputAttribute &mtl_attr = interface->get_attribute(input->location); + BLI_assert(mtl_attr.location >= 0); + /* Verify that the attribute location from the shader interface + * matches the attribute location returned. */ + BLI_assert(mtl_attr.location == input->location); + + /* Check if attribute is already present in the given slot. */ + if ((~attr_mask) & (1 << mtl_attr.location)) { + MTL_LOG_INFO( + " -- [Batch] Skipping attribute with input location %d (As one is already bound)\n", + mtl_attr.location); + } + else { + + /* Update attribute used-slot mask. */ + attr_mask &= ~(1 << mtl_attr.location); + + /* Add buffer layout entry in descriptor if it has not yet been added + * for current vertex buffer. */ + if (!buffer_added) { + buffer_index = desc.vertex_descriptor.num_vert_buffers; + desc.vertex_descriptor.buffer_layouts[buffer_index].step_function = + (instanced) ? MTLVertexStepFunctionPerInstance : MTLVertexStepFunctionPerVertex; + desc.vertex_descriptor.buffer_layouts[buffer_index].step_rate = 1; + desc.vertex_descriptor.buffer_layouts[buffer_index].stride = buffer_stride; + desc.vertex_descriptor.num_vert_buffers++; + buffer_added = true; + + MTL_LOG_INFO(" -- [Batch] Adding source %s buffer (Index: %d, Stride: %d)\n", + (instanced) ? "instance" : "vertex", + buffer_index, + buffer_stride); + } + else { + /* Ensure stride is correct for de-interleaved attributes. */ + desc.vertex_descriptor.buffer_layouts[buffer_index].stride = buffer_stride; + } + + /* Handle Matrix/Array vertex attribute types. + * Metal does not natively support these as attribute types, so we handle these cases + * by stacking together compatible types (e.g. 4xVec4 for Mat4) and combining + * the data in the shader. + * The generated Metal shader will contain a generated input binding, which reads + * in individual attributes and merges them into the desired type after vertex + * assembly. e.g. a Mat4 (Float4x4) will generate 4 Float4 attributes. */ + if (a->comp_len == 16 || a->comp_len == 12 || a->comp_len == 8) { + BLI_assert_msg( + a->comp_len == 16, + "only mat4 attributes currently supported -- Not ready to handle other long " + "component length attributes yet"); + + /* SSBO Vertex Fetch Attribute safety checks. */ + if (active_shader_->get_uses_ssbo_vertex_fetch()) { + /* When using SSBO vertex fetch, we do not need to expose split attributes, + * A matrix can be read directly as a whole block of contiguous data. */ + MTLSSBOAttribute ssbo_attr(mtl_attr.index, + buffer_index, + attribute_offset, + buffer_stride, + GPU_SHADER_ATTR_TYPE_MAT4, + instanced); + active_shader_->ssbo_vertex_fetch_bind_attribute(ssbo_attr); + desc.vertex_descriptor.ssbo_attributes[desc.vertex_descriptor.num_ssbo_attributes] = + ssbo_attr; + desc.vertex_descriptor.num_ssbo_attributes++; + } + else { + + /* Handle Mat4 attributes. */ + if (a->comp_len == 16) { + /* Debug safety checks. */ + BLI_assert_msg(mtl_attr.matrix_element_count == 4, + "mat4 type expected but there are fewer components"); + BLI_assert_msg(mtl_attr.size == 16, "Expecting subtype 'vec4' with 16 bytes"); + BLI_assert_msg( + mtl_attr.format == MTLVertexFormatFloat4, + "Per-attribute vertex format MUST be float4 for an input type of 'mat4'"); + + /* We have found the 'ROOT' attribute. A mat4 contains 4 consecutive float4 attribute + * locations we must map to. */ + for (int i = 0; i < a->comp_len / 4; i++) { + desc.vertex_descriptor.attributes[mtl_attr.location + i].format = + MTLVertexFormatFloat4; + /* Data is consecutive in the buffer for the whole matrix, each float4 will shift + * the offset by 16 bytes. */ + desc.vertex_descriptor.attributes[mtl_attr.location + i].offset = + attribute_offset + i * 16; + /* All source data for a matrix is in the same singular buffer. */ + desc.vertex_descriptor.attributes[mtl_attr.location + i].buffer_index = + buffer_index; + + /* Update total attribute account. */ + desc.vertex_descriptor.num_attributes = max_ii( + mtl_attr.location + i + 1, desc.vertex_descriptor.num_attributes); + MTL_LOG_INFO("-- Sub-Attrib Location: %d, offset: %d, buffer index: %d\n", + mtl_attr.location + i, + attribute_offset + i * 16, + buffer_index); + } + MTL_LOG_INFO( + "Float4x4 attribute type added for '%s' at attribute locations: %d to %d\n", + name, + mtl_attr.location, + mtl_attr.location + 3); + } + + /* Ensure we are not exceeding the attribute limit. */ + BLI_assert(desc.vertex_descriptor.num_attributes <= MTL_MAX_VERTEX_INPUT_ATTRIBUTES); + } + } + else { + + /* Handle Any required format conversions. + * NOTE(Metal): If there is a mis-match between the format of an attribute + * in the shader interface, and the specified format in the VertexBuffer VertexFormat, + * we need to perform a format conversion. + * + * The Metal API can perform certain conversions internally during vertex assembly: + * - Type Normalization e.g short2 to float2 between 0.0 to 1.0. + * - Type Truncation e.g. Float4 to Float2. + * - Type expansion e,g, Float3 to Float4 (Following 0,0,0,1 for assignment to empty + * elements). + * + * Certain conversion cannot be performed however, and in these cases, we need to + * instruct the shader to generate a specialized version with a conversion routine upon + * attribute read. + * - This handles cases such as conversion between types e.g. Integer to float without + * normalization. + * + * For more information on the supported and unsupported conversions, see: + * https://developer.apple.com/documentation/metal/mtlvertexattributedescriptor/1516081-format?language=objc + */ + MTLVertexFormat converted_format; + bool can_use_internal_conversion = mtl_convert_vertex_format( + mtl_attr.format, + (GPUVertCompType)a->comp_type, + a->comp_len, + (GPUVertFetchMode)a->fetch_mode, + &converted_format); + bool is_floating_point_format = (a->comp_type == GPU_COMP_F32); + + if (can_use_internal_conversion) { + desc.vertex_descriptor.attributes[mtl_attr.location].format = converted_format; + desc.vertex_descriptor.attributes[mtl_attr.location].format_conversion_mode = + is_floating_point_format ? (GPUVertFetchMode)GPU_FETCH_FLOAT : + (GPUVertFetchMode)GPU_FETCH_INT; + BLI_assert(converted_format != MTLVertexFormatInvalid); + } + else { + /* The internal implicit conversion is not supported. + * In this case, we need to handle conversion inside the shader. + * This is handled using `format_conversion_mode`. + * `format_conversion_mode` is assigned the blender-specified fetch mode (GPU_FETCH_*). + * This then controls how a given attribute is interpreted. The data will be read + * as specified and then converted appropriately to the correct form. + * + * e.g. if `GPU_FETCH_INT_TO_FLOAT` is specified, the specialized read-routine + * in the shader will read the data as an int, and cast this to floating point + * representation. (Rather than reading the source data as float). + * + * NOTE: Even if full conversion is not supported, we may still partially perform an + * implicit conversion where possible, such as vector truncation or expansion. */ + MTLVertexFormat converted_format; + bool can_convert = mtl_vertex_format_resize( + mtl_attr.format, a->comp_len, &converted_format); + desc.vertex_descriptor.attributes[mtl_attr.location].format = can_convert ? + converted_format : + mtl_attr.format; + desc.vertex_descriptor.attributes[mtl_attr.location].format_conversion_mode = + (GPUVertFetchMode)a->fetch_mode; + BLI_assert(desc.vertex_descriptor.attributes[mtl_attr.location].format != + MTLVertexFormatInvalid); + } + desc.vertex_descriptor.attributes[mtl_attr.location].offset = attribute_offset; + desc.vertex_descriptor.attributes[mtl_attr.location].buffer_index = buffer_index; + desc.vertex_descriptor.num_attributes = ((mtl_attr.location + 1) > + desc.vertex_descriptor.num_attributes) ? + (mtl_attr.location + 1) : + desc.vertex_descriptor.num_attributes; + + /* SSBO Vertex Fetch attribute bind. */ + if (active_shader_->get_uses_ssbo_vertex_fetch()) { + BLI_assert_msg(desc.vertex_descriptor.attributes[mtl_attr.location].format == + mtl_attr.format, + "SSBO Vertex Fetch does not support attribute conversion."); + + MTLSSBOAttribute ssbo_attr( + mtl_attr.index, + buffer_index, + attribute_offset, + buffer_stride, + MTLShader::ssbo_vertex_type_to_attr_type( + desc.vertex_descriptor.attributes[mtl_attr.location].format), + instanced); + + active_shader_->ssbo_vertex_fetch_bind_attribute(ssbo_attr); + desc.vertex_descriptor.ssbo_attributes[desc.vertex_descriptor.num_ssbo_attributes] = + ssbo_attr; + desc.vertex_descriptor.num_ssbo_attributes++; + } + + /* NOTE: We are setting num_attributes to be up to the maximum found index, because of + * this, it is possible that we may skip over certain attributes if they were not in the + * source GPUVertFormat. */ + MTL_LOG_INFO( + " -- Batch Attribute(%d): ORIG Shader Format: %d, ORIG Vert format: %d, Vert " + "components: %d, Fetch Mode %d --> FINAL FORMAT: %d\n", + mtl_attr.location, + (int)mtl_attr.format, + (int)a->comp_type, + (int)a->comp_len, + (int)a->fetch_mode, + (int)desc.vertex_descriptor.attributes[mtl_attr.location].format); + + MTL_LOG_INFO( + " -- [Batch] matching %s attribute '%s' (Attribute Index: %d, Buffer index: %d, " + "offset: %d)\n", + (instanced) ? "instance" : "vertex", + name, + mtl_attr.location, + buffer_index, + attribute_offset); + } + } + } + } + if (buffer_added) { + return buffer_index; + } + return -1; +} + +id<MTLRenderCommandEncoder> MTLBatch::bind(uint v_first, uint v_count, uint i_first, uint i_count) +{ + /* Setup draw call and render pipeline state here. Called by every draw, but setup here so that + * MTLDrawList only needs to perform setup a single time. */ + BLI_assert(this); + + /* Fetch Metal device. */ + MTLContext *ctx = MTLContext::get(); + if (!ctx) { + BLI_assert_msg(false, "No context available for rendering."); + return nil; + } + + /* Verify Shader. */ + active_shader_ = (shader) ? static_cast<MTLShader *>(unwrap(shader)) : nullptr; + + if (active_shader_ == nullptr || !active_shader_->is_valid()) { + /* Skip drawing if there is no valid Metal shader. + * This will occur if the path through which the shader is prepared + * is invalid (e.g. Python without create-info), or, the source shader uses a geometry pass. */ + BLI_assert_msg(false, "No valid Metal shader!"); + return nil; + } + + /* Check if using SSBO Fetch Mode. + * This is an alternative drawing mode to geometry shaders, wherein vertex buffers + * are bound as readable (random-access) GPU buffers and certain descriptor properties + * are passed using Shader uniforms. */ + bool uses_ssbo_fetch = active_shader_->get_uses_ssbo_vertex_fetch(); + + /* Prepare Vertex Descriptor and extract VertexBuffers to bind. */ + MTLVertBuf *buffers[GPU_BATCH_VBO_MAX_LEN] = {nullptr}; + int num_buffers = 0; + + /* Ensure Index Buffer is ready. */ + MTLIndexBuf *mtl_elem = static_cast<MTLIndexBuf *>(reinterpret_cast<IndexBuf *>(this->elem)); + if (mtl_elem != NULL) { + mtl_elem->upload_data(); + } + + /* Populate vertex descriptor with attribute binding information. + * The vertex descriptor and buffer layout descriptors describe + * how vertex data from bound vertex buffers maps to the + * shader's input. + * A unique vertex descriptor will result in a new PipelineStateObject + * being generated for the currently bound shader. */ + prepare_vertex_descriptor_and_bindings(buffers, num_buffers, v_first, v_count, i_first, i_count); + + /* Prepare Vertex Buffers - Run before RenderCommandEncoder in case BlitCommandEncoder buffer + * data operations are required. */ + for (int i = 0; i < num_buffers; i++) { + MTLVertBuf *buf_at_index = buffers[i]; + if (buf_at_index == NULL) { + BLI_assert_msg( + false, + "Total buffer count does not match highest buffer index, could be gaps in bindings"); + continue; + } + + MTLVertBuf *mtlvbo = static_cast<MTLVertBuf *>(reinterpret_cast<VertBuf *>(buf_at_index)); + mtlvbo->bind(); + } + + /* Ensure render pass is active and fetch active RenderCommandEncoder. */ + id<MTLRenderCommandEncoder> rec = ctx->ensure_begin_render_pass(); + + /* Fetch RenderPassState to enable resource binding for active pass. */ + MTLRenderPassState &rps = ctx->main_command_buffer.get_render_pass_state(); + + /* Debug Check: Ensure Frame-buffer instance is not dirty. */ + BLI_assert(!ctx->main_command_buffer.get_active_framebuffer()->get_dirty()); + + /* Bind Shader. */ + this->shader_bind(); + + /* GPU debug markers. */ + if (G.debug & G_DEBUG_GPU) { + [rec pushDebugGroup:[NSString stringWithFormat:@"batch_bind%@(shader: %s)", + this->elem ? @"(indexed)" : @"", + active_shader_->get_interface()->get_name()]]; + [rec insertDebugSignpost:[NSString + stringWithFormat:@"batch_bind%@(shader: %s)", + this->elem ? @"(indexed)" : @"", + active_shader_->get_interface()->get_name()]]; + } + + /* Ensure Context Render Pipeline State is fully setup and ready to execute the draw. */ + MTLPrimitiveType mtl_prim_type = gpu_prim_type_to_metal(this->prim_type); + if (!ctx->ensure_render_pipeline_state(mtl_prim_type)) { + printf("FAILED TO ENSURE RENDER PIPELINE STATE"); + BLI_assert(false); + + if (G.debug & G_DEBUG_GPU) { + [rec popDebugGroup]; + } + return nil; + } + + /*** Bind Vertex Buffers and Index Buffers **/ + + /* SSBO Vertex Fetch Buffer bindings. */ + if (uses_ssbo_fetch) { + + /* SSBO Vertex Fetch - Bind Index Buffer to appropriate slot -- if used. */ + id<MTLBuffer> idx_buffer = nil; + GPUPrimType final_prim_type = this->prim_type; + + if (mtl_elem != nullptr) { + + /* Fetch index buffer. This function can situationally return an optimized + * index buffer of a different primitive type. If this is the case, `final_prim_type` + * and `v_count` will be updated with the new format. + * NOTE: For indexed rendering, v_count represents the number of indices. */ + idx_buffer = mtl_elem->get_index_buffer(final_prim_type, v_count); + BLI_assert(idx_buffer != nil); + + /* Update uniforms for SSBO-vertex-fetch-mode indexed rendering to flag usage. */ + int &uniform_ssbo_index_mode_u16 = active_shader_->uni_ssbo_uses_index_mode_u16; + BLI_assert(uniform_ssbo_index_mode_u16 != -1); + int uses_index_mode_u16 = (mtl_elem->index_type_ == GPU_INDEX_U16) ? 1 : 0; + active_shader_->uniform_int(uniform_ssbo_index_mode_u16, 1, 1, &uses_index_mode_u16); + } + else { + idx_buffer = ctx->get_null_buffer(); + } + rps.bind_vertex_buffer(idx_buffer, 0, MTL_SSBO_VERTEX_FETCH_IBO_INDEX); + + /* Ensure all attributes are set */ + active_shader_->ssbo_vertex_fetch_bind_attributes_end(rec); + + /* Bind NULL Buffers for unused vertex data slots. */ + id<MTLBuffer> null_buffer = ctx->get_null_buffer(); + BLI_assert(null_buffer != nil); + for (int i = num_buffers; i < MTL_SSBO_VERTEX_FETCH_MAX_VBOS; i++) { + if (rps.cached_vertex_buffer_bindings[i].metal_buffer == nil) { + rps.bind_vertex_buffer(null_buffer, 0, i); + } + } + + /* Flag whether Indexed rendering is used or not. */ + int &uniform_ssbo_use_indexed = active_shader_->uni_ssbo_uses_indexed_rendering; + BLI_assert(uniform_ssbo_use_indexed != -1); + int uses_indexed_rendering = (mtl_elem != NULL) ? 1 : 0; + active_shader_->uniform_int(uniform_ssbo_use_indexed, 1, 1, &uses_indexed_rendering); + + /* Set SSBO-fetch-mode status uniforms. */ + BLI_assert(active_shader_->uni_ssbo_input_prim_type_loc != -1); + BLI_assert(active_shader_->uni_ssbo_input_vert_count_loc != -1); + GPU_shader_uniform_vector_int(reinterpret_cast<GPUShader *>(wrap(active_shader_)), + active_shader_->uni_ssbo_input_prim_type_loc, + 1, + 1, + (const int *)(&final_prim_type)); + GPU_shader_uniform_vector_int(reinterpret_cast<GPUShader *>(wrap(active_shader_)), + active_shader_->uni_ssbo_input_vert_count_loc, + 1, + 1, + (const int *)(&v_count)); + } + + /* Bind Vertex Buffers. */ + for (int i = 0; i < num_buffers; i++) { + MTLVertBuf *buf_at_index = buffers[i]; + if (buf_at_index == NULL) { + BLI_assert_msg( + false, + "Total buffer count does not match highest buffer index, could be gaps in bindings"); + continue; + } + /* Buffer handle. */ + MTLVertBuf *mtlvbo = static_cast<MTLVertBuf *>(reinterpret_cast<VertBuf *>(buf_at_index)); + mtlvbo->flag_used(); + + /* Fetch buffer from MTLVertexBuffer and bind. */ + id<MTLBuffer> mtl_buffer = mtlvbo->get_metal_buffer(); + + BLI_assert(mtl_buffer != nil); + rps.bind_vertex_buffer(mtl_buffer, 0, i); + } + + if (G.debug & G_DEBUG_GPU) { + [rec popDebugGroup]; + } + + /* Return Render Command Encoder used with setup. */ + return rec; +} + +void MTLBatch::unbind() +{ +} + +void MTLBatch::prepare_vertex_descriptor_and_bindings( + MTLVertBuf **buffers, int &num_buffers, int v_first, int v_count, int i_first, int i_count) +{ + + /* Here we populate the MTLContext vertex descriptor and resolve which buffers need to be bound. + */ + MTLStateManager *state_manager = static_cast<MTLStateManager *>( + MTLContext::get()->state_manager); + MTLRenderPipelineStateDescriptor &desc = state_manager->get_pipeline_descriptor(); + const MTLShaderInterface *interface = active_shader_->get_interface(); + uint16_t attr_mask = interface->get_enabled_attribute_mask(); + + /* Reset vertex descriptor to default state. */ + desc.reset_vertex_descriptor(); + + /* Fetch Vertex and Instance Buffers. */ + Span<MTLVertBuf *> mtl_verts(reinterpret_cast<MTLVertBuf **>(this->verts), + GPU_BATCH_VBO_MAX_LEN); + Span<MTLVertBuf *> mtl_inst(reinterpret_cast<MTLVertBuf **>(this->inst), + GPU_BATCH_INST_VBO_MAX_LEN); + + /* SSBO Vertex fetch also passes vertex descriptor information into the shader. */ + if (active_shader_->get_uses_ssbo_vertex_fetch()) { + active_shader_->ssbo_vertex_fetch_bind_attributes_begin(); + } + + /* Resolve Metal vertex buffer bindings. */ + /* Vertex Descriptors + * ------------------ + * Vertex Descriptors are required to generate a pipeline state, based on the current Batch's + * buffer bindings. These bindings are a unique matching, depending on what input attributes a + * batch has in its buffers, and those which are supported by the shader interface. + + * We iterate through the buffers and resolve which attributes satisfy the requirements of the + * currently bound shader. We cache this data, for a given Batch<->ShderInterface pairing in a + * VAO cache to avoid the need to recalculate this data. */ + bool buffer_is_instanced[GPU_BATCH_VBO_MAX_LEN] = {false}; + + VertexDescriptorShaderInterfacePair *descriptor = this->vao_cache.find(interface); + if (descriptor) { + desc.vertex_descriptor = descriptor->vertex_descriptor; + attr_mask = descriptor->attr_mask; + num_buffers = descriptor->num_buffers; + + for (int bid = 0; bid < GPU_BATCH_VBO_MAX_LEN; ++bid) { + if (descriptor->bufferIds[bid].used) { + if (descriptor->bufferIds[bid].is_instance) { + buffers[bid] = mtl_inst[descriptor->bufferIds[bid].id]; + buffer_is_instanced[bid] = true; + } + else { + buffers[bid] = mtl_verts[descriptor->bufferIds[bid].id]; + buffer_is_instanced[bid] = false; + } + } + } + + /* Use cached ssbo attribute binding data. */ + if (active_shader_->get_uses_ssbo_vertex_fetch()) { + BLI_assert(desc.vertex_descriptor.uses_ssbo_vertex_fetch); + for (int attr_id = 0; attr_id < desc.vertex_descriptor.num_ssbo_attributes; attr_id++) { + active_shader_->ssbo_vertex_fetch_bind_attribute( + desc.vertex_descriptor.ssbo_attributes[attr_id]); + } + } + } + else { + VertexDescriptorShaderInterfacePair pair{}; + pair.interface = interface; + + for (int i = 0; i < GPU_BATCH_VBO_MAX_LEN; ++i) { + pair.bufferIds[i].id = -1; + pair.bufferIds[i].is_instance = 0; + pair.bufferIds[i].used = 0; + } + /* NOTE: Attribute extraction order from buffer is the reverse of the OpenGL as we flag once an + * attribute is found, rather than pre-setting the mask. */ + /* Extract Instance attributes (These take highest priority). */ + for (int v = 0; v < GPU_BATCH_INST_VBO_MAX_LEN; v++) { + if (mtl_inst[v]) { + MTL_LOG_INFO(" -- [Batch] Checking bindings for bound instance buffer %p\n", mtl_inst[v]); + int buffer_ind = this->prepare_vertex_binding( + mtl_inst[v], desc, interface, attr_mask, true); + if (buffer_ind >= 0) { + buffers[buffer_ind] = mtl_inst[v]; + buffer_is_instanced[buffer_ind] = true; + + pair.bufferIds[buffer_ind].id = v; + pair.bufferIds[buffer_ind].used = 1; + pair.bufferIds[buffer_ind].is_instance = 1; + num_buffers = ((buffer_ind + 1) > num_buffers) ? (buffer_ind + 1) : num_buffers; + } + } + } + + /* Extract Vertex attributes (First-bound vertex buffer takes priority). */ + for (int v = 0; v < GPU_BATCH_VBO_MAX_LEN; v++) { + if (mtl_verts[v] != NULL) { + MTL_LOG_INFO(" -- [Batch] Checking bindings for bound vertex buffer %p\n", mtl_verts[v]); + int buffer_ind = this->prepare_vertex_binding( + mtl_verts[v], desc, interface, attr_mask, false); + if (buffer_ind >= 0) { + buffers[buffer_ind] = mtl_verts[v]; + buffer_is_instanced[buffer_ind] = false; + + pair.bufferIds[buffer_ind].id = v; + pair.bufferIds[buffer_ind].used = 1; + pair.bufferIds[buffer_ind].is_instance = 0; + num_buffers = ((buffer_ind + 1) > num_buffers) ? (buffer_ind + 1) : num_buffers; + } + } + } + + /* Add to VertexDescriptor cache */ + desc.vertex_descriptor.uses_ssbo_vertex_fetch = active_shader_->get_uses_ssbo_vertex_fetch(); + pair.attr_mask = attr_mask; + pair.vertex_descriptor = desc.vertex_descriptor; + pair.num_buffers = num_buffers; + if (!this->vao_cache.insert(pair)) { + printf( + "[Performance Warning] cache is full (Size: %d), vertex descriptor will not be cached\n", + GPU_VAO_STATIC_LEN); + } + } + +/* DEBUG: verify if our attribute bindings have been fully provided as expected. */ +#if MTL_DEBUG_SHADER_ATTRIBUTES == 1 + if (attr_mask != 0) { + for (uint16_t mask = 1, a = 0; a < 16; a++, mask <<= 1) { + if (attr_mask & mask) { + /* Fallback for setting default attributes, for missed slots. Attributes flagged with + * 'MTLVertexFormatInvalid' in the vertex descriptor are bound to a NULL buffer during PSO + * creation. */ + MTL_LOG_WARNING("MTLBatch: Missing expected attribute '%s' at index '%d' for shader: %s\n", + this->active_shader->interface->attributes[a].name, + a, + interface->name); + /* Ensure any assigned attribute has not been given an invalid format. This should not + * occur and may be the result of an unsupported attribute type conversion. */ + BLI_assert(desc.attributes[a].format == MTLVertexFormatInvalid); + } + } + } +#endif +} + +void MTLBatch::draw_advanced(int v_first, int v_count, int i_first, int i_count) +{ + +#if TRUST_NO_ONE + BLI_assert(v_count > 0 && i_count > 0); +#endif + + /* Setup RenderPipelineState for batch. */ + MTLContext *ctx = reinterpret_cast<MTLContext *>(GPU_context_active_get()); + id<MTLRenderCommandEncoder> rec = this->bind(v_first, v_count, i_first, i_count); + if (rec == nil) { + return; + } + + /* Fetch IndexBuffer and resolve primitive type. */ + MTLIndexBuf *mtl_elem = static_cast<MTLIndexBuf *>(reinterpret_cast<IndexBuf *>(this->elem)); + MTLPrimitiveType mtl_prim_type = gpu_prim_type_to_metal(this->prim_type); + + /* Render using SSBO Vertex Fetch. */ + if (active_shader_->get_uses_ssbo_vertex_fetch()) { + + /* Submit draw call with modified vertex count, which reflects vertices per primitive defined + * in the USE_SSBO_VERTEX_FETCH pragma. */ + int num_input_primitives = gpu_get_prim_count_from_type(v_count, this->prim_type); + int output_num_verts = num_input_primitives * + active_shader_->get_ssbo_vertex_fetch_output_num_verts(); + BLI_assert_msg( + mtl_vertex_count_fits_primitive_type( + output_num_verts, active_shader_->get_ssbo_vertex_fetch_output_prim_type()), + "Output Vertex count is not compatible with the requested output vertex primitive type"); + [rec drawPrimitives:active_shader_->get_ssbo_vertex_fetch_output_prim_type() + vertexStart:0 + vertexCount:output_num_verts + instanceCount:i_count + baseInstance:i_first]; + ctx->main_command_buffer.register_draw_counters(output_num_verts * i_count); + } + /* Perform regular draw. */ + else if (mtl_elem == NULL) { + + /* Primitive Type toplogy emulation. */ + if (mtl_needs_topology_emulation(this->prim_type)) { + + /* Generate index buffer for primitive types requiring emulation. */ + GPUPrimType emulated_prim_type = this->prim_type; + uint32_t emulated_v_count = v_count; + id<MTLBuffer> generated_index_buffer = this->get_emulated_toplogy_buffer(emulated_prim_type, + emulated_v_count); + BLI_assert(generated_index_buffer != nil); + + MTLPrimitiveType emulated_mtl_prim_type = gpu_prim_type_to_metal(emulated_prim_type); + + /* Temp: Disable culling for emulated primitive types. + * TODO(Metal): Support face winding in topology buffer. */ + [rec setCullMode:MTLCullModeNone]; + + if (generated_index_buffer != nil) { + BLI_assert(emulated_mtl_prim_type == MTLPrimitiveTypeTriangle || + emulated_mtl_prim_type == MTLPrimitiveTypeLine); + if (emulated_mtl_prim_type == MTLPrimitiveTypeTriangle) { + BLI_assert(emulated_v_count % 3 == 0); + } + if (emulated_mtl_prim_type == MTLPrimitiveTypeLine) { + BLI_assert(emulated_v_count % 2 == 0); + } + + /* Set depth stencil state (requires knowledge of primitive type). */ + ctx->ensure_depth_stencil_state(emulated_mtl_prim_type); + + [rec drawIndexedPrimitives:emulated_mtl_prim_type + indexCount:emulated_v_count + indexType:MTLIndexTypeUInt32 + indexBuffer:generated_index_buffer + indexBufferOffset:0 + instanceCount:i_count + baseVertex:v_first + baseInstance:i_first]; + } + else { + printf("[Note] Cannot draw batch -- Emulated Topology mode: %u not yet supported\n", + this->prim_type); + } + } + else { + /* Set depth stencil state (requires knowledge of primitive type). */ + ctx->ensure_depth_stencil_state(mtl_prim_type); + + /* Issue draw call. */ + [rec drawPrimitives:mtl_prim_type + vertexStart:v_first + vertexCount:v_count + instanceCount:i_count + baseInstance:i_first]; + } + ctx->main_command_buffer.register_draw_counters(v_count * i_count); + } + /* Perform indexed draw. */ + else { + + MTLIndexType index_type = MTLIndexBuf::gpu_index_type_to_metal(mtl_elem->index_type_); + uint32_t base_index = mtl_elem->index_base_; + uint32_t index_size = (mtl_elem->index_type_ == GPU_INDEX_U16) ? 2 : 4; + uint32_t v_first_ofs = ((v_first + mtl_elem->index_start_) * index_size); + BLI_assert_msg((v_first_ofs % index_size) == 0, + "Index offset is not 2/4-byte aligned as per METAL spec"); + + /* Fetch index buffer. May return an index buffer of a differing format, + * if index buffer optimization is used. In these cases, final_prim_type and + * index_count get updated with the new properties. */ + GPUPrimType final_prim_type = this->prim_type; + uint index_count = v_count; + + id<MTLBuffer> index_buffer = mtl_elem->get_index_buffer(final_prim_type, index_count); + mtl_prim_type = gpu_prim_type_to_metal(final_prim_type); + BLI_assert(index_buffer != nil); + + if (index_buffer != nil) { + + /* Set depth stencil state (requires knowledge of primitive type). */ + ctx->ensure_depth_stencil_state(mtl_prim_type); + + /* Issue draw call. */ + [rec drawIndexedPrimitives:mtl_prim_type + indexCount:index_count + indexType:index_type + indexBuffer:index_buffer + indexBufferOffset:v_first_ofs + instanceCount:i_count + baseVertex:base_index + baseInstance:i_first]; + ctx->main_command_buffer.register_draw_counters(index_count * i_count); + } + else { + BLI_assert_msg(false, "Index buffer does not have backing Metal buffer"); + } + } + + /* End of draw. */ + this->unbind(); +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Topology emulation and optimization + * \{ */ + +id<MTLBuffer> MTLBatch::get_emulated_toplogy_buffer(GPUPrimType &in_out_prim_type, + uint32_t &in_out_v_count) +{ + + BLI_assert(in_out_v_count > 0); + /* Determine emulated primitive types. */ + GPUPrimType input_prim_type = in_out_prim_type; + uint32_t v_count = in_out_v_count; + GPUPrimType output_prim_type; + switch (input_prim_type) { + case GPU_PRIM_POINTS: + case GPU_PRIM_LINES: + case GPU_PRIM_TRIS: + BLI_assert_msg(false, "Optimal primitive types should not reach here."); + return nil; + break; + case GPU_PRIM_LINES_ADJ: + case GPU_PRIM_TRIS_ADJ: + BLI_assert_msg(false, "Adjacency primitive types should not reach here."); + return nil; + break; + case GPU_PRIM_LINE_STRIP: + case GPU_PRIM_LINE_LOOP: + case GPU_PRIM_LINE_STRIP_ADJ: + output_prim_type = GPU_PRIM_LINES; + break; + case GPU_PRIM_TRI_STRIP: + case GPU_PRIM_TRI_FAN: + output_prim_type = GPU_PRIM_TRIS; + break; + default: + BLI_assert_msg(false, "Invalid primitive type."); + return nil; + } + + /* Check if topology buffer exists and is valid. */ + if (this->emulated_topology_buffer_ != nullptr && + (emulated_topology_type_ != input_prim_type || topology_buffer_input_v_count_ != v_count)) { + + /* Release existing topology buffer. */ + emulated_topology_buffer_->free(); + emulated_topology_buffer_ = nullptr; + } + + /* Generate new topology index buffer. */ + if (this->emulated_topology_buffer_ == nullptr) { + /* Calculate IB len. */ + uint32_t output_prim_count = 0; + switch (input_prim_type) { + case GPU_PRIM_LINE_STRIP: + case GPU_PRIM_LINE_STRIP_ADJ: + output_prim_count = v_count - 1; + break; + case GPU_PRIM_LINE_LOOP: + output_prim_count = v_count; + break; + case GPU_PRIM_TRI_STRIP: + case GPU_PRIM_TRI_FAN: + output_prim_count = v_count - 2; + break; + default: + BLI_assert_msg(false, "Cannot generate optimized topology buffer for other types."); + break; + } + uint32_t output_IB_elems = output_prim_count * ((output_prim_type == GPU_PRIM_TRIS) ? 3 : 2); + + /* Allocate buffer. */ + uint32_t buffer_bytes = output_IB_elems * 4; + BLI_assert(buffer_bytes > 0); + this->emulated_topology_buffer_ = MTLContext::get_global_memory_manager().allocate( + buffer_bytes, true); + + /* Populate. */ + uint32_t *data = (uint32_t *)this->emulated_topology_buffer_->get_host_ptr(); + BLI_assert(data != nullptr); + + /* TODO(Metal): Support inverse winding modes. */ + bool winding_clockwise = false; + UNUSED_VARS(winding_clockwise); + + switch (input_prim_type) { + /* Line Loop. */ + case GPU_PRIM_LINE_LOOP: { + int line = 0; + for (line = 0; line < output_prim_count - 1; line++) { + data[line * 3 + 0] = line + 0; + data[line * 3 + 1] = line + 1; + } + /* Closing line. */ + data[line * 2 + 0] = line + 0; + data[line * 2 + 1] = 0; + } break; + + /* Triangle Fan. */ + case GPU_PRIM_TRI_FAN: { + for (int triangle = 0; triangle < output_prim_count; triangle++) { + data[triangle * 3 + 0] = 0; /* Always 0 */ + data[triangle * 3 + 1] = triangle + 1; + data[triangle * 3 + 2] = triangle + 2; + } + } break; + + default: + BLI_assert_msg(false, "Other primitive types do not require emulation."); + return nil; + } + + /* Flush. */ + this->emulated_topology_buffer_->flush(); + /* Assign members relating to current cached IB. */ + topology_buffer_input_v_count_ = v_count; + topology_buffer_output_v_count_ = output_IB_elems; + emulated_topology_type_ = input_prim_type; + } + + /* Return. */ + in_out_v_count = topology_buffer_output_v_count_; + in_out_prim_type = output_prim_type; + return (emulated_topology_buffer_) ? emulated_topology_buffer_->get_metal_buffer() : nil; +} + +/** \} */ + +} // blender::gpu diff --git a/source/blender/gpu/metal/mtl_context.mm b/source/blender/gpu/metal/mtl_context.mm index ef66a1f2111..50576379f0d 100644 --- a/source/blender/gpu/metal/mtl_context.mm +++ b/source/blender/gpu/metal/mtl_context.mm @@ -995,19 +995,21 @@ bool MTLContext::ensure_uniform_buffer_bindings( if (ubo.buffer_index >= 0) { - const uint32_t buffer_index = ubo.buffer_index; + /* Uniform Buffer index offset by 1 as the first shader buffer binding slot is reserved for + * the uniform PushConstantBlock. */ + const uint32_t buffer_index = ubo.buffer_index + 1; int ubo_offset = 0; id<MTLBuffer> ubo_buffer = nil; int ubo_size = 0; bool bind_dummy_buffer = false; - if (this->pipeline_state.ubo_bindings[buffer_index].bound) { + if (this->pipeline_state.ubo_bindings[ubo_index].bound) { /* Fetch UBO global-binding properties from slot. */ ubo_offset = 0; - ubo_buffer = this->pipeline_state.ubo_bindings[buffer_index].ubo->get_metal_buffer( + ubo_buffer = this->pipeline_state.ubo_bindings[ubo_index].ubo->get_metal_buffer( &ubo_offset); - ubo_size = this->pipeline_state.ubo_bindings[buffer_index].ubo->get_size(); + ubo_size = this->pipeline_state.ubo_bindings[ubo_index].ubo->get_size(); /* Use dummy zero buffer if no buffer assigned -- this is an optimization to avoid * allocating zero buffers. */ diff --git a/source/blender/gpu/metal/mtl_drawlist.hh b/source/blender/gpu/metal/mtl_drawlist.hh index ed99c76faa7..47055f3d7f4 100644 --- a/source/blender/gpu/metal/mtl_drawlist.hh +++ b/source/blender/gpu/metal/mtl_drawlist.hh @@ -9,34 +9,50 @@ #pragma once -#pragma once - +#include "BLI_sys_types.h" +#include "GPU_batch.h" +#include "MEM_guardedalloc.h" #include "gpu_drawlist_private.hh" -namespace blender { -namespace gpu { +#include "mtl_batch.hh" +#include "mtl_context.hh" + +namespace blender::gpu { /** - * TODO(Metal): MTLDrawList Implementation. Included as temporary stub. - */ + * Implementation of Multi Draw Indirect using OpenGL. + **/ class MTLDrawList : public DrawList { + + private: + /** Batch for which we are recording commands for. */ + MTLBatch *batch_; + /** Mapped memory bounds. */ + void *data_; + /** Length of the mapped buffer (in byte). */ + size_t data_size_; + /** Current offset inside the mapped buffer (in byte). */ + size_t command_offset_; + /** Current number of command recorded inside the mapped buffer. */ + uint32_t command_len_; + /** Is UINT_MAX if not drawing indexed geom. Also Avoid dereferencing batch. */ + uint32_t base_index_; + /** Also Avoid dereferencing batch. */ + uint32_t v_first_, v_count_; + /** Length of whole the buffer (in byte). */ + uint32_t buffer_size_; + public: - MTLDrawList(int length) - { - } - ~MTLDrawList() - { - } - - void append(GPUBatch *batch, int i_first, int i_count) override - { - } - void submit() override - { - } + MTLDrawList(int length); + ~MTLDrawList(); + + void append(GPUBatch *batch, int i_first, int i_count) override; + void submit() override; + + private: + void init(); MEM_CXX_CLASS_ALLOC_FUNCS("MTLDrawList"); }; -} // namespace gpu -} // namespace blender +} // namespace blender::gpu diff --git a/source/blender/gpu/metal/mtl_drawlist.mm b/source/blender/gpu/metal/mtl_drawlist.mm new file mode 100644 index 00000000000..99194d2b72c --- /dev/null +++ b/source/blender/gpu/metal/mtl_drawlist.mm @@ -0,0 +1,284 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +/** \file + * \ingroup gpu + * + * Implementation of Multi Draw Indirect using OpenGL. + * Fallback if the needed extensions are not supported. + */ + +#include "BLI_assert.h" + +#include "GPU_batch.h" +#include "mtl_common.hh" +#include "mtl_drawlist.hh" +#include "mtl_primitive.hh" + +using namespace blender::gpu; + +namespace blender::gpu { + +/* Indirect draw call structure for reference. */ +/* MTLDrawPrimitivesIndirectArguments -- + * https://developer.apple.com/documentation/metal/mtldrawprimitivesindirectarguments?language=objc + */ +/* struct MTLDrawPrimitivesIndirectArguments { + * uint32_t vertexCount; + * uint32_t instanceCount; + * uint32_t vertexStart; + * uint32_t baseInstance; +};*/ + +/* MTLDrawIndexedPrimitivesIndirectArguments -- + * https://developer.apple.com/documentation/metal/mtldrawindexedprimitivesindirectarguments?language=objc + */ +/* struct MTLDrawIndexedPrimitivesIndirectArguments { + * uint32_t indexCount; + * uint32_t instanceCount; + * uint32_t indexStart; + * uint32_t baseVertex; + * uint32_t baseInstance; +};*/ + +#define MDI_ENABLED (buffer_size_ != 0) +#define MDI_DISABLED (buffer_size_ == 0) +#define MDI_INDEXED (base_index_ != UINT_MAX) + +MTLDrawList::MTLDrawList(int length) +{ + BLI_assert(length > 0); + batch_ = nullptr; + command_len_ = 0; + base_index_ = 0; + command_offset_ = 0; + data_size_ = 0; + buffer_size_ = sizeof(MTLDrawIndexedPrimitivesIndirectArguments) * length; + data_ = (void *)MEM_mallocN(buffer_size_, __func__); +} + +MTLDrawList::~MTLDrawList() +{ + if (data_) { + MEM_freeN(data_); + data_ = nullptr; + } +} + +void MTLDrawList::init() +{ + MTLContext *ctx = reinterpret_cast<MTLContext *>(GPU_context_active_get()); + BLI_assert(ctx); + BLI_assert(MDI_ENABLED); + BLI_assert(data_ == nullptr); + UNUSED_VARS_NDEBUG(ctx); + + batch_ = nullptr; + command_len_ = 0; + BLI_assert(data_); + + command_offset_ = 0; +} + +void MTLDrawList::append(GPUBatch *gpu_batch, int i_first, int i_count) +{ + /* Fallback when MultiDrawIndirect is not supported/enabled. */ + MTLShader *shader = static_cast<MTLShader *>(unwrap(gpu_batch->shader)); + bool requires_ssbo = (shader->get_uses_ssbo_vertex_fetch()); + bool requires_emulation = mtl_needs_topology_emulation(gpu_batch->prim_type); + if (MDI_DISABLED || requires_ssbo || requires_emulation) { + GPU_batch_draw_advanced(gpu_batch, 0, 0, i_first, i_count); + return; + } + + if (data_ == nullptr) { + this->init(); + } + BLI_assert(data_); + + MTLBatch *mtl_batch = static_cast<MTLBatch *>(gpu_batch); + BLI_assert(mtl_batch); + if (mtl_batch != batch_) { + /* Submit existing calls. */ + this->submit(); + + /* Begin new batch. */ + batch_ = mtl_batch; + + /* Cached for faster access. */ + MTLIndexBuf *el = batch_->elem_(); + base_index_ = el ? el->index_base_ : UINT_MAX; + v_first_ = el ? el->index_start_ : 0; + v_count_ = el ? el->index_len_ : batch_->verts_(0)->vertex_len; + } + + if (v_count_ == 0) { + /* Nothing to draw. */ + return; + } + + if (MDI_INDEXED) { + MTLDrawIndexedPrimitivesIndirectArguments *cmd = + reinterpret_cast<MTLDrawIndexedPrimitivesIndirectArguments *>((char *)data_ + + command_offset_); + cmd->indexStart = v_first_; + cmd->indexCount = v_count_; + cmd->instanceCount = i_count; + cmd->baseVertex = base_index_; + cmd->baseInstance = i_first; + } + else { + MTLDrawPrimitivesIndirectArguments *cmd = + reinterpret_cast<MTLDrawPrimitivesIndirectArguments *>((char *)data_ + command_offset_); + cmd->vertexStart = v_first_; + cmd->vertexCount = v_count_; + cmd->instanceCount = i_count; + cmd->baseInstance = i_first; + } + + size_t command_size = MDI_INDEXED ? sizeof(MTLDrawIndexedPrimitivesIndirectArguments) : + sizeof(MTLDrawPrimitivesIndirectArguments); + + command_offset_ += command_size; + command_len_++; + + /* Check if we can fit at least one other command. */ + if (command_offset_ + command_size > buffer_size_) { + this->submit(); + } + + return; +} + +void MTLDrawList::submit() +{ + /* Metal does not support MDI from the host side, but we still benefit from only executing the + * batch bind a single time, rather than per-draw. + * NOTE(Metal): Consider using #MTLIndirectCommandBuffer to achieve similar behavior. */ + if (command_len_ == 0) { + return; + } + + /* Something's wrong if we get here without MDI support. */ + BLI_assert(MDI_ENABLED); + BLI_assert(data_); + + /* Host-side MDI Currently unsupported on Metal. */ + bool can_use_MDI = false; + + /* Verify context. */ + MTLContext *ctx = reinterpret_cast<MTLContext *>(GPU_context_active_get()); + BLI_assert(ctx); + + /* Execute indirect draw calls. */ + MTLShader *shader = static_cast<MTLShader *>(unwrap(batch_->shader)); + bool SSBO_MODE = (shader->get_uses_ssbo_vertex_fetch()); + if (SSBO_MODE) { + can_use_MDI = false; + BLI_assert(false); + return; + } + + /* Heuristic to determine whether using indirect drawing is more efficient. */ + size_t command_size = MDI_INDEXED ? sizeof(MTLDrawIndexedPrimitivesIndirectArguments) : + sizeof(MTLDrawPrimitivesIndirectArguments); + const bool is_finishing_a_buffer = (command_offset_ + command_size > buffer_size_); + can_use_MDI = can_use_MDI && (is_finishing_a_buffer || command_len_ > 2); + + /* Bind Batch to setup render pipeline state. */ + id<MTLRenderCommandEncoder> rec = batch_->bind(0, 0, 0, 0); + if (!rec) { + BLI_assert_msg(false, "A RenderCommandEncoder should always be available!\n"); + return; + } + + /* Common properties. */ + MTLPrimitiveType mtl_prim_type = gpu_prim_type_to_metal(batch_->prim_type); + + /* Execute multi-draw indirect. */ + if (can_use_MDI && false) { + /* Metal Doesn't support MDI -- Singular Indirect draw calls are supported, + * but Multi-draw is not. + * TODO(Metal): Consider using #IndirectCommandBuffers to provide similar + * behavior. */ + } + else { + + /* Execute draws manually. */ + if (MDI_INDEXED) { + MTLDrawIndexedPrimitivesIndirectArguments *cmd = + (MTLDrawIndexedPrimitivesIndirectArguments *)data_; + MTLIndexBuf *mtl_elem = static_cast<MTLIndexBuf *>( + reinterpret_cast<IndexBuf *>(batch_->elem)); + BLI_assert(mtl_elem); + MTLIndexType index_type = MTLIndexBuf::gpu_index_type_to_metal(mtl_elem->index_type_); + uint32_t index_size = (mtl_elem->index_type_ == GPU_INDEX_U16) ? 2 : 4; + uint32_t v_first_ofs = (mtl_elem->index_start_ * index_size); + uint32_t index_count = cmd->indexCount; + + /* Fetch index buffer. May return an index buffer of a differing format, + * if index buffer optimization is used. In these cases, mtl_prim_type and + * index_count get updated with the new properties. */ + GPUPrimType final_prim_type = batch_->prim_type; + id<MTLBuffer> index_buffer = mtl_elem->get_index_buffer(final_prim_type, index_count); + BLI_assert(index_buffer != nil); + + /* Final primitive type. */ + mtl_prim_type = gpu_prim_type_to_metal(final_prim_type); + + if (index_buffer != nil) { + + /* Set depth stencil state (requires knowledge of primitive type). */ + ctx->ensure_depth_stencil_state(mtl_prim_type); + + for (int i = 0; i < command_len_; i++, cmd++) { + [rec drawIndexedPrimitives:mtl_prim_type + indexCount:index_count + indexType:index_type + indexBuffer:index_buffer + indexBufferOffset:v_first_ofs + instanceCount:cmd->instanceCount + baseVertex:cmd->baseVertex + baseInstance:cmd->baseInstance]; + ctx->main_command_buffer.register_draw_counters(cmd->indexCount * cmd->instanceCount); + } + } + else { + BLI_assert_msg(false, "Index buffer does not have backing Metal buffer"); + } + } + else { + MTLDrawPrimitivesIndirectArguments *cmd = (MTLDrawPrimitivesIndirectArguments *)data_; + + /* Verify if topology emulation is required. */ + if (mtl_needs_topology_emulation(batch_->prim_type)) { + BLI_assert_msg(false, "topology emulation cases should use fallback."); + } + else { + + /* Set depth stencil state (requires knowledge of primitive type). */ + ctx->ensure_depth_stencil_state(mtl_prim_type); + + for (int i = 0; i < command_len_; i++, cmd++) { + [rec drawPrimitives:mtl_prim_type + vertexStart:cmd->vertexStart + vertexCount:cmd->vertexCount + instanceCount:cmd->instanceCount + baseInstance:cmd->baseInstance]; + ctx->main_command_buffer.register_draw_counters(cmd->vertexCount * cmd->instanceCount); + } + } + } + } + + /* Unbind batch. */ + batch_->unbind(); + + /* Reset command offsets. */ + command_len_ = 0; + command_offset_ = 0; + + /* Avoid keeping reference to the batch. */ + batch_ = nullptr; +} + +} // namespace blender::gpu diff --git a/source/blender/gpu/metal/mtl_immediate.mm b/source/blender/gpu/metal/mtl_immediate.mm index 4b63a3b1ce2..ee48bdd6ee1 100644 --- a/source/blender/gpu/metal/mtl_immediate.mm +++ b/source/blender/gpu/metal/mtl_immediate.mm @@ -99,6 +99,9 @@ void MTLImmediate::end() MTLRenderPipelineStateDescriptor &desc = state_manager->get_pipeline_descriptor(); const MTLShaderInterface *interface = active_mtl_shader->get_interface(); + /* Reset vertex descriptor to default state. */ + desc.reset_vertex_descriptor(); + desc.vertex_descriptor.num_attributes = interface->get_total_attributes(); desc.vertex_descriptor.num_vert_buffers = 1; diff --git a/source/blender/gpu/metal/mtl_pso_descriptor_state.hh b/source/blender/gpu/metal/mtl_pso_descriptor_state.hh index 198d309874b..04ceb5bdf03 100644 --- a/source/blender/gpu/metal/mtl_pso_descriptor_state.hh +++ b/source/blender/gpu/metal/mtl_pso_descriptor_state.hh @@ -243,6 +243,19 @@ struct MTLRenderPipelineStateDescriptor { return hash; } + + /* Reset the Vertex Descriptor to default. */ + void reset_vertex_descriptor() + { + vertex_descriptor.num_attributes = 0; + vertex_descriptor.num_vert_buffers = 0; + for (int i = 0; i < GPU_VERT_ATTR_MAX_LEN; i++) { + vertex_descriptor.attributes[i].format = MTLVertexFormatInvalid; + vertex_descriptor.attributes[i].offset = 0; + } + vertex_descriptor.uses_ssbo_vertex_fetch = false; + vertex_descriptor.num_ssbo_attributes = 0; + } }; } // namespace blender::gpu diff --git a/source/blender/gpu/metal/mtl_shader_generator.hh b/source/blender/gpu/metal/mtl_shader_generator.hh index 43890ca0170..63e2e6d5924 100644 --- a/source/blender/gpu/metal/mtl_shader_generator.hh +++ b/source/blender/gpu/metal/mtl_shader_generator.hh @@ -497,7 +497,7 @@ inline std::string get_stage_class_name(ShaderStage stage) inline bool is_builtin_type(std::string type) { /* Add Types as needed. */ - /* TODO(Metal): Consider replacing this with a switch and constexpr hash and switch. + /* TODO(Metal): Consider replacing this with a switch and `constexpr` hash and switch. * Though most efficient and maintainable approach to be determined. */ static std::map<std::string, eMTLDataType> glsl_builtin_types = { {"float", MTL_DATATYPE_FLOAT}, diff --git a/source/blender/gpu/metal/mtl_shader_interface.mm b/source/blender/gpu/metal/mtl_shader_interface.mm index 3703d5b5684..97a82345761 100644 --- a/source/blender/gpu/metal/mtl_shader_interface.mm +++ b/source/blender/gpu/metal/mtl_shader_interface.mm @@ -117,9 +117,7 @@ uint32_t MTLShaderInterface::add_uniform_block(uint32_t name_offset, MTLShaderUniformBlock &uni_block = ubos_[total_uniform_blocks_]; uni_block.name_offset = name_offset; - /* We offset the buffer binding index by one, as the first slot is reserved for push constant - * data. */ - uni_block.buffer_index = buffer_index + 1; + uni_block.buffer_index = buffer_index; uni_block.size = size; uni_block.current_offset = 0; uni_block.stage_mask = ShaderStage::BOTH; @@ -297,8 +295,10 @@ void MTLShaderInterface::prepare_common_shader_inputs() current_input->name_hash = BLI_hash_string(this->get_name_at_offset(shd_ubo.name_offset)); /* Location refers to the index in the ubos_ array. */ current_input->location = ubo_index; - /* Final binding location refers to the buffer binding index within the shader (Relative to - * MTL_uniform_buffer_base_index). */ + /* Binding location refers to the UBO bind slot in + * #MTLContextGlobalShaderPipelineState::ubo_bindings. The buffer bind index [[buffer(N)]] + * within the shader will apply an offset for bound vertex buffers and the default uniform + * PushConstantBlock. */ current_input->binding = shd_ubo.buffer_index; current_input++; } diff --git a/source/blender/gpu/metal/mtl_texture.hh b/source/blender/gpu/metal/mtl_texture.hh index ebc9eb2e00e..28b55306707 100644 --- a/source/blender/gpu/metal/mtl_texture.hh +++ b/source/blender/gpu/metal/mtl_texture.hh @@ -51,9 +51,9 @@ struct TextureUpdateRoutineSpecialisation { uint64_t hash() const { blender::DefaultHash<std::string> string_hasher; - return uint64_t(string_hasher( + return (uint64_t)string_hasher( this->input_data_type + this->output_data_type + - std::to_string((this->component_count_input << 8) + this->component_count_output))); + std::to_string((this->component_count_input << 8) + this->component_count_output)); } }; diff --git a/source/blender/gpu/metal/mtl_texture.mm b/source/blender/gpu/metal/mtl_texture.mm index 32029db6fd9..29dcc8d32ee 100644 --- a/source/blender/gpu/metal/mtl_texture.mm +++ b/source/blender/gpu/metal/mtl_texture.mm @@ -337,20 +337,6 @@ void gpu::MTLTexture::blit(gpu::MTLTexture *dst, GPU_batch_draw(quad); - /* TMP draw with IMM TODO(Metal): Remove this once GPUBatch is supported. */ - GPUVertFormat *imm_format = immVertexFormat(); - uint pos = GPU_vertformat_attr_add(imm_format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT); - - immBindShader(shader); - immBegin(GPU_PRIM_TRI_STRIP, 4); - immVertex2f(pos, 1, 0); - immVertex2f(pos, 0, 0); - immVertex2f(pos, 1, 1); - immVertex2f(pos, 0, 1); - immEnd(); - immUnbindProgram(); - /**********************/ - /* restoring old pipeline state. */ GPU_depth_mask(depth_write_prev); GPU_stencil_write_mask_set(stencil_mask_prev); @@ -1472,10 +1458,82 @@ bool gpu::MTLTexture::init_internal() bool gpu::MTLTexture::init_internal(GPUVertBuf *vbo) { - /* Not a valid vertex buffer format, though verifying texture is not set as such - * as this is not supported on Apple Silicon. */ - BLI_assert_msg(this->format_ != GPU_DEPTH24_STENCIL8, - "Apple silicon does not support GPU_DEPTH24_S8"); + if (this->format_ == GPU_DEPTH24_STENCIL8) { + /* Apple Silicon requires GPU_DEPTH32F_STENCIL8 instead of GPU_DEPTH24_STENCIL8. */ + this->format_ = GPU_DEPTH32F_STENCIL8; + } + + MTLPixelFormat mtl_format = gpu_texture_format_to_metal(this->format_); + mtl_max_mips_ = 1; + mipmaps_ = 0; + this->mip_range_set(0, 0); + + /* Create texture from GPUVertBuf's buffer. */ + MTLVertBuf *mtl_vbo = static_cast<MTLVertBuf *>(unwrap(vbo)); + mtl_vbo->bind(); + mtl_vbo->flag_used(); + + /* Get Metal Buffer. */ + id<MTLBuffer> source_buffer = mtl_vbo->get_metal_buffer(); + BLI_assert(source_buffer); + + /* Verify size. */ + if (w_ <= 0) { + MTL_LOG_WARNING("Allocating texture buffer of width 0!\n"); + w_ = 1; + } + + /* Verify Texture and vertex buffer alignment. */ + int bytes_per_pixel = get_mtl_format_bytesize(mtl_format); + int bytes_per_row = bytes_per_pixel * w_; + + MTLContext *mtl_ctx = MTLContext::get(); + uint32_t align_requirement = static_cast<uint32_t>( + [mtl_ctx->device minimumLinearTextureAlignmentForPixelFormat:mtl_format]); + + /* Verify per-vertex size aligns with texture size. */ + const GPUVertFormat *format = GPU_vertbuf_get_format(vbo); + BLI_assert(bytes_per_pixel == format->stride && + "Pixel format stride MUST match the texture format stride -- These being different " + "is likely caused by Metal's VBO padding to a minimum of 4-bytes per-vertex"); + UNUSED_VARS_NDEBUG(format); + + /* Create texture descriptor. */ + BLI_assert(type_ == GPU_TEXTURE_BUFFER); + texture_descriptor_ = [[MTLTextureDescriptor alloc] init]; + texture_descriptor_.pixelFormat = mtl_format; + texture_descriptor_.textureType = MTLTextureTypeTextureBuffer; + texture_descriptor_.width = w_; + texture_descriptor_.height = 1; + texture_descriptor_.depth = 1; + texture_descriptor_.arrayLength = 1; + texture_descriptor_.mipmapLevelCount = mtl_max_mips_; + texture_descriptor_.usage = + MTLTextureUsageShaderRead | MTLTextureUsageShaderWrite | + MTLTextureUsagePixelFormatView; /* TODO(Metal): Optimize usage flags. */ + texture_descriptor_.storageMode = [source_buffer storageMode]; + texture_descriptor_.sampleCount = 1; + texture_descriptor_.cpuCacheMode = [source_buffer cpuCacheMode]; + texture_descriptor_.hazardTrackingMode = [source_buffer hazardTrackingMode]; + + texture_ = [source_buffer + newTextureWithDescriptor:texture_descriptor_ + offset:0 + bytesPerRow:ceil_to_multiple_u(bytes_per_row, align_requirement)]; + aligned_w_ = bytes_per_row / bytes_per_pixel; + + BLI_assert(texture_); + texture_.label = [NSString stringWithUTF8String:this->get_name()]; + is_baked_ = true; + is_dirty_ = false; + resource_mode_ = MTL_TEXTURE_MODE_VBO; + + /* Track Status. */ + vert_buffer_ = mtl_vbo; + vert_buffer_mtl_ = source_buffer; + /* Cleanup. */ + [texture_descriptor_ release]; + texture_descriptor_ = nullptr; return true; } @@ -1522,7 +1580,6 @@ bool gpu::MTLTexture::texture_is_baked() /* Prepare texture parameters after initialization, but before baking. */ void gpu::MTLTexture::prepare_internal() { - /* Derive implicit usage flags for Depth/Stencil attachments. */ if (format_flag_ & GPU_FORMAT_DEPTH || format_flag_ & GPU_FORMAT_STENCIL) { gpu_image_usage_flags_ |= GPU_TEXTURE_USAGE_ATTACHMENT; @@ -1687,7 +1744,7 @@ void gpu::MTLTexture::ensure_baked() /* Determine Resource Mode. */ resource_mode_ = MTL_TEXTURE_MODE_DEFAULT; - /* Create texture. */ + /* Standard texture allocation. */ texture_ = [ctx->device newTextureWithDescriptor:texture_descriptor_]; [texture_descriptor_ release]; diff --git a/source/blender/gpu/metal/mtl_texture_util.mm b/source/blender/gpu/metal/mtl_texture_util.mm index 5ed7659f260..33a62e2e3ef 100644 --- a/source/blender/gpu/metal/mtl_texture_util.mm +++ b/source/blender/gpu/metal/mtl_texture_util.mm @@ -34,7 +34,7 @@ MTLPixelFormat gpu_texture_format_to_metal(eGPUTextureFormat tex_format) { switch (tex_format) { - /* Formats texture & renderbuffer. */ + /* Formats texture & render-buffer. */ case GPU_RGBA8UI: return MTLPixelFormatRGBA8Uint; case GPU_RGBA8I: diff --git a/source/blender/gpu/opengl/gl_batch.cc b/source/blender/gpu/opengl/gl_batch.cc index ff8867fe3e6..28105e326ee 100644 --- a/source/blender/gpu/opengl/gl_batch.cc +++ b/source/blender/gpu/opengl/gl_batch.cc @@ -272,8 +272,8 @@ void GLBatch::bind(int i_first) #if GPU_TRACK_INDEX_RANGE /* Can be removed if GL 4.3 is required. */ - if (!GLContext::fixed_restart_index_support && (elem != nullptr)) { - glPrimitiveRestartIndex(this->elem_()->restart_index()); + if (!GLContext::fixed_restart_index_support) { + glPrimitiveRestartIndex((elem != nullptr) ? this->elem_()->restart_index() : 0xFFFFFFFFu); } #endif diff --git a/source/blender/gpu/opengl/gl_shader_interface.cc b/source/blender/gpu/opengl/gl_shader_interface.cc index c9432fca561..ef97d74bf81 100644 --- a/source/blender/gpu/opengl/gl_shader_interface.cc +++ b/source/blender/gpu/opengl/gl_shader_interface.cc @@ -200,6 +200,9 @@ static Type gpu_type_from_gl_type(int gl_type) GLShaderInterface::GLShaderInterface(GLuint program) { + GLuint last_program; + glGetIntegerv(GL_CURRENT_PROGRAM, (GLint *)&last_program); + /* Necessary to make #glUniform works. */ glUseProgram(program); @@ -385,6 +388,8 @@ GLShaderInterface::GLShaderInterface(GLuint program) // this->debug_print(); this->sort_inputs(); + + glUseProgram(last_program); } GLShaderInterface::GLShaderInterface(GLuint program, const shader::ShaderCreateInfo &info) @@ -442,6 +447,9 @@ GLShaderInterface::GLShaderInterface(GLuint program, const shader::ShaderCreateI uint32_t name_buffer_offset = 0; /* Necessary to make #glUniform works. TODO(fclem) Remove. */ + GLuint last_program; + glGetIntegerv(GL_CURRENT_PROGRAM, (GLint *)&last_program); + glUseProgram(program); /* Attributes */ @@ -552,6 +560,8 @@ GLShaderInterface::GLShaderInterface(GLuint program, const shader::ShaderCreateI this->sort_inputs(); // this->debug_print(); + + glUseProgram(last_program); } GLShaderInterface::~GLShaderInterface() diff --git a/source/blender/gpu/shaders/compositor/compositor_blur.glsl b/source/blender/gpu/shaders/compositor/compositor_blur.glsl index 4f981c84f59..c7ac620f99b 100644 --- a/source/blender/gpu/shaders/compositor/compositor_blur.glsl +++ b/source/blender/gpu/shaders/compositor/compositor_blur.glsl @@ -18,13 +18,24 @@ vec4 load_input(ivec2 texel) } /* Given the texel in the range [-radius, radius] in both axis, load the appropriate weight from - * the weights texture, where the texel (0, 0) is considered the center of weights texture. */ + * the weights texture, where the given texel (0, 0) corresponds the center of weights texture. + * Note that we load the weights texture inverted along both directions to maintain the shape of + * the weights if it was not symmetrical. To understand why inversion makes sense, consider a 1D + * weights texture whose right half is all ones and whose left half is all zeros. Further, consider + * that we are blurring a single white pixel on a black background. When computing the value of a + * pixel that is to the right of the white pixel, the white pixel will be in the left region of the + * search window, and consequently, without inversion, a zero will be sampled from the left side of + * the weights texture and result will be zero. However, what we expect is that pixels to the right + * of the white pixel will be white, that is, they should sample a weight of 1 from the right side + * of the weights texture, hence the need for inversion. */ vec4 load_weight(ivec2 texel) { - /* Add the radius to transform the texel into the range [0, radius * 2], then divide by the upper - * bound plus one to transform the texel into the normalized range [0, 1] needed to sample the - * weights sampler. Finally, also add 0.5 to sample at the center of the pixels. */ - return texture(weights_tx, (texel + vec2(radius + 0.5)) / (radius * 2 + 1)); + /* Add the radius to transform the texel into the range [0, radius * 2], with an additional 0.5 + * to sample at the center of the pixels, then divide by the upper bound plus one to transform + * the texel into the normalized range [0, 1] needed to sample the weights sampler. Finally, + * invert the textures coordinates by subtracting from 1 to maintain the shape of the weights as + * mentioned in the function description. */ + return texture(weights_tx, 1.0 - ((texel + vec2(radius + 0.5)) / (radius * 2 + 1))); } void main() diff --git a/source/blender/gpu/shaders/compositor/compositor_blur_variable_size.glsl b/source/blender/gpu/shaders/compositor/compositor_blur_variable_size.glsl index e7e5aac12a5..9383bbf9825 100644 --- a/source/blender/gpu/shaders/compositor/compositor_blur_variable_size.glsl +++ b/source/blender/gpu/shaders/compositor/compositor_blur_variable_size.glsl @@ -2,7 +2,16 @@ #pragma BLENDER_REQUIRE(gpu_shader_compositor_texture_utilities.glsl) /* Given the texel in the range [-radius, radius] in both axis, load the appropriate weight from - * the weights texture, where the texel (0, 0) is considered the center of weights texture. */ + * the weights texture, where the given texel (0, 0) corresponds the center of weights texture. + * Note that we load the weights texture inverted along both directions to maintain the shape of + * the weights if it was not symmetrical. To understand why inversion makes sense, consider a 1D + * weights texture whose right half is all ones and whose left half is all zeros. Further, consider + * that we are blurring a single white pixel on a black background. When computing the value of a + * pixel that is to the right of the white pixel, the white pixel will be in the left region of the + * search window, and consequently, without inversion, a zero will be sampled from the left side of + * the weights texture and result will be zero. However, what we expect is that pixels to the right + * of the white pixel will be white, that is, they should sample a weight of 1 from the right side + * of the weights texture, hence the need for inversion. */ vec4 load_weight(ivec2 texel, float radius) { /* The center zero texel is always assigned a unit weight regardless of the corresponding weight @@ -12,10 +21,12 @@ vec4 load_weight(ivec2 texel, float radius) return vec4(1.0); } - /* Add the radius to transform the texel into the range [0, radius * 2], then divide by the upper - * bound plus one to transform the texel into the normalized range [0, 1] needed to sample the - * weights sampler. Finally, also add 0.5 to sample at the center of the pixels. */ - return texture(weights_tx, (texel + vec2(radius + 0.5)) / (radius * 2 + 1)); + /* Add the radius to transform the texel into the range [0, radius * 2], with an additional 0.5 + * to sample at the center of the pixels, then divide by the upper bound plus one to transform + * the texel into the normalized range [0, 1] needed to sample the weights sampler. Finally, + * invert the textures coordinates by subtracting from 1 to maintain the shape of the weights as + * mentioned in the function description. */ + return texture(weights_tx, 1.0 - ((texel + vec2(radius + 0.5)) / (radius * 2 + 1))); } void main() diff --git a/source/blender/gpu/shaders/compositor/compositor_normalize.glsl b/source/blender/gpu/shaders/compositor/compositor_normalize.glsl new file mode 100644 index 00000000000..53dfeb01730 --- /dev/null +++ b/source/blender/gpu/shaders/compositor/compositor_normalize.glsl @@ -0,0 +1,10 @@ +#pragma BLENDER_REQUIRE(gpu_shader_compositor_texture_utilities.glsl) + +void main() +{ + ivec2 texel = ivec2(gl_GlobalInvocationID.xy); + float value = texture_load(input_tx, texel).x; + float normalized_value = (value - minimum) * scale; + float clamped_value = clamp(normalized_value, 0.0, 1.0); + imageStore(output_img, texel, vec4(clamped_value)); +} diff --git a/source/blender/gpu/shaders/compositor/compositor_tone_map_photoreceptor.glsl b/source/blender/gpu/shaders/compositor/compositor_tone_map_photoreceptor.glsl new file mode 100644 index 00000000000..167006585ca --- /dev/null +++ b/source/blender/gpu/shaders/compositor/compositor_tone_map_photoreceptor.glsl @@ -0,0 +1,22 @@ +#pragma BLENDER_REQUIRE(gpu_shader_compositor_texture_utilities.glsl) + +/* Tone mapping based on equation (1) and the trilinear interpolation between equations (6) and (7) + * from Reinhard, Erik, and Kate Devlin. "Dynamic range reduction inspired by photoreceptor + * physiology." IEEE transactions on visualization and computer graphics 11.1 (2005): 13-24. */ +void main() +{ + ivec2 texel = ivec2(gl_GlobalInvocationID.xy); + + vec4 input_color = texture_load(input_tx, texel); + float input_luminance = dot(input_color.rgb, luminance_coefficients); + + /* Trilinear interpolation between equations (6) and (7) from Reinhard's 2005 paper. */ + vec4 local_adaptation_level = mix(vec4(input_luminance), input_color, chromatic_adaptation); + vec4 adaptation_level = mix(global_adaptation_level, local_adaptation_level, light_adaptation); + + /* Equation (1) from Reinhard's 2005 paper, assuming Vmax is 1. */ + vec4 semi_saturation = pow(intensity * adaptation_level, vec4(contrast)); + vec4 tone_mapped_color = input_color / (input_color + semi_saturation); + + imageStore(output_img, texel, vec4(tone_mapped_color.rgb, input_color.a)); +} diff --git a/source/blender/gpu/shaders/compositor/compositor_tone_map_simple.glsl b/source/blender/gpu/shaders/compositor/compositor_tone_map_simple.glsl new file mode 100644 index 00000000000..ce42d021dd1 --- /dev/null +++ b/source/blender/gpu/shaders/compositor/compositor_tone_map_simple.glsl @@ -0,0 +1,26 @@ +#pragma BLENDER_REQUIRE(gpu_shader_compositor_texture_utilities.glsl) +#pragma BLENDER_REQUIRE(gpu_shader_common_math_utils.glsl) + +/* Tone mapping based on equation (3) from Reinhard, Erik, et al. "Photographic tone reproduction + * for digital images." Proceedings of the 29th annual conference on Computer graphics and + * interactive techniques. 2002. */ +void main() +{ + ivec2 texel = ivec2(gl_GlobalInvocationID.xy); + + vec4 input_color = texture_load(input_tx, texel); + + /* Equation (2) from Reinhard's 2002 paper. */ + vec4 scaled_color = input_color * luminance_scale; + + /* Equation (3) from Reinhard's 2002 paper, but with the 1 replaced with the blend factor for + * more flexibility. See ToneMapOperation::compute_luminance_scale_blend_factor. */ + vec4 denominator = luminance_scale_blend_factor + scaled_color; + vec4 tone_mapped_color = safe_divide(scaled_color, denominator); + + if (inverse_gamma != 0.0) { + tone_mapped_color = pow(max(tone_mapped_color, vec4(0.0)), vec4(inverse_gamma)); + } + + imageStore(output_img, texel, vec4(tone_mapped_color.rgb, input_color.a)); +} diff --git a/source/blender/gpu/shaders/compositor/infos/compositor_normalize_info.hh b/source/blender/gpu/shaders/compositor/infos/compositor_normalize_info.hh new file mode 100644 index 00000000000..02fdc424014 --- /dev/null +++ b/source/blender/gpu/shaders/compositor/infos/compositor_normalize_info.hh @@ -0,0 +1,12 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +#include "gpu_shader_create_info.hh" + +GPU_SHADER_CREATE_INFO(compositor_normalize) + .local_group_size(16, 16) + .push_constant(Type::FLOAT, "minimum") + .push_constant(Type::FLOAT, "scale") + .sampler(0, ImageType::FLOAT_2D, "input_tx") + .image(0, GPU_R16F, Qualifier::WRITE, ImageType::FLOAT_2D, "output_img") + .compute_source("compositor_normalize.glsl") + .do_static_compilation(true); diff --git a/source/blender/gpu/shaders/compositor/infos/compositor_parallel_reduction_info.hh b/source/blender/gpu/shaders/compositor/infos/compositor_parallel_reduction_info.hh index 2e661f280af..e2252b14758 100644 --- a/source/blender/gpu/shaders/compositor/infos/compositor_parallel_reduction_info.hh +++ b/source/blender/gpu/shaders/compositor/infos/compositor_parallel_reduction_info.hh @@ -12,14 +12,17 @@ GPU_SHADER_CREATE_INFO(compositor_parallel_reduction_shared) * Sum Reductions. */ -GPU_SHADER_CREATE_INFO(compositor_sum_float_shared) +GPU_SHADER_CREATE_INFO(compositor_sum_shared) .additional_info("compositor_parallel_reduction_shared") - .image(0, GPU_R32F, Qualifier::WRITE, ImageType::FLOAT_2D, "output_img") - .define("TYPE", "float") .define("IDENTITY", "vec4(0.0)") - .define("LOAD(value)", "value.x") .define("REDUCE(lhs, rhs)", "lhs + rhs"); +GPU_SHADER_CREATE_INFO(compositor_sum_float_shared) + .additional_info("compositor_sum_shared") + .image(0, GPU_R32F, Qualifier::WRITE, ImageType::FLOAT_2D, "output_img") + .define("TYPE", "float") + .define("LOAD(value)", "value.x"); + GPU_SHADER_CREATE_INFO(compositor_sum_red) .additional_info("compositor_sum_float_shared") .define("INITIALIZE(value)", "value.r") @@ -41,6 +44,20 @@ GPU_SHADER_CREATE_INFO(compositor_sum_luminance) .define("INITIALIZE(value)", "dot(value.rgb, luminance_coefficients)") .do_static_compilation(true); +GPU_SHADER_CREATE_INFO(compositor_sum_log_luminance) + .additional_info("compositor_sum_float_shared") + .push_constant(Type::VEC3, "luminance_coefficients") + .define("INITIALIZE(value)", "log(max(dot(value.rgb, luminance_coefficients), 1e-5))") + .do_static_compilation(true); + +GPU_SHADER_CREATE_INFO(compositor_sum_color) + .additional_info("compositor_sum_shared") + .image(0, GPU_RGBA32F, Qualifier::WRITE, ImageType::FLOAT_2D, "output_img") + .define("TYPE", "vec4") + .define("INITIALIZE(value)", "value") + .define("LOAD(value)", "value") + .do_static_compilation(true); + /* -------------------------------------------------------------------- * Sum Of Squared Difference Reductions. */ @@ -74,3 +91,59 @@ GPU_SHADER_CREATE_INFO(compositor_sum_luminance_squared_difference) .push_constant(Type::VEC3, "luminance_coefficients") .define("INITIALIZE(value)", "pow(dot(value.rgb, luminance_coefficients) - subtrahend, 2.0)") .do_static_compilation(true); + +/* -------------------------------------------------------------------- + * Maximum Reductions. + */ + +GPU_SHADER_CREATE_INFO(compositor_maximum_luminance) + .additional_info("compositor_parallel_reduction_shared") + .typedef_source("common_math_lib.glsl") + .image(0, GPU_R32F, Qualifier::WRITE, ImageType::FLOAT_2D, "output_img") + .push_constant(Type::VEC3, "luminance_coefficients") + .define("TYPE", "float") + .define("IDENTITY", "vec4(FLT_MIN)") + .define("INITIALIZE(value)", "dot(value.rgb, luminance_coefficients)") + .define("LOAD(value)", "value.x") + .define("REDUCE(lhs, rhs)", "max(lhs, rhs)") + .do_static_compilation(true); + +GPU_SHADER_CREATE_INFO(compositor_maximum_float_in_range) + .additional_info("compositor_parallel_reduction_shared") + .image(0, GPU_R32F, Qualifier::WRITE, ImageType::FLOAT_2D, "output_img") + .push_constant(Type::FLOAT, "lower_bound") + .push_constant(Type::FLOAT, "upper_bound") + .define("TYPE", "float") + .define("IDENTITY", "vec4(lower_bound)") + .define("INITIALIZE(v)", "((v.x <= upper_bound) && (v.x >= lower_bound)) ? v.x : lower_bound") + .define("LOAD(value)", "value.x") + .define("REDUCE(lhs, rhs)", "((rhs > lhs) && (rhs <= upper_bound)) ? rhs : lhs") + .do_static_compilation(true); + +/* -------------------------------------------------------------------- + * Minimum Reductions. + */ + +GPU_SHADER_CREATE_INFO(compositor_minimum_luminance) + .additional_info("compositor_parallel_reduction_shared") + .typedef_source("common_math_lib.glsl") + .image(0, GPU_R32F, Qualifier::WRITE, ImageType::FLOAT_2D, "output_img") + .push_constant(Type::VEC3, "luminance_coefficients") + .define("TYPE", "float") + .define("IDENTITY", "vec4(FLT_MAX)") + .define("INITIALIZE(value)", "dot(value.rgb, luminance_coefficients)") + .define("LOAD(value)", "value.x") + .define("REDUCE(lhs, rhs)", "min(lhs, rhs)") + .do_static_compilation(true); + +GPU_SHADER_CREATE_INFO(compositor_minimum_float_in_range) + .additional_info("compositor_parallel_reduction_shared") + .image(0, GPU_R32F, Qualifier::WRITE, ImageType::FLOAT_2D, "output_img") + .push_constant(Type::FLOAT, "lower_bound") + .push_constant(Type::FLOAT, "upper_bound") + .define("TYPE", "float") + .define("IDENTITY", "vec4(upper_bound)") + .define("INITIALIZE(v)", "((v.x <= upper_bound) && (v.x >= lower_bound)) ? v.x : upper_bound") + .define("LOAD(value)", "value.x") + .define("REDUCE(lhs, rhs)", "((rhs < lhs) && (rhs >= lower_bound)) ? rhs : lhs") + .do_static_compilation(true); diff --git a/source/blender/gpu/shaders/compositor/infos/compositor_tone_map_photoreceptor_info.hh b/source/blender/gpu/shaders/compositor/infos/compositor_tone_map_photoreceptor_info.hh new file mode 100644 index 00000000000..a460c9d58a6 --- /dev/null +++ b/source/blender/gpu/shaders/compositor/infos/compositor_tone_map_photoreceptor_info.hh @@ -0,0 +1,16 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +#include "gpu_shader_create_info.hh" + +GPU_SHADER_CREATE_INFO(compositor_tone_map_photoreceptor) + .local_group_size(16, 16) + .push_constant(Type::VEC4, "global_adaptation_level") + .push_constant(Type::FLOAT, "contrast") + .push_constant(Type::FLOAT, "intensity") + .push_constant(Type::FLOAT, "chromatic_adaptation") + .push_constant(Type::FLOAT, "light_adaptation") + .push_constant(Type::VEC3, "luminance_coefficients") + .sampler(0, ImageType::FLOAT_2D, "input_tx") + .image(0, GPU_RGBA16F, Qualifier::WRITE, ImageType::FLOAT_2D, "output_img") + .compute_source("compositor_tone_map_photoreceptor.glsl") + .do_static_compilation(true); diff --git a/source/blender/gpu/shaders/compositor/infos/compositor_tone_map_simple_info.hh b/source/blender/gpu/shaders/compositor/infos/compositor_tone_map_simple_info.hh new file mode 100644 index 00000000000..2b220af9460 --- /dev/null +++ b/source/blender/gpu/shaders/compositor/infos/compositor_tone_map_simple_info.hh @@ -0,0 +1,13 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +#include "gpu_shader_create_info.hh" + +GPU_SHADER_CREATE_INFO(compositor_tone_map_simple) + .local_group_size(16, 16) + .push_constant(Type::FLOAT, "luminance_scale") + .push_constant(Type::FLOAT, "luminance_scale_blend_factor") + .push_constant(Type::FLOAT, "inverse_gamma") + .sampler(0, ImageType::FLOAT_2D, "input_tx") + .image(0, GPU_RGBA16F, Qualifier::WRITE, ImageType::FLOAT_2D, "output_img") + .compute_source("compositor_tone_map_simple.glsl") + .do_static_compilation(true); diff --git a/source/blender/gpu/shaders/gpu_shader_icon_frag.glsl b/source/blender/gpu/shaders/gpu_shader_icon_frag.glsl new file mode 100644 index 00000000000..4452349f23c --- /dev/null +++ b/source/blender/gpu/shaders/gpu_shader_icon_frag.glsl @@ -0,0 +1,42 @@ +/** + * Draw the icons, leaving a semi-transparent rectangle on top of the icon. + * + * The top-left corner of the rectangle is rounded and drawned with anti-alias. + * The anti-alias is done by transitioning from the outer to the inner radius of + * the rounded corner, and the rectangle sides. + */ + +void main() +{ + /* Top-left rounded corner parameters. */ + const float circle_radius_outer = 0.1; + const float circle_radius_inner = 0.075; + + /** + * Add a bit transparency to see a bit of the icon, without + * getting on the way of readability. */ + const float mask_transparency = 0.25; + + vec2 circle_center = vec2(circle_radius_outer - text_width, 0.5); + fragColor = texture(image, texCoord_interp) * color; + + /* radius in icon space (1 is the icon width). */ + float radius = length(mask_coord_interp - circle_center); + float mask = smoothstep(circle_radius_inner, circle_radius_outer, radius); + + bool lower_half = mask_coord_interp.y < circle_center.y; + bool right_half = mask_coord_interp.x > circle_center.x; + + if (right_half && mask_coord_interp.y < circle_center.y + circle_radius_outer) { + mask = smoothstep(circle_center.y + circle_radius_inner, + circle_center.y + circle_radius_outer, + mask_coord_interp.y); + } + if (lower_half && mask_coord_interp.x > circle_center.x - circle_radius_outer) { + mask = smoothstep(circle_center.x - circle_radius_inner, + circle_center.x - circle_radius_outer, + mask_coord_interp.x); + } + + fragColor = mix(vec4(0.0), fragColor, max(mask_transparency, mask)); +} diff --git a/source/blender/gpu/shaders/gpu_shader_icon_vert.glsl b/source/blender/gpu/shaders/gpu_shader_icon_vert.glsl new file mode 100644 index 00000000000..25f64bfe0b6 --- /dev/null +++ b/source/blender/gpu/shaders/gpu_shader_icon_vert.glsl @@ -0,0 +1,37 @@ +/** + * Simple shader that just draw one icon at the specified location + * does not need any vertex input (producing less call to immBegin/End) + */ + +void main() +{ + vec2 uv; + vec2 co; + + if (gl_VertexID == 0) { + co = rect_geom.xw; + uv = rect_icon.xw; + mask_coord_interp = vec2(0, 1); + } + else if (gl_VertexID == 1) { + co = rect_geom.xy; + uv = rect_icon.xy; + mask_coord_interp = vec2(0, 0); + } + else if (gl_VertexID == 2) { + co = rect_geom.zw; + uv = rect_icon.zw; + mask_coord_interp = vec2(1, 1); + } + else { + co = rect_geom.zy; + uv = rect_icon.zy; + mask_coord_interp = vec2(1, 0); + } + + /* Put origin in lower right corner. */ + mask_coord_interp.x -= 1; + + gl_Position = ModelViewProjectionMatrix * vec4(co, 0.0f, 1.0f); + texCoord_interp = uv; +} diff --git a/source/blender/gpu/shaders/infos/gpu_interface_info.hh b/source/blender/gpu/shaders/infos/gpu_interface_info.hh index d77c65e48a7..060def16f81 100644 --- a/source/blender/gpu/shaders/infos/gpu_interface_info.hh +++ b/source/blender/gpu/shaders/infos/gpu_interface_info.hh @@ -18,3 +18,6 @@ GPU_SHADER_INTERFACE_INFO(smooth_radii_outline_iface, "").smooth(Type::VEC4, "ra GPU_SHADER_INTERFACE_INFO(flat_color_smooth_tex_coord_interp_iface, "") .flat(Type::VEC4, "finalColor") .smooth(Type::VEC2, "texCoord_interp"); +GPU_SHADER_INTERFACE_INFO(smooth_icon_interp_iface, "") + .smooth(Type::VEC2, "texCoord_interp") + .smooth(Type::VEC2, "mask_coord_interp"); diff --git a/source/blender/gpu/shaders/infos/gpu_shader_icon_info.hh b/source/blender/gpu/shaders/infos/gpu_shader_icon_info.hh new file mode 100644 index 00000000000..3d4077bdb09 --- /dev/null +++ b/source/blender/gpu/shaders/infos/gpu_shader_icon_info.hh @@ -0,0 +1,22 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later + * Copyright 2022 Blender Foundation. All rights reserved. */ + +/** \file + * \ingroup gpu + */ + +#include "gpu_interface_info.hh" +#include "gpu_shader_create_info.hh" + +GPU_SHADER_CREATE_INFO(gpu_shader_icon) + .vertex_out(smooth_icon_interp_iface) + .fragment_out(0, Type::VEC4, "fragColor") + .push_constant(Type::MAT4, "ModelViewProjectionMatrix") + .push_constant(Type::VEC4, "color") + .push_constant(Type::VEC4, "rect_icon") + .push_constant(Type::VEC4, "rect_geom") + .push_constant(Type::FLOAT, "text_width") + .sampler(0, ImageType::FLOAT_2D, "image") + .vertex_source("gpu_shader_icon_vert.glsl") + .fragment_source("gpu_shader_icon_frag.glsl") + .do_static_compilation(true); diff --git a/source/blender/gpu/vulkan/vk_backend.cc b/source/blender/gpu/vulkan/vk_backend.cc new file mode 100644 index 00000000000..00bc43333d6 --- /dev/null +++ b/source/blender/gpu/vulkan/vk_backend.cc @@ -0,0 +1,107 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later + * Copyright 2022 Blender Foundation. All rights reserved. */ + +/** \file + * \ingroup gpu + */ + +#include "vk_backend.hh" + +#include "vk_batch.hh" +#include "vk_context.hh" +#include "vk_drawlist.hh" +#include "vk_framebuffer.hh" +#include "vk_index_buffer.hh" +#include "vk_query.hh" +#include "vk_shader.hh" +#include "vk_storage_buffer.hh" +#include "vk_texture.hh" +#include "vk_uniform_buffer.hh" +#include "vk_vertex_buffer.hh" + +namespace blender::gpu { + +void VKBackend::delete_resources() +{ +} + +void VKBackend::samplers_update() +{ +} + +void VKBackend::compute_dispatch(int /*groups_x_len*/, int /*groups_y_len*/, int /*groups_z_len*/) +{ +} + +void VKBackend::compute_dispatch_indirect(StorageBuf * /*indirect_buf*/) +{ +} + +Context *VKBackend::context_alloc(void * /*ghost_window*/, void * /*ghost_context*/) +{ + return new VKContext(); +} + +Batch *VKBackend::batch_alloc() +{ + return new VKBatch(); +} + +DrawList *VKBackend::drawlist_alloc(int /*list_length*/) +{ + return new VKDrawList(); +} + +FrameBuffer *VKBackend::framebuffer_alloc(const char *name) +{ + return new VKFrameBuffer(name); +} + +IndexBuf *VKBackend::indexbuf_alloc() +{ + return new VKIndexBuffer(); +} + +QueryPool *VKBackend::querypool_alloc() +{ + return new VKQueryPool(); +} + +Shader *VKBackend::shader_alloc(const char *name) +{ + return new VKShader(name); +} + +Texture *VKBackend::texture_alloc(const char *name) +{ + return new VKTexture(name); +} + +UniformBuf *VKBackend::uniformbuf_alloc(int size, const char *name) +{ + return new VKUniformBuffer(size, name); +} + +StorageBuf *VKBackend::storagebuf_alloc(int size, GPUUsageType /*usage*/, const char *name) +{ + return new VKStorageBuffer(size, name); +} + +VertBuf *VKBackend::vertbuf_alloc() +{ + return new VKVertexBuffer(); +} + +void VKBackend::render_begin() +{ +} + +void VKBackend::render_end() +{ +} + +void VKBackend::render_step() +{ +} + +} // namespace blender::gpu
\ No newline at end of file diff --git a/source/blender/gpu/vulkan/vk_backend.hh b/source/blender/gpu/vulkan/vk_backend.hh new file mode 100644 index 00000000000..549478586e8 --- /dev/null +++ b/source/blender/gpu/vulkan/vk_backend.hh @@ -0,0 +1,42 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later + * Copyright 2022 Blender Foundation. All rights reserved. */ + +/** \file + * \ingroup gpu + */ + +#pragma once + +#include "gpu_backend.hh" + +namespace blender::gpu { + +class VKBackend : public GPUBackend { + public: + void delete_resources() override; + + void samplers_update() override; + void compute_dispatch(int groups_x_len, int groups_y_len, int groups_z_len) override; + void compute_dispatch_indirect(StorageBuf *indirect_buf) override; + + Context *context_alloc(void *ghost_window, void *ghost_context) override; + + Batch *batch_alloc() override; + DrawList *drawlist_alloc(int list_length) override; + FrameBuffer *framebuffer_alloc(const char *name) override; + IndexBuf *indexbuf_alloc() override; + QueryPool *querypool_alloc() override; + Shader *shader_alloc(const char *name) override; + Texture *texture_alloc(const char *name) override; + UniformBuf *uniformbuf_alloc(int size, const char *name) override; + StorageBuf *storagebuf_alloc(int size, GPUUsageType usage, const char *name) override; + VertBuf *vertbuf_alloc() override; + + /* Render Frame Coordination -- + * Used for performing per-frame actions globally */ + void render_begin() override; + void render_end() override; + void render_step() override; +}; + +} // namespace blender::gpu
\ No newline at end of file diff --git a/source/blender/gpu/vulkan/vk_batch.cc b/source/blender/gpu/vulkan/vk_batch.cc new file mode 100644 index 00000000000..a25f98a2e24 --- /dev/null +++ b/source/blender/gpu/vulkan/vk_batch.cc @@ -0,0 +1,27 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later + * Copyright 2022 Blender Foundation. All rights reserved. */ + +/** \file + * \ingroup gpu + */ + +#include "vk_batch.hh" + +namespace blender::gpu { + +void VKBatch::draw(int /*v_first*/, int /*v_count*/, int /*i_first*/, int /*i_count*/) +{ +} + +void VKBatch::draw_indirect(GPUStorageBuf * /*indirect_buf*/, intptr_t /*offset*/) +{ +} + +void VKBatch::multi_draw_indirect(GPUStorageBuf * /*indirect_buf*/, + int /*count*/, + intptr_t /*offset*/, + intptr_t /*stride*/) +{ +} + +} // namespace blender::gpu
\ No newline at end of file diff --git a/source/blender/gpu/vulkan/vk_batch.hh b/source/blender/gpu/vulkan/vk_batch.hh new file mode 100644 index 00000000000..0f6df41606d --- /dev/null +++ b/source/blender/gpu/vulkan/vk_batch.hh @@ -0,0 +1,24 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later + * Copyright 2022 Blender Foundation. All rights reserved. */ + +/** \file + * \ingroup gpu + */ + +#pragma once + +#include "gpu_batch_private.hh" + +namespace blender::gpu { + +class VKBatch : public Batch { + public: + void draw(int v_first, int v_count, int i_first, int i_count) override; + void draw_indirect(GPUStorageBuf *indirect_buf, intptr_t offset) override; + void multi_draw_indirect(GPUStorageBuf *indirect_buf, + int count, + intptr_t offset, + intptr_t stride) override; +}; + +} // namespace blender::gpu
\ No newline at end of file diff --git a/source/blender/gpu/vulkan/vk_context.cc b/source/blender/gpu/vulkan/vk_context.cc new file mode 100644 index 00000000000..55b29ea4e2f --- /dev/null +++ b/source/blender/gpu/vulkan/vk_context.cc @@ -0,0 +1,48 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later + * Copyright 2022 Blender Foundation. All rights reserved. */ + +/** \file + * \ingroup gpu + */ + +#include "vk_context.hh" + +namespace blender::gpu { + +void VKContext::activate() +{ +} + +void VKContext::deactivate() +{ +} + +void VKContext::begin_frame() +{ +} + +void VKContext::end_frame() +{ +} + +void VKContext::flush() +{ +} + +void VKContext::finish() +{ +} + +void VKContext::memory_statistics_get(int * /*total_mem*/, int * /*free_mem*/) +{ +} + +void VKContext::debug_group_begin(const char *, int) +{ +} + +void VKContext::debug_group_end() +{ +} + +} // namespace blender::gpu
\ No newline at end of file diff --git a/source/blender/gpu/vulkan/vk_context.hh b/source/blender/gpu/vulkan/vk_context.hh new file mode 100644 index 00000000000..17292b891b6 --- /dev/null +++ b/source/blender/gpu/vulkan/vk_context.hh @@ -0,0 +1,34 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later + * Copyright 2022 Blender Foundation. All rights reserved. */ + +/** \file + * \ingroup gpu + */ + +#pragma once + +#include "gpu_context_private.hh" + +namespace blender::gpu { + +class VKContext : public Context { + public: + VKContext() + { + } + + void activate() override; + void deactivate() override; + void begin_frame() override; + void end_frame() override; + + void flush() override; + void finish() override; + + void memory_statistics_get(int *total_mem, int *free_mem) override; + + void debug_group_begin(const char *, int) override; + void debug_group_end() override; +}; + +} // namespace blender::gpu
\ No newline at end of file diff --git a/source/blender/gpu/vulkan/vk_drawlist.cc b/source/blender/gpu/vulkan/vk_drawlist.cc new file mode 100644 index 00000000000..c8f3c736bb8 --- /dev/null +++ b/source/blender/gpu/vulkan/vk_drawlist.cc @@ -0,0 +1,20 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later + * Copyright 2022 Blender Foundation. All rights reserved. */ + +/** \file + * \ingroup gpu + */ + +#include "vk_drawlist.hh" + +namespace blender::gpu { + +void VKDrawList::append(GPUBatch * /*batch*/, int /*i_first*/, int /*i_count*/) +{ +} + +void VKDrawList::submit() +{ +} + +} // namespace blender::gpu
\ No newline at end of file diff --git a/source/blender/gpu/vulkan/vk_drawlist.hh b/source/blender/gpu/vulkan/vk_drawlist.hh new file mode 100644 index 00000000000..4707bf4bb26 --- /dev/null +++ b/source/blender/gpu/vulkan/vk_drawlist.hh @@ -0,0 +1,20 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later + * Copyright 2022 Blender Foundation. All rights reserved. */ + +/** \file + * \ingroup gpu + */ + +#pragma once + +#include "gpu_drawlist_private.hh" + +namespace blender::gpu { + +class VKDrawList : public DrawList { + public: + void append(GPUBatch *batch, int i_first, int i_count) override; + void submit() override; +}; + +} // namespace blender::gpu
\ No newline at end of file diff --git a/source/blender/gpu/vulkan/vk_framebuffer.cc b/source/blender/gpu/vulkan/vk_framebuffer.cc new file mode 100644 index 00000000000..48b0685bf38 --- /dev/null +++ b/source/blender/gpu/vulkan/vk_framebuffer.cc @@ -0,0 +1,62 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later + * Copyright 2022 Blender Foundation. All rights reserved. */ + +/** \file + * \ingroup gpu + */ + +#include "vk_framebuffer.hh" + +namespace blender::gpu { + +void VKFrameBuffer::bind(bool /*enabled_srgb*/) +{ +} + +bool VKFrameBuffer::check(char /*err_out*/[256]) +{ + return false; +} + +void VKFrameBuffer::clear(eGPUFrameBufferBits /*buffers*/, + const float /*clear_col*/[4], + float /*clear_depth*/, + uint /*clear_stencil*/) +{ +} + +void VKFrameBuffer::clear_multi(const float (*/*clear_col*/)[4]) +{ +} + +void VKFrameBuffer::clear_attachment(GPUAttachmentType /*type*/, + eGPUDataFormat /*data_format*/, + const void * /*clear_value*/) +{ +} + +void VKFrameBuffer::attachment_set_loadstore_op(GPUAttachmentType /*type*/, + eGPULoadOp /*load_action*/, + eGPUStoreOp /*store_action*/) +{ +} + +void VKFrameBuffer::read(eGPUFrameBufferBits /*planes*/, + eGPUDataFormat /*format*/, + const int /*area*/[4], + int /*channel_len*/, + int /*slot*/, + void * /*r_data*/) +{ +} + +void VKFrameBuffer::blit_to(eGPUFrameBufferBits /*planes*/, + int /*src_slot*/, + FrameBuffer * /*dst*/, + int /*dst_slot*/, + int /*dst_offset_x*/, + int /*dst_offset_y*/) +{ +} + +} // namespace blender::gpu
\ No newline at end of file diff --git a/source/blender/gpu/vulkan/vk_framebuffer.hh b/source/blender/gpu/vulkan/vk_framebuffer.hh new file mode 100644 index 00000000000..632d45ce709 --- /dev/null +++ b/source/blender/gpu/vulkan/vk_framebuffer.hh @@ -0,0 +1,50 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later + * Copyright 2022 Blender Foundation. All rights reserved. */ + +/** \file + * \ingroup gpu + */ + +#pragma once + +#include "gpu_framebuffer_private.hh" + +namespace blender::gpu { + +class VKFrameBuffer : public FrameBuffer { + public: + VKFrameBuffer(const char *name) : FrameBuffer(name) + { + } + + void bind(bool enabled_srgb) override; + bool check(char err_out[256]) override; + void clear(eGPUFrameBufferBits buffers, + const float clear_col[4], + float clear_depth, + uint clear_stencil) override; + void clear_multi(const float (*clear_col)[4]) override; + void clear_attachment(GPUAttachmentType type, + eGPUDataFormat data_format, + const void *clear_value) override; + + void attachment_set_loadstore_op(GPUAttachmentType type, + eGPULoadOp load_action, + eGPUStoreOp store_action) override; + + void read(eGPUFrameBufferBits planes, + eGPUDataFormat format, + const int area[4], + int channel_len, + int slot, + void *r_data) override; + + void blit_to(eGPUFrameBufferBits planes, + int src_slot, + FrameBuffer *dst, + int dst_slot, + int dst_offset_x, + int dst_offset_y) override; +}; + +} // namespace blender::gpu
\ No newline at end of file diff --git a/source/blender/gpu/vulkan/vk_index_buffer.cc b/source/blender/gpu/vulkan/vk_index_buffer.cc new file mode 100644 index 00000000000..119a617a159 --- /dev/null +++ b/source/blender/gpu/vulkan/vk_index_buffer.cc @@ -0,0 +1,33 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later + * Copyright 2022 Blender Foundation. All rights reserved. */ + +/** \file + * \ingroup gpu + */ + +#include "vk_index_buffer.hh" + +namespace blender::gpu { + +void VKIndexBuffer::upload_data() +{ +} + +void VKIndexBuffer::bind_as_ssbo(uint /*binding*/) +{ +} + +const uint32_t *VKIndexBuffer::read() const +{ + return 0; +} + +void VKIndexBuffer::update_sub(uint /*start*/, uint /*len*/, const void * /*data*/) +{ +} + +void VKIndexBuffer::strip_restart_indices() +{ +} + +} // namespace blender::gpu
\ No newline at end of file diff --git a/source/blender/gpu/vulkan/vk_index_buffer.hh b/source/blender/gpu/vulkan/vk_index_buffer.hh new file mode 100644 index 00000000000..f002d5581c7 --- /dev/null +++ b/source/blender/gpu/vulkan/vk_index_buffer.hh @@ -0,0 +1,28 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later + * Copyright 2022 Blender Foundation. All rights reserved. */ + +/** \file + * \ingroup gpu + */ + +#pragma once + +#include "gpu_index_buffer_private.hh" + +namespace blender::gpu { + +class VKIndexBuffer : public IndexBuf { + public: + void upload_data() override; + + void bind_as_ssbo(uint binding) override; + + const uint32_t *read() const override; + + void update_sub(uint start, uint len, const void *data) override; + + private: + void strip_restart_indices() override; +}; + +} // namespace blender::gpu
\ No newline at end of file diff --git a/source/blender/gpu/vulkan/vk_query.cc b/source/blender/gpu/vulkan/vk_query.cc new file mode 100644 index 00000000000..e24fe54e5d0 --- /dev/null +++ b/source/blender/gpu/vulkan/vk_query.cc @@ -0,0 +1,28 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later + * Copyright 2022 Blender Foundation. All rights reserved. */ + +/** \file + * \ingroup gpu + */ + +#include "vk_query.hh" + +namespace blender::gpu { + +void VKQueryPool::init(GPUQueryType /*type*/) +{ +} + +void VKQueryPool::begin_query() +{ +} + +void VKQueryPool::end_query() +{ +} + +void VKQueryPool::get_occlusion_result(MutableSpan<uint32_t> /*r_values*/) +{ +} + +} // namespace blender::gpu
\ No newline at end of file diff --git a/source/blender/gpu/vulkan/vk_query.hh b/source/blender/gpu/vulkan/vk_query.hh new file mode 100644 index 00000000000..36558ef9549 --- /dev/null +++ b/source/blender/gpu/vulkan/vk_query.hh @@ -0,0 +1,22 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later + * Copyright 2022 Blender Foundation. All rights reserved. */ + +/** \file + * \ingroup gpu + */ + +#pragma once + +#include "gpu_query.hh" + +namespace blender::gpu { + +class VKQueryPool : public QueryPool { + public: + void init(GPUQueryType type) override; + void begin_query() override; + void end_query() override; + void get_occlusion_result(MutableSpan<uint32_t> r_values) override; +}; + +} // namespace blender::gpu
\ No newline at end of file diff --git a/source/blender/gpu/vulkan/vk_shader.cc b/source/blender/gpu/vulkan/vk_shader.cc new file mode 100644 index 00000000000..d628f3eb851 --- /dev/null +++ b/source/blender/gpu/vulkan/vk_shader.cc @@ -0,0 +1,102 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later + * Copyright 2022 Blender Foundation. All rights reserved. */ + +/** \file + * \ingroup gpu + */ + +#include "vk_shader.hh" + +namespace blender::gpu { +void VKShader::vertex_shader_from_glsl(MutableSpan<const char *> /*sources*/) +{ +} + +void VKShader::geometry_shader_from_glsl(MutableSpan<const char *> /*sources*/) +{ +} + +void VKShader::fragment_shader_from_glsl(MutableSpan<const char *> /*sources*/) +{ +} + +void VKShader::compute_shader_from_glsl(MutableSpan<const char *> /*sources*/) +{ +} + +bool VKShader::finalize(const shader::ShaderCreateInfo * /*info*/) +{ + return false; +} + +void VKShader::transform_feedback_names_set(Span<const char *> /*name_list*/, + eGPUShaderTFBType /*geom_type*/) +{ +} + +bool VKShader::transform_feedback_enable(GPUVertBuf *) +{ + return false; +} + +void VKShader::transform_feedback_disable() +{ +} + +void VKShader::bind() +{ +} + +void VKShader::unbind() +{ +} + +void VKShader::uniform_float(int /*location*/, + int /*comp_len*/, + int /*array_size*/, + const float * /*data*/) +{ +} +void VKShader::uniform_int(int /*location*/, + int /*comp_len*/, + int /*array_size*/, + const int * /*data*/) +{ +} + +std::string VKShader::resources_declare(const shader::ShaderCreateInfo & /*info*/) const +{ + return std::string(); +} + +std::string VKShader::vertex_interface_declare(const shader::ShaderCreateInfo & /*info*/) const +{ + return std::string(); +} + +std::string VKShader::fragment_interface_declare(const shader::ShaderCreateInfo & /*info*/) const +{ + return std::string(); +} + +std::string VKShader::geometry_interface_declare(const shader::ShaderCreateInfo & /*info*/) const +{ + return std::string(); +} + +std::string VKShader::geometry_layout_declare(const shader::ShaderCreateInfo & /*info*/) const +{ + return std::string(); +} + +std::string VKShader::compute_layout_declare(const shader::ShaderCreateInfo & /*info*/) const +{ + return std::string(); +} + +int VKShader::program_handle_get() const +{ + return -1; +} + +} // namespace blender::gpu
\ No newline at end of file diff --git a/source/blender/gpu/vulkan/vk_shader.hh b/source/blender/gpu/vulkan/vk_shader.hh new file mode 100644 index 00000000000..9ab0aca67eb --- /dev/null +++ b/source/blender/gpu/vulkan/vk_shader.hh @@ -0,0 +1,48 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later + * Copyright 2022 Blender Foundation. All rights reserved. */ + +/** \file + * \ingroup gpu + */ + +#pragma once + +#include "gpu_shader_private.hh" + +namespace blender::gpu { + +class VKShader : public Shader { + public: + VKShader(const char *name) : Shader(name) + { + } + + void vertex_shader_from_glsl(MutableSpan<const char *> sources) override; + void geometry_shader_from_glsl(MutableSpan<const char *> sources) override; + void fragment_shader_from_glsl(MutableSpan<const char *> sources) override; + void compute_shader_from_glsl(MutableSpan<const char *> sources) override; + bool finalize(const shader::ShaderCreateInfo *info = nullptr) override; + + void transform_feedback_names_set(Span<const char *> name_list, + eGPUShaderTFBType geom_type) override; + bool transform_feedback_enable(GPUVertBuf *) override; + void transform_feedback_disable() override; + + void bind() override; + void unbind() override; + + void uniform_float(int location, int comp_len, int array_size, const float *data) override; + void uniform_int(int location, int comp_len, int array_size, const int *data) override; + + std::string resources_declare(const shader::ShaderCreateInfo &info) const override; + std::string vertex_interface_declare(const shader::ShaderCreateInfo &info) const override; + std::string fragment_interface_declare(const shader::ShaderCreateInfo &info) const override; + std::string geometry_interface_declare(const shader::ShaderCreateInfo &info) const override; + std::string geometry_layout_declare(const shader::ShaderCreateInfo &info) const override; + std::string compute_layout_declare(const shader::ShaderCreateInfo &info) const override; + + /* DEPRECATED: Kept only because of BGL API. */ + int program_handle_get() const override; +}; + +} // namespace blender::gpu
\ No newline at end of file diff --git a/source/blender/gpu/vulkan/vk_storage_buffer.cc b/source/blender/gpu/vulkan/vk_storage_buffer.cc new file mode 100644 index 00000000000..2b6fda0547d --- /dev/null +++ b/source/blender/gpu/vulkan/vk_storage_buffer.cc @@ -0,0 +1,42 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later + * Copyright 2022 Blender Foundation. All rights reserved. */ + +/** \file + * \ingroup gpu + */ + +#include "vk_vertex_buffer.hh" + +#include "vk_storage_buffer.hh" + +namespace blender::gpu { + +void VKStorageBuffer::update(const void * /*data*/) +{ +} + +void VKStorageBuffer::bind(int /*slot*/) +{ +} + +void VKStorageBuffer::unbind() +{ +} + +void VKStorageBuffer::clear(eGPUTextureFormat /* internal_format*/, + eGPUDataFormat /*data_format*/, + void * /*data*/) +{ +} +void VKStorageBuffer::copy_sub(VertBuf * /*src*/, + uint /*dst_offset*/, + uint /*src_offset*/, + uint /*copy_size*/) +{ +} + +void VKStorageBuffer::read(void * /*data*/) +{ +} + +} // namespace blender::gpu
\ No newline at end of file diff --git a/source/blender/gpu/vulkan/vk_storage_buffer.hh b/source/blender/gpu/vulkan/vk_storage_buffer.hh new file mode 100644 index 00000000000..a51f89f627a --- /dev/null +++ b/source/blender/gpu/vulkan/vk_storage_buffer.hh @@ -0,0 +1,30 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later + * Copyright 2022 Blender Foundation. All rights reserved. */ + +/** \file + * \ingroup gpu + */ + +#pragma once + +#include "GPU_texture.h" + +#include "gpu_storage_buffer_private.hh" + +namespace blender::gpu { + +class VKStorageBuffer : public StorageBuf { + public: + VKStorageBuffer(int size, const char *name) : StorageBuf(size, name) + { + } + + void update(const void *data) override; + void bind(int slot) override; + void unbind() override; + void clear(eGPUTextureFormat internal_format, eGPUDataFormat data_format, void *data) override; + void copy_sub(VertBuf *src, uint dst_offset, uint src_offset, uint copy_size) override; + void read(void *data) override; +}; + +} // namespace blender::gpu
\ No newline at end of file diff --git a/source/blender/gpu/vulkan/vk_texture.cc b/source/blender/gpu/vulkan/vk_texture.cc new file mode 100644 index 00000000000..ea5379e6572 --- /dev/null +++ b/source/blender/gpu/vulkan/vk_texture.cc @@ -0,0 +1,70 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later + * Copyright 2022 Blender Foundation. All rights reserved. */ + +/** \file + * \ingroup gpu + */ + +#include "vk_texture.hh" + +namespace blender::gpu { + +void VKTexture::generate_mipmap() +{ +} + +void VKTexture::copy_to(Texture * /*tex*/) +{ +} + +void VKTexture::clear(eGPUDataFormat /*format*/, const void * /*data*/) +{ +} + +void VKTexture::swizzle_set(const char /*swizzle_mask*/[4]) +{ +} + +void VKTexture::stencil_texture_mode_set(bool /*use_stencil*/) +{ +} + +void VKTexture::mip_range_set(int /*min*/, int /*max*/) +{ +} + +void *VKTexture::read(int /*mip*/, eGPUDataFormat /*format*/) +{ + return nullptr; +} + +void VKTexture::update_sub(int /*mip*/, + int /*offset*/[3], + int /*extent*/[3], + eGPUDataFormat /*format*/, + const void * /*data*/) +{ +} + +/* TODO(fclem): Legacy. Should be removed at some point. */ +uint VKTexture::gl_bindcode_get() const +{ + return 0; +} + +bool VKTexture::init_internal() +{ + return false; +} + +bool VKTexture::init_internal(GPUVertBuf * /*vbo*/) +{ + return false; +} + +bool VKTexture::init_internal(const GPUTexture * /*src*/, int /*mip_offset*/, int /*layer_offset*/) +{ + return false; +} + +} // namespace blender::gpu
\ No newline at end of file diff --git a/source/blender/gpu/vulkan/vk_texture.hh b/source/blender/gpu/vulkan/vk_texture.hh new file mode 100644 index 00000000000..93094b7e540 --- /dev/null +++ b/source/blender/gpu/vulkan/vk_texture.hh @@ -0,0 +1,39 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later + * Copyright 2022 Blender Foundation. All rights reserved. */ + +/** \file + * \ingroup gpu + */ + +#pragma once + +#include "gpu_texture_private.hh" + +namespace blender::gpu { + +class VKTexture : public Texture { + public: + VKTexture(const char *name) : Texture(name) + { + } + + void generate_mipmap() override; + void copy_to(Texture *tex) override; + void clear(eGPUDataFormat format, const void *data) override; + void swizzle_set(const char swizzle_mask[4]) override; + void stencil_texture_mode_set(bool use_stencil) override; + void mip_range_set(int min, int max) override; + void *read(int mip, eGPUDataFormat format) override; + void update_sub( + int mip, int offset[3], int extent[3], eGPUDataFormat format, const void *data) override; + + /* TODO(fclem): Legacy. Should be removed at some point. */ + uint gl_bindcode_get() const override; + + protected: + bool init_internal() override; + bool init_internal(GPUVertBuf *vbo) override; + bool init_internal(const GPUTexture *src, int mip_offset, int layer_offset) override; +}; + +} // namespace blender::gpu
\ No newline at end of file diff --git a/source/blender/gpu/vulkan/vk_uniform_buffer.cc b/source/blender/gpu/vulkan/vk_uniform_buffer.cc new file mode 100644 index 00000000000..8ef5b19273a --- /dev/null +++ b/source/blender/gpu/vulkan/vk_uniform_buffer.cc @@ -0,0 +1,24 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later + * Copyright 2022 Blender Foundation. All rights reserved. */ + +/** \file + * \ingroup gpu + */ + +#include "vk_uniform_buffer.hh" + +namespace blender::gpu { + +void VKUniformBuffer::update(const void * /*data*/) +{ +} + +void VKUniformBuffer::bind(int /*slot*/) +{ +} + +void VKUniformBuffer::unbind() +{ +} + +} // namespace blender::gpu
\ No newline at end of file diff --git a/source/blender/gpu/vulkan/vk_uniform_buffer.hh b/source/blender/gpu/vulkan/vk_uniform_buffer.hh new file mode 100644 index 00000000000..f086a7aa391 --- /dev/null +++ b/source/blender/gpu/vulkan/vk_uniform_buffer.hh @@ -0,0 +1,25 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later + * Copyright 2022 Blender Foundation. All rights reserved. */ + +/** \file + * \ingroup gpu + */ + +#pragma once + +#include "gpu_uniform_buffer_private.hh" + +namespace blender::gpu { + +class VKUniformBuffer : public UniformBuf { + public: + VKUniformBuffer(int size, const char *name) : UniformBuf(size, name) + { + } + + void update(const void *data) override; + void bind(int slot) override; + void unbind() override; +}; + +} // namespace blender::gpu
\ No newline at end of file diff --git a/source/blender/gpu/vulkan/vk_vertex_buffer.cc b/source/blender/gpu/vulkan/vk_vertex_buffer.cc new file mode 100644 index 00000000000..5791e20fb30 --- /dev/null +++ b/source/blender/gpu/vulkan/vk_vertex_buffer.cc @@ -0,0 +1,58 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later + * Copyright 2022 Blender Foundation. All rights reserved. */ + +/** \file + * \ingroup gpu + */ + +#include "vk_vertex_buffer.hh" + +namespace blender::gpu { + +void VKVertexBuffer::bind_as_ssbo(uint /*binding*/) +{ +} + +void VKVertexBuffer::bind_as_texture(uint /*binding*/) +{ +} + +void VKVertexBuffer::wrap_handle(uint64_t /*handle*/) +{ +} + +void VKVertexBuffer::update_sub(uint /*start*/, uint /*len*/, const void * /*data*/) +{ +} + +const void *VKVertexBuffer::read() const +{ + return nullptr; +} + +void *VKVertexBuffer::unmap(const void * /*mapped_data*/) const +{ + return nullptr; +} + +void VKVertexBuffer::acquire_data() +{ +} + +void VKVertexBuffer::resize_data() +{ +} + +void VKVertexBuffer::release_data() +{ +} + +void VKVertexBuffer::upload_data() +{ +} + +void VKVertexBuffer::duplicate_data(VertBuf * /*dst*/) +{ +} + +} // namespace blender::gpu
\ No newline at end of file diff --git a/source/blender/gpu/vulkan/vk_vertex_buffer.hh b/source/blender/gpu/vulkan/vk_vertex_buffer.hh new file mode 100644 index 00000000000..84ccc65bcdf --- /dev/null +++ b/source/blender/gpu/vulkan/vk_vertex_buffer.hh @@ -0,0 +1,32 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later + * Copyright 2022 Blender Foundation. All rights reserved. */ + +/** \file + * \ingroup gpu + */ + +#pragma once + +#include "gpu_vertex_buffer_private.hh" + +namespace blender::gpu { + +class VKVertexBuffer : public VertBuf { + public: + void bind_as_ssbo(uint binding) override; + void bind_as_texture(uint binding) override; + void wrap_handle(uint64_t handle) override; + + void update_sub(uint start, uint len, const void *data) override; + const void *read() const override; + void *unmap(const void *mapped_data) const override; + + protected: + void acquire_data() override; + void resize_data() override; + void release_data() override; + void upload_data() override; + void duplicate_data(VertBuf *dst) override; +}; + +} // namespace blender::gpu
\ No newline at end of file diff --git a/source/blender/ikplugin/intern/iksolver_plugin.c b/source/blender/ikplugin/intern/iksolver_plugin.c index 6d99fde9df6..c467e48d21e 100644 --- a/source/blender/ikplugin/intern/iksolver_plugin.c +++ b/source/blender/ikplugin/intern/iksolver_plugin.c @@ -406,7 +406,7 @@ static void execute_posetree(struct Depsgraph *depsgraph, } copy_v3_v3(rootmat[3], pchan->pose_head); - mul_m4_m4m4(imat, ob->obmat, rootmat); + mul_m4_m4m4(imat, ob->object_to_world, rootmat); invert_m4_m4(goalinv, imat); for (target = tree->targets.first; target; target = target->next) { @@ -465,7 +465,7 @@ static void execute_posetree(struct Depsgraph *depsgraph, /* end effector in world space */ copy_m4_m4(end_pose, pchan->pose_mat); copy_v3_v3(end_pose[3], pchan->pose_tail); - mul_m4_series(world_pose, goalinv, ob->obmat, end_pose); + mul_m4_series(world_pose, goalinv, ob->object_to_world, end_pose); /* blend position */ goalpos[0] = fac * goalpos[0] + mfac * world_pose[3][0]; diff --git a/source/blender/ikplugin/intern/itasc_plugin.cpp b/source/blender/ikplugin/intern/itasc_plugin.cpp index 9317f14b7f1..2878bbb6da7 100644 --- a/source/blender/ikplugin/intern/itasc_plugin.cpp +++ b/source/blender/ikplugin/intern/itasc_plugin.cpp @@ -586,10 +586,10 @@ static bool target_callback(const iTaSC::Timestamp ×tamp, float chanmat[4][4]; copy_m4_m4(chanmat, pchan->pose_mat); copy_v3_v3(chanmat[3], pchan->pose_tail); - mul_m4_series(restmat, target->owner->obmat, chanmat, target->eeRest); + mul_m4_series(restmat, target->owner->object_to_world, chanmat, target->eeRest); } else { - mul_m4_m4m4(restmat, target->owner->obmat, target->eeRest); + mul_m4_m4m4(restmat, target->owner->object_to_world, target->eeRest); } /* blend the target */ blend_m4_m4m4(tarmat, restmat, tarmat, constraint->enforce); @@ -620,10 +620,10 @@ static bool base_callback(const iTaSC::Timestamp ×tamp, ikscene->baseFrame.setValue(&chanmat[0][0]); /* iTaSC armature is scaled to object scale, scale the base frame too */ ikscene->baseFrame.p *= ikscene->blScale; - mul_m4_m4m4(rootmat, ikscene->blArmature->obmat, chanmat); + mul_m4_m4m4(rootmat, ikscene->blArmature->object_to_world, chanmat); } else { - copy_m4_m4(rootmat, ikscene->blArmature->obmat); + copy_m4_m4(rootmat, ikscene->blArmature->object_to_world); ikscene->baseFrame = iTaSC::F_identity; } next.setValue(&rootmat[0][0]); @@ -1065,7 +1065,7 @@ static void convert_pose(IK_Scene *ikscene) int a, joint; /* assume uniform scaling and take Y scale as general scale for the armature */ - scale = len_v3(ikscene->blArmature->obmat[1]); + scale = len_v3(ikscene->blArmature->object_to_world[1]); rot = ikscene->jointArray(0); for (joint = a = 0, ikchan = ikscene->channels; a < ikscene->numchan && joint < ikscene->numjoint; @@ -1105,7 +1105,7 @@ static void BKE_pose_rest(IK_Scene *ikscene) int a, joint; /* assume uniform scaling and take Y scale as general scale for the armature */ - scale = len_v3(ikscene->blArmature->obmat[1]); + scale = len_v3(ikscene->blArmature->object_to_world[1]); /* rest pose is 0 */ SetToZero(ikscene->jointArray); /* except for transY joints */ @@ -1183,7 +1183,7 @@ static IK_Scene *convert_tree( } ikscene->blArmature = ob; /* assume uniform scaling and take Y scale as general scale for the armature */ - ikscene->blScale = len_v3(ob->obmat[1]); + ikscene->blScale = len_v3(ob->object_to_world[1]); ikscene->blInvScale = (ikscene->blScale < KDL::epsilon) ? 0.0f : 1.0f / ikscene->blScale; std::string joint; @@ -1667,7 +1667,7 @@ static void create_scene(struct Depsgraph *depsgraph, Scene *scene, Object *ob, static int init_scene(Object *ob) { /* check also if scaling has changed */ - float scale = len_v3(ob->obmat[1]); + float scale = len_v3(ob->object_to_world[1]); IK_Scene *scene; if (ob->pose->ikdata) { diff --git a/source/blender/imbuf/intern/anim_movie.c b/source/blender/imbuf/intern/anim_movie.c index 71e0d0fe11e..94c0555dcf0 100644 --- a/source/blender/imbuf/intern/anim_movie.c +++ b/source/blender/imbuf/intern/anim_movie.c @@ -1100,7 +1100,12 @@ static int64_t ffmpeg_get_seek_pts(struct anim *anim, int64_t pts_to_search) * experimentally. Note: Too big offset can impact performance. Current 3 frame offset has no * measurable impact. */ - return pts_to_search - (ffmpeg_steps_per_frame_get(anim) * 3); + int64_t seek_pts = pts_to_search - (ffmpeg_steps_per_frame_get(anim) * 3); + + if (seek_pts < 0) { + seek_pts = 0; + } + return seek_pts; } /* This gives us an estimate of which pts our requested frame will have. diff --git a/source/blender/imbuf/intern/colormanagement.c b/source/blender/imbuf/intern/colormanagement.c index ea5f4ec275d..5e132826a4c 100644 --- a/source/blender/imbuf/intern/colormanagement.c +++ b/source/blender/imbuf/intern/colormanagement.c @@ -668,7 +668,7 @@ void colormanagement_init(void) configdir = BKE_appdir_folder_id(BLENDER_DATAFILES, "colormanagement"); if (configdir) { - BLI_join_dirfile(configfile, sizeof(configfile), configdir, BCM_CONFIG_FILE); + BLI_path_join(configfile, sizeof(configfile), configdir, BCM_CONFIG_FILE); #ifdef WIN32 { diff --git a/source/blender/imbuf/intern/indexer.c b/source/blender/imbuf/intern/indexer.c index 735472b6bdf..63836690ee4 100644 --- a/source/blender/imbuf/intern/indexer.c +++ b/source/blender/imbuf/intern/indexer.c @@ -377,9 +377,9 @@ static void get_index_dir(struct anim *anim, char *index_dir, size_t index_dir_l { if (!anim->index_dir[0]) { char filename[FILE_MAXFILE]; - BLI_split_dirfile(anim->name, index_dir, filename, index_dir_len, sizeof(filename)); - BLI_path_append(index_dir, index_dir_len, "BL_proxy"); - BLI_path_append(index_dir, index_dir_len, filename); + char dirname[FILE_MAXDIR]; + BLI_split_dirfile(anim->name, dirname, filename, index_dir_len, sizeof(filename)); + BLI_path_join(index_dir, index_dir_len, dirname, "BL_proxy", filename); } else { BLI_strncpy(index_dir, anim->index_dir, index_dir_len); @@ -426,7 +426,7 @@ static bool get_proxy_filepath(struct anim *anim, return false; } - BLI_join_dirfile(filepath, FILE_MAXFILE + FILE_MAXDIR, index_dir, proxy_name); + BLI_path_join(filepath, FILE_MAXFILE + FILE_MAXDIR, index_dir, proxy_name); return true; } @@ -457,7 +457,7 @@ static void get_tc_filename(struct anim *anim, IMB_Timecode_Type tc, char *filep get_index_dir(anim, index_dir, sizeof(index_dir)); - BLI_join_dirfile(filepath, FILE_MAXFILE + FILE_MAXDIR, index_dir, index_name); + BLI_path_join(filepath, FILE_MAXFILE + FILE_MAXDIR, index_dir, index_name); } /* ---------------------------------------------------------------------- @@ -498,7 +498,9 @@ static struct proxy_output_ctx *alloc_proxy_output_ffmpeg( rv->anim = anim; get_proxy_filepath(rv->anim, rv->proxy_size, filepath, true); - BLI_make_existing_file(filepath); + if (!BLI_make_existing_file(filepath)) { + return NULL; + } rv->of = avformat_alloc_context(); rv->of->oformat = av_guess_format("avi", NULL, NULL); @@ -905,6 +907,14 @@ static IndexBuildContext *index_ffmpeg_create_context(struct anim *anim, } } + if (context->proxy_ctx[0] == NULL && context->proxy_ctx[1] == NULL && + context->proxy_ctx[2] == NULL && context->proxy_ctx[3] == NULL) { + avformat_close_input(&context->iFormatCtx); + avcodec_free_context(&context->iCodecCtx); + MEM_freeN(context); + return NULL; /* Nothing to transcode. */ + } + for (i = 0; i < num_indexers; i++) { if (tcs_in_use & tc_types[i]) { char filepath[FILE_MAX]; diff --git a/source/blender/imbuf/intern/util_gpu.c b/source/blender/imbuf/intern/util_gpu.c index dd509677d8d..35cdefbaaeb 100644 --- a/source/blender/imbuf/intern/util_gpu.c +++ b/source/blender/imbuf/intern/util_gpu.c @@ -174,6 +174,7 @@ static void *imb_gpu_get_data(const ImBuf *ibuf, /* Other colorspace, store as float texture to avoid precision loss. */ data_rect = MEM_mallocN(sizeof(float[4]) * ibuf->x * ibuf->y, __func__); *r_freedata = freedata = true; + is_float_rect = true; if (data_rect == NULL) { return NULL; @@ -300,6 +301,16 @@ GPUTexture *IMB_create_gpu_texture(const char *name, int size[2] = {GPU_texture_size_with_limit(ibuf->x), GPU_texture_size_with_limit(ibuf->y)}; bool do_rescale = (ibuf->x != size[0]) || (ibuf->y != size[1]); + /* Correct the smaller size to maintain the original aspect ratio of the image. */ + if (do_rescale && ibuf->x != ibuf->y) { + if (size[0] > size[1]) { + size[1] = (int)(ibuf->y * ((float)size[0] / ibuf->x)); + } + else { + size[0] = (int)(ibuf->x * ((float)size[1] / ibuf->y)); + } + } + #ifdef WITH_DDS if (ibuf->ftype == IMB_FTYPE_DDS) { eGPUTextureFormat compressed_format; diff --git a/source/blender/imbuf/intern/webp.c b/source/blender/imbuf/intern/webp.c index 27c26fb19c1..3031b8c3e33 100644 --- a/source/blender/imbuf/intern/webp.c +++ b/source/blender/imbuf/intern/webp.c @@ -1,7 +1,7 @@ /* SPDX-License-Identifier: GPL-2.0-or-later */ /** \file - * \ingroup imbuf + * \ingroup imbuf */ #ifdef _WIN32 diff --git a/source/blender/io/alembic/exporter/abc_writer_hair.cc b/source/blender/io/alembic/exporter/abc_writer_hair.cc index f872943ad5c..13136372c56 100644 --- a/source/blender/io/alembic/exporter/abc_writer_hair.cc +++ b/source/blender/io/alembic/exporter/abc_writer_hair.cc @@ -118,7 +118,7 @@ void ABCHairWriter::write_hair_sample(const HierarchyContext &context, { /* Get untransformed vertices, there's a xform under the hair. */ float inv_mat[4][4]; - invert_m4_m4_safe(inv_mat, context.object->obmat); + invert_m4_m4_safe(inv_mat, context.object->object_to_world); MTFace *mtface = (MTFace *)CustomData_get_layer(&mesh->fdata, CD_MTFACE); MFace *mface = (MFace *)CustomData_get_layer(&mesh->fdata, CD_MFACE); @@ -241,7 +241,7 @@ void ABCHairWriter::write_hair_child_sample(const HierarchyContext &context, { /* Get untransformed vertices, there's a xform under the hair. */ float inv_mat[4][4]; - invert_m4_m4_safe(inv_mat, context.object->obmat); + invert_m4_m4_safe(inv_mat, context.object->object_to_world); MFace *mface = (MFace *)CustomData_get_layer(&mesh->fdata, CD_MFACE); MTFace *mtface = (MTFace *)CustomData_get_layer(&mesh->fdata, CD_MTFACE); diff --git a/source/blender/io/alembic/intern/abc_axis_conversion.cc b/source/blender/io/alembic/intern/abc_axis_conversion.cc index 00e5890e9d3..35a19d0fbc0 100644 --- a/source/blender/io/alembic/intern/abc_axis_conversion.cc +++ b/source/blender/io/alembic/intern/abc_axis_conversion.cc @@ -134,15 +134,15 @@ void create_transform_matrix(Object *obj, if (mode == ABC_MATRIX_LOCAL && obj->parent) { /* Note that this produces another matrix than the local matrix, due to * constraints and modifiers as well as the obj->parentinv matrix. */ - invert_m4_m4(obj->parent->imat, obj->parent->obmat); - mul_m4_m4m4(zup_mat, obj->parent->imat, obj->obmat); + invert_m4_m4(obj->parent->imat, obj->parent->object_to_world); + mul_m4_m4m4(zup_mat, obj->parent->imat, obj->object_to_world); } else { - copy_m4_m4(zup_mat, obj->obmat); + copy_m4_m4(zup_mat, obj->object_to_world); } if (proxy_from) { - mul_m4_m4m4(zup_mat, proxy_from->obmat, zup_mat); + mul_m4_m4m4(zup_mat, proxy_from->object_to_world, zup_mat); } copy_m44_axis_swap(r_yup_mat, zup_mat, ABC_YUP_FROM_ZUP); diff --git a/source/blender/io/alembic/intern/abc_reader_mesh.cc b/source/blender/io/alembic/intern/abc_reader_mesh.cc index f08514dc45c..2531bd62609 100644 --- a/source/blender/io/alembic/intern/abc_reader_mesh.cc +++ b/source/blender/io/alembic/intern/abc_reader_mesh.cc @@ -763,7 +763,7 @@ Mesh *AbcMeshReader::read_mesh(Mesh *existing_mesh, std::map<std::string, int> mat_map; bke::MutableAttributeAccessor attributes = new_mesh->attributes_for_write(); bke::SpanAttributeWriter<int> material_indices = - attributes.lookup_or_add_for_write_only_span<int>("material_index", ATTR_DOMAIN_FACE); + attributes.lookup_or_add_for_write_span<int>("material_index", ATTR_DOMAIN_FACE); assign_facesets_to_material_indices(sample_sel, material_indices.span, mat_map); material_indices.finish(); } @@ -823,8 +823,8 @@ void AbcMeshReader::readFaceSetsSample(Main *bmain, Mesh *mesh, const ISampleSel { std::map<std::string, int> mat_map; bke::MutableAttributeAccessor attributes = mesh->attributes_for_write(); - bke::SpanAttributeWriter<int> material_indices = - attributes.lookup_or_add_for_write_only_span<int>("material_index", ATTR_DOMAIN_FACE); + bke::SpanAttributeWriter<int> material_indices = attributes.lookup_or_add_for_write_span<int>( + "material_index", ATTR_DOMAIN_FACE); assign_facesets_to_material_indices(sample_sel, material_indices.span, mat_map); material_indices.finish(); utils::assign_materials(bmain, m_object, mat_map); diff --git a/source/blender/io/alembic/intern/abc_reader_object.cc b/source/blender/io/alembic/intern/abc_reader_object.cc index af26565f8d6..f3a07eaad3f 100644 --- a/source/blender/io/alembic/intern/abc_reader_object.cc +++ b/source/blender/io/alembic/intern/abc_reader_object.cc @@ -165,7 +165,7 @@ void AbcObjectReader::setupObjectTransform(const chrono_t time) /* Apply the matrix to the object. */ BKE_object_apply_mat4(m_object, transform_from_alembic, true, false); - BKE_object_to_mat4(m_object, m_object->obmat); + BKE_object_to_mat4(m_object, m_object->object_to_world); if (!is_constant || m_settings->always_add_cache_reader) { bConstraint *con = BKE_constraint_add_for_object( diff --git a/source/blender/io/collada/AnimationImporter.cpp b/source/blender/io/collada/AnimationImporter.cpp index 2d872377bbf..826d7864067 100644 --- a/source/blender/io/collada/AnimationImporter.cpp +++ b/source/blender/io/collada/AnimationImporter.cpp @@ -332,8 +332,8 @@ void AnimationImporter::read_node_transform(COLLADAFW::Node *node, Object *ob) float mat[4][4]; TransformReader::get_node_mat(mat, node, &uid_animated_map, ob); if (ob) { - copy_m4_m4(ob->obmat, mat); - BKE_object_apply_mat4(ob, ob->obmat, false, false); + copy_m4_m4(ob->object_to_world, mat); + BKE_object_apply_mat4(ob, ob->object_to_world, false, false); } } @@ -2097,7 +2097,7 @@ Object *AnimationImporter::get_joint_object(COLLADAFW::Node *root, if (par_job) { float temp[4][4], ipar[4][4]; - invert_m4_m4(ipar, par_job->obmat); + invert_m4_m4(ipar, par_job->object_to_world); copy_m4_m4(temp, mat); mul_m4_m4m4(mat, ipar, temp); } diff --git a/source/blender/io/collada/ArmatureImporter.cpp b/source/blender/io/collada/ArmatureImporter.cpp index 1310337f501..7de08f89b7d 100644 --- a/source/blender/io/collada/ArmatureImporter.cpp +++ b/source/blender/io/collada/ArmatureImporter.cpp @@ -114,7 +114,7 @@ int ArmatureImporter::create_bone(SkinInfo *skin, Object *ob_arm = skin->BKE_armature_from_object(); if (ob_arm) { float invmat[4][4]; - invert_m4_m4(invmat, ob_arm->obmat); + invert_m4_m4(invmat, ob_arm->object_to_world); mul_m4_m4m4(mat, invmat, mat); } @@ -708,7 +708,7 @@ void ArmatureImporter::set_pose(Object *ob_arm, copy_m4_m4(mat, obmat); float invObmat[4][4]; - invert_m4_m4(invObmat, ob_arm->obmat); + invert_m4_m4(invObmat, ob_arm->object_to_world); mul_m4_m4m4(pchan->pose_mat, invObmat, mat); } diff --git a/source/blender/io/collada/ControllerExporter.cpp b/source/blender/io/collada/ControllerExporter.cpp index 6bf8d904a41..62bcdc5bf4c 100644 --- a/source/blender/io/collada/ControllerExporter.cpp +++ b/source/blender/io/collada/ControllerExporter.cpp @@ -406,7 +406,7 @@ void ControllerExporter::add_bind_shape_mat(Object *ob) bc_add_global_transform(f_obmat, export_settings.get_global_transform()); } - // UnitConverter::mat4_to_dae_double(bind_mat, ob->obmat); + // UnitConverter::mat4_to_dae_double(bind_mat, ob->object_to_world); UnitConverter::mat4_to_dae_double(bind_mat, f_obmat); if (this->export_settings.get_limit_precision()) { BCMatrix::sanitize(bind_mat, LIMITTED_PRECISION); @@ -523,7 +523,7 @@ std::string ControllerExporter::add_inv_bind_mats_source(Object *ob_arm, } /* make world-space matrix (bind_mat is armature-space) */ - mul_m4_m4m4(world, ob_arm->obmat, bind_mat); + mul_m4_m4m4(world, ob_arm->object_to_world, bind_mat); if (!has_bindmat) { if (export_settings.get_apply_global_orientation()) { diff --git a/source/blender/io/collada/DocumentExporter.cpp b/source/blender/io/collada/DocumentExporter.cpp index 56adbca13bd..07392e9c4ce 100644 --- a/source/blender/io/collada/DocumentExporter.cpp +++ b/source/blender/io/collada/DocumentExporter.cpp @@ -145,7 +145,7 @@ static COLLADABU::NativeString make_temp_filepath(const char *name, const char * name = "untitled"; } - BLI_join_dirfile(tempfile, sizeof(tempfile), BKE_tempdir_session(), name); + BLI_path_join(tempfile, sizeof(tempfile), BKE_tempdir_session(), name); if (extension) { BLI_path_extension_ensure(tempfile, FILE_MAX, extension); diff --git a/source/blender/io/collada/DocumentImporter.cpp b/source/blender/io/collada/DocumentImporter.cpp index 660bbd7edb2..dae1c4ba894 100644 --- a/source/blender/io/collada/DocumentImporter.cpp +++ b/source/blender/io/collada/DocumentImporter.cpp @@ -412,8 +412,8 @@ Object *DocumentImporter::create_instance_node(Object *source_ob, } } /* calc new matrix and apply */ - mul_m4_m4m4(obn->obmat, obn->obmat, mat); - BKE_object_apply_mat4(obn, obn->obmat, false, false); + mul_m4_m4m4(obn->object_to_world, obn->object_to_world, mat); + BKE_object_apply_mat4(obn, obn->object_to_world, false, false); } } else { @@ -937,7 +937,7 @@ bool DocumentImporter::writeImage(const COLLADAFW::Image *image) const char *workpath; BLI_split_dir_part(this->import_settings->filepath, dir, sizeof(dir)); - BLI_join_dirfile(absolute_path, sizeof(absolute_path), dir, imagepath.c_str()); + BLI_path_join(absolute_path, sizeof(absolute_path), dir, imagepath.c_str()); if (BLI_exists(absolute_path)) { workpath = absolute_path; } diff --git a/source/blender/io/collada/ImageExporter.cpp b/source/blender/io/collada/ImageExporter.cpp index 1223abbaf95..070eb36de31 100644 --- a/source/blender/io/collada/ImageExporter.cpp +++ b/source/blender/io/collada/ImageExporter.cpp @@ -70,7 +70,7 @@ void ImagesExporter::export_UV_Image(Image *image, bool use_copies) BLI_strncpy(export_file, name.c_str(), sizeof(export_file)); BKE_image_path_ensure_ext_from_imformat(export_file, &imageFormat); - BLI_join_dirfile(export_path, sizeof(export_path), export_dir, export_file); + BLI_path_join(export_path, sizeof(export_path), export_dir, export_file); /* make dest directory if it doesn't exist */ BLI_make_existing_file(export_path); diff --git a/source/blender/io/collada/SkinInfo.cpp b/source/blender/io/collada/SkinInfo.cpp index 0654bae3730..b4615635318 100644 --- a/source/blender/io/collada/SkinInfo.cpp +++ b/source/blender/io/collada/SkinInfo.cpp @@ -214,12 +214,12 @@ void SkinInfo::link_armature(bContext *C, ob->partype = PAROBJECT; BKE_object_workob_calc_parent(scene, ob, &workob); - invert_m4_m4(ob->parentinv, workob.obmat); + invert_m4_m4(ob->parentinv, workob.object_to_world); DEG_id_tag_update(&obn->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY); #endif - copy_m4_m4(ob->obmat, bind_shape_matrix); - BKE_object_apply_mat4(ob, ob->obmat, false, false); + copy_m4_m4(ob->object_to_world, bind_shape_matrix); + BKE_object_apply_mat4(ob, ob->object_to_world, false, false); amd->deformflag = ARM_DEF_VGROUP; diff --git a/source/blender/io/collada/collada_utils.cpp b/source/blender/io/collada/collada_utils.cpp index 22a73cd7db2..96ff78a715a 100644 --- a/source/blender/io/collada/collada_utils.cpp +++ b/source/blender/io/collada/collada_utils.cpp @@ -129,7 +129,7 @@ bool bc_set_parent(Object *ob, Object *par, bContext *C, bool is_parent_space) const bool keep_transform = false; if (par && is_parent_space) { - mul_m4_m4m4(ob->obmat, par->obmat, ob->obmat); + mul_m4_m4m4(ob->object_to_world, par->object_to_world, ob->object_to_world); } bool ok = ED_object_parent_set( @@ -348,10 +348,10 @@ std::string bc_replace_string(std::string data, void bc_match_scale(Object *ob, UnitConverter &bc_unit, bool scale_to_scene) { if (scale_to_scene) { - mul_m4_m4m4(ob->obmat, bc_unit.get_scale(), ob->obmat); + mul_m4_m4m4(ob->object_to_world, bc_unit.get_scale(), ob->object_to_world); } - mul_m4_m4m4(ob->obmat, bc_unit.get_rotation(), ob->obmat); - BKE_object_apply_mat4(ob, ob->obmat, false, false); + mul_m4_m4m4(ob->object_to_world, bc_unit.get_rotation(), ob->object_to_world); + BKE_object_apply_mat4(ob, ob->object_to_world, false, false); } void bc_match_scale(std::vector<Object *> *objects_done, diff --git a/source/blender/io/common/intern/abstract_hierarchy_iterator.cc b/source/blender/io/common/intern/abstract_hierarchy_iterator.cc index 03c1ba94d94..d559b0efe82 100644 --- a/source/blender/io/common/intern/abstract_hierarchy_iterator.cc +++ b/source/blender/io/common/intern/abstract_hierarchy_iterator.cc @@ -416,7 +416,7 @@ void AbstractHierarchyIterator::visit_object(Object *object, context->original_export_path = ""; context->higher_up_export_path = ""; - copy_m4_m4(context->matrix_world, object->obmat); + copy_m4_m4(context->matrix_world, object->object_to_world); ExportGraph::key_type graph_index = determine_graph_index_object(context); context_update_for_graph_index(context, graph_index); diff --git a/source/blender/io/common/intern/path_util.cc b/source/blender/io/common/intern/path_util.cc index 18632b410f8..63ff6cf29ee 100644 --- a/source/blender/io/common/intern/path_util.cc +++ b/source/blender/io/common/intern/path_util.cc @@ -28,8 +28,7 @@ std::string path_reference(StringRefNull filepath, } else if (mode == PATH_REFERENCE_COPY) { char filepath_cpy[PATH_MAX]; - BLI_path_join( - filepath_cpy, PATH_MAX, base_dst.c_str(), BLI_path_basename(filepath_abs), nullptr); + BLI_path_join(filepath_cpy, PATH_MAX, base_dst.c_str(), BLI_path_basename(filepath_abs)); copy_set->add(std::make_pair(filepath_abs, filepath_cpy)); BLI_strncpy(filepath_abs, filepath_cpy, PATH_MAX); mode = PATH_REFERENCE_RELATIVE; diff --git a/source/blender/io/gpencil/intern/gpencil_io_base.cc b/source/blender/io/gpencil/intern/gpencil_io_base.cc index b9d7b6719b1..6cc977bfced 100644 --- a/source/blender/io/gpencil/intern/gpencil_io_base.cc +++ b/source/blender/io/gpencil/intern/gpencil_io_base.cc @@ -79,7 +79,7 @@ void GpencilIO::prepare_camera_params(Scene *scene, const GpencilIOParams *ipara BKE_camera_params_compute_matrix(¶ms); float viewmat[4][4]; - invert_m4_m4(viewmat, cam_ob->obmat); + invert_m4_m4(viewmat, cam_ob->object_to_world); mul_m4_m4m4(persmat_, params.winmat, viewmat); } @@ -152,7 +152,7 @@ void GpencilIO::create_object_list() /* Save z-depth from view to sort from back to front. */ if (is_camera_) { - float camera_z = dot_v3v3(camera_z_axis, object->obmat[3]); + float camera_z = dot_v3v3(camera_z_axis, object->object_to_world[3]); ObjectZ obz = {camera_z, object}; ob_list_.append(obz); } @@ -160,10 +160,10 @@ void GpencilIO::create_object_list() float zdepth = 0; if (rv3d_) { if (rv3d_->is_persp) { - zdepth = ED_view3d_calc_zfac(rv3d_, object->obmat[3]); + zdepth = ED_view3d_calc_zfac(rv3d_, object->object_to_world[3]); } else { - zdepth = -dot_v3v3(rv3d_->viewinv[2], object->obmat[3]); + zdepth = -dot_v3v3(rv3d_->viewinv[2], object->object_to_world[3]); } ObjectZ obz = {zdepth * -1.0f, object}; ob_list_.append(obz); diff --git a/source/blender/io/gpencil/intern/gpencil_io_export_pdf.cc b/source/blender/io/gpencil/intern/gpencil_io_export_pdf.cc index ddd72f816b0..c042ca597c8 100644 --- a/source/blender/io/gpencil/intern/gpencil_io_export_pdf.cc +++ b/source/blender/io/gpencil/intern/gpencil_io_export_pdf.cc @@ -177,7 +177,7 @@ void GpencilExporterPDF::export_gpencil_layers() /* Apply layer thickness change. */ gps_duplicate->thickness += gpl->line_change; /* Apply object scale to thickness. */ - gps_duplicate->thickness *= mat4_to_scale(ob->obmat); + gps_duplicate->thickness *= mat4_to_scale(ob->object_to_world); CLAMP_MIN(gps_duplicate->thickness, 1.0f); /* Fill. */ if ((is_fill) && (params_.flag & GP_EXPORT_FILL)) { diff --git a/source/blender/io/gpencil/intern/gpencil_io_export_svg.cc b/source/blender/io/gpencil/intern/gpencil_io_export_svg.cc index 58f12e9b8b1..8acb87f8e58 100644 --- a/source/blender/io/gpencil/intern/gpencil_io_export_svg.cc +++ b/source/blender/io/gpencil/intern/gpencil_io_export_svg.cc @@ -197,7 +197,7 @@ void GpencilExporterSVG::export_gpencil_layers() /* Apply layer thickness change. */ gps_duplicate->thickness += gpl->line_change; /* Apply object scale to thickness. */ - gps_duplicate->thickness *= mat4_to_scale(ob->obmat); + gps_duplicate->thickness *= mat4_to_scale(ob->object_to_world); CLAMP_MIN(gps_duplicate->thickness, 1.0f); const bool is_normalized = ((params_.flag & GP_EXPORT_NORM_THICKNESS) != 0) || diff --git a/source/blender/io/stl/CMakeLists.txt b/source/blender/io/stl/CMakeLists.txt index 3a21da5c579..f7eb933d198 100644 --- a/source/blender/io/stl/CMakeLists.txt +++ b/source/blender/io/stl/CMakeLists.txt @@ -2,7 +2,7 @@ set(INC . - ./importer + importer ../common ../../blenkernel ../../blenlib diff --git a/source/blender/io/usd/intern/usd_reader_mesh.cc b/source/blender/io/usd/intern/usd_reader_mesh.cc index 77c79852141..8138f38fcad 100644 --- a/source/blender/io/usd/intern/usd_reader_mesh.cc +++ b/source/blender/io/usd/intern/usd_reader_mesh.cc @@ -33,6 +33,7 @@ #include <pxr/base/vt/value.h> #include <pxr/usd/sdf/types.h> #include <pxr/usd/usdGeom/mesh.h> +#include <pxr/usd/usdGeom/primvarsAPI.h> #include <pxr/usd/usdGeom/subset.h> #include <pxr/usd/usdShade/materialBindingAPI.h> @@ -287,11 +288,13 @@ bool USDMeshReader::topology_changed(const Mesh *existing_mesh, const double mot mesh_prim_.GetFaceVertexCountsAttr().Get(&face_counts_, motionSampleTime); mesh_prim_.GetPointsAttr().Get(&positions_, motionSampleTime); + pxr::UsdGeomPrimvarsAPI primvarsAPI(mesh_prim_); + /* TODO(makowalski): Reading normals probably doesn't belong in this function, * as this is not required to determine if the topology has changed. */ /* If 'normals' and 'primvars:normals' are both specified, the latter has precedence. */ - pxr::UsdGeomPrimvar primvar = mesh_prim_.GetPrimvar(usdtokens::normalsPrimvar); + pxr::UsdGeomPrimvar primvar = primvarsAPI.GetPrimvar(usdtokens::normalsPrimvar); if (primvar.HasValue()) { primvar.ComputeFlattened(&normals_, motionSampleTime); normal_interpolation_ = primvar.GetInterpolation(); @@ -355,6 +358,8 @@ void USDMeshReader::read_uvs(Mesh *mesh, const double motionSampleTime, const bo std::vector<UVSample> uv_primvars(ldata->totlayer); + pxr::UsdGeomPrimvarsAPI primvarsAPI(mesh_prim_); + if (has_uvs_) { for (int layer_idx = 0; layer_idx < ldata->totlayer; layer_idx++) { const CustomDataLayer *layer = &ldata->layers[layer_idx]; @@ -385,11 +390,11 @@ void USDMeshReader::read_uvs(Mesh *mesh, const double motionSampleTime, const bo } /* Early out if mesh doesn't have primvar. */ - if (!mesh_prim_.HasPrimvar(uv_token)) { + if (!primvarsAPI.HasPrimvar(uv_token)) { continue; } - if (pxr::UsdGeomPrimvar uv_primvar = mesh_prim_.GetPrimvar(uv_token)) { + if (pxr::UsdGeomPrimvar uv_primvar = primvarsAPI.GetPrimvar(uv_token)) { uv_primvar.ComputeFlattened(&uv_primvars[layer_idx].uvs, motionSampleTime); uv_primvars[layer_idx].interpolation = uv_primvar.GetInterpolation(); } @@ -804,8 +809,8 @@ void USDMeshReader::readFaceSetsSample(Main *bmain, Mesh *mesh, const double mot std::map<pxr::SdfPath, int> mat_map; bke::MutableAttributeAccessor attributes = mesh->attributes_for_write(); - bke::SpanAttributeWriter<int> material_indices = - attributes.lookup_or_add_for_write_only_span<int>("material_index", ATTR_DOMAIN_FACE); + bke::SpanAttributeWriter<int> material_indices = attributes.lookup_or_add_for_write_span<int>( + "material_index", ATTR_DOMAIN_FACE); this->assign_facesets_to_material_indices(motionSampleTime, material_indices.span, &mat_map); material_indices.finish(); /* Build material name map if it's not built yet. */ @@ -835,12 +840,14 @@ Mesh *USDMeshReader::read_mesh(Mesh *existing_mesh, is_left_handed_ = true; } + pxr::UsdGeomPrimvarsAPI primvarsAPI(mesh_prim_); + std::vector<pxr::TfToken> uv_tokens; /* Currently we only handle UV primvars. */ if (read_flag & MOD_MESHSEQ_READ_UV) { - std::vector<pxr::UsdGeomPrimvar> primvars = mesh_prim_.GetPrimvars(); + std::vector<pxr::UsdGeomPrimvar> primvars = primvarsAPI.GetPrimvars(); for (pxr::UsdGeomPrimvar p : primvars) { @@ -914,7 +921,7 @@ Mesh *USDMeshReader::read_mesh(Mesh *existing_mesh, std::map<pxr::SdfPath, int> mat_map; bke::MutableAttributeAccessor attributes = active_mesh->attributes_for_write(); bke::SpanAttributeWriter<int> material_indices = - attributes.lookup_or_add_for_write_only_span<int>("material_index", ATTR_DOMAIN_FACE); + attributes.lookup_or_add_for_write_span<int>("material_index", ATTR_DOMAIN_FACE); assign_facesets_to_material_indices(motionSampleTime, material_indices.span, &mat_map); material_indices.finish(); } diff --git a/source/blender/io/usd/intern/usd_writer_material.cc b/source/blender/io/usd/intern/usd_writer_material.cc index c195bf0e0bd..75abae79519 100644 --- a/source/blender/io/usd/intern/usd_writer_material.cc +++ b/source/blender/io/usd/intern/usd_writer_material.cc @@ -380,7 +380,7 @@ static void export_in_memory_texture(Image *ima, BKE_image_path_ensure_ext_from_imformat(file_name, &imageFormat); char export_path[FILE_MAX]; - BLI_path_join(export_path, FILE_MAX, export_dir.c_str(), file_name, nullptr); + BLI_path_join(export_path, FILE_MAX, export_dir.c_str(), file_name); if (!allow_overwrite && BLI_exists(export_path)) { return; @@ -576,7 +576,7 @@ static std::string get_tex_image_asset_path(bNode *node, BLI_split_file_part(path.c_str(), file_path, FILE_MAX); if (export_params.relative_paths) { - BLI_path_join(exp_path, FILE_MAX, ".", "textures", file_path, nullptr); + BLI_path_join(exp_path, FILE_MAX, ".", "textures", file_path); } else { /* Create absolute path in the textures directory. */ @@ -588,7 +588,7 @@ static std::string get_tex_image_asset_path(bNode *node, char dir_path[FILE_MAX]; BLI_split_dir_part(stage_path.c_str(), dir_path, FILE_MAX); - BLI_path_join(exp_path, FILE_MAX, dir_path, "textures", file_path, nullptr); + BLI_path_join(exp_path, FILE_MAX, dir_path, "textures", file_path); } BLI_str_replace_char(exp_path, '\\', '/'); return exp_path; @@ -645,7 +645,7 @@ static void copy_tiled_textures(Image *ima, BLI_split_file_part(src_tile_path, dest_filename, sizeof(dest_filename)); char dest_tile_path[FILE_MAX]; - BLI_path_join(dest_tile_path, FILE_MAX, dest_dir.c_str(), dest_filename, nullptr); + BLI_path_join(dest_tile_path, FILE_MAX, dest_dir.c_str(), dest_filename); if (!allow_overwrite && BLI_exists(dest_tile_path)) { continue; @@ -680,7 +680,7 @@ static void copy_single_file(Image *ima, const std::string &dest_dir, const bool BLI_split_file_part(source_path, file_name, FILE_MAX); char dest_path[FILE_MAX]; - BLI_path_join(dest_path, FILE_MAX, dest_dir.c_str(), file_name, nullptr); + BLI_path_join(dest_path, FILE_MAX, dest_dir.c_str(), file_name); if (!allow_overwrite && BLI_exists(dest_path)) { return; @@ -726,7 +726,7 @@ static void export_texture(bNode *node, BLI_split_dir_part(stage_path.c_str(), usd_dir_path, FILE_MAX); char tex_dir_path[FILE_MAX]; - BLI_path_join(tex_dir_path, FILE_MAX, usd_dir_path, "textures", SEP_STR, nullptr); + BLI_path_join(tex_dir_path, FILE_MAX, usd_dir_path, "textures", SEP_STR); BLI_dir_create_recursive(tex_dir_path); diff --git a/source/blender/io/usd/intern/usd_writer_mesh.cc b/source/blender/io/usd/intern/usd_writer_mesh.cc index e949bafe517..e7d79e888e4 100644 --- a/source/blender/io/usd/intern/usd_writer_mesh.cc +++ b/source/blender/io/usd/intern/usd_writer_mesh.cc @@ -4,6 +4,7 @@ #include "usd_hierarchy_iterator.h" #include <pxr/usd/usdGeom/mesh.h> +#include <pxr/usd/usdGeom/primvarsAPI.h> #include <pxr/usd/usdShade/material.h> #include <pxr/usd/usdShade/materialBindingAPI.h> @@ -107,6 +108,8 @@ void USDGenericMeshWriter::write_uv_maps(const Mesh *mesh, pxr::UsdGeomMesh usd_ { pxr::UsdTimeCode timecode = get_export_time_code(); + pxr::UsdGeomPrimvarsAPI primvarsAPI(usd_mesh.GetPrim()); + const CustomData *ldata = &mesh->ldata; for (int layer_idx = 0; layer_idx < ldata->totlayer; layer_idx++) { const CustomDataLayer *layer = &ldata->layers[layer_idx]; @@ -119,7 +122,7 @@ void USDGenericMeshWriter::write_uv_maps(const Mesh *mesh, pxr::UsdGeomMesh usd_ * for texture coordinates by naming the UV Map as such, without having to guess which UV Map * is the "standard" one. */ pxr::TfToken primvar_name(pxr::TfMakeValidIdentifier(layer->name)); - pxr::UsdGeomPrimvar uv_coords_primvar = usd_mesh.CreatePrimvar( + pxr::UsdGeomPrimvar uv_coords_primvar = primvarsAPI.CreatePrimvar( primvar_name, pxr::SdfValueTypeNames->TexCoord2fArray, pxr::UsdGeomTokens->faceVarying); MLoopUV *mloopuv = static_cast<MLoopUV *>(layer->data); diff --git a/source/blender/io/usd/intern/usd_writer_volume.cc b/source/blender/io/usd/intern/usd_writer_volume.cc index 8cc3c65ee70..c6a27c5f663 100644 --- a/source/blender/io/usd/intern/usd_writer_volume.cc +++ b/source/blender/io/usd/intern/usd_writer_volume.cc @@ -152,7 +152,7 @@ std::optional<std::string> USDVolumeWriter::construct_vdb_file_path(const Volume strcat(vdb_file_name, ".vdb"); char vdb_file_path[FILE_MAX]; - BLI_path_join(vdb_file_path, sizeof(vdb_file_path), vdb_directory_path, vdb_file_name, nullptr); + BLI_path_join(vdb_file_path, sizeof(vdb_file_path), vdb_directory_path, vdb_file_name); return vdb_file_path; } diff --git a/source/blender/io/usd/tests/usd_imaging_test.cc b/source/blender/io/usd/tests/usd_imaging_test.cc index 5cd3c042e59..80c232ad099 100644 --- a/source/blender/io/usd/tests/usd_imaging_test.cc +++ b/source/blender/io/usd/tests/usd_imaging_test.cc @@ -42,8 +42,8 @@ TEST_F(USDImagingTest, CapsuleAdapterTest) } pxr::UsdImagingCapsuleAdapter capsule_adapter; - pxr::VtValue points_value = pxr::UsdImagingCapsuleAdapter::GetMeshPoints( - capsule.GetPrim(), pxr::UsdTimeCode::Default()); + pxr::VtValue points_value = capsule_adapter.GetPoints(capsule.GetPrim(), + pxr::UsdTimeCode::Default()); if (!points_value.IsHolding<pxr::VtArray<pxr::GfVec3f>>()) { FAIL() << "Mesh points value holding unexpected type."; return; @@ -52,7 +52,8 @@ TEST_F(USDImagingTest, CapsuleAdapterTest) pxr::VtArray<pxr::GfVec3f> points = points_value.Get<pxr::VtArray<pxr::GfVec3f>>(); EXPECT_FALSE(points.empty()); - pxr::VtValue topology_value = pxr::UsdImagingCapsuleAdapter::GetMeshTopology(); + pxr::VtValue topology_value = capsule_adapter.GetTopology( + capsule.GetPrim(), pxr::SdfPath(), pxr::UsdTimeCode::Default()); if (!topology_value.IsHolding<pxr::HdMeshTopology>()) { FAIL() << "Mesh topology value holding unexpected type."; diff --git a/source/blender/io/usd/tests/usd_tests_common.cc b/source/blender/io/usd/tests/usd_tests_common.cc index 9f18a289433..ea4e704006d 100644 --- a/source/blender/io/usd/tests/usd_tests_common.cc +++ b/source/blender/io/usd/tests/usd_tests_common.cc @@ -29,7 +29,7 @@ std::string register_usd_plugins_for_tests() } const size_t path_len = BLI_path_join( - usd_datafiles_dir, FILE_MAX, release_dir.c_str(), "datafiles", "usd", nullptr); + usd_datafiles_dir, FILE_MAX, release_dir.c_str(), "datafiles", "usd"); /* #BLI_path_join removes trailing slashes, but the USD library requires one in order to * recognize the path as directory. */ diff --git a/source/blender/io/wavefront_obj/CMakeLists.txt b/source/blender/io/wavefront_obj/CMakeLists.txt index f7958ef4ec6..bfbc715a45f 100644 --- a/source/blender/io/wavefront_obj/CMakeLists.txt +++ b/source/blender/io/wavefront_obj/CMakeLists.txt @@ -2,8 +2,8 @@ set(INC . - ./exporter - ./importer + exporter + importer ../common ../../blenkernel ../../blenlib diff --git a/source/blender/io/wavefront_obj/exporter/obj_export_mesh.cc b/source/blender/io/wavefront_obj/exporter/obj_export_mesh.cc index d00c09b9013..f5a94b1fc8a 100644 --- a/source/blender/io/wavefront_obj/exporter/obj_export_mesh.cc +++ b/source/blender/io/wavefront_obj/exporter/obj_export_mesh.cc @@ -124,10 +124,11 @@ void OBJMesh::set_world_axes_transform(const eIOAxis forward, const eIOAxis up) unit_m3(axes_transform); /* +Y-forward and +Z-up are the default Blender axis settings. */ mat3_from_axis_conversion(forward, up, IO_AXIS_Y, IO_AXIS_Z, axes_transform); - mul_m4_m3m4(world_and_axes_transform_, axes_transform, export_object_eval_.obmat); + mul_m4_m3m4(world_and_axes_transform_, axes_transform, export_object_eval_.object_to_world); /* mul_m4_m3m4 does not transform last row of obmat, i.e. location data. */ - mul_v3_m3v3(world_and_axes_transform_[3], axes_transform, export_object_eval_.obmat[3]); - world_and_axes_transform_[3][3] = export_object_eval_.obmat[3][3]; + mul_v3_m3v3( + world_and_axes_transform_[3], axes_transform, export_object_eval_.object_to_world[3]); + world_and_axes_transform_[3][3] = export_object_eval_.object_to_world[3][3]; /* Normals need inverse transpose of the regular matrix to handle non-uniform scale. */ float normal_matrix[3][3]; diff --git a/source/blender/io/wavefront_obj/exporter/obj_export_nurbs.cc b/source/blender/io/wavefront_obj/exporter/obj_export_nurbs.cc index 812c3e7b5d4..1b1ee5f8386 100644 --- a/source/blender/io/wavefront_obj/exporter/obj_export_nurbs.cc +++ b/source/blender/io/wavefront_obj/exporter/obj_export_nurbs.cc @@ -31,10 +31,10 @@ void OBJCurve::set_world_axes_transform(const eIOAxis forward, const eIOAxis up) unit_m3(axes_transform); /* +Y-forward and +Z-up are the Blender's default axis settings. */ mat3_from_axis_conversion(forward, up, IO_AXIS_Y, IO_AXIS_Z, axes_transform); - mul_m4_m3m4(world_axes_transform_, axes_transform, export_object_eval_->obmat); - /* #mul_m4_m3m4 does not transform last row of #Object.obmat, i.e. location data. */ - mul_v3_m3v3(world_axes_transform_[3], axes_transform, export_object_eval_->obmat[3]); - world_axes_transform_[3][3] = export_object_eval_->obmat[3][3]; + mul_m4_m3m4(world_axes_transform_, axes_transform, export_object_eval_->object_to_world); + /* #mul_m4_m3m4 does not transform last row of #Object.object_to_world, i.e. location data. */ + mul_v3_m3v3(world_axes_transform_[3], axes_transform, export_object_eval_->object_to_world[3]); + world_axes_transform_[3][3] = export_object_eval_->object_to_world[3][3]; } const char *OBJCurve::get_curve_name() const diff --git a/source/blender/io/wavefront_obj/importer/obj_import_file_reader.cc b/source/blender/io/wavefront_obj/importer/obj_import_file_reader.cc index 0781028c880..7d5f023af4b 100644 --- a/source/blender/io/wavefront_obj/importer/obj_import_file_reader.cc +++ b/source/blender/io/wavefront_obj/importer/obj_import_file_reader.cc @@ -765,7 +765,7 @@ MTLParser::MTLParser(StringRefNull mtl_library, StringRefNull obj_filepath) { char obj_file_dir[FILE_MAXDIR]; BLI_split_dir_part(obj_filepath.data(), obj_file_dir, FILE_MAXDIR); - BLI_path_join(mtl_file_path_, FILE_MAX, obj_file_dir, mtl_library.data(), nullptr); + BLI_path_join(mtl_file_path_, FILE_MAX, obj_file_dir, mtl_library.data()); BLI_split_dir_part(mtl_file_path_, mtl_dir_path_, FILE_MAXDIR); } diff --git a/source/blender/makesdna/DNA_brush_defaults.h b/source/blender/makesdna/DNA_brush_defaults.h index 348e8f4e098..6e88275672a 100644 --- a/source/blender/makesdna/DNA_brush_defaults.h +++ b/source/blender/makesdna/DNA_brush_defaults.h @@ -92,7 +92,7 @@ .hardness = 0.0f, \ .automasking_boundary_edges_propagation_steps = 1, \ .automasking_cavity_blur_steps = 0,\ - .automasking_cavity_factor = 0.5f,\ + .automasking_cavity_factor = 1.0f,\ \ /* A kernel radius of 1 has almost no effect (T63233). */ \ .blur_kernel_radius = 2, \ diff --git a/source/blender/makesdna/DNA_customdata_types.h b/source/blender/makesdna/DNA_customdata_types.h index 287a9e2f3b9..0355ed3febe 100644 --- a/source/blender/makesdna/DNA_customdata_types.h +++ b/source/blender/makesdna/DNA_customdata_types.h @@ -116,7 +116,7 @@ typedef enum eCustomDataType { CD_PROP_BYTE_COLOR = 17, CD_TANGENT = 18, CD_MDISPS = 19, - CD_PREVIEW_MCOL = 20, /* for displaying weightpaint colors */ + CD_PREVIEW_MCOL = 20, /* For displaying weight-paint colors. */ /* CD_ID_MCOL = 21, */ /* CD_TEXTURE_MLOOPCOL = 22, */ /* UNUSED */ CD_CLOTH_ORCO = 23, @@ -209,7 +209,7 @@ typedef enum eCustomDataType { #define CD_MASK_HAIRLENGTH (1ULL << CD_HAIRLENGTH) -/** Multires loop data. */ +/** Multi-resolution loop data. */ #define CD_MASK_MULTIRES_GRIDS (CD_MASK_MDISPS | CD_GRID_PAINT_MASK) /* All data layers. */ diff --git a/source/blender/makesdna/DNA_gpencil_types.h b/source/blender/makesdna/DNA_gpencil_types.h index 26dbb544f52..8b3f4956cfe 100644 --- a/source/blender/makesdna/DNA_gpencil_types.h +++ b/source/blender/makesdna/DNA_gpencil_types.h @@ -243,12 +243,15 @@ typedef struct bGPDstroke_Runtime { /** Runtime falloff factor (only for transform). */ float multi_frame_falloff; - /** Vertex offset in the VBO where this stroke starts. */ + /** Triangle offset in the IBO where this stroke starts. */ int stroke_start; /** Triangle offset in the IBO where this fill starts. */ int fill_start; + /** Vertex offset in the VBO where this stroke starts. */ + int vertex_start; /** Curve Handles offset in the IBO where this handle starts. */ int curve_start; + int _pad0; /** Original stroke (used to dereference evaluated data) */ struct bGPDstroke *gps_orig; @@ -613,8 +616,9 @@ typedef struct bGPdata_Runtime { /** Stroke buffer. */ void *sbuffer; /** Temp batches cleared after drawing. */ - struct GPUBatch *sbuffer_stroke_batch; - struct GPUBatch *sbuffer_fill_batch; + struct GPUVertBuf *sbuffer_position_buf; + struct GPUVertBuf *sbuffer_color_buf; + struct GPUBatch *sbuffer_batch; /** Temp stroke used for drawing. */ struct bGPDstroke *sbuffer_gps; diff --git a/source/blender/makesdna/DNA_layer_types.h b/source/blender/makesdna/DNA_layer_types.h index 827e07725a1..6ea35dfb770 100644 --- a/source/blender/makesdna/DNA_layer_types.h +++ b/source/blender/makesdna/DNA_layer_types.h @@ -134,13 +134,13 @@ typedef struct ViewLayerAOV { typedef struct ViewLayerLightgroup { struct ViewLayerLightgroup *next, *prev; - /* Name of the Lightgroup */ + /* Name of the Light-group. */ char name[64]; } ViewLayerLightgroup; -/* Lightgroup membership information. */ +/* Light-group membership information. */ typedef struct LightgroupMembership { - /* Name of the Lightgroup */ + /* Name of the Light-group. */ char name[64]; } LightgroupMembership; diff --git a/source/blender/makesdna/DNA_meta_types.h b/source/blender/makesdna/DNA_meta_types.h index d0c09a0d6ab..b4a66a46efe 100644 --- a/source/blender/makesdna/DNA_meta_types.h +++ b/source/blender/makesdna/DNA_meta_types.h @@ -42,7 +42,7 @@ typedef struct MetaElem { float rad2; /** Stiffness, how much of the element to fill. */ float s; - /** Old, only used for backwards compat. use dimensions now. */ + /** Old, only used for backwards compatibility. use dimensions now. */ float len; /** Matrix and inverted matrix. */ @@ -63,7 +63,7 @@ typedef struct MetaBall { /* material of the mother ball will define the material used of all others */ struct Material **mat; - /** Flag is enum for updates, flag2 is bitflags for settings. */ + /** Flag is enum for updates, flag2 is bit-flags for settings. */ char flag, flag2; short totcol; /** Used to store MB_AUTOSPACE. */ diff --git a/source/blender/makesdna/DNA_modifier_types.h b/source/blender/makesdna/DNA_modifier_types.h index 7625f04fefa..c4180071352 100644 --- a/source/blender/makesdna/DNA_modifier_types.h +++ b/source/blender/makesdna/DNA_modifier_types.h @@ -195,7 +195,7 @@ typedef struct LatticeModifierData { ModifierData modifier; struct Object *object; - /** Optional vertexgroup name, MAX_VGROUP_NAME. */ + /** Optional vertex-group name, #MAX_VGROUP_NAME. */ char name[64]; float strength; short flag; @@ -212,7 +212,7 @@ typedef struct CurveModifierData { ModifierData modifier; struct Object *object; - /** Optional vertexgroup name, MAX_VGROUP_NAME. */ + /** Optional vertex-group name, #MAX_VGROUP_NAME. */ char name[64]; /** Axis along which curve deforms. */ short defaxis; @@ -262,7 +262,7 @@ typedef struct MaskModifierData { /** Armature to use to in place of hardcoded vgroup. */ struct Object *ob_arm; - /** Name of vertex group to use to mask, MAX_VGROUP_NAME. */ + /** Name of vertex group to use to mask, #MAX_VGROUP_NAME. */ char vgroup[64]; /** Using armature or hardcoded vgroup. */ @@ -447,7 +447,7 @@ typedef struct BevelModifierData { float bevel_angle; float spread; /** if the MOD_BEVEL_VWEIGHT option is set, - * this will be the name of the vert group, MAX_VGROUP_NAME */ + * this will be the name of the vert group, #MAX_VGROUP_NAME */ char defgrp_name[64]; char _pad1[4]; @@ -565,7 +565,7 @@ typedef struct DisplaceModifierData { float strength; int direction; - /** MAX_VGROUP_NAME. */ + /** #MAX_VGROUP_NAME. */ char defgrp_name[64]; float midlevel; int space; @@ -635,7 +635,7 @@ typedef struct DecimateModifierData { /** (mode == MOD_DECIM_MODE_DISSOLVE). */ float angle; - /** MAX_VGROUP_NAME. */ + /** #MAX_VGROUP_NAME. */ char defgrp_name[64]; float defgrp_factor; short flag, mode; @@ -663,7 +663,7 @@ enum { typedef struct SmoothModifierData { ModifierData modifier; float fac; - /** MAX_VGROUP_NAME. */ + /** #MAX_VGROUP_NAME. */ char defgrp_name[64]; short flag, repeat; @@ -684,7 +684,7 @@ typedef struct CastModifierData { float fac; float radius; float size; - /** MAX_VGROUP_NAME. */ + /** #MAX_VGROUP_NAME. */ char defgrp_name[64]; short flag; /** Cast modifier projection type. */ @@ -725,7 +725,7 @@ typedef struct WaveModifierData { /* End MappingInfoModifierData. */ struct Object *objectcenter; - /** MAX_VGROUP_NAME. */ + /** #MAX_VGROUP_NAME. */ char defgrp_name[64]; short flag; @@ -760,7 +760,7 @@ typedef struct ArmatureModifierData { struct Object *object; /** Stored input of previous modifier, for vertex-group blending. */ float (*vert_coords_prev)[3]; - /** MAX_VGROUP_NAME. */ + /** #MAX_VGROUP_NAME. */ char defgrp_name[64]; } ArmatureModifierData; @@ -803,11 +803,11 @@ typedef struct HookModifierData { struct CurveMapping *curfalloff; - /** If NULL, it's using vertexgroup. */ + /** If NULL, it's using vertex-group. */ int *indexar; int indexar_num; float force; - /** Optional vertexgroup name, MAX_VGROUP_NAME. */ + /** Optional vertex-group name, #MAX_VGROUP_NAME. */ char name[64]; void *_pad1; } HookModifierData; @@ -946,7 +946,7 @@ typedef struct MeshDeformModifierData { /** Mesh object. */ struct Object *object; - /** Optional vertexgroup name, MAX_VGROUP_NAME. */ + /** Optional vertex-group name, #MAX_VGROUP_NAME. */ char defgrp_name[64]; short gridsize, flag; @@ -1124,7 +1124,7 @@ typedef struct ShrinkwrapModifierData { struct Object *target; /** Additional shrink target. */ struct Object *auxTarget; - /** Optional vertexgroup name, MAX_VGROUP_NAME. */ + /** Optional vertex-group name, #MAX_VGROUP_NAME. */ char vgroup_name[64]; /** Distance offset to keep from mesh/projection point. */ float keepDist; @@ -1171,9 +1171,9 @@ enum { /** #ShrinkwrapModifierData.shrinkOpts */ enum { - /** allow shrinkwrap to move the vertex in the positive direction of axis */ + /** Allow shrink-wrap to move the vertex in the positive direction of axis. */ MOD_SHRINKWRAP_PROJECT_ALLOW_POS_DIR = (1 << 0), - /** allow shrinkwrap to move the vertex in the negative direction of axis */ + /** Allow shrink-wrap to move the vertex in the negative direction of axis. */ MOD_SHRINKWRAP_PROJECT_ALLOW_NEG_DIR = (1 << 1), /** ignore vertex moves if a vertex ends projected on a front face of the target */ @@ -1207,7 +1207,7 @@ typedef struct SimpleDeformModifierData { /** Object to control the origin of modifier space coordinates. */ struct Object *origin; - /** Optional vertexgroup name, MAX_VGROUP_NAME. */ + /** Optional vertex-group name, #MAX_VGROUP_NAME. */ char vgroup_name[64]; /** Factors to control simple deforms. */ float factor; @@ -1250,7 +1250,7 @@ typedef struct ShapeKeyModifierData { typedef struct SolidifyModifierData { ModifierData modifier; - /** Name of vertex group to use, MAX_VGROUP_NAME. */ + /** Name of vertex group to use, #MAX_VGROUP_NAME. */ char defgrp_name[64]; char shell_defgrp_name[64]; char rim_defgrp_name[64]; @@ -1451,7 +1451,7 @@ typedef struct WarpModifierData { char bone_to[64]; struct CurveMapping *curfalloff; - /** Optional vertexgroup name, MAX_VGROUP_NAME. */ + /** Optional vertex-group name, #MAX_VGROUP_NAME. */ char defgrp_name[64]; float strength; float falloff_radius; @@ -1484,7 +1484,7 @@ typedef enum { typedef struct WeightVGEditModifierData { ModifierData modifier; - /** Name of vertex group to edit. MAX_VGROUP_NAME. */ + /** Name of vertex group to edit. #MAX_VGROUP_NAME. */ char defgrp_name[64]; /** Using MOD_WVG_EDIT_* flags. */ @@ -1504,7 +1504,7 @@ typedef struct WeightVGEditModifierData { /* Masking options. */ /** The global "influence", if no vgroup nor tex is used as mask. */ float mask_constant; - /** Name of mask vertex group from which to get weight factors. MAX_VGROUP_NAME. */ + /** Name of mask vertex group from which to get weight factors. #MAX_VGROUP_NAME. */ char mask_defgrp_name[64]; /* Texture masking. */ @@ -1540,9 +1540,9 @@ enum { typedef struct WeightVGMixModifierData { ModifierData modifier; - /** Name of vertex group to modify/weight. MAX_VGROUP_NAME. */ + /** Name of vertex group to modify/weight. #MAX_VGROUP_NAME. */ char defgrp_name_a[64]; - /** Name of other vertex group to mix in. MAX_VGROUP_NAME. */ + /** Name of other vertex group to mix in. #MAX_VGROUP_NAME. */ char defgrp_name_b[64]; /** Default weight value for first vgroup. */ float default_weight_a; @@ -1558,7 +1558,7 @@ typedef struct WeightVGMixModifierData { /* Masking options. */ /** The global "influence", if no vgroup nor tex is used as mask. */ float mask_constant; - /** Name of mask vertex group from which to get weight factors. MAX_VGROUP_NAME. */ + /** Name of mask vertex group from which to get weight factors. #MAX_VGROUP_NAME. */ char mask_defgrp_name[64]; /* Texture masking. */ @@ -1628,7 +1628,7 @@ enum { typedef struct WeightVGProximityModifierData { ModifierData modifier; - /** Name of vertex group to modify/weight. MAX_VGROUP_NAME. */ + /** Name of vertex group to modify/weight. #MAX_VGROUP_NAME. */ char defgrp_name[64]; /* Mapping stuff. */ @@ -1646,7 +1646,7 @@ typedef struct WeightVGProximityModifierData { /* Masking options. */ /** The global "influence", if no vgroup nor tex is used as mask. */ float mask_constant; - /** Name of mask vertex group from which to get weight factors. MAX_VGROUP_NAME. */ + /** Name of mask vertex group from which to get weight factors. #MAX_VGROUP_NAME. */ char mask_defgrp_name[64]; /* Texture masking. */ @@ -1840,7 +1840,7 @@ typedef struct LaplacianSmoothModifierData { float lambda, lambda_border; char _pad1[4]; - /** MAX_VGROUP_NAME. */ + /** #MAX_VGROUP_NAME. */ char defgrp_name[64]; short flag, repeat; } LaplacianSmoothModifierData; @@ -1887,7 +1887,7 @@ typedef struct CorrectiveSmoothModifierData { char smooth_type, rest_source; char _pad[6]; - /** MAX_VGROUP_NAME. */ + /** #MAX_VGROUP_NAME. */ char defgrp_name[64]; /* runtime-only cache */ @@ -1932,7 +1932,7 @@ typedef struct UVWarpModifierData { /** Optional name of bone target, MAX_ID_NAME-2. */ char bone_dst[64]; - /** Optional vertexgroup name, MAX_VGROUP_NAME. */ + /** Optional vertex-group name, #MAX_VGROUP_NAME. */ char vgroup_name[64]; /** MAX_CUSTOMDATA_LAYER_NAME. */ char uvlayer_name[64]; @@ -2013,7 +2013,7 @@ enum { typedef struct LaplacianDeformModifierData { ModifierData modifier; - /** MAX_VGROUP_NAME. */ + /** #MAX_VGROUP_NAME. */ char anchor_grp_name[64]; int verts_num, repeat; float *vertexco; @@ -2035,7 +2035,7 @@ enum { */ typedef struct WireframeModifierData { ModifierData modifier; - /** MAX_VGROUP_NAME. */ + /** #MAX_VGROUP_NAME. */ char defgrp_name[64]; float offset; float offset_fac; @@ -2059,7 +2059,7 @@ typedef struct WeldModifierData { /* The limit below which to merge vertices. */ float merge_dist; - /* Name of vertex group to use to mask, MAX_VGROUP_NAME. */ + /** Name of vertex group to use to mask, #MAX_VGROUP_NAME. */ char defgrp_name[64]; char mode; @@ -2107,7 +2107,7 @@ typedef struct DataTransferModifierData { /** See CDT_MIX_ enum in BKE_customdata.h. */ int mix_mode; float mix_factor; - /** MAX_VGROUP_NAME. */ + /** #MAX_VGROUP_NAME. */ char defgrp_name[64]; int flags; @@ -2130,7 +2130,7 @@ enum { /** Set Split Normals modifier. */ typedef struct NormalEditModifierData { ModifierData modifier; - /** MAX_VGROUP_NAME. */ + /** #MAX_VGROUP_NAME. */ char defgrp_name[64]; /** Source of normals, or center of ellipsoid. */ struct Object *target; @@ -2253,7 +2253,7 @@ enum { typedef struct WeightedNormalModifierData { ModifierData modifier; - /** MAX_VGROUP_NAME. */ + /** #MAX_VGROUP_NAME. */ char defgrp_name[64]; char mode, flag; short weight; diff --git a/source/blender/makesdna/DNA_node_types.h b/source/blender/makesdna/DNA_node_types.h index 315bcbd971c..74714cf7e41 100644 --- a/source/blender/makesdna/DNA_node_types.h +++ b/source/blender/makesdna/DNA_node_types.h @@ -931,7 +931,7 @@ typedef struct NodeImageMultiFileSocket { char path[1024]; ImageFormatData format; - /* multilayer output */ + /* Multi-layer output. */ /** EXR_TOT_MAXNAME-2 ('.' and channel char are appended). */ char layer[30]; char _pad2[2]; @@ -1273,7 +1273,7 @@ typedef struct CryptomatteLayer { typedef struct NodeCryptomatte_Runtime { /* Contains `CryptomatteLayer`. */ ListBase layers; - /* Temp storage for the cryptomatte picker. */ + /* Temp storage for the crypto-matte picker. */ float add[3]; float remove[3]; } NodeCryptomatte_Runtime; @@ -2083,6 +2083,12 @@ typedef enum CMPNodeLevelsChannel { CMP_NODE_LEVLES_LUMINANCE_BT709 = 5, } CMPNodeLevelsChannel; +/* Tone Map Node. Stored in NodeTonemap.type. */ +typedef enum CMPNodeToneMapType { + CMP_NODE_TONE_MAP_SIMPLE = 0, + CMP_NODE_TONE_MAP_PHOTORECEPTOR = 1, +} CMPNodeToneMapType; + /* Plane track deform node. */ enum { diff --git a/source/blender/makesdna/DNA_object_defaults.h b/source/blender/makesdna/DNA_object_defaults.h index 14683869bc4..2a5796d2aea 100644 --- a/source/blender/makesdna/DNA_object_defaults.h +++ b/source/blender/makesdna/DNA_object_defaults.h @@ -23,7 +23,7 @@ \ .constinv = _DNA_DEFAULT_UNIT_M4, \ .parentinv = _DNA_DEFAULT_UNIT_M4, \ - .obmat = _DNA_DEFAULT_UNIT_M4, \ + .object_to_world = _DNA_DEFAULT_UNIT_M4, \ \ .scale = {1, 1, 1}, \ .dscale = {1, 1, 1}, \ diff --git a/source/blender/makesdna/DNA_object_types.h b/source/blender/makesdna/DNA_object_types.h index 8296855ec29..3ef32d28e85 100644 --- a/source/blender/makesdna/DNA_object_types.h +++ b/source/blender/makesdna/DNA_object_types.h @@ -323,7 +323,7 @@ typedef struct Object { /** Axis angle rotation - angle part. */ float rotAngle, drotAngle; /** Final world-space matrix with constraints & animsys applied. */ - float obmat[4][4]; + float object_to_world[4][4]; /** Inverse result of parent, so that object doesn't 'stick' to parent. */ float parentinv[4][4]; /** Inverse result of constraints. @@ -333,7 +333,7 @@ typedef struct Object { * Inverse matrix of 'obmat' for any other use than rendering! * * \note this isn't assured to be valid as with 'obmat', - * before using this value you should do: `invert_m4_m4(ob->imat, ob->obmat)` + * before using this value you should do: `invert_m4_m4(ob->imat, ob->object_to_world)` */ float imat[4][4]; diff --git a/source/blender/makesdna/DNA_particle_types.h b/source/blender/makesdna/DNA_particle_types.h index 44f1d3479b1..c4f11905e10 100644 --- a/source/blender/makesdna/DNA_particle_types.h +++ b/source/blender/makesdna/DNA_particle_types.h @@ -465,7 +465,7 @@ enum { #define PART_REACT_MULTIPLE 2 //#define PART_LOOP 4 /* not used anymore */ -/* for dopesheet */ +/* For dope-sheet. */ #define PART_DS_EXPAND 8 #define PART_HAIR_REGROW 16 /* regrow hair for each frame */ diff --git a/source/blender/makesdna/DNA_scene_types.h b/source/blender/makesdna/DNA_scene_types.h index 5fa5d4c7787..28359038be5 100644 --- a/source/blender/makesdna/DNA_scene_types.h +++ b/source/blender/makesdna/DNA_scene_types.h @@ -472,6 +472,7 @@ typedef struct ImageFormatData { #define R_IMF_IMTYPE_THEORA 33 #define R_IMF_IMTYPE_PSD 34 #define R_IMF_IMTYPE_WEBP 35 +#define R_IMF_IMTYPE_AV1 36 #define R_IMF_IMTYPE_INVALID 255 diff --git a/source/blender/makesdna/DNA_space_types.h b/source/blender/makesdna/DNA_space_types.h index 809c8be7bc4..4bb92e6fcc5 100644 --- a/source/blender/makesdna/DNA_space_types.h +++ b/source/blender/makesdna/DNA_space_types.h @@ -667,7 +667,7 @@ typedef struct SpaceSeq { struct SequencerPreviewOverlay preview_overlay; struct SequencerTimelineOverlay timeline_overlay; - /** Multiview current eye - for internal use. */ + /** Multi-view current eye - for internal use. */ char multiview_eye; char _pad2[7]; @@ -1169,6 +1169,10 @@ enum { FILE_ENTRY_NAME_FREE = 1 << 1, /* The preview for this entry is being loaded on another thread. */ FILE_ENTRY_PREVIEW_LOADING = 1 << 2, + /** For #FILE_TYPE_BLENDERLIB only: Denotes that the ID is known to not have a preview (none was + * found in the .blend). Stored so we don't keep trying to find non-existent previews every time + * we reload previews. When dealing with heavy files this can have quite an impact. */ + FILE_ENTRY_BLENDERLIB_NO_PREVIEW = 1 << 3, }; /** \} */ diff --git a/source/blender/makesdna/DNA_windowmanager_types.h b/source/blender/makesdna/DNA_windowmanager_types.h index 9b235fac049..7231a995f10 100644 --- a/source/blender/makesdna/DNA_windowmanager_types.h +++ b/source/blender/makesdna/DNA_windowmanager_types.h @@ -89,13 +89,13 @@ typedef struct Report { } Report; /** - * \note Saved in the wm, don't remove. + * \note Saved in the #wmWindowManager, don't remove. */ typedef struct ReportList { ListBase list; - /** eReportType. */ + /** #eReportType. */ int printlevel; - /** eReportType. */ + /** #eReportType. */ int storelevel; int flag; char _pad[4]; diff --git a/source/blender/makesdna/DNA_workspace_types.h b/source/blender/makesdna/DNA_workspace_types.h index e99f317f057..0cd1144b30d 100644 --- a/source/blender/makesdna/DNA_workspace_types.h +++ b/source/blender/makesdna/DNA_workspace_types.h @@ -199,8 +199,10 @@ typedef struct WorkSpaceInstanceHook { WorkSpace *active; struct WorkSpaceLayout *act_layout; - /** Needed because we can't change workspaces/layouts in running handler loop, - * it would break context. */ + /** + * Needed because we can't change work-spaces/layouts in running handler loop, + * it would break context. + */ WorkSpace *temp_workspace_store; struct WorkSpaceLayout *temp_layout_store; } WorkSpaceInstanceHook; diff --git a/source/blender/makesdna/intern/CMakeLists.txt b/source/blender/makesdna/intern/CMakeLists.txt index 0d04d7df067..50fd51e88a1 100644 --- a/source/blender/makesdna/intern/CMakeLists.txt +++ b/source/blender/makesdna/intern/CMakeLists.txt @@ -116,8 +116,8 @@ blender_add_lib(bf_dna "${SRC}" "${INC}" "${INC_SYS}" "${LIB}") # ----------------------------------------------------------------------------- # Build bf_dna_blenlib library set(INC + .. ../../blenlib - ../../makesdna ../../../../intern/atomic ../../../../intern/guardedalloc ) diff --git a/source/blender/makesdna/intern/dna_rename_defs.h b/source/blender/makesdna/intern/dna_rename_defs.h index ec624bcb64e..4a009a88f1a 100644 --- a/source/blender/makesdna/intern/dna_rename_defs.h +++ b/source/blender/makesdna/intern/dna_rename_defs.h @@ -96,6 +96,7 @@ DNA_STRUCT_RENAME_ELEM(Object, dup_group, instance_collection) DNA_STRUCT_RENAME_ELEM(Object, dupfacesca, instance_faces_scale) DNA_STRUCT_RENAME_ELEM(Object, restrictflag, visibility_flag) DNA_STRUCT_RENAME_ELEM(Object, size, scale) +DNA_STRUCT_RENAME_ELEM(Object, obmat, object_to_world) DNA_STRUCT_RENAME_ELEM(Object_Runtime, crazyspace_num_verts, crazyspace_verts_num) DNA_STRUCT_RENAME_ELEM(MEdge, bweight, bweight_legacy) DNA_STRUCT_RENAME_ELEM(MEdge, crease, crease_legacy) diff --git a/source/blender/makesrna/intern/CMakeLists.txt b/source/blender/makesrna/intern/CMakeLists.txt index 2b06daf34e3..f028b199098 100644 --- a/source/blender/makesrna/intern/CMakeLists.txt +++ b/source/blender/makesrna/intern/CMakeLists.txt @@ -200,7 +200,7 @@ set(INC ../../imbuf ../../makesdna ../../modifiers - ../../nodes/ + ../../nodes ../../sequencer ../../simulation ../../windowmanager diff --git a/source/blender/makesrna/intern/rna_armature.c b/source/blender/makesrna/intern/rna_armature.c index e6b1ea1321c..a2386205013 100644 --- a/source/blender/makesrna/intern/rna_armature.c +++ b/source/blender/makesrna/intern/rna_armature.c @@ -1129,7 +1129,7 @@ static void rna_def_bone_common(StructRNA *srna, int editbone) RNA_define_lib_overridable(false); } -/* err... bones should not be directly edited (only editbones should be...) */ +/* Err... bones should not be directly edited (only edit-bones should be...). */ static void rna_def_bone(BlenderRNA *brna) { StructRNA *srna; diff --git a/source/blender/makesrna/intern/rna_asset.c b/source/blender/makesrna/intern/rna_asset.c index f919cfbeffd..3c7eb3d208f 100644 --- a/source/blender/makesrna/intern/rna_asset.c +++ b/source/blender/makesrna/intern/rna_asset.c @@ -472,6 +472,12 @@ static void rna_def_asset_handle(BlenderRNA *brna) rna_def_asset_handle_api(srna); } +static void rna_def_asset_catalog_path(BlenderRNA *brna) +{ + StructRNA *srna = RNA_def_struct(brna, "AssetCatalogPath", NULL); + RNA_def_struct_ui_text(srna, "Catalog Path", ""); +} + static void rna_def_asset_library_reference(BlenderRNA *brna) { StructRNA *srna = RNA_def_struct(brna, "AssetLibraryReference", NULL); @@ -498,6 +504,7 @@ void RNA_def_asset(BlenderRNA *brna) rna_def_asset_data(brna); rna_def_asset_library_reference(brna); rna_def_asset_handle(brna); + rna_def_asset_catalog_path(brna); RNA_define_animate_sdna(true); } diff --git a/source/blender/makesrna/intern/rna_brush.c b/source/blender/makesrna/intern/rna_brush.c index 5e4b08d8a41..5ba31070e1d 100644 --- a/source/blender/makesrna/intern/rna_brush.c +++ b/source/blender/makesrna/intern/rna_brush.c @@ -3240,18 +3240,20 @@ static void rna_def_brush(BlenderRNA *brna) RNA_def_property_update(prop, 0, "rna_Brush_update"); } while ((++entry)->identifier); - prop = RNA_def_property(srna, "automasking_cavity_factor", PROP_FLOAT, PROP_NONE); + prop = RNA_def_property(srna, "automasking_cavity_factor", PROP_FLOAT, PROP_FACTOR); RNA_def_property_float_sdna(prop, NULL, "automasking_cavity_factor"); RNA_def_property_ui_text(prop, "Cavity Factor", "The contrast of the cavity mask"); - RNA_def_property_ui_range(prop, 0.0f, 1.0f, 0.1, 3); RNA_def_property_range(prop, 0.0f, 5.0f); + RNA_def_property_ui_range(prop, 0.0f, 1.0f, 0.1, 3); RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY); RNA_def_property_update(prop, 0, "rna_Brush_update"); prop = RNA_def_property(srna, "automasking_cavity_blur_steps", PROP_INT, PROP_NONE); RNA_def_property_int_sdna(prop, NULL, "automasking_cavity_blur_steps"); + RNA_def_property_int_default(prop, 0); RNA_def_property_ui_text(prop, "Blur Steps", "The number of times the cavity mask is blurred"); - RNA_def_property_range(prop, 0.0f, 25.0f); + RNA_def_property_range(prop, 0, 25); + RNA_def_property_ui_range(prop, 0, 10, 1, 1); RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY); RNA_def_property_update(prop, 0, "rna_Brush_update"); @@ -3614,6 +3616,10 @@ static void rna_def_brush(BlenderRNA *brna) RNA_def_property_ui_text( prop, "Use Vertex", "Use this brush in grease pencil vertex color mode"); + prop = RNA_def_property(srna, "use_paint_sculpt_curves", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "ob_mode", OB_MODE_SCULPT_CURVES); + RNA_def_property_ui_text(prop, "Use Sculpt", "Use this brush in sculpt curves mode"); + /* texture */ prop = RNA_def_property(srna, "texture_slot", PROP_POINTER, PROP_NONE); RNA_def_property_struct_type(prop, "BrushTextureSlot"); @@ -3657,13 +3663,13 @@ static void rna_def_brush(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Mask Texture Overlay Alpha", ""); RNA_def_property_update(prop, 0, "rna_Brush_update"); - prop = RNA_def_property(srna, "cursor_color_add", PROP_FLOAT, PROP_COLOR); + prop = RNA_def_property(srna, "cursor_color_add", PROP_FLOAT, PROP_COLOR_GAMMA); RNA_def_property_float_sdna(prop, NULL, "add_col"); RNA_def_property_array(prop, 4); RNA_def_property_ui_text(prop, "Add Color", "Color of cursor when adding"); RNA_def_property_update(prop, 0, "rna_Brush_update"); - prop = RNA_def_property(srna, "cursor_color_subtract", PROP_FLOAT, PROP_COLOR); + prop = RNA_def_property(srna, "cursor_color_subtract", PROP_FLOAT, PROP_COLOR_GAMMA); RNA_def_property_float_sdna(prop, NULL, "sub_col"); RNA_def_property_array(prop, 4); RNA_def_property_ui_text(prop, "Subtract Color", "Color of cursor when subtracting"); diff --git a/source/blender/makesrna/intern/rna_depsgraph.c b/source/blender/makesrna/intern/rna_depsgraph.c index db5b3c33c59..9af76de2a2b 100644 --- a/source/blender/makesrna/intern/rna_depsgraph.c +++ b/source/blender/makesrna/intern/rna_depsgraph.c @@ -168,7 +168,7 @@ static void rna_DepsgraphObjectInstance_matrix_world_get(PointerRNA *ptr, float /* We can return actual object's matrix here, no reason to return identity matrix * when this is not actually an instance... */ Object *ob = (Object *)di->iter.current; - copy_m4_m4((float(*)[4])mat, ob->obmat); + copy_m4_m4((float(*)[4])mat, ob->object_to_world); } } diff --git a/source/blender/makesrna/intern/rna_fcurve.c b/source/blender/makesrna/intern/rna_fcurve.c index 727d329781d..9fe7dda0e20 100644 --- a/source/blender/makesrna/intern/rna_fcurve.c +++ b/source/blender/makesrna/intern/rna_fcurve.c @@ -2416,7 +2416,7 @@ static void rna_def_fcurve(BlenderRNA *brna) prop, "Color Mode", "Method used to determine color of F-Curve in Graph Editor"); RNA_def_property_update(prop, NC_ANIMATION, NULL); - prop = RNA_def_property(srna, "color", PROP_FLOAT, PROP_COLOR); + prop = RNA_def_property(srna, "color", PROP_FLOAT, PROP_COLOR_GAMMA); RNA_def_property_array(prop, 3); RNA_def_property_range(prop, 0.0f, 1.0f); RNA_def_property_ui_text(prop, "Color", "Color of the F-Curve in the Graph Editor"); diff --git a/source/blender/makesrna/intern/rna_gpencil.c b/source/blender/makesrna/intern/rna_gpencil.c index cf0ff546d41..a55a1b0ffcd 100644 --- a/source/blender/makesrna/intern/rna_gpencil.c +++ b/source/blender/makesrna/intern/rna_gpencil.c @@ -334,13 +334,13 @@ static int rna_GPencilLayer_active_frame_editable(PointerRNA *ptr, const char ** static void set_parent(bGPDlayer *gpl, Object *par, const int type, const char *substr) { if (type == PAROBJECT) { - invert_m4_m4(gpl->inverse, par->obmat); + invert_m4_m4(gpl->inverse, par->object_to_world); gpl->parent = par; gpl->partype |= PAROBJECT; gpl->parsubstr[0] = 0; } else if (type == PARSKEL) { - invert_m4_m4(gpl->inverse, par->obmat); + invert_m4_m4(gpl->inverse, par->object_to_world); gpl->parent = par; gpl->partype |= PARSKEL; gpl->parsubstr[0] = 0; @@ -349,7 +349,7 @@ static void set_parent(bGPDlayer *gpl, Object *par, const int type, const char * bPoseChannel *pchan = BKE_pose_channel_find_name(par->pose, substr); if (pchan) { float tmp_mat[4][4]; - mul_m4_m4m4(tmp_mat, par->obmat, pchan->pose_mat); + mul_m4_m4m4(tmp_mat, par->object_to_world, pchan->pose_mat); invert_m4_m4(gpl->inverse, tmp_mat); gpl->parent = par; @@ -357,7 +357,7 @@ static void set_parent(bGPDlayer *gpl, Object *par, const int type, const char * BLI_strncpy(gpl->parsubstr, substr, sizeof(gpl->parsubstr)); } else { - invert_m4_m4(gpl->inverse, par->obmat); + invert_m4_m4(gpl->inverse, par->object_to_world); gpl->parent = par; gpl->partype |= PAROBJECT; gpl->parsubstr[0] = 0; diff --git a/source/blender/makesrna/intern/rna_gpencil_modifier.c b/source/blender/makesrna/intern/rna_gpencil_modifier.c index 4a36443ca42..320ef169ae5 100644 --- a/source/blender/makesrna/intern/rna_gpencil_modifier.c +++ b/source/blender/makesrna/intern/rna_gpencil_modifier.c @@ -9,11 +9,8 @@ #include <stdlib.h> #include "DNA_armature_types.h" -#include "DNA_brush_types.h" -#include "DNA_cachefile_types.h" #include "DNA_gpencil_modifier_types.h" #include "DNA_gpencil_types.h" -#include "DNA_mesh_types.h" #include "DNA_modifier_types.h" #include "DNA_object_force_types.h" #include "DNA_object_types.h" @@ -21,20 +18,13 @@ #include "MEM_guardedalloc.h" -#include "BLI_math.h" -#include "BLI_rand.h" +#include "BLI_math_base.h" +#include "BLI_math_rotation.h" #include "BLI_string_utils.h" #include "BLT_translation.h" #include "BKE_animsys.h" -#include "BKE_data_transfer.h" -#include "BKE_dynamicpaint.h" -#include "BKE_effect.h" -#include "BKE_fluid.h" /* For BKE_fluid_modifier_free & BKE_fluid_modifier_create_type_data */ -#include "BKE_mesh_mapping.h" -#include "BKE_mesh_remap.h" -#include "BKE_multires.h" #include "RNA_access.h" #include "RNA_define.h" diff --git a/source/blender/makesrna/intern/rna_internal.h b/source/blender/makesrna/intern/rna_internal.h index 8e652753ec0..ea829e5cd86 100644 --- a/source/blender/makesrna/intern/rna_internal.h +++ b/source/blender/makesrna/intern/rna_internal.h @@ -322,7 +322,9 @@ void rna_object_vcollayer_name_set(struct PointerRNA *ptr, PointerRNA rna_object_shapekey_index_get(struct ID *id, int value); int rna_object_shapekey_index_set(struct ID *id, PointerRNA value, int current); -void rna_def_object_type_visibility_flags_common(StructRNA *srna, int noteflag); +void rna_def_object_type_visibility_flags_common(StructRNA *srna, + int noteflag, + const char *update_func); int rna_object_type_visibility_icon_get_common(int object_type_exclude_viewport, const int *object_type_exclude_select); diff --git a/source/blender/makesrna/intern/rna_nodetree.c b/source/blender/makesrna/intern/rna_nodetree.c index 0b0970a835e..865399df9ef 100644 --- a/source/blender/makesrna/intern/rna_nodetree.c +++ b/source/blender/makesrna/intern/rna_nodetree.c @@ -12230,7 +12230,7 @@ static void rna_def_node(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Custom Color", "Use custom color for the node"); RNA_def_property_update(prop, NC_NODE | ND_DISPLAY, NULL); - prop = RNA_def_property(srna, "color", PROP_FLOAT, PROP_COLOR); + prop = RNA_def_property(srna, "color", PROP_FLOAT, PROP_COLOR_GAMMA); RNA_def_property_array(prop, 3); RNA_def_property_range(prop, 0.0f, 1.0f); RNA_def_property_ui_text(prop, "Color", "Custom color of the node body"); diff --git a/source/blender/makesrna/intern/rna_object.c b/source/blender/makesrna/intern/rna_object.c index 46a89d3a6e0..1d6b3d5d69e 100644 --- a/source/blender/makesrna/intern/rna_object.c +++ b/source/blender/makesrna/intern/rna_object.c @@ -356,7 +356,8 @@ static void rna_Object_internal_update_draw(Main *UNUSED(bmain), static void rna_Object_matrix_world_update(Main *bmain, Scene *scene, PointerRNA *ptr) { /* don't use compat so we get predictable rotation */ - BKE_object_apply_mat4((Object *)ptr->owner_id, ((Object *)ptr->owner_id)->obmat, false, true); + BKE_object_apply_mat4( + (Object *)ptr->owner_id, ((Object *)ptr->owner_id)->object_to_world, false, true); rna_Object_internal_update(bmain, scene, ptr); } @@ -407,7 +408,7 @@ static void rna_Object_matrix_local_set(PointerRNA *ptr, const float values[16]) Object *ob = (Object *)ptr->owner_id; float local_mat[4][4]; - /* Localspace matrix is truly relative to the parent, + /* Local-space matrix is truly relative to the parent, * but parameters stored in object are relative to parentinv matrix. * Undo the parent inverse part before applying it as local matrix. */ if (ob->parent) { @@ -3390,7 +3391,7 @@ static void rna_def_object(BlenderRNA *brna) /* matrix */ prop = RNA_def_property(srna, "matrix_world", PROP_FLOAT, PROP_MATRIX); - RNA_def_property_float_sdna(prop, NULL, "obmat"); + RNA_def_property_float_sdna(prop, NULL, "object_to_world"); RNA_def_property_multi_array(prop, 2, rna_matrix_dimsize_4x4); RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); RNA_def_property_override_flag(prop, PROPOVERRIDE_NO_COMPARISON); diff --git a/source/blender/makesrna/intern/rna_object_api.c b/source/blender/makesrna/intern/rna_object_api.c index c99c5fb723d..366a3597ce6 100644 --- a/source/blender/makesrna/intern/rna_object_api.c +++ b/source/blender/makesrna/intern/rna_object_api.c @@ -199,7 +199,7 @@ static bool rna_Object_holdout_get(Object *ob, bContext *C, PointerRNA *view_lay return false; } - return ((base->flag & BASE_HOLDOUT) != 0); + return ((base->flag & BASE_HOLDOUT) != 0) || ((ob->visibility_flag & OB_HOLDOUT) != 0); } static bool rna_Object_indirect_only_get(Object *ob, bContext *C, PointerRNA *view_layer_ptr) diff --git a/source/blender/makesrna/intern/rna_particle.c b/source/blender/makesrna/intern/rna_particle.c index 07702f3b4b6..02105c7b425 100644 --- a/source/blender/makesrna/intern/rna_particle.c +++ b/source/blender/makesrna/intern/rna_particle.c @@ -471,7 +471,7 @@ static void rna_ParticleSystem_co_hair( if (step >= 0 && step <= max_k) { copy_v3_v3(n_co, (cache + step)->co); mul_m4_v3(particlesystem->imat, n_co); - mul_m4_v3(object->obmat, n_co); + mul_m4_v3(object->object_to_world, n_co); } } diff --git a/source/blender/makesrna/intern/rna_scene.c b/source/blender/makesrna/intern/rna_scene.c index 8fc504f192e..fde8fcf651c 100644 --- a/source/blender/makesrna/intern/rna_scene.c +++ b/source/blender/makesrna/intern/rna_scene.c @@ -5945,7 +5945,8 @@ static void rna_def_scene_ffmpeg_settings(BlenderRNA *brna) {AV_CODEC_ID_PNG, "PNG", 0, "PNG", ""}, {AV_CODEC_ID_QTRLE, "QTRLE", 0, "QT rle / QT Animation", ""}, {AV_CODEC_ID_THEORA, "THEORA", 0, "Theora", ""}, - {AV_CODEC_ID_VP9, "WEBM", 0, "WEBM / VP9", ""}, + {AV_CODEC_ID_VP9, "WEBM", 0, "WebM / VP9", ""}, + {AV_CODEC_ID_AV1, "AV1", 0, "AV1", ""}, {0, NULL, 0, NULL, NULL}, }; diff --git a/source/blender/makesrna/intern/rna_sculpt_paint.c b/source/blender/makesrna/intern/rna_sculpt_paint.c index d8ad3d1f41e..440309849ab 100644 --- a/source/blender/makesrna/intern/rna_sculpt_paint.c +++ b/source/blender/makesrna/intern/rna_sculpt_paint.c @@ -927,17 +927,20 @@ static void rna_def_sculpt(BlenderRNA *brna) RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL); } while ((++entry)->identifier); - prop = RNA_def_property(srna, "automasking_cavity_factor", PROP_FLOAT, PROP_NONE); + prop = RNA_def_property(srna, "automasking_cavity_factor", PROP_FLOAT, PROP_FACTOR); RNA_def_property_float_sdna(prop, NULL, "automasking_cavity_factor"); RNA_def_property_ui_text(prop, "Cavity Factor", "The contrast of the cavity mask"); - RNA_def_property_ui_range(prop, 0.0f, 1.0f, 0.1, 3); + RNA_def_property_float_default(prop, 1.0f); RNA_def_property_range(prop, 0.0f, 5.0f); + RNA_def_property_ui_range(prop, 0.0f, 1.0f, 0.1, 3); RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL); prop = RNA_def_property(srna, "automasking_cavity_blur_steps", PROP_INT, PROP_NONE); RNA_def_property_int_sdna(prop, NULL, "automasking_cavity_blur_steps"); RNA_def_property_ui_text(prop, "Blur Steps", "The number of times the cavity mask is blurred"); - RNA_def_property_range(prop, 0.0f, 25.0f); + RNA_def_property_int_default(prop, 0); + RNA_def_property_range(prop, 0, 25); + RNA_def_property_ui_range(prop, 0, 10, 1, 1); RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL); prop = RNA_def_property(srna, "automasking_cavity_curve", PROP_POINTER, PROP_NONE); diff --git a/source/blender/makesrna/intern/rna_sequencer.c b/source/blender/makesrna/intern/rna_sequencer.c index 634754d54cc..c952210eecf 100644 --- a/source/blender/makesrna/intern/rna_sequencer.c +++ b/source/blender/makesrna/intern/rna_sequencer.c @@ -778,7 +778,7 @@ static void rna_Sequence_filepath_get(PointerRNA *ptr, char *value) { Sequence *seq = (Sequence *)(ptr->data); - BLI_join_dirfile(value, FILE_MAX, seq->strip->dir, seq->strip->stripdata->name); + BLI_path_join(value, FILE_MAX, seq->strip->dir, seq->strip->stripdata->name); } static int rna_Sequence_filepath_length(PointerRNA *ptr) @@ -786,7 +786,7 @@ static int rna_Sequence_filepath_length(PointerRNA *ptr) Sequence *seq = (Sequence *)(ptr->data); char path[FILE_MAX]; - BLI_join_dirfile(path, sizeof(path), seq->strip->dir, seq->strip->stripdata->name); + BLI_path_join(path, sizeof(path), seq->strip->dir, seq->strip->stripdata->name); return strlen(path); } @@ -804,7 +804,7 @@ static void rna_Sequence_proxy_filepath_get(PointerRNA *ptr, char *value) { StripProxy *proxy = (StripProxy *)(ptr->data); - BLI_join_dirfile(value, FILE_MAX, proxy->dir, proxy->file); + BLI_path_join(value, FILE_MAX, proxy->dir, proxy->file); } static int rna_Sequence_proxy_filepath_length(PointerRNA *ptr) @@ -812,7 +812,7 @@ static int rna_Sequence_proxy_filepath_length(PointerRNA *ptr) StripProxy *proxy = (StripProxy *)(ptr->data); char path[FILE_MAX]; - BLI_join_dirfile(path, sizeof(path), proxy->dir, proxy->file); + BLI_path_join(path, sizeof(path), proxy->dir, proxy->file); return strlen(path); } diff --git a/source/blender/makesrna/intern/rna_space.c b/source/blender/makesrna/intern/rna_space.c index 3cd8020ca6c..b2663b89333 100644 --- a/source/blender/makesrna/intern/rna_space.c +++ b/source/blender/makesrna/intern/rna_space.c @@ -426,7 +426,11 @@ static const EnumPropertyItem rna_enum_shading_color_type_items[] = { {V3D_SHADING_OBJECT_COLOR, "OBJECT", 0, "Object", "Show object color"}, {V3D_SHADING_RANDOM_COLOR, "RANDOM", 0, "Random", "Show random object color"}, {V3D_SHADING_VERTEX_COLOR, "VERTEX", 0, "Attribute", "Show active color attribute"}, - {V3D_SHADING_TEXTURE_COLOR, "TEXTURE", 0, "Texture", "Show texture"}, + {V3D_SHADING_TEXTURE_COLOR, + "TEXTURE", + 0, + "Texture", + "Show the texture from the active image texture node using the active UV map coordinates"}, {0, NULL, 0, NULL, NULL}, }; @@ -986,6 +990,13 @@ static PointerRNA rna_SpaceView3D_region_3d_get(PointerRNA *ptr) return rna_pointer_inherit_refine(ptr, &RNA_RegionView3D, regiondata); } +static void rna_SpaceView3D_object_type_visibility_update(Main *UNUSED(bmain), + Scene *scene, + PointerRNA *UNUSED(ptr)) +{ + DEG_id_tag_update(&scene->id, ID_RECALC_BASE_FLAGS); +} + static void rna_SpaceView3D_region_quadviews_begin(CollectionPropertyIterator *iter, PointerRNA *ptr) { @@ -5082,7 +5093,8 @@ static void rna_def_space_view3d(BlenderRNA *brna) prop, NC_SPACE | ND_SPACE_VIEW3D, "rna_SpaceView3D_mirror_xr_session_update"); rna_def_object_type_visibility_flags_common(srna, - NC_SPACE | ND_SPACE_VIEW3D | NS_VIEW3D_SHADING); + NC_SPACE | ND_SPACE_VIEW3D | NS_VIEW3D_SHADING, + "rna_SpaceView3D_object_type_visibility_update"); /* Helper for drawing the icon. */ prop = RNA_def_property(srna, "icon_from_show_object_viewport", PROP_INT, PROP_NONE); diff --git a/source/blender/makesrna/intern/rna_space_api.c b/source/blender/makesrna/intern/rna_space_api.c index b3896919275..9790a85e1c8 100644 --- a/source/blender/makesrna/intern/rna_space_api.c +++ b/source/blender/makesrna/intern/rna_space_api.c @@ -119,7 +119,9 @@ void RNA_api_space_text(StructRNA *srna) RNA_def_function_output(func, parm); } -void rna_def_object_type_visibility_flags_common(StructRNA *srna, int noteflag) +void rna_def_object_type_visibility_flags_common(StructRNA *srna, + int noteflag, + const char *update_func) { PropertyRNA *prop; @@ -173,7 +175,7 @@ void rna_def_object_type_visibility_flags_common(StructRNA *srna, int noteflag) RNA_def_property_boolean_negative_sdna( prop, NULL, view_mask_member[mask_index], info[type_index].type_mask); RNA_def_property_ui_text(prop, info[type_index].name, ""); - RNA_def_property_update(prop, noteflag, NULL); + RNA_def_property_update(prop, noteflag, update_func); } } } diff --git a/source/blender/makesrna/intern/rna_tracking.c b/source/blender/makesrna/intern/rna_tracking.c index c4a11d4e9e0..44df0db9ade 100644 --- a/source/blender/makesrna/intern/rna_tracking.c +++ b/source/blender/makesrna/intern/rna_tracking.c @@ -1640,7 +1640,7 @@ static void rna_def_trackingTrack(BlenderRNA *brna) RNA_def_property_update(prop, NC_MOVIECLIP | ND_DISPLAY, NULL); /* color */ - prop = RNA_def_property(srna, "color", PROP_FLOAT, PROP_COLOR); + prop = RNA_def_property(srna, "color", PROP_FLOAT, PROP_COLOR_GAMMA); RNA_def_property_array(prop, 3); RNA_def_property_range(prop, 0.0f, 1.0f); RNA_def_property_ui_text( diff --git a/source/blender/makesrna/intern/rna_ui_api.c b/source/blender/makesrna/intern/rna_ui_api.c index fc68e8421d7..eac29ac5e61 100644 --- a/source/blender/makesrna/intern/rna_ui_api.c +++ b/source/blender/makesrna/intern/rna_ui_api.c @@ -1785,6 +1785,10 @@ void RNA_api_ui_layout(StructRNA *srna) parm = RNA_def_pointer(func, "socket", "NodeSocket", "", ""); RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); + func = RNA_def_function(srna, "template_node_asset_menu_items", "uiTemplateNodeAssetMenuItems"); + RNA_def_function_flag(func, FUNC_USE_CONTEXT); + parm = RNA_def_string(func, "catalog_path", NULL, 0, "", ""); + func = RNA_def_function(srna, "template_texture_user", "uiTemplateTextureUser"); RNA_def_function_flag(func, FUNC_USE_CONTEXT); diff --git a/source/blender/makesrna/intern/rna_userdef.c b/source/blender/makesrna/intern/rna_userdef.c index e22ae205b0a..58189ab2478 100644 --- a/source/blender/makesrna/intern/rna_userdef.c +++ b/source/blender/makesrna/intern/rna_userdef.c @@ -574,7 +574,7 @@ static void rna_Userdef_disk_cache_dir_update(Main *UNUSED(bmain), { if (U.sequencer_disk_cache_dir[0] != '\0') { BLI_path_abs(U.sequencer_disk_cache_dir, BKE_main_blendfile_path_from_global()); - BLI_path_slash_ensure(U.sequencer_disk_cache_dir); + BLI_path_slash_ensure(U.sequencer_disk_cache_dir, sizeof(U.sequencer_disk_cache_dir)); BLI_path_make_safe(U.sequencer_disk_cache_dir); } diff --git a/source/blender/makesrna/intern/rna_wm.c b/source/blender/makesrna/intern/rna_wm.c index 5b5544120a1..eebe595820e 100644 --- a/source/blender/makesrna/intern/rna_wm.c +++ b/source/blender/makesrna/intern/rna_wm.c @@ -99,13 +99,6 @@ static const EnumPropertyItem event_ndof_type_items[] = { {NDOF_BUTTON_DOMINANT, "NDOF_BUTTON_DOMINANT", 0, "Dominant", ""}, {NDOF_BUTTON_PLUS, "NDOF_BUTTON_PLUS", 0, "Plus", ""}, {NDOF_BUTTON_MINUS, "NDOF_BUTTON_MINUS", 0, "Minus", ""}, -# if 0 /* Never used (converted to keyboard events by GHOST). */ - /* keyboard emulation */ - {NDOF_BUTTON_ESC, "NDOF_BUTTON_ESC", 0, "Esc"}, - {NDOF_BUTTON_ALT, "NDOF_BUTTON_ALT", 0, "Alt"}, - {NDOF_BUTTON_SHIFT, "NDOF_BUTTON_SHIFT", 0, "Shift"}, - {NDOF_BUTTON_CTRL, "NDOF_BUTTON_CTRL", 0, "Ctrl"}, -# endif /* general-purpose buttons */ {NDOF_BUTTON_1, "NDOF_BUTTON_1", 0, "Button 1", ""}, {NDOF_BUTTON_2, "NDOF_BUTTON_2", 0, "Button 2", ""}, @@ -120,6 +113,21 @@ static const EnumPropertyItem event_ndof_type_items[] = { {NDOF_BUTTON_A, "NDOF_BUTTON_A", 0, "Button A", ""}, {NDOF_BUTTON_B, "NDOF_BUTTON_B", 0, "Button B", ""}, {NDOF_BUTTON_C, "NDOF_BUTTON_C", 0, "Button C", ""}, + /* View buttons. */ + {NDOF_BUTTON_V1, "NDOF_BUTTON_V1", 0, "View 1", ""}, + {NDOF_BUTTON_V2, "NDOF_BUTTON_V2", 0, "View 2", ""}, + {NDOF_BUTTON_V3, "NDOF_BUTTON_V3", 0, "View 3", ""}, +# if 0 /* Never used (converted to keyboard events by GHOST). */ + /* keyboard emulation */ + {NDOF_BUTTON_ESC, "NDOF_BUTTON_ESC", 0, "Esc"}, + {NDOF_BUTTON_ENTER, "NDOF_BUTTON_ENTER", 0, "Enter"}, + {NDOF_BUTTON_DELETE, "NDOF_BUTTON_DELETE", 0, "Delete"}, + {NDOF_BUTTON_TAB, "NDOF_BUTTON_TAB", 0, "Tab"}, + {NDOF_BUTTON_SPACE, "NDOF_BUTTON_SPACE", 0, "Space"}, + {NDOF_BUTTON_ALT, "NDOF_BUTTON_ALT", 0, "Alt"}, + {NDOF_BUTTON_SHIFT, "NDOF_BUTTON_SHIFT", 0, "Shift"}, + {NDOF_BUTTON_CTRL, "NDOF_BUTTON_CTRL", 0, "Ctrl"}, +# endif {0, NULL, 0, NULL, NULL}, }; #endif /* RNA_RUNTIME */ diff --git a/source/blender/makesrna/intern/rna_xr.c b/source/blender/makesrna/intern/rna_xr.c index dcfa1bbca51..c803e5dc9a8 100644 --- a/source/blender/makesrna/intern/rna_xr.c +++ b/source/blender/makesrna/intern/rna_xr.c @@ -2052,7 +2052,7 @@ static void rna_def_xr_session_settings(BlenderRNA *brna) "Allow the VR tracking origin to be defined independently of the headset location"); RNA_def_property_update(prop, NC_WM | ND_XR_DATA_CHANGED, NULL); - rna_def_object_type_visibility_flags_common(srna, NC_WM | ND_XR_DATA_CHANGED); + rna_def_object_type_visibility_flags_common(srna, NC_WM | ND_XR_DATA_CHANGED, NULL); /* Helper for drawing the icon. */ prop = RNA_def_property(srna, "icon_from_show_object_viewport", PROP_INT, PROP_NONE); diff --git a/source/blender/modifiers/intern/MOD_array.c b/source/blender/modifiers/intern/MOD_array.c index bf534b0d586..2d725af7fe4 100644 --- a/source/blender/modifiers/intern/MOD_array.c +++ b/source/blender/modifiers/intern/MOD_array.c @@ -456,13 +456,13 @@ static Mesh *arrayModifier_doArray(ArrayModifierData *amd, float result_mat[4][4]; if (ctx->object) { - invert_m4_m4(obinv, ctx->object->obmat); + invert_m4_m4(obinv, ctx->object->object_to_world); } else { unit_m4(obinv); } - mul_m4_series(result_mat, offset, obinv, amd->offset_ob->obmat); + mul_m4_series(result_mat, offset, obinv, amd->offset_ob->object_to_world); copy_m4_m4(offset, result_mat); } @@ -474,7 +474,7 @@ static Mesh *arrayModifier_doArray(ArrayModifierData *amd, Object *curve_ob = amd->curve_ob; CurveCache *curve_cache = curve_ob->runtime.curve_cache; if (curve_cache != NULL && curve_cache->anim_path_accum_length != NULL) { - float scale_fac = mat4_to_scale(curve_ob->obmat); + float scale_fac = mat4_to_scale(curve_ob->object_to_world); length = scale_fac * BKE_anim_path_get_length(curve_cache); } } diff --git a/source/blender/modifiers/intern/MOD_boolean.cc b/source/blender/modifiers/intern/MOD_boolean.cc index 7ad49f43e1b..21f05158e8b 100644 --- a/source/blender/modifiers/intern/MOD_boolean.cc +++ b/source/blender/modifiers/intern/MOD_boolean.cc @@ -139,8 +139,8 @@ static Mesh *get_quick_mesh( float imat[4][4]; float omat[4][4]; - invert_m4_m4(imat, ob_self->obmat); - mul_m4_m4m4(omat, imat, ob_operand_ob->obmat); + invert_m4_m4(imat, ob_self->object_to_world); + mul_m4_m4m4(omat, imat, ob_operand_ob->object_to_world); MutableSpan<MVert> verts = result->verts_for_write(); for (const int i : verts.index_range()) { @@ -227,7 +227,8 @@ static BMesh *BMD_mesh_bm_create( SCOPED_TIMER(__func__); #endif - *r_is_flip = (is_negative_m4(object->obmat) != is_negative_m4(operand_ob->obmat)); + *r_is_flip = (is_negative_m4(object->object_to_world) != + is_negative_m4(operand_ob->object_to_world)); const BMAllocTemplate allocsize = BMALLOC_TEMPLATE_FROM_ME(mesh, mesh_operand_ob); @@ -294,8 +295,8 @@ static void BMD_mesh_intersection(BMesh *bm, float imat[4][4]; float omat[4][4]; - invert_m4_m4(imat, object->obmat); - mul_m4_m4m4(omat, imat, operand_ob->obmat); + invert_m4_m4(imat, object->object_to_world); + mul_m4_m4m4(omat, imat, operand_ob->object_to_world); BMVert *eve; i = 0; @@ -414,7 +415,7 @@ static Mesh *exact_boolean_mesh(BooleanModifierData *bmd, } meshes.append(mesh); - obmats.append((float4x4 *)&ctx->object->obmat); + obmats.append((float4x4 *)&ctx->object->object_to_world); material_remaps.append({}); if (mesh->totcol == 0) { /* Necessary for faces using the default material when there are no material slots. */ @@ -431,7 +432,7 @@ static Mesh *exact_boolean_mesh(BooleanModifierData *bmd, } BKE_mesh_wrapper_ensure_mdata(mesh_operand); meshes.append(mesh_operand); - obmats.append((float4x4 *)&bmd->object->obmat); + obmats.append((float4x4 *)&bmd->object->object_to_world); material_remaps.append(get_material_remap(*bmd->object, *mesh_operand, materials)); } else if (bmd->flag & eBooleanModifierFlag_Collection) { @@ -446,7 +447,7 @@ static Mesh *exact_boolean_mesh(BooleanModifierData *bmd, } BKE_mesh_wrapper_ensure_mdata(collection_mesh); meshes.append(collection_mesh); - obmats.append((float4x4 *)&ob->obmat); + obmats.append((float4x4 *)&ob->object_to_world); material_remaps.append(get_material_remap(*ob, *collection_mesh, materials)); } } @@ -456,14 +457,15 @@ static Mesh *exact_boolean_mesh(BooleanModifierData *bmd, const bool use_self = (bmd->flag & eBooleanModifierFlag_Self) != 0; const bool hole_tolerant = (bmd->flag & eBooleanModifierFlag_HoleTolerant) != 0; - Mesh *result = blender::meshintersect::direct_mesh_boolean(meshes, - obmats, - *(float4x4 *)&ctx->object->obmat, - material_remaps, - use_self, - hole_tolerant, - bmd->operation, - nullptr); + Mesh *result = blender::meshintersect::direct_mesh_boolean( + meshes, + obmats, + *(float4x4 *)&ctx->object->object_to_world, + material_remaps, + use_self, + hole_tolerant, + bmd->operation, + nullptr); MEM_SAFE_FREE(result->mat); result->mat = (Material **)MEM_malloc_arrayN(materials.size(), sizeof(Material *), __func__); result->totcol = materials.size(); diff --git a/source/blender/modifiers/intern/MOD_cast.c b/source/blender/modifiers/intern/MOD_cast.c index 30be1d33653..7581b2aa8e5 100644 --- a/source/blender/modifiers/intern/MOD_cast.c +++ b/source/blender/modifiers/intern/MOD_cast.c @@ -126,13 +126,13 @@ static void sphere_do(CastModifierData *cmd, * we use its location, transformed to ob's local space */ if (ctrl_ob) { if (flag & MOD_CAST_USE_OB_TRANSFORM) { - invert_m4_m4(imat, ctrl_ob->obmat); - mul_m4_m4m4(mat, imat, ob->obmat); + invert_m4_m4(imat, ctrl_ob->object_to_world); + mul_m4_m4m4(mat, imat, ob->object_to_world); invert_m4_m4(imat, mat); } - invert_m4_m4(ob->imat, ob->obmat); - mul_v3_m4v3(center, ob->imat, ctrl_ob->obmat[3]); + invert_m4_m4(ob->imat, ob->object_to_world); + mul_v3_m4v3(center, ob->imat, ctrl_ob->object_to_world[3]); } /* now we check which options the user wants */ @@ -275,13 +275,13 @@ static void cuboid_do(CastModifierData *cmd, if (ctrl_ob) { if (flag & MOD_CAST_USE_OB_TRANSFORM) { - invert_m4_m4(imat, ctrl_ob->obmat); - mul_m4_m4m4(mat, imat, ob->obmat); + invert_m4_m4(imat, ctrl_ob->object_to_world); + mul_m4_m4m4(mat, imat, ob->object_to_world); invert_m4_m4(imat, mat); } - invert_m4_m4(ob->imat, ob->obmat); - mul_v3_m4v3(center, ob->imat, ctrl_ob->obmat[3]); + invert_m4_m4(ob->imat, ob->object_to_world); + mul_v3_m4v3(center, ob->imat, ctrl_ob->object_to_world[3]); } if ((flag & MOD_CAST_SIZE_FROM_RADIUS) && has_radius) { diff --git a/source/blender/modifiers/intern/MOD_collision.c b/source/blender/modifiers/intern/MOD_collision.c index e38bf96500e..82faf08b349 100644 --- a/source/blender/modifiers/intern/MOD_collision.c +++ b/source/blender/modifiers/intern/MOD_collision.c @@ -149,7 +149,7 @@ static void deformVerts(ModifierData *md, for (uint i = 0; i < mvert_num; i++) { /* we save global positions */ - mul_m4_v3(ob->obmat, collmd->x[i].co); + mul_m4_v3(ob->object_to_world, collmd->x[i].co); } collmd->xnew = MEM_dupallocN(collmd->x); /* Frame end position. */ @@ -188,7 +188,7 @@ static void deformVerts(ModifierData *md, for (uint i = 0; i < mvert_num; i++) { /* we save global positions */ - mul_m4_v3(ob->obmat, collmd->xnew[i].co); + mul_m4_v3(ob->object_to_world, collmd->xnew[i].co); /* detect motion */ is_static = is_static && equals_v3v3(collmd->x[i].co, collmd->xnew[i].co); diff --git a/source/blender/modifiers/intern/MOD_displace.c b/source/blender/modifiers/intern/MOD_displace.c index ad5be57ad68..fc12a9c2aad 100644 --- a/source/blender/modifiers/intern/MOD_displace.c +++ b/source/blender/modifiers/intern/MOD_displace.c @@ -322,7 +322,7 @@ static void displaceModifier_do(DisplaceModifierData *dmd, } else if (ELEM(direction, MOD_DISP_DIR_X, MOD_DISP_DIR_Y, MOD_DISP_DIR_Z, MOD_DISP_DIR_RGB_XYZ) && use_global_direction) { - copy_m4_m4(local_mat, ob->obmat); + copy_m4_m4(local_mat, ob->object_to_world); } DisplaceUserdata data = {NULL}; diff --git a/source/blender/modifiers/intern/MOD_explode.c b/source/blender/modifiers/intern/MOD_explode.c index af167bf9b32..96bf836fa4a 100644 --- a/source/blender/modifiers/intern/MOD_explode.c +++ b/source/blender/modifiers/intern/MOD_explode.c @@ -985,7 +985,7 @@ static Mesh *explodeMesh(ExplodeModifierData *emd, MTFace *mtface = CustomData_get_layer_named(&explode->fdata, CD_MTFACE, emd->uvname); /* getting back to object space */ - invert_m4_m4(imat, ctx->object->obmat); + invert_m4_m4(imat, ctx->object->object_to_world); psmd->psys->lattice_deform_data = psys_create_lattice_deform_data(&sim); @@ -1020,7 +1020,7 @@ static Mesh *explodeMesh(ExplodeModifierData *emd, psys_get_particle_state(&sim, ed_v2, &state, 1); vertco = explode_verts[v].co; - mul_m4_v3(ctx->object->obmat, vertco); + mul_m4_v3(ctx->object->object_to_world, vertco); sub_v3_v3(vertco, birth.co); diff --git a/source/blender/modifiers/intern/MOD_hook.c b/source/blender/modifiers/intern/MOD_hook.c index 11bc9ee9574..6cf2e1538e9 100644 --- a/source/blender/modifiers/intern/MOD_hook.c +++ b/source/blender/modifiers/intern/MOD_hook.c @@ -338,13 +338,13 @@ static void deformVerts_do(HookModifierData *hmd, /* get world-space matrix of target, corrected for the space the verts are in */ if (hmd->subtarget[0] && pchan) { /* bone target if there's a matching pose-channel */ - mul_m4_m4m4(dmat, ob_target->obmat, pchan->pose_mat); + mul_m4_m4m4(dmat, ob_target->object_to_world, pchan->pose_mat); } else { /* just object target */ - copy_m4_m4(dmat, ob_target->obmat); + copy_m4_m4(dmat, ob_target->object_to_world); } - invert_m4_m4(ob->imat, ob->obmat); + invert_m4_m4(ob->imat, ob->object_to_world); mul_m4_series(hd.mat, ob->imat, dmat, hmd->parentinv); /* --- done with 'hd' init --- */ diff --git a/source/blender/modifiers/intern/MOD_mesh_to_volume.cc b/source/blender/modifiers/intern/MOD_mesh_to_volume.cc index cad9fdfe30d..778f12d6745 100644 --- a/source/blender/modifiers/intern/MOD_mesh_to_volume.cc +++ b/source/blender/modifiers/intern/MOD_mesh_to_volume.cc @@ -135,7 +135,7 @@ static Volume *mesh_to_volume(ModifierData *md, BKE_mesh_wrapper_ensure_mdata(mesh); const float4x4 mesh_to_own_object_space_transform = float4x4(ctx->object->imat) * - float4x4(object_to_convert->obmat); + float4x4(object_to_convert->object_to_world); geometry::MeshToVolumeResolution resolution; resolution.mode = (MeshToVolumeModifierResolutionMode)mvmd->resolution_mode; if (resolution.mode == MESH_TO_VOLUME_RESOLUTION_MODE_VOXEL_AMOUNT) { diff --git a/source/blender/modifiers/intern/MOD_meshdeform.c b/source/blender/modifiers/intern/MOD_meshdeform.c index d7ed346a61f..2aaaee2ccc7 100644 --- a/source/blender/modifiers/intern/MOD_meshdeform.c +++ b/source/blender/modifiers/intern/MOD_meshdeform.c @@ -358,8 +358,8 @@ static void meshdeformModifier_do(ModifierData *md, } /* compute matrices to go in and out of cage object space */ - invert_m4_m4(imat, ob_target->obmat); - mul_m4_m4m4(cagemat, imat, ob->obmat); + invert_m4_m4(imat, ob_target->object_to_world); + mul_m4_m4m4(cagemat, imat, ob->object_to_world); mul_m4_m4m4(cmat, mmd->bindmat, cagemat); invert_m4_m4(iobmat, cmat); copy_m3_m4(icagemat, iobmat); diff --git a/source/blender/modifiers/intern/MOD_normal_edit.cc b/source/blender/modifiers/intern/MOD_normal_edit.cc index 43ded18fcc4..7d422826cf8 100644 --- a/source/blender/modifiers/intern/MOD_normal_edit.cc +++ b/source/blender/modifiers/intern/MOD_normal_edit.cc @@ -94,8 +94,8 @@ static void generate_vert_coordinates(Mesh *mesh, /* Translate our coordinates so that center of ob_center is at (0, 0, 0). */ /* Get ob_center (world) coordinates in ob local coordinates. * No need to take into account ob_center's space here, see T44027. */ - invert_m4_m4(inv_obmat, ob->obmat); - mul_v3_m4v3(diff, inv_obmat, ob_center->obmat[3]); + invert_m4_m4(inv_obmat, ob->object_to_world); + mul_v3_m4v3(diff, inv_obmat, ob_center->object_to_world[3]); negate_v3(diff); do_diff = true; @@ -383,8 +383,8 @@ static void normalEditModifier_do_directional(NormalEditModifierData *enmd, /* Get target's center coordinates in ob local coordinates. */ float mat[4][4]; - invert_m4_m4(mat, ob->obmat); - mul_m4_m4m4(mat, mat, ob_target->obmat); + invert_m4_m4(mat, ob->object_to_world); + mul_m4_m4m4(mat, mat, ob_target->object_to_world); copy_v3_v3(target_co, mat[3]); if (use_parallel_normals) { diff --git a/source/blender/modifiers/intern/MOD_particleinstance.c b/source/blender/modifiers/intern/MOD_particleinstance.c index aab48101351..f65f8bc4fb3 100644 --- a/source/blender/modifiers/intern/MOD_particleinstance.c +++ b/source/blender/modifiers/intern/MOD_particleinstance.c @@ -273,7 +273,7 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh * break; case eParticleInstanceSpace_Local: /* get particle states in the particle object's local space */ - invert_m4_m4(spacemat, pimd->ob->obmat); + invert_m4_m4(spacemat, pimd->ob->object_to_world); break; default: /* should not happen */ diff --git a/source/blender/modifiers/intern/MOD_screw.c b/source/blender/modifiers/intern/MOD_screw.c index 91f8947bbc3..afd7f5a2e48 100644 --- a/source/blender/modifiers/intern/MOD_screw.c +++ b/source/blender/modifiers/intern/MOD_screw.c @@ -274,8 +274,8 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh * if (ob_axis != NULL) { /* Calculate the matrix relative to the axis object. */ - invert_m4_m4(mtx_tmp_a, ctx->object->obmat); - copy_m4_m4(mtx_tx_inv, ob_axis->obmat); + invert_m4_m4(mtx_tmp_a, ctx->object->object_to_world); + copy_m4_m4(mtx_tx_inv, ob_axis->object_to_world); mul_m4_m4m4(mtx_tx, mtx_tmp_a, mtx_tx_inv); /* Calculate the axis vector. */ diff --git a/source/blender/modifiers/intern/MOD_surface.c b/source/blender/modifiers/intern/MOD_surface.c index c5e117635b5..a34d66f394b 100644 --- a/source/blender/modifiers/intern/MOD_surface.c +++ b/source/blender/modifiers/intern/MOD_surface.c @@ -154,7 +154,7 @@ static void deformVerts(ModifierData *md, MVert *verts = BKE_mesh_verts_for_write(surmd->mesh); for (i = 0, x = surmd->x, v = surmd->v; i < mesh_verts_num; i++, x++, v++) { float *vec = verts[i].co; - mul_m4_v3(ctx->object->obmat, vec); + mul_m4_v3(ctx->object->object_to_world, vec); if (init) { v->co[0] = v->co[1] = v->co[2] = 0.0f; diff --git a/source/blender/modifiers/intern/MOD_surfacedeform.c b/source/blender/modifiers/intern/MOD_surfacedeform.c index 53bfdc35b31..6a9321a78a2 100644 --- a/source/blender/modifiers/intern/MOD_surfacedeform.c +++ b/source/blender/modifiers/intern/MOD_surfacedeform.c @@ -1466,8 +1466,8 @@ static void surfacedeformModifier_do(ModifierData *md, ob, md); float tmp_mat[4][4]; - invert_m4_m4(tmp_mat, ob->obmat); - mul_m4_m4m4(smd_orig->mat, tmp_mat, ob_target->obmat); + invert_m4_m4(tmp_mat, ob->object_to_world); + mul_m4_m4m4(smd_orig->mat, tmp_mat, ob_target->object_to_world); /* Avoid converting edit-mesh data, binding is an exception. */ BKE_mesh_wrapper_ensure_mdata(target); diff --git a/source/blender/modifiers/intern/MOD_util.cc b/source/blender/modifiers/intern/MOD_util.cc index 589a3d28ad9..a94fc6732a0 100644 --- a/source/blender/modifiers/intern/MOD_util.cc +++ b/source/blender/modifiers/intern/MOD_util.cc @@ -75,15 +75,15 @@ void MOD_get_texture_coords(MappingInfoModifierData *dmd, bPoseChannel *pchan = BKE_pose_channel_find_name(map_object->pose, dmd->map_bone); if (pchan) { float mat_bone_world[4][4]; - mul_m4_m4m4(mat_bone_world, map_object->obmat, pchan->pose_mat); + mul_m4_m4m4(mat_bone_world, map_object->object_to_world, pchan->pose_mat); invert_m4_m4(mapref_imat, mat_bone_world); } else { - invert_m4_m4(mapref_imat, map_object->obmat); + invert_m4_m4(mapref_imat, map_object->object_to_world); } } else { - invert_m4_m4(mapref_imat, map_object->obmat); + invert_m4_m4(mapref_imat, map_object->object_to_world); } } else { /* if there is no map object, default to local */ @@ -138,10 +138,10 @@ void MOD_get_texture_coords(MappingInfoModifierData *dmd, copy_v3_v3(*r_texco, cos != nullptr ? *cos : mv->co); break; case MOD_DISP_MAP_GLOBAL: - mul_v3_m4v3(*r_texco, ob->obmat, cos != nullptr ? *cos : mv->co); + mul_v3_m4v3(*r_texco, ob->object_to_world, cos != nullptr ? *cos : mv->co); break; case MOD_DISP_MAP_OBJECT: - mul_v3_m4v3(*r_texco, ob->obmat, cos != nullptr ? *cos : mv->co); + mul_v3_m4v3(*r_texco, ob->object_to_world, cos != nullptr ? *cos : mv->co); mul_m4_v3(mapref_imat, *r_texco); break; } diff --git a/source/blender/modifiers/intern/MOD_uvproject.cc b/source/blender/modifiers/intern/MOD_uvproject.cc index c07b2059b5b..895572d9477 100644 --- a/source/blender/modifiers/intern/MOD_uvproject.cc +++ b/source/blender/modifiers/intern/MOD_uvproject.cc @@ -132,7 +132,7 @@ static Mesh *uvprojectModifier_do(UVProjectModifierData *umd, float offsetmat[4][4]; Camera *cam = nullptr; /* calculate projection matrix */ - invert_m4_m4(projectors[i].projmat, projectors[i].ob->obmat); + invert_m4_m4(projectors[i].projmat, projectors[i].ob->object_to_world); projectors[i].uci = nullptr; @@ -178,7 +178,7 @@ static Mesh *uvprojectModifier_do(UVProjectModifierData *umd, projectors[i].normal[0] = 0; projectors[i].normal[1] = 0; projectors[i].normal[2] = 1; - mul_mat3_m4_v3(projectors[i].ob->obmat, projectors[i].normal); + mul_mat3_m4_v3(projectors[i].ob->object_to_world, projectors[i].normal); } polys_num = mesh->totpoly; @@ -192,7 +192,7 @@ static Mesh *uvprojectModifier_do(UVProjectModifierData *umd, /* Convert coords to world-space. */ for (i = 0, co = coords; i < verts_num; i++, co++) { - mul_m4_v3(ob->obmat, *co); + mul_m4_v3(ob->object_to_world, *co); } /* if only one projector, project coords to UVs */ diff --git a/source/blender/modifiers/intern/MOD_uvwarp.cc b/source/blender/modifiers/intern/MOD_uvwarp.cc index 4ec273bcbc6..a96b28b4e2e 100644 --- a/source/blender/modifiers/intern/MOD_uvwarp.cc +++ b/source/blender/modifiers/intern/MOD_uvwarp.cc @@ -72,10 +72,10 @@ static void matrix_from_obj_pchan(float mat[4][4], Object *ob, const char *bonen { bPoseChannel *pchan = BKE_pose_channel_find_name(ob->pose, bonename); if (pchan) { - mul_m4_m4m4(mat, ob->obmat, pchan->pose_mat); + mul_m4_m4m4(mat, ob->object_to_world, pchan->pose_mat); } else { - copy_m4_m4(mat, ob->obmat); + copy_m4_m4(mat, ob->object_to_world); } } diff --git a/source/blender/modifiers/intern/MOD_volume_displace.cc b/source/blender/modifiers/intern/MOD_volume_displace.cc index e66793d7cce..fbd5f27f69a 100644 --- a/source/blender/modifiers/intern/MOD_volume_displace.cc +++ b/source/blender/modifiers/intern/MOD_volume_displace.cc @@ -254,14 +254,14 @@ struct DisplaceGridOp { return index_to_object; } case MOD_VOLUME_DISPLACE_MAP_GLOBAL: { - const openvdb::Mat4s object_to_world = matrix_to_openvdb(ctx.object->obmat); + const openvdb::Mat4s object_to_world = matrix_to_openvdb(ctx.object->object_to_world); return index_to_object * object_to_world; } case MOD_VOLUME_DISPLACE_MAP_OBJECT: { if (vdmd.texture_map_object == nullptr) { return index_to_object; } - const openvdb::Mat4s object_to_world = matrix_to_openvdb(ctx.object->obmat); + const openvdb::Mat4s object_to_world = matrix_to_openvdb(ctx.object->object_to_world); const openvdb::Mat4s world_to_texture = matrix_to_openvdb(vdmd.texture_map_object->imat); return index_to_object * object_to_world * world_to_texture; } diff --git a/source/blender/modifiers/intern/MOD_volume_to_mesh.cc b/source/blender/modifiers/intern/MOD_volume_to_mesh.cc index 35fd5a4af42..b4ac23b5c61 100644 --- a/source/blender/modifiers/intern/MOD_volume_to_mesh.cc +++ b/source/blender/modifiers/intern/MOD_volume_to_mesh.cc @@ -157,7 +157,7 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh * volume_grid); openvdb::math::Transform::Ptr transform = local_grid->transform().copy(); - transform->postMult(openvdb::Mat4d((float *)vmmd->object->obmat)); + transform->postMult(openvdb::Mat4d((float *)vmmd->object->object_to_world)); openvdb::Mat4d imat = openvdb::Mat4d((float *)ctx->object->imat); /* `imat` had floating point issues and wasn't affine. */ imat.setCol(3, openvdb::Vec4d(0, 0, 0, 1)); diff --git a/source/blender/modifiers/intern/MOD_warp.c b/source/blender/modifiers/intern/MOD_warp.c index 3fafbd97fee..791eed28a71 100644 --- a/source/blender/modifiers/intern/MOD_warp.c +++ b/source/blender/modifiers/intern/MOD_warp.c @@ -93,11 +93,11 @@ static void matrix_from_obj_pchan(float mat[4][4], bPoseChannel *pchan = BKE_pose_channel_find_name(ob->pose, bonename); if (pchan) { float mat_bone_world[4][4]; - mul_m4_m4m4(mat_bone_world, ob->obmat, pchan->pose_mat); + mul_m4_m4m4(mat_bone_world, ob->object_to_world, pchan->pose_mat); mul_m4_m4m4(mat, obinv, mat_bone_world); } else { - mul_m4_m4m4(mat, obinv, ob->obmat); + mul_m4_m4m4(mat, obinv, ob->object_to_world); } } @@ -215,7 +215,7 @@ static void warpModifier_do(WarpModifierData *wmd, BKE_curvemapping_init(wmd->curfalloff); } - invert_m4_m4(obinv, ob->obmat); + invert_m4_m4(obinv, ob->object_to_world); /* Checks that the objects/bones are available. */ matrix_from_obj_pchan(mat_from, obinv, wmd->object_from, wmd->bone_from); diff --git a/source/blender/modifiers/intern/MOD_wave.cc b/source/blender/modifiers/intern/MOD_wave.cc index 647e0324707..1489927ba34 100644 --- a/source/blender/modifiers/intern/MOD_wave.cc +++ b/source/blender/modifiers/intern/MOD_wave.cc @@ -152,8 +152,8 @@ static void waveModifier_do(WaveModifierData *md, if (wmd->objectcenter != nullptr) { float mat[4][4]; /* get the control object's location in local coordinates */ - invert_m4_m4(ob->imat, ob->obmat); - mul_m4_m4m4(mat, ob->imat, wmd->objectcenter->obmat); + invert_m4_m4(ob->imat, ob->object_to_world); + mul_m4_m4m4(mat, ob->imat, wmd->objectcenter->object_to_world); wmd->startx = mat[3][0]; wmd->starty = mat[3][1]; diff --git a/source/blender/modifiers/intern/MOD_weightvgproximity.cc b/source/blender/modifiers/intern/MOD_weightvgproximity.cc index 93052f4215d..e4e03a2cbc9 100644 --- a/source/blender/modifiers/intern/MOD_weightvgproximity.cc +++ b/source/blender/modifiers/intern/MOD_weightvgproximity.cc @@ -223,9 +223,9 @@ static void get_vert2ob_distance( while (i-- > 0) { /* Get world-coordinates of the vertex (constraints and anim included). */ - mul_v3_m4v3(v_wco, ob->obmat, v_cos[i]); + mul_v3_m4v3(v_wco, ob->object_to_world, v_cos[i]); /* Return distance between both coordinates. */ - dist[i] = len_v3v3(v_wco, obr->obmat[3]); + dist[i] = len_v3v3(v_wco, obr->object_to_world[3]); } } @@ -235,7 +235,7 @@ static void get_vert2ob_distance( */ static float get_ob2ob_distance(const Object *ob, const Object *obr) { - return len_v3v3(ob->obmat[3], obr->obmat[3]); + return len_v3v3(ob->object_to_world[3], obr->object_to_world[3]); } /** diff --git a/source/blender/nodes/composite/nodes/node_composite_normalize.cc b/source/blender/nodes/composite/nodes/node_composite_normalize.cc index 21765825468..34fd63e5805 100644 --- a/source/blender/nodes/composite/nodes/node_composite_normalize.cc +++ b/source/blender/nodes/composite/nodes/node_composite_normalize.cc @@ -5,7 +5,9 @@ * \ingroup cmpnodes */ +#include "COM_algorithm_parallel_reduction.hh" #include "COM_node_operation.hh" +#include "COM_utilities.hh" #include "node_composite_util.hh" @@ -15,19 +17,60 @@ namespace blender::nodes::node_composite_normalize_cc { static void cmp_node_normalize_declare(NodeDeclarationBuilder &b) { - b.add_input<decl::Float>(N_("Value")).default_value(1.0f).min(0.0f).max(1.0f); + b.add_input<decl::Float>(N_("Value")) + .default_value(1.0f) + .min(0.0f) + .max(1.0f) + .compositor_domain_priority(0); b.add_output<decl::Float>(N_("Value")); } using namespace blender::realtime_compositor; class NormalizeOperation : public NodeOperation { + private: + /* The normalize operation is specifically designed to normalize Z Depth information. But since Z + * Depth can contain near infinite values, normalization is limited to [-range_, range], meaning + * that values outside of that range will be ignored when computing the maximum and minimum for + * normalization and will eventually be 0 or 1 if they are less than or larger than the range + * respectively. */ + constexpr static float range_ = 10000.0f; + public: using NodeOperation::NodeOperation; void execute() override { - get_input("Value").pass_through(get_result("Value")); + Result &input_image = get_input("Value"); + Result &output_image = get_result("Value"); + if (input_image.is_single_value()) { + input_image.pass_through(output_image); + return; + } + + const float maximum = maximum_float_in_range( + context(), input_image.texture(), -range_, range_); + const float minimum = minimum_float_in_range( + context(), input_image.texture(), -range_, range_); + const float scale = (maximum != minimum) ? (1.0f / (maximum - minimum)) : 0.0f; + + GPUShader *shader = shader_manager().get("compositor_normalize"); + GPU_shader_bind(shader); + + GPU_shader_uniform_1f(shader, "minimum", minimum); + GPU_shader_uniform_1f(shader, "scale", scale); + + input_image.bind_as_texture(shader, "input_tx"); + + const Domain domain = compute_domain(); + output_image.allocate_texture(domain); + output_image.bind_as_image(shader, "output_img"); + + compute_dispatch_threads_at_least(shader, domain.size); + + GPU_shader_unbind(); + output_image.unbind_as_image(); + input_image.unbind_as_texture(); } }; diff --git a/source/blender/nodes/composite/nodes/node_composite_tonemap.cc b/source/blender/nodes/composite/nodes/node_composite_tonemap.cc index 2e06ad99df1..d26a01bb3c9 100644 --- a/source/blender/nodes/composite/nodes/node_composite_tonemap.cc +++ b/source/blender/nodes/composite/nodes/node_composite_tonemap.cc @@ -5,20 +5,35 @@ * \ingroup cmpnodes */ +#include <cmath> + +#include "BLI_assert.h" +#include "BLI_math_base.hh" +#include "BLI_math_vec_types.hh" +#include "BLI_math_vector.hh" + #include "RNA_access.h" #include "UI_interface.h" #include "UI_resources.h" +#include "IMB_colormanagement.h" + +#include "COM_algorithm_parallel_reduction.hh" #include "COM_node_operation.hh" +#include "COM_utilities.hh" #include "node_composite_util.hh" namespace blender::nodes::node_composite_tonemap_cc { +NODE_STORAGE_FUNCS(NodeTonemap) + static void cmp_node_tonemap_declare(NodeDeclarationBuilder &b) { - b.add_input<decl::Color>(N_("Image")).default_value({1.0f, 1.0f, 1.0f, 1.0f}); + b.add_input<decl::Color>(N_("Image")) + .default_value({1.0f, 1.0f, 1.0f, 1.0f}) + .compositor_domain_priority(0); b.add_output<decl::Color>(N_("Image")); } @@ -68,7 +83,236 @@ class ToneMapOperation : public NodeOperation { void execute() override { - get_input("Image").pass_through(get_result("Image")); + Result &input_image = get_input("Image"); + Result &output_image = get_result("Image"); + if (input_image.is_single_value()) { + input_image.pass_through(output_image); + return; + } + + switch (get_type()) { + case CMP_NODE_TONE_MAP_SIMPLE: + execute_simple(); + return; + case CMP_NODE_TONE_MAP_PHOTORECEPTOR: + execute_photoreceptor(); + return; + default: + BLI_assert_unreachable(); + return; + } + } + + /* Tone mapping based on equation (3) from Reinhard, Erik, et al. "Photographic tone reproduction + * for digital images." Proceedings of the 29th annual conference on Computer graphics and + * interactive techniques. 2002. */ + void execute_simple() + { + const float luminance_scale = compute_luminance_scale(); + const float luminance_scale_blend_factor = compute_luminance_scale_blend_factor(); + const float gamma = node_storage(bnode()).gamma; + const float inverse_gamma = gamma != 0.0f ? 1.0f / gamma : 0.0f; + + GPUShader *shader = shader_manager().get("compositor_tone_map_simple"); + GPU_shader_bind(shader); + + GPU_shader_uniform_1f(shader, "luminance_scale", luminance_scale); + GPU_shader_uniform_1f(shader, "luminance_scale_blend_factor", luminance_scale_blend_factor); + GPU_shader_uniform_1f(shader, "inverse_gamma", inverse_gamma); + + const Result &input_image = get_input("Image"); + input_image.bind_as_texture(shader, "input_tx"); + + const Domain domain = compute_domain(); + Result &output_image = get_result("Image"); + output_image.allocate_texture(domain); + output_image.bind_as_image(shader, "output_img"); + + compute_dispatch_threads_at_least(shader, domain.size); + + GPU_shader_unbind(); + output_image.unbind_as_image(); + input_image.unbind_as_texture(); + } + + /* Computes the scaling factor in equation (2) from Reinhard's 2002 paper. */ + float compute_luminance_scale() + { + const float geometric_mean = compute_geometric_mean_of_luminance(); + return geometric_mean != 0.0 ? node_storage(bnode()).key / geometric_mean : 0.0f; + } + + /* Computes equation (1) from Reinhard's 2002 paper. However, note that the equation in the paper + * is most likely wrong, and the intention is actually to compute the geometric mean through a + * logscale arithmetic mean, that is, the division should happen inside the exponential function, + * not outside of it. That's because the sum of the log luminance will be a very large negative + * number, whose exponential will almost always be zero, which is unexpected and useless. */ + float compute_geometric_mean_of_luminance() + { + return std::exp(compute_average_log_luminance()); + } + + /* Equation (3) from Reinhard's 2002 paper blends between high luminance scaling for high + * luminance values and low luminance scaling for low luminance values. This is done by adding 1 + * to the denominator, since for low luminance values, the denominator will be close to 1 and for + * high luminance values, the 1 in the denominator will be relatively insignificant. But the + * response of such function is not always ideal, so in this implementation, the 1 was exposed as + * a parameter to the user for more flexibility. */ + float compute_luminance_scale_blend_factor() + { + return node_storage(bnode()).offset; + } + + /* Tone mapping based on equation (1) and the trilinear interpolation between equations (6) and + * (7) from Reinhard, Erik, and Kate Devlin. "Dynamic range reduction inspired by photoreceptor + * physiology." IEEE transactions on visualization and computer graphics 11.1 (2005): 13-24. */ + void execute_photoreceptor() + { + const float4 global_adaptation_level = compute_global_adaptation_level(); + const float contrast = compute_contrast(); + const float intensity = compute_intensity(); + const float chromatic_adaptation = get_chromatic_adaptation(); + const float light_adaptation = get_light_adaptation(); + + GPUShader *shader = shader_manager().get("compositor_tone_map_photoreceptor"); + GPU_shader_bind(shader); + + GPU_shader_uniform_4fv(shader, "global_adaptation_level", global_adaptation_level); + GPU_shader_uniform_1f(shader, "contrast", contrast); + GPU_shader_uniform_1f(shader, "intensity", intensity); + GPU_shader_uniform_1f(shader, "chromatic_adaptation", chromatic_adaptation); + GPU_shader_uniform_1f(shader, "light_adaptation", light_adaptation); + + float luminance_coefficients[3]; + IMB_colormanagement_get_luminance_coefficients(luminance_coefficients); + GPU_shader_uniform_3fv(shader, "luminance_coefficients", luminance_coefficients); + + const Result &input_image = get_input("Image"); + input_image.bind_as_texture(shader, "input_tx"); + + const Domain domain = compute_domain(); + Result &output_image = get_result("Image"); + output_image.allocate_texture(domain); + output_image.bind_as_image(shader, "output_img"); + + compute_dispatch_threads_at_least(shader, domain.size); + + GPU_shader_unbind(); + output_image.unbind_as_image(); + input_image.unbind_as_texture(); + } + + /* Computes the global adaptation level from the trilinear interpolation equations constructed + * from equations (6) and (7) in Reinhard's 2005 paper. */ + float4 compute_global_adaptation_level() + { + const float4 average_color = compute_average_color(); + const float average_luminance = compute_average_luminance(); + const float chromatic_adaptation = get_chromatic_adaptation(); + return math::interpolate(float4(average_luminance), average_color, chromatic_adaptation); + } + + float4 compute_average_color() + { + /* The average color will reduce to zero if chromatic adaptation is zero, so just return zero + * in this case to avoid needlessly computing the average. See the trilinear interpolation + * equations constructed from equations (6) and (7) in Reinhard's 2005 paper. */ + if (get_chromatic_adaptation() == 0.0f) { + return float4(0.0f); + } + + const Result &input = get_input("Image"); + return sum_color(context(), input.texture()) / (input.domain().size.x * input.domain().size.y); + } + + float compute_average_luminance() + { + /* The average luminance will reduce to zero if chromatic adaptation is one, so just return + * zero in this case to avoid needlessly computing the average. See the trilinear interpolation + * equations constructed from equations (6) and (7) in Reinhard's 2005 paper. */ + if (get_chromatic_adaptation() == 1.0f) { + return 0.0f; + } + + float luminance_coefficients[3]; + IMB_colormanagement_get_luminance_coefficients(luminance_coefficients); + const Result &input = get_input("Image"); + float sum = sum_luminance(context(), input.texture(), luminance_coefficients); + return sum / (input.domain().size.x * input.domain().size.y); + } + + /* Computes equation (5) from Reinhard's 2005 paper. */ + float compute_intensity() + { + return std::exp(-node_storage(bnode()).f); + } + + /* If the contrast is not zero, return it, otherwise, a zero contrast denote automatic derivation + * of the contrast value based on equations (2) and (4) from Reinhard's 2005 paper. */ + float compute_contrast() + { + if (node_storage(bnode()).m != 0.0f) { + return node_storage(bnode()).m; + } + + const float log_maximum_luminance = compute_log_maximum_luminance(); + const float log_minimum_luminance = compute_log_minimum_luminance(); + + /* This is merely to guard against zero division later. */ + if (log_maximum_luminance == log_minimum_luminance) { + return 1.0f; + } + + const float average_log_luminance = compute_average_log_luminance(); + const float dynamic_range = log_maximum_luminance - log_minimum_luminance; + const float luminance_key = (log_maximum_luminance - average_log_luminance) / (dynamic_range); + + return 0.3f + 0.7f * std::pow(luminance_key, 1.4f); + } + + float compute_average_log_luminance() + { + const Result &input_image = get_input("Image"); + + float luminance_coefficients[3]; + IMB_colormanagement_get_luminance_coefficients(luminance_coefficients); + const float sum_of_log_luminance = sum_log_luminance( + context(), input_image.texture(), luminance_coefficients); + + return sum_of_log_luminance / (input_image.domain().size.x * input_image.domain().size.y); + } + + float compute_log_maximum_luminance() + { + float luminance_coefficients[3]; + IMB_colormanagement_get_luminance_coefficients(luminance_coefficients); + const float maximum = maximum_luminance( + context(), get_input("Image").texture(), luminance_coefficients); + return std::log(math::max(maximum, 1e-5f)); + } + + float compute_log_minimum_luminance() + { + float luminance_coefficients[3]; + IMB_colormanagement_get_luminance_coefficients(luminance_coefficients); + const float minimum = minimum_luminance( + context(), get_input("Image").texture(), luminance_coefficients); + return std::log(math::max(minimum, 1e-5f)); + } + + float get_chromatic_adaptation() + { + return node_storage(bnode()).c; + } + + float get_light_adaptation() + { + return node_storage(bnode()).a; + } + + CMPNodeToneMapType get_type() + { + return static_cast<CMPNodeToneMapType>(node_storage(bnode()).type); } }; 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 c4bee09e07b..51393ed8709 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_collection_info.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_collection_info.cc @@ -8,6 +8,7 @@ #include "UI_resources.h" #include "BKE_collection.h" +#include "BKE_instances.hh" #include "node_geometry_util.hh" @@ -69,8 +70,7 @@ static void node_geo_exec(GeoNodeExecParams params) const bool use_relative_transform = (storage.transform_space == GEO_NODE_TRANSFORM_SPACE_RELATIVE); - GeometrySet geometry_set_out; - InstancesComponent &instances = geometry_set_out.get_component_for_write<InstancesComponent>(); + std::unique_ptr<bke::Instances> instances = std::make_unique<bke::Instances>(); const bool separate_children = params.get_input<bool>("Separate Children"); if (separate_children) { @@ -84,7 +84,7 @@ static void node_geo_exec(GeoNodeExecParams params) children_objects.append(collection_object->ob); } - instances.reserve(children_collections.size() + children_objects.size()); + instances->reserve(children_collections.size() + children_objects.size()); Vector<InstanceListEntry> entries; entries.reserve(children_collections.size() + children_objects.size()); @@ -99,11 +99,11 @@ static void node_geo_exec(GeoNodeExecParams params) sub_v3_v3(transform.values[3], collection->instance_offset); } } - const int handle = instances.add_reference(*child_collection); + const int handle = instances->add_reference(*child_collection); entries.append({handle, &(child_collection->id.name[2]), transform}); } for (Object *child_object : children_objects) { - const int handle = instances.add_reference(*child_object); + const int handle = instances->add_reference(*child_object); float4x4 transform = float4x4::identity(); if (!reset_children) { if (use_relative_transform) { @@ -112,7 +112,7 @@ static void node_geo_exec(GeoNodeExecParams params) else { sub_v3_v3(transform.values[3], collection->instance_offset); } - mul_m4_m4_post(transform.values, child_object->obmat); + mul_m4_m4_post(transform.values, child_object->object_to_world); } entries.append({handle, &(child_object->id.name[2]), transform}); } @@ -123,7 +123,7 @@ static void node_geo_exec(GeoNodeExecParams params) return BLI_strcasecmp_natural(a.name, b.name) < 0; }); for (const InstanceListEntry &entry : entries) { - instances.add_instance(entry.handle, entry.transform); + instances->add_instance(entry.handle, entry.transform); } } else { @@ -133,11 +133,11 @@ static void node_geo_exec(GeoNodeExecParams params) mul_m4_m4_pre(transform.values, self_object->imat); } - const int handle = instances.add_reference(*collection); - instances.add_instance(handle, transform); + const int handle = instances->add_reference(*collection); + instances->add_instance(handle, transform); } - params.set_output("Geometry", geometry_set_out); + params.set_output("Geometry", GeometrySet::create_with_instances(instances.release())); } } // namespace blender::nodes::node_geo_collection_info_cc diff --git a/source/blender/nodes/geometry/nodes/node_geo_deform_curves_on_surface.cc b/source/blender/nodes/geometry/nodes/node_geo_deform_curves_on_surface.cc index a12ae9bbb92..dabd2a1a9f2 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_deform_curves_on_surface.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_deform_curves_on_surface.cc @@ -310,7 +310,8 @@ static void node_geo_exec(GeoNodeExecParams params) ATTR_DOMAIN_CORNER); const VArraySpan<float3> rest_positions = mesh_attributes_eval.lookup<float3>(rest_position_name, ATTR_DOMAIN_POINT); - const Span<float2> surface_uv_coords = curves.surface_uv_coords(); + const VArraySpan<float2> surface_uv_coords = curves.attributes().lookup_or_default( + "surface_uv_coordinate", ATTR_DOMAIN_CURVE, float2(0)); const Span<MLoopTri> looptris_orig = surface_mesh_orig->looptris(); const Span<MLoopTri> looptris_eval = surface_mesh_eval->looptris(); @@ -379,19 +380,23 @@ static void node_geo_exec(GeoNodeExecParams params) invalid_uv_count); /* Then also deform edit curve information for use in sculpt mode. */ const CurvesGeometry &curves_orig = CurvesGeometry::wrap(edit_hints->curves_id_orig.geometry); - deform_curves(curves_orig, - *surface_mesh_orig, - *surface_mesh_eval, - surface_uv_coords, - reverse_uv_sampler_orig, - reverse_uv_sampler_eval, - corner_normals_orig, - corner_normals_eval, - rest_positions, - transforms.surface_to_curves, - edit_hint_positions, - edit_hint_rotations, - invalid_uv_count); + const VArraySpan<float2> surface_uv_coords_orig = curves_orig.attributes().lookup_or_default( + "surface_uv_coordinate", ATTR_DOMAIN_CURVE, float2(0)); + if (!surface_uv_coords_orig.is_empty()) { + deform_curves(curves_orig, + *surface_mesh_orig, + *surface_mesh_eval, + surface_uv_coords_orig, + reverse_uv_sampler_orig, + reverse_uv_sampler_eval, + corner_normals_orig, + corner_normals_eval, + rest_positions, + transforms.surface_to_curves, + edit_hint_positions, + edit_hint_rotations, + invalid_uv_count); + } } curves.tag_positions_changed(); 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 86c8cd64489..3e48a9fd923 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_delete_geometry.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_delete_geometry.cc @@ -4,6 +4,7 @@ #include "UI_resources.h" #include "BLI_array.hh" +#include "BLI_array_utils.hh" #include "DNA_mesh_types.h" #include "DNA_meshdata_types.h" @@ -12,6 +13,7 @@ #include "BKE_attribute_math.hh" #include "BKE_curves.hh" #include "BKE_customdata.h" +#include "BKE_instances.hh" #include "BKE_mesh.h" #include "BKE_pointcloud.h" @@ -22,15 +24,9 @@ namespace blender::nodes::node_geo_delete_geometry_cc { using blender::bke::CustomDataAttributes; template<typename T> -static void copy_data_based_on_mask(Span<T> data, MutableSpan<T> r_data, IndexMask mask) -{ - for (const int i_out : mask.index_range()) { - r_data[i_out] = data[mask[i_out]]; - } -} - -template<typename T> -static void copy_data_based_on_map(Span<T> src, MutableSpan<T> dst, Span<int> index_map) +static void copy_data_based_on_map(const Span<T> src, + const Span<int> index_map, + MutableSpan<T> dst) { for (const int i_src : index_map.index_range()) { const int i_dst = index_map[i_src]; @@ -54,26 +50,17 @@ static void copy_attributes(const Map<AttributeIDRef, AttributeKind> &attributes if (!attribute) { continue; } - /* Only copy if it is on a domain we want. */ if (!domains.contains(attribute.domain)) { continue; } const eCustomDataType data_type = bke::cpp_type_to_custom_data_type(attribute.varray.type()); - GSpanAttributeWriter result_attribute = dst_attributes.lookup_or_add_for_write_only_span( attribute_id, attribute.domain, data_type); - if (!result_attribute) { continue; } - - attribute_math::convert_to_static_type(data_type, [&](auto dummy) { - using T = decltype(dummy); - VArraySpan<T> span{attribute.varray.typed<T>()}; - MutableSpan<T> out_span = result_attribute.span.typed<T>(); - out_span.copy_from(span); - }); + attribute.varray.materialize(result_attribute.span.data()); result_attribute.finish(); } } @@ -94,26 +81,19 @@ static void copy_attributes_based_on_mask(const Map<AttributeIDRef, AttributeKin if (!attribute) { continue; } - /* Only copy if it is on a domain we want. */ if (domain != attribute.domain) { continue; } const eCustomDataType data_type = bke::cpp_type_to_custom_data_type(attribute.varray.type()); - GSpanAttributeWriter result_attribute = dst_attributes.lookup_or_add_for_write_only_span( attribute_id, attribute.domain, data_type); - if (!result_attribute) { continue; } - attribute_math::convert_to_static_type(data_type, [&](auto dummy) { - using T = decltype(dummy); - VArraySpan<T> span{attribute.varray.typed<T>()}; - MutableSpan<T> out_span = result_attribute.span.typed<T>(); - copy_data_based_on_mask(span, out_span, mask); - }); + array_utils::gather(attribute.varray, mask, result_attribute.span); + result_attribute.finish(); } } @@ -130,16 +110,13 @@ static void copy_attributes_based_on_map(const Map<AttributeIDRef, AttributeKind if (!attribute) { continue; } - /* Only copy if it is on a domain we want. */ if (domain != attribute.domain) { continue; } const eCustomDataType data_type = bke::cpp_type_to_custom_data_type(attribute.varray.type()); - GSpanAttributeWriter result_attribute = dst_attributes.lookup_or_add_for_write_only_span( attribute_id, attribute.domain, data_type); - if (!result_attribute) { continue; } @@ -148,7 +125,7 @@ static void copy_attributes_based_on_map(const Map<AttributeIDRef, AttributeKind using T = decltype(dummy); VArraySpan<T> span{attribute.varray.typed<T>()}; MutableSpan<T> out_span = result_attribute.span.typed<T>(); - copy_data_based_on_map(span, out_span, index_map); + copy_data_based_on_map(span, index_map, out_span); }); result_attribute.finish(); } @@ -392,8 +369,8 @@ static void separate_point_cloud_selection(GeometrySet &geometry_set, static void delete_selected_instances(GeometrySet &geometry_set, const Field<bool> &selection_field) { - InstancesComponent &instances = geometry_set.get_component_for_write<InstancesComponent>(); - bke::GeometryFieldContext field_context{instances, ATTR_DOMAIN_INSTANCE}; + bke::Instances &instances = *geometry_set.get_instances_for_write(); + bke::InstancesFieldContext field_context{instances}; fn::FieldEvaluator evaluator{field_context, instances.instances_num()}; evaluator.set_selection(selection_field); @@ -404,7 +381,7 @@ static void delete_selected_instances(GeometrySet &geometry_set, return; } - instances.remove_instances(selection); + instances.remove(selection); } static void compute_selected_verts_from_vertex_selection(const Span<bool> vertex_selection, diff --git a/source/blender/nodes/geometry/nodes/node_geo_distribute_points_in_volume.cc b/source/blender/nodes/geometry/nodes/node_geo_distribute_points_in_volume.cc index 091337c28cf..95173bd23a5 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_distribute_points_in_volume.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_distribute_points_in_volume.cc @@ -15,6 +15,8 @@ #include "UI_interface.h" #include "UI_resources.h" +#include "DEG_depsgraph_query.h" + #include "node_geometry_util.hh" namespace blender::nodes { @@ -208,6 +210,7 @@ static void geo_node_distribute_points_in_volume_exec(GeoNodeExecParams params) } const VolumeComponent *component = geometry_set.get_component_for_read<VolumeComponent>(); const Volume *volume = component->get_for_read(); + BKE_volume_load(volume, DEG_get_bmain(params.depsgraph())); Vector<float3> positions; diff --git a/source/blender/nodes/geometry/nodes/node_geo_dual_mesh.cc b/source/blender/nodes/geometry/nodes/node_geo_dual_mesh.cc index 84e63845b84..9b1c13bf563 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_dual_mesh.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_dual_mesh.cc @@ -1,5 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-or-later */ +#include "BLI_array_utils.hh" #include "BLI_task.hh" #include "DNA_mesh_types.h" @@ -105,18 +106,6 @@ static void copy_data_based_on_pairs(Span<T> data, } } -/* Copy using the map. */ -template<typename T> -static void copy_data_based_on_new_to_old_map(Span<T> data, - MutableSpan<T> r_data, - const Span<int> new_to_old_map) -{ - for (const int i : r_data.index_range()) { - const int old_i = new_to_old_map[i]; - r_data[i] = data[old_i]; - } -} - /** * Transfers the attributes from the original mesh to the new mesh using the following logic: * - If the attribute was on the face domain it is now on the point domain, and this is true @@ -168,7 +157,6 @@ static void transfer_attributes( src_attribute.varray.type()); GSpanAttributeWriter dst_attribute = dst_attributes.lookup_or_add_for_write_only_span( attribute_id, out_domain, data_type); - if (!dst_attribute) { continue; } @@ -177,20 +165,24 @@ static void transfer_attributes( using T = decltype(dummy); VArraySpan<T> span{src_attribute.varray.typed<T>()}; MutableSpan<T> dst_span = dst_attribute.span.typed<T>(); - if (src_attribute.domain == ATTR_DOMAIN_FACE) { - dst_span.take_front(span.size()).copy_from(span); - if (keep_boundaries) { - copy_data_based_on_pairs(span, dst_span, boundary_vertex_to_relevant_face_map); - } - } - else if (src_attribute.domain == ATTR_DOMAIN_POINT) { - copy_data_based_on_vertex_types(span, dst_span, vertex_types, keep_boundaries); - } - else if (src_attribute.domain == ATTR_DOMAIN_EDGE) { - copy_data_based_on_new_to_old_map(span, dst_span, new_to_old_edges_map); - } - else { - copy_data_based_on_new_to_old_map(span, dst_span, new_to_old_face_corners_map); + switch (src_attribute.domain) { + case ATTR_DOMAIN_POINT: + copy_data_based_on_vertex_types(span, dst_span, vertex_types, keep_boundaries); + break; + case ATTR_DOMAIN_EDGE: + array_utils::gather(span, new_to_old_edges_map, dst_span); + break; + case ATTR_DOMAIN_FACE: + dst_span.take_front(span.size()).copy_from(span); + if (keep_boundaries) { + copy_data_based_on_pairs(span, dst_span, boundary_vertex_to_relevant_face_map); + } + break; + case ATTR_DOMAIN_CORNER: + array_utils::gather(span, new_to_old_face_corners_map, dst_span); + break; + default: + BLI_assert_unreachable(); } }); dst_attribute.finish(); diff --git a/source/blender/nodes/geometry/nodes/node_geo_duplicate_elements.cc b/source/blender/nodes/geometry/nodes/node_geo_duplicate_elements.cc index 82d7e1d3652..486f900aca5 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_duplicate_elements.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_duplicate_elements.cc @@ -1,5 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-or-later */ +#include "BLI_array_utils.hh" #include "BLI_map.hh" #include "BLI_noise.hh" #include "BLI_span.hh" @@ -11,6 +12,7 @@ #include "BKE_attribute_math.hh" #include "BKE_curves.hh" +#include "BKE_instances.hh" #include "BKE_mesh.h" #include "BKE_pointcloud.h" @@ -104,16 +106,6 @@ static void threaded_slice_fill(Span<int> offsets, }); } -template<typename T> -static void threaded_mapped_copy(const Span<int> mapping, const Span<T> src, MutableSpan<T> dst) -{ - threading::parallel_for(mapping.index_range(), 512, [&](IndexRange range) { - for (const int i : range) { - dst[i] = src[mapping[i]]; - } - }); -} - static void copy_hashed_ids(const Span<int> src, const int hash, MutableSpan<int> dst) { for (const int i : src.index_range()) { @@ -439,17 +431,17 @@ static void copy_face_attributes_without_id(GeometrySet &geometry_set, MutableSpan<T> dst = dst_attribute.span.typed<T>(); switch (out_domain) { - case ATTR_DOMAIN_FACE: - threaded_slice_fill<T>(offsets, selection, src, dst); + case ATTR_DOMAIN_POINT: + array_utils::gather(src, vert_mapping, dst); break; case ATTR_DOMAIN_EDGE: - threaded_mapped_copy<T>(edge_mapping, src, dst); + array_utils::gather(src, edge_mapping, dst); break; - case ATTR_DOMAIN_POINT: - threaded_mapped_copy<T>(vert_mapping, src, dst); + case ATTR_DOMAIN_FACE: + threaded_slice_fill<T>(offsets, selection, src, dst); break; case ATTR_DOMAIN_CORNER: - threaded_mapped_copy<T>(loop_mapping, src, dst); + array_utils::gather(src, loop_mapping, dst); break; default: break; @@ -652,7 +644,7 @@ static void copy_edge_attributes_without_id(GeometrySet &geometry_set, threaded_slice_fill<T>(offsets, selection, src, dst); break; case ATTR_DOMAIN_POINT: - threaded_mapped_copy<T>(point_mapping, src, dst); + array_utils::gather(src, point_mapping, dst); break; default: break; @@ -1031,10 +1023,9 @@ static void duplicate_instances(GeometrySet &geometry_set, return; } - const InstancesComponent &src_instances = - *geometry_set.get_component_for_read<InstancesComponent>(); + const bke::Instances &src_instances = *geometry_set.get_instances_for_read(); - bke::GeometryFieldContext field_context{src_instances, ATTR_DOMAIN_INSTANCE}; + bke::InstancesFieldContext field_context{src_instances}; FieldEvaluator evaluator{field_context, src_instances.instances_num()}; evaluator.add(count_field); evaluator.set_selection(selection_field); @@ -1048,20 +1039,20 @@ static void duplicate_instances(GeometrySet &geometry_set, return; } - GeometrySet dst_geometry; - InstancesComponent &dst_instances = dst_geometry.get_component_for_write<InstancesComponent>(); - dst_instances.resize(offsets.last()); + std::unique_ptr<bke::Instances> dst_instances = std::make_unique<bke::Instances>(); + + dst_instances->resize(offsets.last()); for (const int i_selection : selection.index_range()) { const IndexRange range = range_for_offsets_index(offsets, i_selection); if (range.size() == 0) { continue; } - const int old_handle = src_instances.instance_reference_handles()[i_selection]; - const InstanceReference reference = src_instances.references()[old_handle]; - const int new_handle = dst_instances.add_reference(reference); - const float4x4 transform = src_instances.instance_transforms()[i_selection]; - dst_instances.instance_transforms().slice(range).fill(transform); - dst_instances.instance_reference_handles().slice(range).fill(new_handle); + const int old_handle = src_instances.reference_handles()[i_selection]; + const bke::InstanceReference reference = src_instances.references()[old_handle]; + const int new_handle = dst_instances->add_reference(reference); + const float4x4 transform = src_instances.transforms()[i_selection]; + dst_instances->transforms().slice(range).fill(transform); + dst_instances->reference_handles().slice(range).fill(new_handle); } copy_attributes_without_id(geometry_set, @@ -1069,18 +1060,18 @@ static void duplicate_instances(GeometrySet &geometry_set, ATTR_DOMAIN_INSTANCE, offsets, selection, - *src_instances.attributes(), - *dst_instances.attributes_for_write()); + src_instances.attributes(), + dst_instances->attributes_for_write()); if (attribute_outputs.duplicate_index) { - create_duplicate_index_attribute(*dst_instances.attributes_for_write(), + create_duplicate_index_attribute(dst_instances->attributes_for_write(), ATTR_DOMAIN_INSTANCE, selection, attribute_outputs, offsets); } - geometry_set = std::move(dst_geometry); + geometry_set = GeometrySet::create_with_instances(dst_instances.release()); } /** \} */ diff --git a/source/blender/nodes/geometry/nodes/node_geo_extrude_mesh.cc b/source/blender/nodes/geometry/nodes/node_geo_extrude_mesh.cc index 1d8c9d6312c..151ba3e59cc 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_extrude_mesh.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_extrude_mesh.cc @@ -1,5 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-or-later */ +#include "BLI_array_utils.hh" #include "BLI_disjoint_set.hh" #include "BLI_task.hh" #include "BLI_vector_set.hh" @@ -175,24 +176,6 @@ static MPoly new_poly(const int loopstart, const int totloop) return poly; } -template<typename T> void copy_with_indices(MutableSpan<T> dst, Span<T> src, Span<int> indices) -{ - BLI_assert(dst.size() == indices.size()); - for (const int i : dst.index_range()) { - dst[i] = src[indices[i]]; - } -} - -template<typename T> void copy_with_mask(MutableSpan<T> dst, Span<T> src, IndexMask mask) -{ - BLI_assert(dst.size() == mask.size()); - threading::parallel_for(mask.index_range(), 512, [&](const IndexRange range) { - for (const int i : range) { - dst[i] = src[mask[i]]; - } - }); -} - /** * \param get_mix_indices_fn: Returns a Span of indices of the source points to mix for every * result point. @@ -260,28 +243,29 @@ static void extrude_mesh_vertices(Mesh &mesh, if (!ELEM(meta_data.domain, ATTR_DOMAIN_POINT, ATTR_DOMAIN_EDGE)) { return true; } + if (meta_data.data_type == CD_PROP_STRING) { + return true; + } GSpanAttributeWriter attribute = attributes.lookup_or_add_for_write_span( id, meta_data.domain, meta_data.data_type); - attribute_math::convert_to_static_type(meta_data.data_type, [&](auto dummy) { - using T = decltype(dummy); - MutableSpan<T> data = attribute.span.typed<T>(); - switch (attribute.domain) { - case ATTR_DOMAIN_POINT: { - /* New vertices copy the attribute values from their source vertex. */ - copy_with_mask(data.slice(new_vert_range), data.as_span(), selection); - break; - } - case ATTR_DOMAIN_EDGE: { + switch (attribute.domain) { + case ATTR_DOMAIN_POINT: + /* New vertices copy the attribute values from their source vertex. */ + array_utils::gather(attribute.span, selection, attribute.span.slice(new_vert_range)); + break; + case ATTR_DOMAIN_EDGE: + attribute_math::convert_to_static_type(meta_data.data_type, [&](auto dummy) { + using T = decltype(dummy); + MutableSpan<T> data = attribute.span.typed<T>(); /* New edge values are mixed from of all the edges connected to the source vertex. */ copy_with_mixing(data.slice(new_edge_range), data.as_span(), [&](const int i) { return vert_to_edge_map[selection[i]].as_span(); }); - break; - } - default: - BLI_assert_unreachable(); - } - }); + }); + break; + default: + BLI_assert_unreachable(); + } attribute.finish(); return true; @@ -506,6 +490,9 @@ static void extrude_mesh_edges(Mesh &mesh, MutableAttributeAccessor attributes = mesh.attributes_for_write(); attributes.for_all([&](const AttributeIDRef &id, const AttributeMetaData meta_data) { + if (meta_data.data_type == CD_PROP_STRING) { + return true; + } GSpanAttributeWriter attribute = attributes.lookup_or_add_for_write_span( id, meta_data.domain, meta_data.data_type); if (!attribute) { @@ -518,13 +505,14 @@ static void extrude_mesh_edges(Mesh &mesh, switch (attribute.domain) { case ATTR_DOMAIN_POINT: { /* New vertices copy the attribute values from their source vertex. */ - copy_with_indices(data.slice(new_vert_range), data.as_span(), new_vert_indices); + array_utils::gather( + data.as_span(), new_vert_indices.as_span(), data.slice(new_vert_range)); break; } case ATTR_DOMAIN_EDGE: { /* Edges parallel to original edges copy the edge attributes from the original edges. */ MutableSpan<T> duplicate_data = data.slice(duplicate_edge_range); - copy_with_mask(duplicate_data, data.as_span(), edge_selection); + array_utils::gather(data.as_span(), edge_selection, duplicate_data); /* Edges connected to original vertices mix values of selected connected edges. */ MutableSpan<T> connect_data = data.slice(connect_edge_range); @@ -889,6 +877,9 @@ static void extrude_mesh_face_regions(Mesh &mesh, MutableAttributeAccessor attributes = mesh.attributes_for_write(); attributes.for_all([&](const AttributeIDRef &id, const AttributeMetaData meta_data) { + if (meta_data.data_type == CD_PROP_STRING) { + return true; + } GSpanAttributeWriter attribute = attributes.lookup_or_add_for_write_span( id, meta_data.domain, meta_data.data_type); if (!attribute) { @@ -901,17 +892,18 @@ static void extrude_mesh_face_regions(Mesh &mesh, switch (attribute.domain) { case ATTR_DOMAIN_POINT: { /* New vertices copy the attributes from their original vertices. */ - copy_with_indices(data.slice(new_vert_range), data.as_span(), new_vert_indices); + array_utils::gather( + data.as_span(), new_vert_indices.as_span(), data.slice(new_vert_range)); break; } case ATTR_DOMAIN_EDGE: { /* Edges parallel to original edges copy the edge attributes from the original edges. */ MutableSpan<T> boundary_data = data.slice(boundary_edge_range); - copy_with_indices(boundary_data, data.as_span(), boundary_edge_indices); + array_utils::gather(data.as_span(), boundary_edge_indices.as_span(), boundary_data); /* Edges inside of face regions also just duplicate their source data. */ MutableSpan<T> new_inner_data = data.slice(new_inner_edge_range); - copy_with_indices(new_inner_data, data.as_span(), new_inner_edge_indices); + array_utils::gather(data.as_span(), new_inner_edge_indices.as_span(), new_inner_data); /* Edges connected to original vertices mix values of selected connected edges. */ MutableSpan<T> connect_data = data.slice(connect_edge_range); @@ -923,8 +915,8 @@ static void extrude_mesh_face_regions(Mesh &mesh, case ATTR_DOMAIN_FACE: { /* New faces on the side of extrusions get the values from the corresponding selected * face. */ - copy_with_indices( - data.slice(side_poly_range), data.as_span(), edge_extruded_face_indices); + array_utils::gather( + data.as_span(), edge_extruded_face_indices.as_span(), data.slice(side_poly_range)); break; } case ATTR_DOMAIN_CORNER: { @@ -1143,6 +1135,9 @@ static void extrude_individual_mesh_faces(Mesh &mesh, MutableAttributeAccessor attributes = mesh.attributes_for_write(); attributes.for_all([&](const AttributeIDRef &id, const AttributeMetaData meta_data) { + if (meta_data.data_type == CD_PROP_STRING) { + return true; + } GSpanAttributeWriter attribute = attributes.lookup_or_add_for_write_span( id, meta_data.domain, meta_data.data_type); if (!attribute) { diff --git a/source/blender/nodes/geometry/nodes/node_geo_flip_faces.cc b/source/blender/nodes/geometry/nodes/node_geo_flip_faces.cc index 613425716d4..95a0013a9e1 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_flip_faces.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_flip_faces.cc @@ -47,6 +47,9 @@ static void mesh_flip_faces(Mesh &mesh, const Field<bool> &selection_field) MutableAttributeAccessor attributes = mesh.attributes_for_write(); attributes.for_all( [&](const bke::AttributeIDRef &attribute_id, const AttributeMetaData &meta_data) { + if (meta_data.data_type == CD_PROP_STRING) { + return true; + } if (meta_data.domain == ATTR_DOMAIN_CORNER) { GSpanAttributeWriter attribute = attributes.lookup_or_add_for_write_span( attribute_id, ATTR_DOMAIN_CORNER, meta_data.data_type); diff --git a/source/blender/nodes/geometry/nodes/node_geo_geometry_to_instance.cc b/source/blender/nodes/geometry/nodes/node_geo_geometry_to_instance.cc index 8e64209a418..45808ff9996 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_geometry_to_instance.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_geometry_to_instance.cc @@ -1,5 +1,7 @@ /* SPDX-License-Identifier: GPL-2.0-or-later */ +#include "BKE_instances.hh" + #include "node_geometry_util.hh" namespace blender::nodes::node_geo_geometry_to_instance_cc { @@ -13,15 +15,13 @@ static void node_declare(NodeDeclarationBuilder &b) static void node_geo_exec(GeoNodeExecParams params) { Vector<GeometrySet> geometries = params.extract_input<Vector<GeometrySet>>("Geometry"); - GeometrySet instances_geometry; - InstancesComponent &instances_component = - instances_geometry.get_component_for_write<InstancesComponent>(); + std::unique_ptr<bke::Instances> instances = std::make_unique<bke::Instances>(); for (GeometrySet &geometry : geometries) { geometry.ensure_owns_direct_data(); - const int handle = instances_component.add_reference(std::move(geometry)); - instances_component.add_instance(handle, float4x4::identity()); + const int handle = instances->add_reference(std::move(geometry)); + instances->add_instance(handle, float4x4::identity()); } - params.set_output("Instances", std::move(instances_geometry)); + params.set_output("Instances", GeometrySet::create_with_instances(instances.release())); } } // namespace blender::nodes::node_geo_geometry_to_instance_cc diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_instance_rotation.cc b/source/blender/nodes/geometry/nodes/node_geo_input_instance_rotation.cc index 75d43d2f771..f78815ebe74 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_input_instance_rotation.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_input_instance_rotation.cc @@ -2,6 +2,8 @@ #include "node_geometry_util.hh" +#include "BKE_instances.hh" + namespace blender::nodes::node_geo_input_instance_rotation_cc { static void node_declare(NodeDeclarationBuilder &b) @@ -15,12 +17,9 @@ class InstanceRotationFieldInput final : public bke::InstancesFieldInput { { } - GVArray get_varray_for_context(const InstancesComponent &instances, - const IndexMask /*mask*/) const final + GVArray get_varray_for_context(const bke::Instances &instances, IndexMask /*mask*/) const final { - auto rotation_fn = [&](const int i) -> float3 { - return instances.instance_transforms()[i].to_euler(); - }; + auto rotation_fn = [&](const int i) -> float3 { return instances.transforms()[i].to_euler(); }; return VArray<float3>::ForFunc(instances.instances_num(), rotation_fn); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_instance_scale.cc b/source/blender/nodes/geometry/nodes/node_geo_input_instance_scale.cc index dbb98d7e393..12ac48f8f11 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_input_instance_scale.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_input_instance_scale.cc @@ -2,6 +2,8 @@ #include "node_geometry_util.hh" +#include "BKE_instances.hh" + namespace blender::nodes::node_geo_input_instance_scale_cc { static void node_declare(NodeDeclarationBuilder &b) @@ -15,12 +17,9 @@ class InstanceScaleFieldInput final : public bke::InstancesFieldInput { { } - GVArray get_varray_for_context(const InstancesComponent &instances, - const IndexMask /*mask*/) const final + GVArray get_varray_for_context(const bke::Instances &instances, IndexMask /*mask*/) const final { - auto scale_fn = [&](const int i) -> float3 { - return instances.instance_transforms()[i].scale(); - }; + auto scale_fn = [&](const int i) -> float3 { return instances.transforms()[i].scale(); }; return VArray<float3>::ForFunc(instances.instances_num(), scale_fn); } 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 c6f214e72ac..64546684186 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 @@ -2,6 +2,7 @@ #include "DNA_collection_types.h" +#include "BLI_array_utils.hh" #include "BLI_hash.h" #include "BLI_task.hh" @@ -9,6 +10,7 @@ #include "UI_resources.h" #include "BKE_attribute_math.hh" +#include "BKE_instances.hh" #include "node_geometry_util.hh" @@ -43,7 +45,7 @@ static void node_declare(NodeDeclarationBuilder &b) } static void add_instances_from_component( - InstancesComponent &dst_component, + bke::Instances &dst_component, const GeometryComponent &src_component, const GeometrySet &instance, const GeoNodeExecParams ¶ms, @@ -80,25 +82,23 @@ static void add_instances_from_component( const int select_len = selection.index_range().size(); dst_component.resize(start_len + select_len); - MutableSpan<int> dst_handles = dst_component.instance_reference_handles().slice(start_len, - select_len); - MutableSpan<float4x4> dst_transforms = dst_component.instance_transforms().slice(start_len, - select_len); + MutableSpan<int> dst_handles = dst_component.reference_handles().slice(start_len, select_len); + MutableSpan<float4x4> dst_transforms = dst_component.transforms().slice(start_len, select_len); VArray<float3> positions = src_component.attributes()->lookup_or_default<float3>( "position", domain, {0, 0, 0}); - const InstancesComponent *src_instances = instance.get_component_for_read<InstancesComponent>(); + const bke::Instances *src_instances = instance.get_instances_for_read(); /* Maps handles from the source instances to handles on the new instance. */ 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())) { - Span<InstanceReference> src_references = src_instances->references(); + Span<bke::InstanceReference> src_references = src_instances->references(); handle_mapping.reinitialize(src_references.size()); for (const int src_instance_handle : src_references.index_range()) { - const InstanceReference &reference = src_references[src_instance_handle]; + const bke::InstanceReference &reference = src_references[src_instance_handle]; const int dst_instance_handle = dst_component.add_reference(reference); handle_mapping[src_instance_handle] = dst_instance_handle; } @@ -106,7 +106,7 @@ static void add_instances_from_component( const int full_instance_handle = dst_component.add_reference(instance); /* Add this reference last, because it is the most likely one to be removed later on. */ - const int empty_reference_handle = dst_component.add_reference(InstanceReference()); + const int empty_reference_handle = dst_component.add_reference(bke::InstanceReference()); threading::parallel_for(selection.index_range(), 1024, [&](IndexRange selection_range) { for (const int range_i : selection_range) { @@ -129,12 +129,11 @@ static void add_instances_from_component( const int index = mod_i(original_index, std::max(src_instances_num, 1)); if (index < src_instances_num) { /* Get the reference to the source instance. */ - const int src_handle = src_instances->instance_reference_handles()[index]; + const int src_handle = src_instances->reference_handles()[index]; dst_handle = handle_mapping[src_handle]; /* Take transforms of the source instance into account. */ - mul_m4_m4_post(dst_transform.values, - src_instances->instance_transforms()[index].values); + mul_m4_m4_post(dst_transform.values, src_instances->transforms()[index].values); } } } @@ -157,7 +156,7 @@ static void add_instances_from_component( } } - bke::CustomDataAttributes &instance_attributes = dst_component.instance_attributes(); + bke::CustomDataAttributes &instance_attributes = dst_component.custom_data_attributes(); for (const auto item : attributes_to_propagate.items()) { const AttributeIDRef &attribute_id = item.key; const AttributeKind attribute_kind = item.value; @@ -174,18 +173,7 @@ static void add_instances_from_component( dst_attribute_opt = instance_attributes.get_for_write(attribute_id); } BLI_assert(dst_attribute_opt); - const GMutableSpan dst_attribute = dst_attribute_opt->slice(start_len, select_len); - threading::parallel_for(selection.index_range(), 1024, [&](IndexRange selection_range) { - attribute_math::convert_to_static_type(attribute_kind.data_type, [&](auto dummy) { - using T = decltype(dummy); - VArray<T> src = src_attribute.typed<T>(); - MutableSpan<T> dst = dst_attribute.typed<T>(); - for (const int range_i : selection_range) { - const int i = selection[range_i]; - dst[range_i] = src[i]; - } - }); - }); + array_utils::gather(src_attribute, selection, dst_attribute_opt->slice(start_len, select_len)); } } @@ -196,7 +184,15 @@ static void node_geo_exec(GeoNodeExecParams params) instance.ensure_owns_direct_data(); geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) { - InstancesComponent &instances = geometry_set.get_component_for_write<InstancesComponent>(); + /* It's important not to invalidate the existing #InstancesComponent because it owns references + * to other geometry sets that are processed by this node. */ + InstancesComponent &instances_component = + geometry_set.get_component_for_write<InstancesComponent>(); + bke::Instances *dst_instances = instances_component.get_for_write(); + if (dst_instances == nullptr) { + dst_instances = new bke::Instances(); + instances_component.replace(dst_instances); + } const Array<GeometryComponentType> types{ GEO_COMPONENT_TYPE_MESH, GEO_COMPONENT_TYPE_POINT_CLOUD, GEO_COMPONENT_TYPE_CURVE}; @@ -208,14 +204,13 @@ static void node_geo_exec(GeoNodeExecParams params) for (const GeometryComponentType type : types) { if (geometry_set.has(type)) { - add_instances_from_component(instances, + add_instances_from_component(*dst_instances, *geometry_set.get_component_for_read(type), instance, params, attributes_to_propagate); } } - geometry_set.remove_geometry_during_modify(); }); @@ -223,8 +218,9 @@ static void node_geo_exec(GeoNodeExecParams params) * process them needlessly. * This should eventually be moved into the loop above, but currently this is quite tricky * because it might remove references that the loop still wants to iterate over. */ - InstancesComponent &instances = geometry_set.get_component_for_write<InstancesComponent>(); - instances.remove_unused_references(); + if (bke::Instances *instances = geometry_set.get_instances_for_write()) { + instances->remove_unused_references(); + } params.set_output("Instances", std::move(geometry_set)); } 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 d4072a05e5f..acd00d119ab 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 @@ -3,6 +3,7 @@ #include "DNA_pointcloud_types.h" #include "BKE_attribute_math.hh" +#include "BKE_instances.hh" #include "BKE_pointcloud.h" #include "node_geometry_util.hh" @@ -27,7 +28,7 @@ static void convert_instances_to_points(GeometrySet &geometry_set, Field<float> radius_field, const Field<bool> selection_field) { - const InstancesComponent &instances = *geometry_set.get_component_for_read<InstancesComponent>(); + const bke::Instances &instances = *geometry_set.get_instances_for_read(); const bke::InstancesFieldContext context{instances}; fn::FieldEvaluator evaluator{context, instances.instances_num()}; @@ -70,7 +71,7 @@ static void convert_instances_to_points(GeometrySet &geometry_set, const AttributeIDRef &attribute_id = item.key; const AttributeKind attribute_kind = item.value; - const GVArray src = instances.attributes()->lookup_or_default( + const GVArray src = instances.attributes().lookup_or_default( attribute_id, ATTR_DOMAIN_INSTANCE, attribute_kind.data_type); BLI_assert(src); GSpanAttributeWriter dst = point_attributes.lookup_or_add_for_write_only_span( 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 74d1b5561bb..ea2646a9786 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_join_geometry.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_join_geometry.cc @@ -2,6 +2,8 @@ #include "GEO_realize_instances.hh" +#include "BKE_instances.hh" + #include "node_geometry_util.hh" namespace blender::nodes::node_geo_join_geometry_cc { @@ -29,6 +31,9 @@ static Map<AttributeIDRef, AttributeMetaData> get_final_attribute_info( if (attribute_id.is_named() && ignored_attributes.contains(attribute_id.name())) { return true; } + if (meta_data.data_type == CD_PROP_STRING) { + return true; + } info.add_or_modify( attribute_id, [&](AttributeMetaData *meta_data_final) { *meta_data_final = meta_data; }, @@ -97,31 +102,36 @@ static void join_attributes(Span<const GeometryComponent *> src_components, static void join_components(Span<const InstancesComponent *> src_components, GeometrySet &result) { - InstancesComponent &dst_component = result.get_component_for_write<InstancesComponent>(); + std::unique_ptr<bke::Instances> dst_instances = std::make_unique<bke::Instances>(); int tot_instances = 0; for (const InstancesComponent *src_component : src_components) { - tot_instances += src_component->instances_num(); + tot_instances += src_component->get_for_read()->instances_num(); } - dst_component.reserve(tot_instances); + dst_instances->reserve(tot_instances); for (const InstancesComponent *src_component : src_components) { - Span<InstanceReference> src_references = src_component->references(); + const bke::Instances &src_instances = *src_component->get_for_read(); + + Span<bke::InstanceReference> src_references = src_instances.references(); Array<int> handle_map(src_references.size()); for (const int src_handle : src_references.index_range()) { - handle_map[src_handle] = dst_component.add_reference(src_references[src_handle]); + handle_map[src_handle] = dst_instances->add_reference(src_references[src_handle]); } - Span<float4x4> src_transforms = src_component->instance_transforms(); - Span<int> src_reference_handles = src_component->instance_reference_handles(); + Span<float4x4> src_transforms = src_instances.transforms(); + Span<int> src_reference_handles = src_instances.reference_handles(); for (const int i : src_transforms.index_range()) { const int src_handle = src_reference_handles[i]; const int dst_handle = handle_map[src_handle]; const float4x4 &transform = src_transforms[i]; - dst_component.add_instance(dst_handle, transform); + dst_instances->add_instance(dst_handle, transform); } } + + result.replace_instances(dst_instances.release()); + InstancesComponent &dst_component = result.get_component_for_write<InstancesComponent>(); join_attributes(to_base_components(src_components), dst_component, {"position"}); } @@ -151,25 +161,23 @@ static void join_component_type(Span<GeometrySet> src_geometry_sets, GeometrySet return; } - GeometrySet instances_geometry_set; - InstancesComponent &instances = - instances_geometry_set.get_component_for_write<InstancesComponent>(); - if constexpr (is_same_any_v<Component, InstancesComponent, VolumeComponent>) { join_components(components, result); } else { + std::unique_ptr<bke::Instances> instances = std::make_unique<bke::Instances>(); for (const Component *component : components) { GeometrySet tmp_geo; tmp_geo.add(*component); - const int handle = instances.add_reference(InstanceReference{tmp_geo}); - instances.add_instance(handle, float4x4::identity()); + const int handle = instances->add_reference(bke::InstanceReference{tmp_geo}); + instances->add_instance(handle, float4x4::identity()); } geometry::RealizeInstancesOptions options; options.keep_original_ids = true; options.realize_instance_attributes = false; - GeometrySet joined_components = geometry::realize_instances(instances_geometry_set, options); + GeometrySet joined_components = geometry::realize_instances( + GeometrySet::create_with_instances(instances.release()), options); result.add(joined_components.get_component_for_write<Component>()); } } diff --git a/source/blender/nodes/geometry/nodes/node_geo_mesh_topology_corners_of_vertex.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_topology_corners_of_vertex.cc index cce3f4e3648..036af2d3b93 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_mesh_topology_corners_of_vertex.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_mesh_topology_corners_of_vertex.cc @@ -93,6 +93,10 @@ class CornersOfVertInput final : public bke::MeshFieldInput { } const Span<int> corners = vert_to_loop_map[vert_i]; + if (corners.is_empty()) { + corner_of_vertex[selection_i] = 0; + continue; + } /* Retrieve the connected edge indices as 64 bit integers for #materialize_compressed. */ corner_indices.reinitialize(corners.size()); diff --git a/source/blender/nodes/geometry/nodes/node_geo_mesh_topology_edges_of_vertex.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_topology_edges_of_vertex.cc index 053ef61deed..f0cc191e217 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_mesh_topology_edges_of_vertex.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_mesh_topology_edges_of_vertex.cc @@ -93,6 +93,10 @@ class EdgesOfVertInput final : public bke::MeshFieldInput { } const Span<int> edges = vert_to_edge_map[vert_i]; + if (edges.is_empty()) { + edge_of_vertex[selection_i] = 0; + continue; + } /* Retrieve the connected edge indices as 64 bit integers for #materialize_compressed. */ edge_indices.reinitialize(edges.size()); 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 3ce16fac464..dc35607fe45 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_object_info.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_object_info.cc @@ -3,6 +3,7 @@ #include "BLI_math_matrix.h" #include "BKE_geometry_set_instances.hh" +#include "BKE_instances.hh" #include "UI_interface.h" #include "UI_resources.h" @@ -44,7 +45,7 @@ static void node_geo_exec(GeoNodeExecParams params) return; } - const float4x4 &object_matrix = object->obmat; + const float4x4 &object_matrix = object->object_to_world; const float4x4 transform = float4x4(self_object->imat) * object_matrix; if (transform_space_relative) { @@ -68,14 +69,15 @@ static void node_geo_exec(GeoNodeExecParams params) 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); + std::unique_ptr<bke::Instances> instances = std::make_unique<bke::Instances>(); + const int handle = instances->add_reference(*object); if (transform_space_relative) { - instances.add_instance(handle, transform); + instances->add_instance(handle, transform); } else { - instances.add_instance(handle, float4x4::identity()); + instances->add_instance(handle, float4x4::identity()); } + geometry_set = GeometrySet::create_with_instances(instances.release()); } else { geometry_set = bke::object_get_evaluated_geometry_set(*object); 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 4ed94e67e74..fac92a7500c 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_rotate_instances.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_rotate_instances.cc @@ -2,6 +2,8 @@ #include "BLI_task.hh" +#include "BKE_instances.hh" + #include "node_geometry_util.hh" namespace blender::nodes::node_geo_rotate_instances_cc { @@ -16,10 +18,10 @@ static void node_declare(NodeDeclarationBuilder &b) b.add_output<decl::Geometry>(N_("Instances")); } -static void rotate_instances(GeoNodeExecParams ¶ms, InstancesComponent &instances_component) +static void rotate_instances(GeoNodeExecParams ¶ms, bke::Instances &instances) { - const bke::InstancesFieldContext context{instances_component}; - fn::FieldEvaluator evaluator{context, instances_component.instances_num()}; + const bke::InstancesFieldContext context{instances}; + fn::FieldEvaluator evaluator{context, instances.instances_num()}; evaluator.set_selection(params.extract_input<Field<bool>>("Selection")); evaluator.add(params.extract_input<Field<float3>>("Rotation")); evaluator.add(params.extract_input<Field<float3>>("Pivot Point")); @@ -31,14 +33,14 @@ static void rotate_instances(GeoNodeExecParams ¶ms, InstancesComponent &inst const VArray<float3> pivots = evaluator.get_evaluated<float3>(1); const VArray<bool> local_spaces = evaluator.get_evaluated<bool>(2); - MutableSpan<float4x4> instance_transforms = instances_component.instance_transforms(); + MutableSpan<float4x4> transforms = instances.transforms(); threading::parallel_for(selection.index_range(), 512, [&](IndexRange range) { for (const int i_selection : range) { const int i = selection[i_selection]; const float3 pivot = pivots[i]; const float3 euler = rotations[i]; - float4x4 &instance_transform = instance_transforms[i]; + float4x4 &instance_transform = transforms[i]; float4x4 rotation_matrix; float3 used_pivot; @@ -81,9 +83,8 @@ static void rotate_instances(GeoNodeExecParams ¶ms, InstancesComponent &inst static void node_geo_exec(GeoNodeExecParams params) { GeometrySet geometry_set = params.extract_input<GeometrySet>("Instances"); - if (geometry_set.has_instances()) { - InstancesComponent &instances = geometry_set.get_component_for_write<InstancesComponent>(); - rotate_instances(params, instances); + if (bke::Instances *instances = geometry_set.get_instances_for_write()) { + rotate_instances(params, *instances); } params.set_output("Instances", std::move(geometry_set)); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_sample_nearest_surface.cc b/source/blender/nodes/geometry/nodes/node_geo_sample_nearest_surface.cc index 44851a0ade5..95bf7199d63 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_sample_nearest_surface.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_sample_nearest_surface.cc @@ -240,7 +240,11 @@ static void node_geo_exec(GeoNodeExecParams params) params.set_default_remaining_outputs(); return; } - if (mesh->totpoly == 0 && mesh->totvert != 0) { + if (mesh->totvert == 0) { + params.set_default_remaining_outputs(); + return; + } + if (mesh->totpoly == 0) { params.error_message_add(NodeWarningType::Error, TIP_("The source mesh must have faces")); params.set_default_remaining_outputs(); return; 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 21fe724e194..dacb130337f 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_scale_instances.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_scale_instances.cc @@ -2,6 +2,8 @@ #include "BLI_task.hh" +#include "BKE_instances.hh" + #include "node_geometry_util.hh" namespace blender::nodes::node_geo_scale_instances_cc { @@ -19,10 +21,10 @@ static void node_declare(NodeDeclarationBuilder &b) b.add_output<decl::Geometry>(N_("Instances")); } -static void scale_instances(GeoNodeExecParams ¶ms, InstancesComponent &instances_component) +static void scale_instances(GeoNodeExecParams ¶ms, bke::Instances &instances) { - const bke::InstancesFieldContext context{instances_component}; - fn::FieldEvaluator evaluator{context, instances_component.instances_num()}; + const bke::InstancesFieldContext context{instances}; + fn::FieldEvaluator evaluator{context, instances.instances_num()}; evaluator.set_selection(params.extract_input<Field<bool>>("Selection")); evaluator.add(params.extract_input<Field<float3>>("Scale")); evaluator.add(params.extract_input<Field<float3>>("Center")); @@ -34,13 +36,13 @@ static void scale_instances(GeoNodeExecParams ¶ms, InstancesComponent &insta const VArray<float3> pivots = evaluator.get_evaluated<float3>(1); const VArray<bool> local_spaces = evaluator.get_evaluated<bool>(2); - MutableSpan<float4x4> instance_transforms = instances_component.instance_transforms(); + MutableSpan<float4x4> transforms = instances.transforms(); threading::parallel_for(selection.index_range(), 512, [&](IndexRange range) { for (const int i_selection : range) { const int i = selection[i_selection]; const float3 pivot = pivots[i]; - float4x4 &instance_transform = instance_transforms[i]; + float4x4 &instance_transform = transforms[i]; if (local_spaces[i]) { instance_transform *= float4x4::from_location(pivot); @@ -61,9 +63,8 @@ static void scale_instances(GeoNodeExecParams ¶ms, InstancesComponent &insta static void node_geo_exec(GeoNodeExecParams params) { GeometrySet geometry_set = params.extract_input<GeometrySet>("Instances"); - if (geometry_set.has_instances()) { - InstancesComponent &instances = geometry_set.get_component_for_write<InstancesComponent>(); - scale_instances(params, instances); + if (bke::Instances *instances = geometry_set.get_instances_for_write()) { + scale_instances(params, *instances); } params.set_output("Instances", std::move(geometry_set)); } 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 bbdabc09099..769a63f58cf 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 @@ -6,6 +6,7 @@ #include "BKE_curve.h" #include "BKE_curve_legacy_convert.hh" #include "BKE_curves.hh" +#include "BKE_instances.hh" #include "BKE_vfont.h" #include "BLI_hash.h" @@ -270,7 +271,7 @@ static std::optional<TextLayout> get_text_layout(GeoNodeExecParams ¶ms) /* Returns a mapping of UTF-32 character code to instance handle. */ static Map<int, int> create_curve_instances(GeoNodeExecParams ¶ms, TextLayout &layout, - InstancesComponent &instances) + bke::Instances &instances) { VFont *vfont = reinterpret_cast<VFont *>(params.node().id); Map<int, int> handles; @@ -315,13 +316,13 @@ static Map<int, int> create_curve_instances(GeoNodeExecParams ¶ms, return handles; } -static void add_instances_from_handles(InstancesComponent &instances, +static void add_instances_from_handles(bke::Instances &instances, const Map<int, int> &char_handles, const TextLayout &layout) { instances.resize(layout.positions.size()); - MutableSpan<int> handles = instances.instance_reference_handles(); - MutableSpan<float4x4> transforms = instances.instance_transforms(); + MutableSpan<int> handles = instances.reference_handles(); + MutableSpan<float4x4> transforms = instances.transforms(); threading::parallel_for(IndexRange(layout.positions.size()), 256, [&](IndexRange range) { for (const int i : range) { @@ -333,9 +334,9 @@ static void add_instances_from_handles(InstancesComponent &instances, static void create_attributes(GeoNodeExecParams ¶ms, const TextLayout &layout, - InstancesComponent &instances) + bke::Instances &instances) { - MutableAttributeAccessor attributes = *instances.attributes_for_write(); + MutableAttributeAccessor attributes = instances.attributes_for_write(); if (params.output_is_required("Line")) { StrongAnonymousAttributeID line_id = StrongAnonymousAttributeID("Line"); @@ -385,13 +386,12 @@ static void node_geo_exec(GeoNodeExecParams params) } /* Create and add instances. */ - GeometrySet geometry_set_out; - InstancesComponent &instances = geometry_set_out.get_component_for_write<InstancesComponent>(); - Map<int, int> char_handles = create_curve_instances(params, *layout, instances); - add_instances_from_handles(instances, char_handles, *layout); - create_attributes(params, *layout, instances); + std::unique_ptr<bke::Instances> instances = std::make_unique<bke::Instances>(); + Map<int, int> char_handles = create_curve_instances(params, *layout, *instances); + add_instances_from_handles(*instances, char_handles, *layout); + create_attributes(params, *layout, *instances); - params.set_output("Curve Instances", std::move(geometry_set_out)); + params.set_output("Curve Instances", GeometrySet::create_with_instances(instances.release())); } } // namespace blender::nodes::node_geo_string_to_curves_cc diff --git a/source/blender/nodes/geometry/nodes/node_geo_transform.cc b/source/blender/nodes/geometry/nodes/node_geo_transform.cc index 4130cad3bda..3c8a3f3ca76 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_transform.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_transform.cc @@ -11,6 +11,7 @@ #include "DNA_volume_types.h" #include "BKE_curves.hh" +#include "BKE_instances.hh" #include "BKE_mesh.h" #include "BKE_pointcloud.h" #include "BKE_volume.h" @@ -67,18 +68,18 @@ static void transform_pointcloud(PointCloud &pointcloud, const float4x4 &transfo position.finish(); } -static void translate_instances(InstancesComponent &instances, const float3 translation) +static void translate_instances(bke::Instances &instances, const float3 translation) { - MutableSpan<float4x4> transforms = instances.instance_transforms(); + MutableSpan<float4x4> transforms = instances.transforms(); for (float4x4 &transform : transforms) { add_v3_v3(transform.ptr()[3], translation); } } -static void transform_instances(InstancesComponent &instances, const float4x4 &transform) +static void transform_instances(bke::Instances &instances, const float4x4 &transform) { - MutableSpan<float4x4> instance_transforms = instances.instance_transforms(); - for (float4x4 &instance_transform : instance_transforms) { + MutableSpan<float4x4> transforms = instances.transforms(); + for (float4x4 &instance_transform : transforms) { instance_transform = transform * instance_transform; } } @@ -185,8 +186,8 @@ static void translate_geometry_set(GeoNodeExecParams ¶ms, if (Volume *volume = geometry.get_volume_for_write()) { translate_volume(params, *volume, translation, depsgraph); } - if (geometry.has_instances()) { - translate_instances(geometry.get_component_for_write<InstancesComponent>(), translation); + if (bke::Instances *instances = geometry.get_instances_for_write()) { + translate_instances(*instances, translation); } if (bke::CurvesEditHints *curve_edit_hints = geometry.get_curve_edit_hints_for_write()) { translate_curve_edit_hints(*curve_edit_hints, translation); @@ -210,8 +211,8 @@ void transform_geometry_set(GeoNodeExecParams ¶ms, if (Volume *volume = geometry.get_volume_for_write()) { transform_volume(params, *volume, transform, depsgraph); } - if (geometry.has_instances()) { - transform_instances(geometry.get_component_for_write<InstancesComponent>(), transform); + if (bke::Instances *instances = geometry.get_instances_for_write()) { + transform_instances(*instances, transform); } if (bke::CurvesEditHints *curve_edit_hints = geometry.get_curve_edit_hints_for_write()) { transform_curve_edit_hints(*curve_edit_hints, transform); 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 3e9fe99adb0..23052abddc4 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_translate_instances.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_translate_instances.cc @@ -2,6 +2,8 @@ #include "BLI_task.hh" +#include "BKE_instances.hh" + #include "node_geometry_util.hh" namespace blender::nodes::node_geo_translate_instances_cc { @@ -15,10 +17,10 @@ static void node_declare(NodeDeclarationBuilder &b) b.add_output<decl::Geometry>(N_("Instances")); } -static void translate_instances(GeoNodeExecParams ¶ms, InstancesComponent &instances_component) +static void translate_instances(GeoNodeExecParams ¶ms, bke::Instances &instances) { - const bke::InstancesFieldContext context{instances_component}; - fn::FieldEvaluator evaluator{context, instances_component.instances_num()}; + const bke::InstancesFieldContext context{instances}; + fn::FieldEvaluator evaluator{context, instances.instances_num()}; evaluator.set_selection(params.extract_input<Field<bool>>("Selection")); evaluator.add(params.extract_input<Field<float3>>("Translation")); evaluator.add(params.extract_input<Field<bool>>("Local Space")); @@ -28,16 +30,16 @@ static void translate_instances(GeoNodeExecParams ¶ms, InstancesComponent &i const VArray<float3> translations = evaluator.get_evaluated<float3>(0); const VArray<bool> local_spaces = evaluator.get_evaluated<bool>(1); - MutableSpan<float4x4> instance_transforms = instances_component.instance_transforms(); + MutableSpan<float4x4> transforms = instances.transforms(); threading::parallel_for(selection.index_range(), 1024, [&](IndexRange range) { for (const int i_selection : range) { const int i = selection[i_selection]; if (local_spaces[i]) { - instance_transforms[i] *= float4x4::from_location(translations[i]); + transforms[i] *= float4x4::from_location(translations[i]); } else { - add_v3_v3(instance_transforms[i].values[3], translations[i]); + add_v3_v3(transforms[i].values[3], translations[i]); } } }); @@ -46,9 +48,8 @@ static void translate_instances(GeoNodeExecParams ¶ms, InstancesComponent &i static void node_geo_exec(GeoNodeExecParams params) { GeometrySet geometry_set = params.extract_input<GeometrySet>("Instances"); - if (geometry_set.has_instances()) { - InstancesComponent &instances = geometry_set.get_component_for_write<InstancesComponent>(); - translate_instances(params, instances); + if (bke::Instances *instances = geometry_set.get_instances_for_write()) { + translate_instances(params, *instances); } params.set_output("Instances", std::move(geometry_set)); } diff --git a/source/blender/nodes/intern/geometry_nodes_lazy_function.cc b/source/blender/nodes/intern/geometry_nodes_lazy_function.cc index 6475a16477a..197f0997160 100644 --- a/source/blender/nodes/intern/geometry_nodes_lazy_function.cc +++ b/source/blender/nodes/intern/geometry_nodes_lazy_function.cc @@ -158,8 +158,9 @@ class LazyFunctionForMultiInput : public LazyFunction { base_type_ = get_socket_cpp_type(socket); BLI_assert(base_type_ != nullptr); BLI_assert(socket.is_multi_input()); + const bNodeTree &btree = socket.owner_tree(); for (const bNodeLink *link : socket.directly_linked_links()) { - if (!link->is_muted()) { + if (!(link->is_muted() || nodeIsDanglingReroute(&btree, link->fromnode))) { inputs_.append({"Input", *base_type_}); } } @@ -603,6 +604,7 @@ class LazyFunctionForGroupNode : public LazyFunction { private: const bNode &group_node_; bool has_many_nodes_ = false; + bool use_fallback_outputs_ = false; std::optional<GeometryNodesLazyFunctionLogger> lf_logger_; std::optional<GeometryNodesLazyFunctionSideEffectProvider> lf_side_effect_provider_; std::optional<lf::GraphExecutor> graph_executor_; @@ -639,6 +641,9 @@ class LazyFunctionForGroupNode : public LazyFunction { } } } + else { + use_fallback_outputs_ = true; + } lf_logger_.emplace(lf_graph_info); lf_side_effect_provider_.emplace(); @@ -659,6 +664,11 @@ class LazyFunctionForGroupNode : public LazyFunction { * if every individual node is very small. */ lazy_threading::send_hint(); } + if (use_fallback_outputs_) { + /* The node group itself does not have an output node, so use default values as outputs. + * The group should still be executed in case it has side effects. */ + params.set_default_remaining_outputs(); + } /* The compute context changes when entering a node group. */ bke::NodeGroupComputeContext compute_context{user_data->compute_context, group_node_.name}; @@ -1073,9 +1083,7 @@ struct GeometryNodesLazyFunctionGraphBuilder { void insert_links_from_socket(const bNodeSocket &from_bsocket, lf::OutputSocket &from_lf_socket) { - const bNode &from_bnode = from_bsocket.owner_node(); - if (this->is_dangling_reroute_input(from_bnode)) { - /* Dangling reroutes should not be used as source of values. */ + if (nodeIsDanglingReroute(&btree_, &from_bsocket.owner_node())) { return; } @@ -1145,7 +1153,8 @@ struct GeometryNodesLazyFunctionGraphBuilder { if (multi_input_link == link) { break; } - if (!multi_input_link->is_muted()) { + if (!(multi_input_link->is_muted() || + nodeIsDanglingReroute(&btree_, multi_input_link->fromnode))) { link_index++; } } @@ -1174,33 +1183,6 @@ struct GeometryNodesLazyFunctionGraphBuilder { } } - bool is_dangling_reroute_input(const bNode &node) - { - if (!node.is_reroute()) { - return false; - } - const bNode *iter_node = &node; - /* It is guaranteed at a higher level that there are no link cycles. */ - while (true) { - const Span<const bNodeLink *> links = iter_node->input_socket(0).directly_linked_links(); - BLI_assert(links.size() <= 1); - if (links.is_empty()) { - return true; - } - const bNodeLink &link = *links[0]; - if (!link.is_available()) { - return false; - } - if (link.is_muted()) { - return false; - } - iter_node = link.fromnode; - if (!iter_node->is_reroute()) { - return false; - } - } - } - lf::OutputSocket *insert_type_conversion_if_necessary( lf::OutputSocket &from_socket, const CPPType &to_type, diff --git a/source/blender/nodes/intern/geometry_nodes_log.cc b/source/blender/nodes/intern/geometry_nodes_log.cc index 167bfef0f83..0f122307328 100644 --- a/source/blender/nodes/intern/geometry_nodes_log.cc +++ b/source/blender/nodes/intern/geometry_nodes_log.cc @@ -101,7 +101,7 @@ GeometryInfoLog::GeometryInfoLog(const GeometrySet &geometry_set) case GEO_COMPONENT_TYPE_INSTANCES: { const InstancesComponent &instances_component = *(const InstancesComponent *)component; InstancesInfo &info = this->instances_info.emplace(); - info.instances_num = instances_component.instances_num(); + info.instances_num = instances_component.attribute_domain_size(ATTR_DOMAIN_INSTANCE); break; } case GEO_COMPONENT_TYPE_EDIT: { diff --git a/source/blender/nodes/intern/node_exec.cc b/source/blender/nodes/intern/node_exec.cc index 724d6f1a1e1..af783ca391f 100644 --- a/source/blender/nodes/intern/node_exec.cc +++ b/source/blender/nodes/intern/node_exec.cc @@ -162,7 +162,7 @@ bNodeTreeExec *ntree_exec_begin(bNodeExecContext *context, /* XXX could let callbacks do this for specialized data */ exec = MEM_cnew<bNodeTreeExec>("node tree execution data"); - /* backpointer to node tree */ + /* Back-pointer to node tree. */ exec->nodetree = ntree; /* set stack indices */ diff --git a/source/blender/nodes/intern/node_exec.h b/source/blender/nodes/intern/node_exec.h index dc07f52e23f..55bf409444e 100644 --- a/source/blender/nodes/intern/node_exec.h +++ b/source/blender/nodes/intern/node_exec.h @@ -27,7 +27,7 @@ struct bNodeTree; /* Node execution data */ typedef struct bNodeExec { - /** Backpointer to node. */ + /** Back-pointer to node. */ struct bNode *node; bNodeExecData data; @@ -37,7 +37,7 @@ typedef struct bNodeExec { /* Execution Data for each instance of node tree execution */ typedef struct bNodeTreeExec { - struct bNodeTree *nodetree; /* backpointer to node tree */ + struct bNodeTree *nodetree; /* Back-pointer to node tree. */ int totnodes; /* total node count */ struct bNodeExec *nodeexec; /* per-node execution data */ diff --git a/source/blender/nodes/shader/node_shader_tree.cc b/source/blender/nodes/shader/node_shader_tree.cc index 52edf68b3ff..f177fc95ef8 100644 --- a/source/blender/nodes/shader/node_shader_tree.cc +++ b/source/blender/nodes/shader/node_shader_tree.cc @@ -1126,7 +1126,8 @@ void ntreeShaderEndExecTree(bNodeTreeExec *exec) bNodeTree *ntree = exec->nodetree; ntreeShaderEndExecTree_internal(exec); - /* XXX clear nodetree backpointer to exec data, same problem as noted in ntreeBeginExecTree */ + /* XXX: clear node-tree back-pointer to exec data, + * same problem as noted in #ntreeBeginExecTree. */ ntree->execdata = nullptr; } } diff --git a/source/blender/nodes/texture/CMakeLists.txt b/source/blender/nodes/texture/CMakeLists.txt index 77db71d4b1a..2d704ac2228 100644 --- a/source/blender/nodes/texture/CMakeLists.txt +++ b/source/blender/nodes/texture/CMakeLists.txt @@ -2,7 +2,7 @@ set(INC . - ../ + .. ../intern ../../editors/include ../../blenkernel diff --git a/source/blender/nodes/texture/node_texture_tree.c b/source/blender/nodes/texture/node_texture_tree.c index 81d0b0fbc84..99146f1a25c 100644 --- a/source/blender/nodes/texture/node_texture_tree.c +++ b/source/blender/nodes/texture/node_texture_tree.c @@ -308,7 +308,8 @@ void ntreeTexEndExecTree(bNodeTreeExec *exec) bNodeTree *ntree = exec->nodetree; ntreeTexEndExecTree_internal(exec); - /* XXX clear nodetree backpointer to exec data, same problem as noted in ntreeBeginExecTree */ + /* XXX: clear node-tree back-pointer to exec data, + * same problem as noted in #ntreeBeginExecTree. */ ntree->execdata = NULL; } } diff --git a/source/blender/python/gpu/gpu_py_platform.c b/source/blender/python/gpu/gpu_py_platform.c index b877e3ceb98..c6e964405fa 100644 --- a/source/blender/python/gpu/gpu_py_platform.c +++ b/source/blender/python/gpu/gpu_py_platform.c @@ -11,6 +11,7 @@ #include "BLI_utildefines.h" +#include "GPU_context.h" #include "GPU_platform.h" #include "gpu_py_platform.h" /* Own include. */ @@ -83,6 +84,30 @@ static PyObject *pygpu_platform_device_type_get(PyObject *UNUSED(self)) return PyUnicode_FromString("UNKNOWN"); } +PyDoc_STRVAR(pygpu_platform_backend_type_get_doc, + ".. function:: backend_type_get()\n" + "\n" + " Get actuve GPU backend.\n" + "\n" + " :return: Backend type ('OPENGL', 'VULKAN', 'METAL', 'NONE', 'UNKNOWN').\n" + " :rtype: str\n"); +static PyObject *pygpu_platform_backend_type_get(PyObject *UNUSED(self)) +{ + switch (GPU_backend_get_type()) { + case GPU_BACKEND_VULKAN: + return PyUnicode_FromString("VULKAN"); + case GPU_BACKEND_METAL: + return PyUnicode_FromString("METAL"); + case GPU_BACKEND_NONE: + return PyUnicode_FromString("NONE"); + case GPU_BACKEND_OPENGL: + return PyUnicode_FromString("OPENGL"); + case GPU_BACKEND_ANY: + break; + } + return PyUnicode_FromString("UNKNOWN"); +} + /** \} */ /* -------------------------------------------------------------------- */ @@ -106,6 +131,10 @@ static struct PyMethodDef pygpu_platform__tp_methods[] = { (PyCFunction)pygpu_platform_device_type_get, METH_NOARGS, pygpu_platform_device_type_get_doc}, + {"backend_type_get", + (PyCFunction)pygpu_platform_backend_type_get, + METH_NOARGS, + pygpu_platform_backend_type_get_doc}, {NULL, NULL, 0, NULL}, }; diff --git a/source/blender/python/intern/bpy_gizmo_wrap.h b/source/blender/python/intern/bpy_gizmo_wrap.h index 6a876747e22..7d5edebed0f 100644 --- a/source/blender/python/intern/bpy_gizmo_wrap.h +++ b/source/blender/python/intern/bpy_gizmo_wrap.h @@ -13,7 +13,7 @@ struct wmGizmoType; extern "C" { #endif -/* exposed to rna/wm api */ +/* Exposed to RNA/WM API. */ void BPY_RNA_gizmo_wrapper(struct wmGizmoType *gzt, void *userdata); void BPY_RNA_gizmogroup_wrapper(struct wmGizmoGroupType *gzgt, void *userdata); diff --git a/source/blender/python/intern/bpy_operator_wrap.h b/source/blender/python/intern/bpy_operator_wrap.h index de3779332da..4b8ceba5f0c 100644 --- a/source/blender/python/intern/bpy_operator_wrap.h +++ b/source/blender/python/intern/bpy_operator_wrap.h @@ -12,10 +12,11 @@ struct wmOperatorType; extern "C" { #endif -/* these are used for operator methods, used by bpy_operator.c */ +/** These are used for operator methods, used by `bpy_operator.c`. */ PyObject *PYOP_wrap_macro_define(PyObject *self, PyObject *args); -/* exposed to rna/wm api */ +/* Exposed to RNA/WM API. */ + /** * Generic function used by all Python defined operators * it's passed as an argument to #WM_operatortype_append_ptr in for operator registration. diff --git a/source/blender/python/intern/bpy_rna.c b/source/blender/python/intern/bpy_rna.c index 0eaa5d6b6c7..02f7e16e805 100644 --- a/source/blender/python/intern/bpy_rna.c +++ b/source/blender/python/intern/bpy_rna.c @@ -380,10 +380,10 @@ static short pyrna_rotation_euler_order_get(PointerRNA *ptr, const short order_fallback, PropertyRNA **r_prop_eul_order); -/* bpyrna vector/euler/quat callbacks. */ +/* `bpyrna` vector/euler/quaternion callbacks. */ static uchar mathutils_rna_array_cb_index = -1; /* Index for our callbacks. */ -/* Subtype not used much yet. */ +/* Sub-type not used much yet. */ # define MATHUTILS_CB_SUBTYPE_EUL 0 # define MATHUTILS_CB_SUBTYPE_VEC 1 # define MATHUTILS_CB_SUBTYPE_QUAT 2 diff --git a/source/blender/python/mathutils/mathutils_noise.c b/source/blender/python/mathutils/mathutils_noise.c index 3a3297f27f7..3c564142160 100644 --- a/source/blender/python/mathutils/mathutils_noise.c +++ b/source/blender/python/mathutils/mathutils_noise.c @@ -40,7 +40,7 @@ * * Any feedback is very welcome. * http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/emt.html - * email: m-mat @ math.sci.hiroshima-u.ac.jp (remove space). */ + * email: `m-mat @ math.sci.hiroshima-u.ac.jp` (remove space). */ /* Period parameters */ #define N 624 @@ -120,7 +120,7 @@ static void setRndSeed(int seed) } } -/* float number in range [0, 1) using the mersenne twister rng */ +/* Float number in range [0, 1) using the mersenne twister random number generator. */ static float frand(void) { ulong y; diff --git a/source/blender/render/intern/bake.c b/source/blender/render/intern/bake.c index 8fd62f7ec34..9b56e18bb26 100644 --- a/source/blender/render/intern/bake.c +++ b/source/blender/render/intern/bake.c @@ -967,7 +967,7 @@ void RE_bake_normal_world_to_object(const BakePixel pixel_array[], size_t i; float iobmat[4][4]; - invert_m4_m4(iobmat, ob->obmat); + invert_m4_m4(iobmat, ob->object_to_world); for (i = 0; i < pixels_num; i++) { size_t offset; diff --git a/source/blender/render/intern/engine.cc b/source/blender/render/intern/engine.cc index 5eb4db6faa4..b8757d33580 100644 --- a/source/blender/render/intern/engine.cc +++ b/source/blender/render/intern/engine.cc @@ -969,6 +969,40 @@ static void engine_render_view_layer(Render *re, engine_depsgraph_exit(engine); } +/* Callback function for engine_render_create_result to add all render passes to the result. */ +static void engine_render_add_result_pass_cb(void *user_data, + struct Scene *UNUSED(scene), + struct ViewLayer *view_layer, + const char *name, + int channels, + const char *chanid, + eNodeSocketDatatype UNUSED(type)) +{ + RenderResult *rr = (RenderResult *)user_data; + RE_create_render_pass(rr, name, channels, chanid, view_layer->name, RR_ALL_VIEWS, false); +} + +static RenderResult *engine_render_create_result(Render *re) +{ + RenderResult *rr = render_result_new(re, &re->disprect, RR_ALL_LAYERS, RR_ALL_VIEWS); + if (rr == nullptr) { + return nullptr; + } + + FOREACH_VIEW_LAYER_TO_RENDER_BEGIN (re, view_layer) { + RE_engine_update_render_passes( + re->engine, re->scene, view_layer, engine_render_add_result_pass_cb, rr); + } + FOREACH_VIEW_LAYER_TO_RENDER_END; + + /* Preview does not support deferred render result allocation. */ + if (re->r.scemode & R_BUTS_PREVIEW) { + render_result_passes_allocated_ensure(rr); + } + + return rr; +} + bool RE_engine_render(Render *re, bool do_all) { RenderEngineType *type = RE_engines_find(re->r.engine); @@ -1008,6 +1042,14 @@ bool RE_engine_render(Render *re, bool do_all) render_update_anim_renderdata(re, &re->scene->r, &re->scene->view_layers); } + /* Create engine. */ + RenderEngine *engine = re->engine; + + if (!engine) { + engine = RE_engine_create(type); + re->engine = engine; + } + /* create render result */ BLI_rw_mutex_lock(&re->resultmutex, THREAD_LOCK_WRITE); if (re->result == nullptr || !(re->r.scemode & R_BUTS_PREVIEW)) { @@ -1015,7 +1057,7 @@ bool RE_engine_render(Render *re, bool do_all) render_result_free(re->result); } - re->result = render_result_new(re, &re->disprect, RR_ALL_LAYERS, RR_ALL_VIEWS); + re->result = engine_render_create_result(re); } BLI_rw_mutex_unlock(&re->resultmutex); @@ -1024,6 +1066,9 @@ bool RE_engine_render(Render *re, bool do_all) if (re->draw_lock) { re->draw_lock(re->dlh, false); } + /* Free engine. */ + RE_engine_free(engine); + re->engine = nullptr; /* Too small image is handled earlier, here it could only happen if * there was no sufficient memory to allocate all passes. */ @@ -1036,14 +1081,6 @@ bool RE_engine_render(Render *re, bool do_all) re->i.cfra = re->scene->r.cfra; BLI_strncpy(re->i.scene_name, re->scene->id.name + 2, sizeof(re->i.scene_name)); - /* render */ - RenderEngine *engine = re->engine; - - if (!engine) { - engine = RE_engine_create(type); - re->engine = engine; - } - engine->flag |= RE_ENGINE_RENDERING; /* TODO: actually link to a parent which shouldn't happen */ diff --git a/source/blender/render/intern/render_result.cc b/source/blender/render/intern/render_result.cc index e8603f5e1b3..94f6e2f1509 100644 --- a/source/blender/render/intern/render_result.cc +++ b/source/blender/render/intern/render_result.cc @@ -262,7 +262,7 @@ RenderResult *render_result_new(Render *re, render_result_views_new(rr, &re->r); - /* check renderdata for amount of layers */ + /* Check render-data for amount of layers. */ FOREACH_VIEW_LAYER_TO_RENDER_BEGIN (re, view_layer) { if (layername && layername[0]) { if (!STREQ(view_layer->name, layername)) { @@ -290,90 +290,8 @@ RenderResult *render_result_new(Render *re, } } -#define RENDER_LAYER_ADD_PASS_SAFE(rr, rl, channels, name, viewname, chan_id) \ - do { \ - if (render_layer_add_pass(rr, rl, channels, name, viewname, chan_id, false) == nullptr) { \ - render_result_free(rr); \ - return nullptr; \ - } \ - } while (false) - /* A render-layer should always have a "Combined" pass. */ render_layer_add_pass(rr, rl, 4, "Combined", view, "RGBA", false); - - if (view_layer->passflag & SCE_PASS_Z) { - RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 1, RE_PASSNAME_Z, view, "Z"); - } - if (view_layer->passflag & SCE_PASS_VECTOR) { - RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 4, RE_PASSNAME_VECTOR, view, "XYZW"); - } - if (view_layer->passflag & SCE_PASS_NORMAL) { - RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 3, RE_PASSNAME_NORMAL, view, "XYZ"); - } - if (view_layer->passflag & SCE_PASS_POSITION) { - RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 3, RE_PASSNAME_POSITION, view, "XYZ"); - } - if (view_layer->passflag & SCE_PASS_UV) { - RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 3, RE_PASSNAME_UV, view, "UVA"); - } - if (view_layer->passflag & SCE_PASS_EMIT) { - RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 3, RE_PASSNAME_EMIT, view, "RGB"); - } - if (view_layer->passflag & SCE_PASS_AO) { - RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 3, RE_PASSNAME_AO, view, "RGB"); - } - if (view_layer->passflag & SCE_PASS_ENVIRONMENT) { - RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 3, RE_PASSNAME_ENVIRONMENT, view, "RGB"); - } - if (view_layer->passflag & SCE_PASS_SHADOW) { - RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 3, RE_PASSNAME_SHADOW, view, "RGB"); - } - if (view_layer->passflag & SCE_PASS_INDEXOB) { - RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 1, RE_PASSNAME_INDEXOB, view, "X"); - } - if (view_layer->passflag & SCE_PASS_INDEXMA) { - RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 1, RE_PASSNAME_INDEXMA, view, "X"); - } - if (view_layer->passflag & SCE_PASS_MIST) { - RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 1, RE_PASSNAME_MIST, view, "Z"); - } - if (view_layer->passflag & SCE_PASS_DIFFUSE_DIRECT) { - RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 3, RE_PASSNAME_DIFFUSE_DIRECT, view, "RGB"); - } - if (view_layer->passflag & SCE_PASS_DIFFUSE_INDIRECT) { - RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 3, RE_PASSNAME_DIFFUSE_INDIRECT, view, "RGB"); - } - if (view_layer->passflag & SCE_PASS_DIFFUSE_COLOR) { - RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 3, RE_PASSNAME_DIFFUSE_COLOR, view, "RGB"); - } - if (view_layer->passflag & SCE_PASS_GLOSSY_DIRECT) { - RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 3, RE_PASSNAME_GLOSSY_DIRECT, view, "RGB"); - } - if (view_layer->passflag & SCE_PASS_GLOSSY_INDIRECT) { - RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 3, RE_PASSNAME_GLOSSY_INDIRECT, view, "RGB"); - } - if (view_layer->passflag & SCE_PASS_GLOSSY_COLOR) { - RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 3, RE_PASSNAME_GLOSSY_COLOR, view, "RGB"); - } - if (view_layer->passflag & SCE_PASS_TRANSM_DIRECT) { - RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 3, RE_PASSNAME_TRANSM_DIRECT, view, "RGB"); - } - if (view_layer->passflag & SCE_PASS_TRANSM_INDIRECT) { - RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 3, RE_PASSNAME_TRANSM_INDIRECT, view, "RGB"); - } - if (view_layer->passflag & SCE_PASS_TRANSM_COLOR) { - RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 3, RE_PASSNAME_TRANSM_COLOR, view, "RGB"); - } - if (view_layer->passflag & SCE_PASS_SUBSURFACE_DIRECT) { - RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 3, RE_PASSNAME_SUBSURFACE_DIRECT, view, "RGB"); - } - if (view_layer->passflag & SCE_PASS_SUBSURFACE_INDIRECT) { - RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 3, RE_PASSNAME_SUBSURFACE_INDIRECT, view, "RGB"); - } - if (view_layer->passflag & SCE_PASS_SUBSURFACE_COLOR) { - RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 3, RE_PASSNAME_SUBSURFACE_COLOR, view, "RGB"); - } -#undef RENDER_LAYER_ADD_PASS_SAFE } } FOREACH_VIEW_LAYER_TO_RENDER_END; @@ -411,11 +329,6 @@ RenderResult *render_result_new(Render *re, rr->xof = re->disprect.xmin + BLI_rcti_cent_x(&re->disprect) - (re->winx / 2); rr->yof = re->disprect.ymin + BLI_rcti_cent_y(&re->disprect) - (re->winy / 2); - /* Preview does not support deferred render result allocation. */ - if (re->r.scemode & R_BUTS_PREVIEW) { - render_result_passes_allocated_ensure(rr); - } - return rr; } @@ -962,7 +875,7 @@ static void render_result_exr_file_cache_path(Scene *sce, sce->id.name + 2, path_hexdigest); - BLI_join_dirfile(r_path, FILE_CACHE_MAX, root, filename_full); + BLI_path_join(r_path, FILE_CACHE_MAX, root, filename_full); if (BLI_path_is_rel(r_path)) { BLI_path_abs(r_path, dirname); } diff --git a/source/blender/render/intern/texture_pointdensity.c b/source/blender/render/intern/texture_pointdensity.c index 2a2b62be1f0..b285bbd1459 100644 --- a/source/blender/render/intern/texture_pointdensity.c +++ b/source/blender/render/intern/texture_pointdensity.c @@ -175,7 +175,7 @@ static void pointdensity_cache_psys( sim.psmd = psys_get_modifier(ob, psys); /* in case ob->imat isn't up-to-date */ - invert_m4_m4(ob->imat, ob->obmat); + invert_m4_m4(ob->imat, ob->object_to_world); total_particles = psys->totpart + psys->totchild; psys->lattice_deform_data = psys_create_lattice_deform_data(&sim); @@ -399,12 +399,12 @@ static void pointdensity_cache_object(PointDensity *pd, Object *ob) case TEX_PD_OBJECTSPACE: break; case TEX_PD_OBJECTLOC: - mul_m4_v3(ob->obmat, co); + mul_m4_v3(ob->object_to_world, co); sub_v3_v3(co, ob->loc); break; case TEX_PD_WORLDSPACE: default: - mul_m4_v3(ob->obmat, co); + mul_m4_v3(ob->object_to_world, co); break; } @@ -778,7 +778,7 @@ static void particle_system_minmax(Depsgraph *depsgraph, sim.psys = psys; sim.psmd = psys_get_modifier(object, psys); - invert_m4_m4(imat, object->obmat); + invert_m4_m4(imat, object->object_to_world); total_particles = psys->totpart + psys->totchild; psys->lattice_deform_data = psys_create_lattice_deform_data(&sim); diff --git a/source/blender/sequencer/intern/disk_cache.c b/source/blender/sequencer/intern/disk_cache.c index 1f52d2ea41b..596a28201cc 100644 --- a/source/blender/sequencer/intern/disk_cache.c +++ b/source/blender/sequencer/intern/disk_cache.c @@ -182,7 +182,7 @@ static void seq_disk_cache_get_files(SeqDiskCache *disk_cache, char *path) if (is_dir && !FILENAME_IS_CURRPAR(file)) { char subpath[FILE_MAX]; BLI_strncpy(subpath, fl->path, sizeof(subpath)); - BLI_path_slash_ensure(subpath); + BLI_path_slash_ensure(subpath, sizeof(sizeof(subpath))); seq_disk_cache_get_files(disk_cache, subpath); } @@ -291,8 +291,8 @@ static void seq_disk_cache_get_project_dir(SeqDiskCache *disk_cache, char *path, /* Use suffix, so that the cache directory name does not conflict with the bmain's blend file. */ const char *suffix = "_seq_cache"; strncat(cache_dir, suffix, sizeof(cache_dir) - strlen(cache_dir) - 1); - BLI_strncpy(path, seq_disk_cache_base_dir(), path_len); - BLI_path_append(path, path_len, cache_dir); + + BLI_path_join(path, path_len, seq_disk_cache_base_dir(), cache_dir); } static void seq_disk_cache_get_dir( @@ -307,9 +307,8 @@ static void seq_disk_cache_get_dir( BLI_strncpy(seq_name, seq->name, sizeof(seq_name)); BLI_filename_make_safe(scene_name); BLI_filename_make_safe(seq_name); - BLI_strncpy(path, project_dir, path_len); - BLI_path_append(path, path_len, scene_name); - BLI_path_append(path, path_len, seq_name); + + BLI_path_join(path, path_len, project_dir, scene_name, seq_name); } static void seq_disk_cache_get_file_path(SeqDiskCache *disk_cache, @@ -350,8 +349,7 @@ static void seq_disk_cache_handle_versioning(SeqDiskCache *disk_cache) int version = 0; seq_disk_cache_get_project_dir(disk_cache, filepath, sizeof(filepath)); - BLI_strncpy(path_version_file, filepath, sizeof(path_version_file)); - BLI_path_append(path_version_file, sizeof(path_version_file), "cache_version"); + BLI_path_join(path_version_file, sizeof(path_version_file), filepath, "cache_version"); if (BLI_exists(filepath) && BLI_is_dir(filepath)) { FILE *file = BLI_fopen(path_version_file, "r"); @@ -384,7 +382,7 @@ static void seq_disk_cache_delete_invalid_files(SeqDiskCache *disk_cache, DiskCacheFile *next_file, *cache_file = disk_cache->files.first; char cache_dir[FILE_MAX]; seq_disk_cache_get_dir(disk_cache, scene, seq, cache_dir, sizeof(cache_dir)); - BLI_path_slash_ensure(cache_dir); + BLI_path_slash_ensure(cache_dir, sizeof(cache_dir)); while (cache_file) { next_file = cache_file->next; diff --git a/source/blender/sequencer/intern/proxy.c b/source/blender/sequencer/intern/proxy.c index 4220efab8bf..fc1df4dc3ac 100644 --- a/source/blender/sequencer/intern/proxy.c +++ b/source/blender/sequencer/intern/proxy.c @@ -106,7 +106,7 @@ bool seq_proxy_get_custom_file_fname(Sequence *seq, char *name, const int view_i return false; } - BLI_join_dirfile(fname, PROXY_MAXFILE, proxy->dir, proxy->file); + BLI_path_join(fname, PROXY_MAXFILE, proxy->dir, proxy->file); BLI_path_abs(fname, BKE_main_blendfile_path_from_global()); if (view_id > 0) { @@ -325,7 +325,7 @@ static bool seq_proxy_multiview_context_invalid(Sequence *seq, Scene *scene, con if (view_id == 0) { char path[FILE_MAX]; - BLI_join_dirfile(path, sizeof(path), seq->strip->dir, seq->strip->stripdata->name); + BLI_path_join(path, sizeof(path), seq->strip->dir, seq->strip->stripdata->name); BLI_path_abs(path, BKE_main_blendfile_path_from_global()); BKE_scene_multiview_view_prefix_get(scene, path, prefix, &ext); } @@ -585,8 +585,7 @@ void seq_proxy_index_dir_set(struct anim *anim, const char *base_dir) char fname[FILE_MAXFILE]; IMB_anim_get_fname(anim, fname, FILE_MAXFILE); - BLI_strncpy(dir, base_dir, sizeof(dir)); - BLI_path_append(dir, sizeof(dir), fname); + BLI_path_join(dir, sizeof(dir), base_dir, fname); IMB_anim_set_index_dir(anim, dir); } diff --git a/source/blender/sequencer/intern/render.c b/source/blender/sequencer/intern/render.c index 91ecccbe0f8..e3fd9216842 100644 --- a/source/blender/sequencer/intern/render.c +++ b/source/blender/sequencer/intern/render.c @@ -938,7 +938,7 @@ static ImBuf *seq_render_image_strip(const SeqRenderData *context, return NULL; } - BLI_join_dirfile(name, sizeof(name), seq->strip->dir, s_elem->name); + BLI_path_join(name, sizeof(name), seq->strip->dir, s_elem->name); BLI_path_abs(name, BKE_main_blendfile_path_from_global()); /* Try to get a proxy image. */ @@ -1026,6 +1026,15 @@ static ImBuf *seq_render_movie_strip_custom_file_proxy(const SeqRenderData *cont return IMB_anim_absolute(proxy->anim, frameno, IMB_TC_NONE, IMB_PROXY_NONE); } +static IMB_Timecode_Type seq_render_movie_strip_timecode_get(Sequence *seq) +{ + bool use_timecodes = (seq->flag & SEQ_USE_PROXY) != 0; + if (!use_timecodes) { + return IMB_TC_NONE; + } + return seq->strip->proxy ? seq->strip->proxy->tc : IMB_TC_NONE; +} + /** * Render individual view for multi-view or single (default view) for mono-view. */ @@ -1049,7 +1058,7 @@ static ImBuf *seq_render_movie_strip_view(const SeqRenderData *context, else { ibuf = IMB_anim_absolute(sanim->anim, frame_index + seq->anim_startofs, - seq->strip->proxy ? seq->strip->proxy->tc : IMB_TC_RECORD_RUN, + seq_render_movie_strip_timecode_get(seq), psize); } @@ -1062,7 +1071,7 @@ static ImBuf *seq_render_movie_strip_view(const SeqRenderData *context, if (ibuf == NULL) { ibuf = IMB_anim_absolute(sanim->anim, frame_index + seq->anim_startofs, - seq->strip->proxy ? seq->strip->proxy->tc : IMB_TC_RECORD_RUN, + seq_render_movie_strip_timecode_get(seq), IMB_PROXY_NONE); } if (ibuf == NULL) { diff --git a/source/blender/sequencer/intern/strip_add.c b/source/blender/sequencer/intern/strip_add.c index 753a6ee39e0..7f4c91724fc 100644 --- a/source/blender/sequencer/intern/strip_add.c +++ b/source/blender/sequencer/intern/strip_add.c @@ -204,7 +204,7 @@ void SEQ_add_image_init_alpha_mode(Sequence *seq) char name[FILE_MAX]; ImBuf *ibuf; - BLI_join_dirfile(name, sizeof(name), seq->strip->dir, seq->strip->stripdata->name); + BLI_path_join(name, sizeof(name), seq->strip->dir, seq->strip->stripdata->name); BLI_path_abs(name, BKE_main_blendfile_path_from_global()); /* Initialize input color space. */ @@ -545,7 +545,7 @@ void SEQ_add_reload_new_file(Main *bmain, Scene *scene, Sequence *seq, const boo const bool is_multiview = (seq->flag & SEQ_USE_VIEWS) != 0 && (scene->r.scemode & R_MULTIVIEW) != 0; - BLI_join_dirfile(path, sizeof(path), seq->strip->dir, seq->strip->stripdata->name); + BLI_path_join(path, sizeof(path), seq->strip->dir, seq->strip->stripdata->name); BLI_path_abs(path, BKE_main_blendfile_path_from_global()); SEQ_relations_sequence_free_anim(seq); diff --git a/source/blender/sequencer/intern/utils.c b/source/blender/sequencer/intern/utils.c index 6d182b6bcca..5b70bc33e88 100644 --- a/source/blender/sequencer/intern/utils.c +++ b/source/blender/sequencer/intern/utils.c @@ -224,7 +224,7 @@ void seq_open_anim_file(Scene *scene, Sequence *seq, bool openfile) /* reset all the previously created anims */ SEQ_relations_sequence_free_anim(seq); - BLI_join_dirfile(name, sizeof(name), seq->strip->dir, seq->strip->stripdata->name); + BLI_path_join(name, sizeof(name), seq->strip->dir, seq->strip->stripdata->name); BLI_path_abs(name, BKE_main_blendfile_path_from_global()); proxy = seq->strip->proxy; diff --git a/source/blender/windowmanager/WM_types.h b/source/blender/windowmanager/WM_types.h index e25169109e7..e4050397aaa 100644 --- a/source/blender/windowmanager/WM_types.h +++ b/source/blender/windowmanager/WM_types.h @@ -359,7 +359,7 @@ typedef struct wmNotifier { /* data type, 256 entries is enough, it can overlap */ #define NOTE_DATA 0x00FF0000 -/* NC_WM windowmanager */ +/* NC_WM (window-manager). */ #define ND_FILEREAD (1 << 16) #define ND_FILESAVE (2 << 16) #define ND_DATACHANGED (3 << 16) diff --git a/source/blender/windowmanager/intern/wm_dragdrop.cc b/source/blender/windowmanager/intern/wm_dragdrop.cc index 0896daec561..fb63abed9e9 100644 --- a/source/blender/windowmanager/intern/wm_dragdrop.cc +++ b/source/blender/windowmanager/intern/wm_dragdrop.cc @@ -853,7 +853,8 @@ static void wm_drag_draw_icon(bContext * /*C*/, wmWindow * /*win*/, wmDrag *drag y = xy[1] - 2 * UI_DPI_FAC; const uchar text_col[] = {255, 255, 255, 255}; - UI_icon_draw_ex(x, y, drag->icon, U.inv_dpi_fac, 0.8, 0.0f, text_col, false); + UI_icon_draw_ex( + x, y, drag->icon, U.inv_dpi_fac, 0.8, 0.0f, text_col, false, UI_NO_ICON_OVERLAY_TEXT); } } diff --git a/source/blender/windowmanager/intern/wm_event_system.cc b/source/blender/windowmanager/intern/wm_event_system.cc index affe0bcf45a..181ec89cabd 100644 --- a/source/blender/windowmanager/intern/wm_event_system.cc +++ b/source/blender/windowmanager/intern/wm_event_system.cc @@ -5620,7 +5620,7 @@ void wm_event_add_ghostevent(wmWindowManager *wm, wmWindow *win, int type, void case GHOST_kEventNDOFButton: { GHOST_TEventNDOFButtonData *e = static_cast<GHOST_TEventNDOFButtonData *>(customdata); - event.type = NDOF_BUTTON_NONE + e->button; + event.type = NDOF_BUTTON_INDEX_AS_EVENT(e->button); switch (e->action) { case GHOST_kPress: diff --git a/source/blender/windowmanager/intern/wm_files.c b/source/blender/windowmanager/intern/wm_files.c index 7ac55b2c27a..b009a67efba 100644 --- a/source/blender/windowmanager/intern/wm_files.c +++ b/source/blender/windowmanager/intern/wm_files.c @@ -1166,12 +1166,10 @@ void wm_homefile_read_ex(bContext *C, const char *const cfgdir = BKE_appdir_folder_id(BLENDER_USER_CONFIG, NULL); if (!use_factory_settings) { if (cfgdir) { - BLI_path_join( - filepath_startup, sizeof(filepath_startup), cfgdir, BLENDER_STARTUP_FILE, NULL); + BLI_path_join(filepath_startup, sizeof(filepath_startup), cfgdir, BLENDER_STARTUP_FILE); filepath_startup_is_factory = false; if (use_userdef) { - BLI_path_join( - filepath_userdef, sizeof(filepath_startup), cfgdir, BLENDER_USERPREF_FILE, NULL); + BLI_path_join(filepath_userdef, sizeof(filepath_startup), cfgdir, BLENDER_USERPREF_FILE); } } else { @@ -1214,12 +1212,9 @@ void wm_homefile_read_ex(bContext *C, /* note that the path is being set even when 'use_factory_settings == true' * this is done so we can load a templates factory-settings */ if (!use_factory_settings) { - BLI_path_join(app_template_config, sizeof(app_template_config), cfgdir, app_template, NULL); - BLI_path_join(filepath_startup, - sizeof(filepath_startup), - app_template_config, - BLENDER_STARTUP_FILE, - NULL); + BLI_path_join(app_template_config, sizeof(app_template_config), cfgdir, app_template); + BLI_path_join( + filepath_startup, sizeof(filepath_startup), app_template_config, BLENDER_STARTUP_FILE); filepath_startup_is_factory = false; if (BLI_access(filepath_startup, R_OK) != 0) { filepath_startup[0] = '\0'; @@ -1230,11 +1225,8 @@ void wm_homefile_read_ex(bContext *C, } if (filepath_startup[0] == '\0') { - BLI_path_join(filepath_startup, - sizeof(filepath_startup), - app_template_system, - BLENDER_STARTUP_FILE, - NULL); + BLI_path_join( + filepath_startup, sizeof(filepath_startup), app_template_system, BLENDER_STARTUP_FILE); filepath_startup_is_factory = true; /* Update defaults only for system templates. */ @@ -1303,16 +1295,14 @@ void wm_homefile_read_ex(bContext *C, char temp_path[FILE_MAX]; temp_path[0] = '\0'; if (!use_factory_settings) { - BLI_path_join( - temp_path, sizeof(temp_path), app_template_config, BLENDER_USERPREF_FILE, NULL); + BLI_path_join(temp_path, sizeof(temp_path), app_template_config, BLENDER_USERPREF_FILE); if (BLI_access(temp_path, R_OK) != 0) { temp_path[0] = '\0'; } } if (temp_path[0] == '\0') { - BLI_path_join( - temp_path, sizeof(temp_path), app_template_system, BLENDER_USERPREF_FILE, NULL); + BLI_path_join(temp_path, sizeof(temp_path), app_template_system, BLENDER_USERPREF_FILE); } if (use_userdef) { @@ -1416,7 +1406,7 @@ void wm_history_file_read(void) LinkNode *l; int num; - BLI_join_dirfile(name, sizeof(name), cfgdir, BLENDER_HISTORY_FILE); + BLI_path_join(name, sizeof(name), cfgdir, BLENDER_HISTORY_FILE); LinkNode *lines = BLI_file_read_as_lines(name); @@ -1479,7 +1469,7 @@ static void wm_history_file_write(void) return; } - BLI_join_dirfile(name, sizeof(name), user_config_dir, BLENDER_HISTORY_FILE); + BLI_path_join(name, sizeof(name), user_config_dir, BLENDER_HISTORY_FILE); fp = BLI_fopen(name, "w"); if (fp) { @@ -1940,7 +1930,7 @@ static void wm_autosave_location(char filepath[FILE_MAX]) } #endif - BLI_join_dirfile(filepath, FILE_MAX, tempdir_base, path); + BLI_path_join(filepath, FILE_MAX, tempdir_base, path); } static void wm_autosave_write(Main *bmain, wmWindowManager *wm) @@ -2030,7 +2020,7 @@ void wm_autosave_delete(void) if (BLI_exists(filepath)) { char str[FILE_MAX]; - BLI_join_dirfile(str, sizeof(str), BKE_tempdir_base(), BLENDER_QUIT_FILE); + BLI_path_join(str, sizeof(str), BKE_tempdir_base(), BLENDER_QUIT_FILE); /* if global undo; remove tempsave, otherwise rename */ if (U.uiflag & USER_GLOBALUNDO) { @@ -2132,7 +2122,7 @@ static int wm_homefile_write_exec(bContext *C, wmOperator *op) /* update keymaps in user preferences */ WM_keyconfig_update(wm); - BLI_path_join(filepath, sizeof(filepath), cfgdir, BLENDER_STARTUP_FILE, NULL); + BLI_path_join(filepath, sizeof(filepath), cfgdir, BLENDER_STARTUP_FILE); printf("Writing homefile: '%s' ", filepath); @@ -2925,7 +2915,7 @@ void WM_OT_revert_mainfile(wmOperatorType *ot) bool WM_file_recover_last_session(bContext *C, ReportList *reports) { char filepath[FILE_MAX]; - BLI_join_dirfile(filepath, sizeof(filepath), BKE_tempdir_base(), BLENDER_QUIT_FILE); + BLI_path_join(filepath, sizeof(filepath), BKE_tempdir_base(), BLENDER_QUIT_FILE); G.fileflags |= G_FILE_RECOVER_READ; const bool success = wm_file_read_opwrap(C, filepath, reports); G.fileflags &= ~G_FILE_RECOVER_READ; diff --git a/source/blender/windowmanager/intern/wm_files_link.c b/source/blender/windowmanager/intern/wm_files_link.c index 0ea783af1af..bbe53bf7355 100644 --- a/source/blender/windowmanager/intern/wm_files_link.c +++ b/source/blender/windowmanager/intern/wm_files_link.c @@ -210,7 +210,7 @@ static int wm_link_append_exec(bContext *C, wmOperator *op) RNA_string_get(op->ptr, "filename", relname); RNA_string_get(op->ptr, "directory", root); - BLI_join_dirfile(path, sizeof(path), root, relname); + BLI_path_join(path, sizeof(path), root, relname); /* test if we have a valid data */ if (!BLO_library_path_explode(path, libname, &group, &name)) { @@ -284,7 +284,7 @@ static int wm_link_append_exec(bContext *C, wmOperator *op) RNA_BEGIN (op->ptr, itemptr, "files") { RNA_string_get(&itemptr, "name", relname); - BLI_join_dirfile(path, sizeof(path), root, relname); + BLI_path_join(path, sizeof(path), root, relname); if (BLO_library_path_explode(path, libname, &group, &name)) { if (!wm_link_append_item_poll(NULL, path, group, name, do_append)) { @@ -303,7 +303,7 @@ static int wm_link_append_exec(bContext *C, wmOperator *op) RNA_BEGIN (op->ptr, itemptr, "files") { RNA_string_get(&itemptr, "name", relname); - BLI_join_dirfile(path, sizeof(path), root, relname); + BLI_path_join(path, sizeof(path), root, relname); if (BLO_library_path_explode(path, libname, &group, &name)) { BlendfileLinkAppendContextItem *item; @@ -683,7 +683,7 @@ static int wm_lib_relocate_exec_do(bContext *C, wmOperator *op, bool do_reload) return OPERATOR_CANCELLED; } - BLI_join_dirfile(path, sizeof(path), root, libname); + BLI_path_join(path, sizeof(path), root, libname); if (!BLI_exists(path)) { BKE_reportf(op->reports, @@ -739,7 +739,7 @@ static int wm_lib_relocate_exec_do(bContext *C, wmOperator *op, bool do_reload) RNA_BEGIN (op->ptr, itemptr, "files") { RNA_string_get(&itemptr, "name", relname); - BLI_join_dirfile(path, sizeof(path), root, relname); + BLI_path_join(path, sizeof(path), root, relname); if (BLI_path_cmp(path, lib->filepath_abs) == 0 || !BLO_has_bfile_extension(relname)) { continue; diff --git a/source/blender/windowmanager/intern/wm_init_exit.c b/source/blender/windowmanager/intern/wm_init_exit.c index 32890b4014f..c5d7152246c 100644 --- a/source/blender/windowmanager/intern/wm_init_exit.c +++ b/source/blender/windowmanager/intern/wm_init_exit.c @@ -447,7 +447,7 @@ void WM_exit_ex(bContext *C, const bool do_python) bool has_edited; const int fileflags = G.fileflags & ~G_FILE_COMPRESS; - BLI_join_dirfile(filepath, sizeof(filepath), BKE_tempdir_base(), BLENDER_QUIT_FILE); + BLI_path_join(filepath, sizeof(filepath), BKE_tempdir_base(), BLENDER_QUIT_FILE); has_edited = ED_editors_flush_edits(bmain); diff --git a/source/blender/windowmanager/intern/wm_platform_support.c b/source/blender/windowmanager/intern/wm_platform_support.c index a0519506d29..ee93621545f 100644 --- a/source/blender/windowmanager/intern/wm_platform_support.c +++ b/source/blender/windowmanager/intern/wm_platform_support.c @@ -42,7 +42,7 @@ static bool wm_platform_support_check_approval(const char *platform_support_key, bool result = false; char filepath[FILE_MAX]; - BLI_join_dirfile(filepath, sizeof(filepath), cfgdir, BLENDER_PLATFORM_SUPPORT_FILE); + BLI_path_join(filepath, sizeof(filepath), cfgdir, BLENDER_PLATFORM_SUPPORT_FILE); LinkNode *lines = BLI_file_read_as_lines(filepath); for (LinkNode *line_node = lines; line_node; line_node = line_node->next) { char *line = line_node->link; diff --git a/source/blender/windowmanager/intern/wm_playanim.c b/source/blender/windowmanager/intern/wm_playanim.c index bf793ee41a0..3e5399a6f56 100644 --- a/source/blender/windowmanager/intern/wm_playanim.c +++ b/source/blender/windowmanager/intern/wm_playanim.c @@ -59,6 +59,8 @@ #include "DEG_depsgraph.h" +#include "wm_window_private.h" + #include "WM_api.h" /* only for WM_main_playanim */ #ifdef WITH_AUDASPACE @@ -1340,6 +1342,8 @@ static bool ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr ps_void) static void playanim_window_open(const char *title, int posx, int posy, int sizex, int sizey) { GHOST_GLSettings glsettings = {0}; + const eGPUBackendType gpu_backend = GPU_backend_type_selection_get(); + glsettings.context_type = wm_ghost_drawing_context_type(gpu_backend); uint32_t scr_w, scr_h; GHOST_GetMainDisplayDimensions(g_WS.ghost_system, &scr_w, &scr_h); @@ -1356,7 +1360,6 @@ static void playanim_window_open(const char *title, int posx, int posy, int size /* Could optionally start full-screen. */ GHOST_kWindowStateNormal, false, - GHOST_kDrawingContextTypeOpenGL, glsettings); } diff --git a/source/blender/windowmanager/intern/wm_splash_screen.c b/source/blender/windowmanager/intern/wm_splash_screen.c index 8fca3deef92..16e5f983bea 100644 --- a/source/blender/windowmanager/intern/wm_splash_screen.c +++ b/source/blender/windowmanager/intern/wm_splash_screen.c @@ -140,7 +140,7 @@ static ImBuf *wm_block_splash_image(int width, int *r_height) char template_directory[FILE_MAX]; if (BKE_appdir_app_template_id_search( U.app_template, template_directory, sizeof(template_directory))) { - BLI_join_dirfile(splash_filepath, sizeof(splash_filepath), template_directory, "splash.png"); + BLI_path_join(splash_filepath, sizeof(splash_filepath), template_directory, "splash.png"); ibuf = IMB_loadiffname(splash_filepath, IB_rect, NULL); } } @@ -218,7 +218,7 @@ static uiBlock *wm_block_create_splash(bContext *C, ARegion *region, void *UNUSE const char *const cfgdir = BKE_appdir_folder_id(BLENDER_USER_CONFIG, NULL); if (cfgdir) { - BLI_path_join(userpref, sizeof(userpref), cfgdir, BLENDER_USERPREF_FILE, NULL); + BLI_path_join(userpref, sizeof(userpref), cfgdir, BLENDER_USERPREF_FILE); } /* Draw setup screen if no preferences have been saved yet. */ diff --git a/source/blender/windowmanager/intern/wm_window.c b/source/blender/windowmanager/intern/wm_window.c index b1b13390932..265aa08a6b1 100644 --- a/source/blender/windowmanager/intern/wm_window.c +++ b/source/blender/windowmanager/intern/wm_window.c @@ -556,6 +556,9 @@ static void wm_window_ghostwindow_add(wmWindowManager *wm, glSettings.flags |= GHOST_glDebugContext; } + eGPUBackendType gpu_backend = GPU_backend_type_selection_get(); + glSettings.context_type = wm_ghost_drawing_context_type(gpu_backend); + int scr_w, scr_h; wm_get_desktopsize(&scr_w, &scr_h); int posy = (scr_h - win->posy - win->sizey); @@ -573,7 +576,6 @@ static void wm_window_ghostwindow_add(wmWindowManager *wm, win->sizey, (GHOST_TWindowState)win->windowstate, is_dialog, - GHOST_kDrawingContextTypeOpenGL, glSettings); if (ghostwin) { @@ -1615,6 +1617,32 @@ const char *WM_ghost_backend(void) #endif } +GHOST_TDrawingContextType wm_ghost_drawing_context_type(const eGPUBackendType gpu_backend) +{ + switch (gpu_backend) { + case GPU_BACKEND_NONE: + return GHOST_kDrawingContextTypeNone; + case GPU_BACKEND_ANY: + case GPU_BACKEND_OPENGL: + return GHOST_kDrawingContextTypeOpenGL; + case GPU_BACKEND_VULKAN: + BLI_assert_unreachable(); + return GHOST_kDrawingContextTypeNone; + case GPU_BACKEND_METAL: +#ifdef WITH_METAL_BACKEND + return GHOST_kDrawingContextTypeMetal; +#else + BLI_assert_unreachable(); + return GHOST_kDrawingContextTypeNone; +#endif + } + + /* Avoid control reaches end of non-void function compilation warning, which could be promoted + * to error. */ + BLI_assert_unreachable(); + return GHOST_kDrawingContextTypeNone; +} + /** \} */ /* -------------------------------------------------------------------- */ diff --git a/source/blender/windowmanager/intern/wm_window_private.h b/source/blender/windowmanager/intern/wm_window_private.h index f68d4e3e693..dad3e749817 100644 --- a/source/blender/windowmanager/intern/wm_window_private.h +++ b/source/blender/windowmanager/intern/wm_window_private.h @@ -7,8 +7,11 @@ #pragma once #include "BLI_sys_types.h" + #include "GHOST_Types.h" +#include "GPU_context.h" + /* *************** Message box *************** */ /* `WM_ghost_show_message_box` is implemented in `wm_windows.c` it is * defined here as it was implemented to be used for showing @@ -21,3 +24,5 @@ void WM_ghost_show_message_box(const char *title, const char *continue_label, const char *link, GHOST_DialogOptions dialog_options); + +GHOST_TDrawingContextType wm_ghost_drawing_context_type(const eGPUBackendType gpu_backend); diff --git a/source/blender/windowmanager/wm.h b/source/blender/windowmanager/wm.h index 0b54560c56a..0a27b9c1cfd 100644 --- a/source/blender/windowmanager/wm.h +++ b/source/blender/windowmanager/wm.h @@ -45,12 +45,12 @@ extern void wm_close_and_free_all(bContext *C, ListBase *); extern void wm_add_default(struct Main *bmain, bContext *C); extern void wm_clear_default_size(bContext *C); -/* register to windowmanager for redo or macro */ +/* Register to window-manager for redo or macro. */ /** * Called on event handling by `event_system.c`. * - * All operations get registered in the windowmanager here. + * All operations get registered in the window-manager here. */ void wm_operator_register(bContext *C, wmOperator *op); diff --git a/source/blender/windowmanager/wm_event_types.h b/source/blender/windowmanager/wm_event_types.h index 405b7225bd5..c36c57a12ae 100644 --- a/source/blender/windowmanager/wm_event_types.h +++ b/source/blender/windowmanager/wm_event_types.h @@ -252,8 +252,6 @@ enum { #define _NDOF_MIN NDOF_MOTION #define _NDOF_BUTTON_MIN NDOF_BUTTON_MENU - /* used internally, never sent */ - NDOF_BUTTON_NONE = NDOF_MOTION, /* these two are available from any 3Dconnexion device */ NDOF_BUTTON_MENU = 0x0191, /* 401 */ @@ -281,35 +279,42 @@ enum { NDOF_BUTTON_DOMINANT = 0x01a3, /* 419 */ NDOF_BUTTON_PLUS = 0x01a4, /* 420 */ NDOF_BUTTON_MINUS = 0x01a5, /* 421 */ + /* General-purpose buttons. */ + NDOF_BUTTON_1 = 0x01a6, /* 422 */ + NDOF_BUTTON_2 = 0x01a7, /* 423 */ + NDOF_BUTTON_3 = 0x01a8, /* 424 */ + NDOF_BUTTON_4 = 0x01a9, /* 425 */ + NDOF_BUTTON_5 = 0x01aa, /* 426 */ + NDOF_BUTTON_6 = 0x01ab, /* 427 */ + NDOF_BUTTON_7 = 0x01ac, /* 428 */ + NDOF_BUTTON_8 = 0x01ad, /* 429 */ + NDOF_BUTTON_9 = 0x01ae, /* 430 */ + NDOF_BUTTON_10 = 0x01af, /* 431 */ + /* more general-purpose buttons */ + NDOF_BUTTON_A = 0x01b0, /* 432 */ + NDOF_BUTTON_B = 0x01b1, /* 433 */ + NDOF_BUTTON_C = 0x01b2, /* 434 */ + /* Store/restore views. */ + NDOF_BUTTON_V1 = 0x01b3, /* 435 */ + NDOF_BUTTON_V2 = 0x01b4, /* 436 */ + NDOF_BUTTON_V3 = 0x01b5, /* 437 */ /* Disabled as GHOST converts these to keyboard events * which use regular keyboard event handling logic. */ #if 0 /* keyboard emulation */ - NDOF_BUTTON_ESC = 0x01a6, /* 422 */ - NDOF_BUTTON_ALT = 0x01a7, /* 423 */ - NDOF_BUTTON_SHIFT = 0x01a8, /* 424 */ - NDOF_BUTTON_CTRL = 0x01a9, /* 425 */ + NDOF_BUTTON_ESC = 0x01b6, /* 438 */ + NDOF_BUTTON_ENTER = 0x01b7, /* 439 */ + NDOF_BUTTON_DELETE = 0x01b8, /* 440 */ + NDOF_BUTTON_TAB = 0x01b9, /* 441 */ + NDOF_BUTTON_SPACE = 0x01ba, /* 442 */ + NDOF_BUTTON_ALT = 0x01bb, /* 443 */ + NDOF_BUTTON_SHIFT = 0x01bc, /* 444 */ + NDOF_BUTTON_CTRL = 0x01bd, /* 445 */ #endif - /* general-purpose buttons */ - NDOF_BUTTON_1 = 0x01aa, /* 426 */ - NDOF_BUTTON_2 = 0x01ab, /* 427 */ - NDOF_BUTTON_3 = 0x01ac, /* 428 */ - NDOF_BUTTON_4 = 0x01ad, /* 429 */ - NDOF_BUTTON_5 = 0x01ae, /* 430 */ - NDOF_BUTTON_6 = 0x01af, /* 431 */ - NDOF_BUTTON_7 = 0x01b0, /* 432 */ - NDOF_BUTTON_8 = 0x01b1, /* 433 */ - NDOF_BUTTON_9 = 0x01b2, /* 434 */ - NDOF_BUTTON_10 = 0x01b3, /* 435 */ - /* more general-purpose buttons */ - NDOF_BUTTON_A = 0x01b4, /* 436 */ - NDOF_BUTTON_B = 0x01b5, /* 437 */ - NDOF_BUTTON_C = 0x01b6, /* 438 */ - -#define _NDOF_MAX NDOF_BUTTON_C -#define _NDOF_BUTTON_MAX NDOF_BUTTON_C +#define _NDOF_MAX NDOF_BUTTON_V3 +#define _NDOF_BUTTON_MAX NDOF_BUTTON_V3 /* ********** End of Input devices. ********** */ @@ -449,6 +454,8 @@ enum eEventType_Mask { (EVT_TYPE_MASK_KEYBOARD | EVT_TYPE_MASK_MOUSE | EVT_TYPE_MASK_NDOF) #define EVT_TYPE_MASK_HOTKEY_EXCLUDE EVT_TYPE_MASK_KEYBOARD_MODIFIER +#define NDOF_BUTTON_INDEX_AS_EVENT(i) (_NDOF_BUTTON_MIN + (i)) + bool WM_event_type_mask_test(int event_type, enum eEventType_Mask mask); /** \} */ diff --git a/source/blender/windowmanager/xr/intern/wm_xr_session.c b/source/blender/windowmanager/xr/intern/wm_xr_session.c index abc41833de6..aefc3afff66 100644 --- a/source/blender/windowmanager/xr/intern/wm_xr_session.c +++ b/source/blender/windowmanager/xr/intern/wm_xr_session.c @@ -178,7 +178,7 @@ static void wm_xr_session_base_pose_calc(const Scene *scene, float tmp_quat[4]; float tmp_eul[3]; - mat4_to_loc_quat(r_base_pose->position, tmp_quat, base_pose_object->obmat); + mat4_to_loc_quat(r_base_pose->position, tmp_quat, base_pose_object->object_to_world); /* Only use rotation around Z-axis to align view with floor. */ quat_to_eul(tmp_eul, tmp_quat); |