Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/source
diff options
context:
space:
mode:
Diffstat (limited to 'source')
-rw-r--r--source/blender/blenfont/intern/blf_thumbs.c2
-rw-r--r--source/blender/blenkernel/BKE_asset.h19
-rw-r--r--source/blender/blenkernel/BKE_asset_library.h40
-rw-r--r--source/blender/blenkernel/BKE_asset_library.hh80
-rw-r--r--source/blender/blenkernel/BKE_asset_representation.hh64
-rw-r--r--source/blender/blenkernel/BKE_attribute.h2
-rw-r--r--source/blender/blenkernel/BKE_curves_utils.hh327
-rw-r--r--source/blender/blenkernel/BKE_fcurve.h23
-rw-r--r--source/blender/blenkernel/BKE_mesh_mapping.h7
-rw-r--r--source/blender/blenkernel/BKE_node.h9
-rw-r--r--source/blender/blenkernel/BKE_paint.h1
-rw-r--r--source/blender/blenkernel/BKE_particle.h8
-rw-r--r--source/blender/blenkernel/BKE_pbvh.h2
-rw-r--r--source/blender/blenkernel/CMakeLists.txt2
-rw-r--r--source/blender/blenkernel/intern/asset.cc28
-rw-r--r--source/blender/blenkernel/intern/asset_catalog.cc9
-rw-r--r--source/blender/blenkernel/intern/asset_library.cc90
-rw-r--r--source/blender/blenkernel/intern/asset_library_service.cc25
-rw-r--r--source/blender/blenkernel/intern/asset_library_service.hh8
-rw-r--r--source/blender/blenkernel/intern/asset_library_service_test.cc23
-rw-r--r--source/blender/blenkernel/intern/asset_representation.cc98
-rw-r--r--source/blender/blenkernel/intern/asset_test.cc2
-rw-r--r--source/blender/blenkernel/intern/attribute.cc27
-rw-r--r--source/blender/blenkernel/intern/context.c2
-rw-r--r--source/blender/blenkernel/intern/customdata.cc23
-rw-r--r--source/blender/blenkernel/intern/fcurve.c30
-rw-r--r--source/blender/blenkernel/intern/fluid.c14
-rw-r--r--source/blender/blenkernel/intern/fmodifier.c2
-rw-r--r--source/blender/blenkernel/intern/lib_id_delete.c10
-rw-r--r--source/blender/blenkernel/intern/material.c47
-rw-r--r--source/blender/blenkernel/intern/node.cc10
-rw-r--r--source/blender/blenkernel/intern/object_dupli.cc51
-rw-r--r--source/blender/blenkernel/intern/particle.c50
-rw-r--r--source/blender/blenkernel/intern/particle_system.c27
-rw-r--r--source/blender/blenkernel/intern/pbvh.c7
-rw-r--r--source/blender/blenkernel/intern/pbvh_bmesh.c8
-rw-r--r--source/blender/blenlib/BLI_string.h7
-rw-r--r--source/blender/blenlib/intern/math_rotation.c101
-rw-r--r--source/blender/blenlib/tests/BLI_math_rotation_test.cc16
-rw-r--r--source/blender/blenloader/intern/versioning_260.c12
-rw-r--r--source/blender/compositor/nodes/COM_OutputFileNode.cc2
-rw-r--r--source/blender/compositor/operations/COM_MovieDistortionOperation.cc51
-rw-r--r--source/blender/compositor/operations/COM_OutputFileMultiViewOperation.h2
-rw-r--r--source/blender/compositor/operations/COM_OutputFileOperation.h2
-rw-r--r--source/blender/compositor/realtime_compositor/COM_scheduler.hh2
-rw-r--r--source/blender/compositor/realtime_compositor/intern/realize_on_domain_operation.cc4
-rw-r--r--source/blender/compositor/realtime_compositor/intern/scheduler.cc96
-rw-r--r--source/blender/depsgraph/DEG_depsgraph.h8
-rw-r--r--source/blender/depsgraph/DEG_depsgraph_build.h3
-rw-r--r--source/blender/depsgraph/intern/depsgraph.cc7
-rw-r--r--source/blender/depsgraph/intern/depsgraph.h3
-rw-r--r--source/blender/depsgraph/intern/depsgraph_build.cc5
-rw-r--r--source/blender/depsgraph/intern/eval/deg_eval.cc56
-rw-r--r--source/blender/depsgraph/intern/eval/deg_eval_visibility.cc6
-rw-r--r--source/blender/draw/engines/eevee_next/eevee_camera.cc4
-rw-r--r--source/blender/draw/engines/eevee_next/eevee_depth_of_field.cc4
-rw-r--r--source/blender/draw/intern/draw_cache_impl_particles.c4
-rw-r--r--source/blender/draw/intern/draw_manager.c1
-rw-r--r--source/blender/editors/asset/intern/asset_handle.cc9
-rw-r--r--source/blender/editors/asset/intern/asset_temp_id_consumer.cc2
-rw-r--r--source/blender/editors/geometry/geometry_attributes.cc154
-rw-r--r--source/blender/editors/geometry/geometry_intern.hh1
-rw-r--r--source/blender/editors/geometry/geometry_ops.cc1
-rw-r--r--source/blender/editors/include/ED_geometry.h17
-rw-r--r--source/blender/editors/include/ED_mesh.h7
-rw-r--r--source/blender/editors/include/ED_sculpt.h2
-rw-r--r--source/blender/editors/include/UI_interface.h1
-rw-r--r--source/blender/editors/interface/interface_drag.cc5
-rw-r--r--source/blender/editors/interface/interface_ops.cc2
-rw-r--r--source/blender/editors/interface/interface_region_color_picker.cc28
-rw-r--r--source/blender/editors/interface/interface_template_asset_view.cc1
-rw-r--r--source/blender/editors/interface/view2d_gizmo_navigate.cc4
-rw-r--r--source/blender/editors/mesh/editmesh_utils.c39
-rw-r--r--source/blender/editors/object/object_modifier.cc59
-rw-r--r--source/blender/editors/sculpt_paint/CMakeLists.txt2
-rw-r--r--source/blender/editors/sculpt_paint/curves_sculpt_ops.cc6
-rw-r--r--source/blender/editors/sculpt_paint/paint_vertex.cc78
-rw-r--r--source/blender/editors/sculpt_paint/paint_vertex_weight_ops.c5
-rw-r--r--source/blender/editors/sculpt_paint/sculpt.cc (renamed from source/blender/editors/sculpt_paint/sculpt.c)647
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_intern.h10
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_ops.c28
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_undo.c4
-rw-r--r--source/blender/editors/space_file/CMakeLists.txt4
-rw-r--r--source/blender/editors/space_file/asset_catalog_tree_view.cc5
-rw-r--r--source/blender/editors/space_file/file_draw.c2
-rw-r--r--source/blender/editors/space_file/file_indexer.cc3
-rw-r--r--source/blender/editors/space_file/file_intern.h18
-rw-r--r--source/blender/editors/space_file/filelist.cc144
-rw-r--r--source/blender/editors/space_file/space_file.c2
-rw-r--r--source/blender/editors/space_graph/graph_edit.c46
-rw-r--r--source/blender/editors/space_graph/graph_slider_ops.c15
-rw-r--r--source/blender/editors/space_node/node_relationships.cc1
-rw-r--r--source/blender/editors/space_node/space_node.cc10
-rw-r--r--source/blender/editors/space_text/text_ops.c6
-rw-r--r--source/blender/editors/space_view3d/view3d_draw.cc1
-rw-r--r--source/blender/editors/space_view3d/view3d_gizmo_navigate.c4
-rw-r--r--source/blender/editors/transform/transform_convert.c2
-rw-r--r--source/blender/editors/transform/transform_generics.c2
-rw-r--r--source/blender/geometry/GEO_trim_curves.hh20
-rw-r--r--source/blender/geometry/intern/set_curve_type.cc9
-rw-r--r--source/blender/geometry/intern/trim_curves.cc978
-rw-r--r--source/blender/gpencil_modifiers/intern/MOD_gpenciloutline.c7
-rw-r--r--source/blender/gpu/intern/gpu_node_graph.h2
-rw-r--r--source/blender/gpu/intern/gpu_shader_builder.cc2
-rw-r--r--source/blender/imbuf/intern/jp2.c2
-rw-r--r--source/blender/imbuf/intern/openexr/openexr_api.cpp2
-rw-r--r--source/blender/io/alembic/exporter/abc_writer_points.cc7
-rw-r--r--source/blender/makesdna/DNA_asset_types.h6
-rw-r--r--source/blender/makesdna/DNA_scene_types.h1
-rw-r--r--source/blender/makesdna/DNA_space_types.h4
-rw-r--r--source/blender/makesrna/intern/rna_attribute.c2
-rw-r--r--source/blender/makesrna/intern/rna_nodetree.c27
-rw-r--r--source/blender/makesrna/intern/rna_space.c15
-rw-r--r--source/blender/modifiers/intern/MOD_explode.c7
-rw-r--r--source/blender/modifiers/intern/MOD_particleinstance.c7
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_topology_curve_of_point.cc2
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_topology_points_of_curve.cc4
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_trim.cc47
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_mesh_topology_corners_of_face.cc4
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_mesh_topology_corners_of_vertex.cc4
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_mesh_topology_edges_of_corner.cc4
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_mesh_topology_edges_of_vertex.cc4
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_mesh_topology_offset_corner_in_face.cc2
-rw-r--r--source/blender/render/intern/bake.c6
-rw-r--r--source/blender/render/intern/texture_pointdensity.c14
-rw-r--r--source/blender/sequencer/intern/effects.c11
-rw-r--r--source/blender/windowmanager/WM_api.h1
-rw-r--r--source/blender/windowmanager/intern/wm_dragdrop.cc10
128 files changed, 2384 insertions, 1777 deletions
diff --git a/source/blender/blenfont/intern/blf_thumbs.c b/source/blender/blenfont/intern/blf_thumbs.c
index ac2f2f35ca3..8a640ac86a7 100644
--- a/source/blender/blenfont/intern/blf_thumbs.c
+++ b/source/blender/blenfont/intern/blf_thumbs.c
@@ -46,7 +46,7 @@ typedef struct UnicodeSample {
* those need to be checked last. */
static const UnicodeSample unicode_samples[] = {
/* Chinese, Japanese, Korean, ordered specific to general. */
- {U"\uc870\uc120\uae00", 2, TT_UCR_HANGUL}, /* 조선글 */
+ {U"\ud55c\uad6d\uc5b4", 2, TT_UCR_HANGUL}, /* 한국어 */
{U"\u3042\u30a2\u4e9c", 2, TT_UCR_HIRAGANA}, /* あア亜 */
{U"\u30a2\u30a4\u4e9c", 2, TT_UCR_KATAKANA}, /* アイ亜 */
{U"\u1956\u195b\u1966", 3, TT_UCR_TAI_LE}, /* ᥖᥛᥦ */
diff --git a/source/blender/blenkernel/BKE_asset.h b/source/blender/blenkernel/BKE_asset.h
index 81b520a1db0..bcbe19c0f3e 100644
--- a/source/blender/blenkernel/BKE_asset.h
+++ b/source/blender/blenkernel/BKE_asset.h
@@ -23,6 +23,9 @@ struct ID;
struct IDProperty;
struct PreviewImage;
+/** C handle for #bke::AssetRepresentation. */
+typedef struct AssetRepresentation AssetRepresentation;
+
typedef void (*PreSaveFn)(void *asset_ptr, struct AssetMetaData *asset_data);
typedef struct AssetTypeInfo {
@@ -68,6 +71,22 @@ struct PreviewImage *BKE_asset_metadata_preview_get_from_id(const struct AssetMe
void BKE_asset_metadata_write(struct BlendWriter *writer, struct AssetMetaData *asset_data);
void BKE_asset_metadata_read(struct BlendDataReader *reader, struct AssetMetaData *asset_data);
+const char *BKE_asset_representation_name_get(const AssetRepresentation *asset)
+ ATTR_WARN_UNUSED_RESULT;
+AssetMetaData *BKE_asset_representation_metadata_get(const AssetRepresentation *asset)
+ ATTR_WARN_UNUSED_RESULT;
+bool BKE_asset_representation_is_local_id(const AssetRepresentation *asset)
+ ATTR_WARN_UNUSED_RESULT;
+
#ifdef __cplusplus
}
#endif
+
+#ifdef __cplusplus
+
+# include <memory>
+
+[[nodiscard]] std::unique_ptr<AssetMetaData> BKE_asset_metadata_move_to_unique_ptr(
+ AssetMetaData *asset_data);
+
+#endif
diff --git a/source/blender/blenkernel/BKE_asset_library.h b/source/blender/blenkernel/BKE_asset_library.h
index 824bc24203d..fc648ff6976 100644
--- a/source/blender/blenkernel/BKE_asset_library.h
+++ b/source/blender/blenkernel/BKE_asset_library.h
@@ -6,6 +6,7 @@
#pragma once
+struct IDRemapper;
struct Main;
#ifdef __cplusplus
@@ -24,41 +25,6 @@ typedef struct AssetLibrary AssetLibrary;
*/
struct AssetLibrary *BKE_asset_library_load(const char *library_path);
-/**
- * Try to find an appropriate location for an asset library root from a file or directory path.
- * Does not check if \a input_path exists.
- *
- * The design is made to find an appropriate asset library path from a .blend file path, but
- * technically works with any file or directory as \a input_path.
- * Design is:
- * * If \a input_path lies within a known asset library path (i.e. an asset library registered in
- * the Preferences), return the asset library path.
- * * Otherwise, if \a input_path has a parent path, return the parent path (e.g. to use the
- * directory a .blend file is in as asset library root).
- * * If \a input_path is empty or doesn't have a parent path (e.g. because a .blend wasn't saved
- * yet), there is no suitable path. The caller has to decide how to handle this case.
- *
- * \param r_library_path: The returned asset library path with a trailing slash, or an empty string
- * if no suitable path is found. Assumed to be a buffer of at least
- * #FILE_MAXDIR bytes.
- *
- * \return True if the function could find a valid, that is, a non-empty path to return in \a
- * r_library_path.
- */
-bool BKE_asset_library_find_suitable_root_path_from_path(
- const char *input_path, char r_library_path[768 /* FILE_MAXDIR */]);
-/**
- * Uses the current location on disk of the file represented by \a bmain as input to
- * #BKE_asset_library_find_suitable_root_path_from_path(). Refer to it for a design
- * description.
- *
- * \return True if the function could find a valid, that is, a non-empty path to return in \a
- * r_library_path. If \a bmain wasn't saved into a file yet, the return value will be
- * false.
- */
-bool BKE_asset_library_find_suitable_root_path_from_main(
- const struct Main *bmain, char r_library_path[768 /* FILE_MAXDIR */]);
-
/** Look up the asset's catalog and copy its simple name into #asset_data. */
void BKE_asset_library_refresh_catalog_simplename(struct AssetLibrary *asset_library,
struct AssetMetaData *asset_data);
@@ -66,6 +32,10 @@ void BKE_asset_library_refresh_catalog_simplename(struct AssetLibrary *asset_lib
/** Return whether any loaded AssetLibrary has unsaved changes to its catalogs. */
bool BKE_asset_library_has_any_unsaved_catalogs(void);
+/** An asset library can include local IDs (IDs in the current file). Their pointers need to be
+ * remapped on change (or assets removed as IDs gets removed). */
+void BKE_asset_library_remap_ids(struct IDRemapper *mappings);
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/blenkernel/BKE_asset_library.hh b/source/blender/blenkernel/BKE_asset_library.hh
index 2058df71f6a..f69847bd1ed 100644
--- a/source/blender/blenkernel/BKE_asset_library.hh
+++ b/source/blender/blenkernel/BKE_asset_library.hh
@@ -12,6 +12,9 @@
#include "DNA_asset_types.h"
+#include "BLI_string_ref.hh"
+#include "BLI_vector.hh"
+
#include "BKE_asset_library.h"
#include "BKE_asset_catalog.hh"
@@ -19,11 +22,18 @@
#include <memory>
+struct AssetLibraryReference;
+struct Main;
+
namespace blender::bke {
+class AssetRepresentation;
+
/**
* AssetLibrary provides access to an asset library's data.
- * For now this is only for catalogs, later this can be expanded to indexes/caches/more.
+ *
+ * The asset library contains catalogs and storage for asset representations. It could be extended
+ * to also include asset indexes and more.
*/
struct AssetLibrary {
/* Controlled by #ED_asset_catalogs_set_save_catalogs_when_file_is_saved,
@@ -35,12 +45,25 @@ struct AssetLibrary {
AssetLibrary();
~AssetLibrary();
- void load(StringRefNull library_root_directory);
+ void load_catalogs(StringRefNull library_root_directory);
/** Load catalogs that have changed on disk. */
void refresh();
/**
+ * Create a representation of an asset to be considered part of this library. Once the
+ * representation is not needed anymore, it must be freed using #remove_asset(), or there will be
+ * leaking that's only cleared when the library storage is destructed (typically on exit or
+ * loading a different file).
+ */
+ AssetRepresentation &add_external_asset(StringRef name, std::unique_ptr<AssetMetaData> metadata);
+ AssetRepresentation &add_local_id_asset(ID &id);
+ /** Remove an asset from the library that was added using #add_external_asset() or
+ * #add_local_id_asset().
+ * \return True on success, false if the asset couldn't be found inside the library. */
+ bool remove_asset(AssetRepresentation &asset);
+
+ /**
* Update `catalog_simple_name` by looking up the asset's catalog by its ID.
*
* No-op if the catalog cannot be found. This could be the kind of "the
@@ -53,8 +76,27 @@ struct AssetLibrary {
void on_blend_save_post(Main *bmain, PointerRNA **pointers, int num_pointers);
+ void remap_ids(struct IDRemapper &mappings);
+
private:
bCallbackFuncStore on_save_callback_store_{};
+
+ /** Storage for assets (better said their representations) that are considered to be part of this
+ * library. Assets are not automatically loaded into this when loading an asset library. Assets
+ * have to be loaded externally and added to this storage via #add_external_asset() or
+ * #add_local_id_asset(). So this really is arbitrary storage as far as #AssetLibrary is
+ * concerned (allowing the API user to manage partial library storage and partial loading, so
+ * only relevant parts of a library are kept in memory).
+ *
+ * For now, multiple parts of Blender just keep adding their own assets to this storage. E.g.
+ * multiple asset browsers might load multiple representations for the same asset into this.
+ * Currently there is just no way to properly identify assets, or keep track of which assets are
+ * already in memory and which not. Neither do we keep track of how many parts of Blender are
+ * using an asset or an asset library, which is needed to know when assets can be freed.
+ */
+ Vector<std::unique_ptr<AssetRepresentation>> asset_storage_;
+
+ std::optional<int> find_asset_index(const AssetRepresentation &asset);
};
Vector<AssetLibraryReference> all_valid_asset_library_refs();
@@ -64,6 +106,40 @@ Vector<AssetLibraryReference> all_valid_asset_library_refs();
blender::bke::AssetLibrary *BKE_asset_library_load(const Main *bmain,
const AssetLibraryReference &library_reference);
+/**
+ * Try to find an appropriate location for an asset library root from a file or directory path.
+ * Does not check if \a input_path exists.
+ *
+ * The design is made to find an appropriate asset library path from a .blend file path, but
+ * technically works with any file or directory as \a input_path.
+ * Design is:
+ * * If \a input_path lies within a known asset library path (i.e. an asset library registered in
+ * the Preferences), return the asset library path.
+ * * Otherwise, if \a input_path has a parent path, return the parent path (e.g. to use the
+ * directory a .blend file is in as asset library root).
+ * * If \a input_path is empty or doesn't have a parent path (e.g. because a .blend wasn't saved
+ * yet), there is no suitable path. The caller has to decide how to handle this case.
+ *
+ * \param r_library_path: The returned asset library path with a trailing slash, or an empty string
+ * if no suitable path is found. Assumed to be a buffer of at least
+ * #FILE_MAXDIR bytes.
+ *
+ * \return True if the function could find a valid, that is, a non-empty path to return in \a
+ * r_library_path.
+ */
+std::string BKE_asset_library_find_suitable_root_path_from_path(blender::StringRefNull input_path);
+
+/**
+ * Uses the current location on disk of the file represented by \a bmain as input to
+ * #BKE_asset_library_find_suitable_root_path_from_path(). Refer to it for a design
+ * description.
+ *
+ * \return True if the function could find a valid, that is, a non-empty path to return in \a
+ * r_library_path. If \a bmain wasn't saved into a file yet, the return value will be
+ * false.
+ */
+std::string BKE_asset_library_find_suitable_root_path_from_main(const struct Main *bmain);
+
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_asset_representation.hh b/source/blender/blenkernel/BKE_asset_representation.hh
new file mode 100644
index 00000000000..edaa5a203ba
--- /dev/null
+++ b/source/blender/blenkernel/BKE_asset_representation.hh
@@ -0,0 +1,64 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+/** \file
+ * \ingroup bke
+ */
+
+#pragma once
+
+#include <memory>
+#include <string>
+
+#include "BLI_string_ref.hh"
+
+struct AssetMetaData;
+struct ID;
+
+namespace blender::bke {
+
+/**
+ * \brief Abstraction to reference an asset, with necessary data for display & interaction.
+ *
+ * https://wiki.blender.org/wiki/Source/Architecture/Asset_System/Back_End#Asset_Representation
+ */
+class AssetRepresentation {
+ friend struct AssetLibrary;
+
+ struct ExternalAsset {
+ std::string name;
+ std::unique_ptr<AssetMetaData> metadata_ = nullptr;
+ };
+
+ /** Indicate if this is a local or external asset, and as such, which of the union members below
+ * should be used. */
+ const bool is_local_id_ = false;
+
+ union {
+ ExternalAsset external_asset_;
+ ID *local_asset_id_ = nullptr; /* Non-owning. */
+ };
+
+ public:
+ /** Constructs an asset representation for an external ID. The asset will not be editable. */
+ explicit AssetRepresentation(StringRef name, std::unique_ptr<AssetMetaData> metadata);
+ /** Constructs an asset representation for an ID stored in the current file. This makes the asset
+ * local and fully editable. */
+ explicit AssetRepresentation(ID &id);
+ AssetRepresentation(AssetRepresentation &&other);
+ /* Non-copyable type. */
+ AssetRepresentation(const AssetRepresentation &other) = delete;
+ ~AssetRepresentation();
+
+ /* Non-move-assignable type. Move construction is fine, but treat the "identity" (e.g. local vs
+ * external asset) of an asset representation as immutable. */
+ AssetRepresentation &operator=(AssetRepresentation &&other) = delete;
+ /* Non-copyable type. */
+ AssetRepresentation &operator=(const AssetRepresentation &other) = delete;
+
+ StringRefNull get_name() const;
+ AssetMetaData &get_metadata() const;
+ /** Returns if this asset is stored inside this current file, and as such fully editable. */
+ bool is_local_id() const;
+};
+
+} // namespace blender::bke
diff --git a/source/blender/blenkernel/BKE_attribute.h b/source/blender/blenkernel/BKE_attribute.h
index b5d880bdc07..236cc44a77f 100644
--- a/source/blender/blenkernel/BKE_attribute.h
+++ b/source/blender/blenkernel/BKE_attribute.h
@@ -93,7 +93,7 @@ int BKE_id_attributes_length(const struct ID *id,
eCustomDataMask mask);
struct CustomDataLayer *BKE_id_attributes_active_get(struct ID *id);
-void BKE_id_attributes_active_set(struct ID *id, struct CustomDataLayer *layer);
+void BKE_id_attributes_active_set(struct ID *id, const char *name);
int *BKE_id_attributes_active_index_p(struct ID *id);
CustomData *BKE_id_attributes_iterator_next_domain(struct ID *id, struct CustomDataLayer *layers);
diff --git a/source/blender/blenkernel/BKE_curves_utils.hh b/source/blender/blenkernel/BKE_curves_utils.hh
index f9155023db7..1e06cb2d4c7 100644
--- a/source/blender/blenkernel/BKE_curves_utils.hh
+++ b/source/blender/blenkernel/BKE_curves_utils.hh
@@ -67,86 +67,228 @@ struct CurvePoint : public CurveSegment {
};
/**
- * Cyclical index range. Iterates the interval [start, end).
+ * Cyclical index range. Allows iteration over a plain 'IndexRange' interval on form [start, end)
+ * while also supporting treating the underlying array as a cyclic array where the last index is
+ * followed by the first index in the 'cyclical' range. The cyclical index range can then be
+ * considered a combination of the intervals separated by the last index of the underlying array,
+ * namely [start, range_size) and [0, end) where start/end is the indices iterated between and
+ * range_size is the size of the underlying array. To cycle the underlying array the interval
+ * [0, range_size) can be iterated over an arbitrary amount of times in between.
*/
class IndexRangeCyclic {
/* Index to the start and end of the iterated range.
*/
- int64_t start_ = 0;
- int64_t end_ = 0;
- /* Index for the start and end of the entire iterable range which contains the iterated range
- * (e.g. the point range for an individual spline/curve within the entire Curves point domain).
+ int start_ = 0;
+ int end_ = 0;
+ /* Size of the underlying iterable range.
*/
- int64_t range_start_ = 0;
- int64_t range_end_ = 0;
+ int range_size_ = 0;
/* Number of times the range end is passed when the range is iterated.
*/
- int64_t cycles_ = 0;
-
- constexpr IndexRangeCyclic(int64_t begin,
- int64_t end,
- int64_t iterable_range_start,
- int64_t iterable_range_end,
- int64_t cycles)
- : start_(begin),
- end_(end),
- range_start_(iterable_range_start),
- range_end_(iterable_range_end),
- cycles_(cycles)
- {
- }
+ int cycles_ = 0;
public:
constexpr IndexRangeCyclic() = default;
~IndexRangeCyclic() = default;
- constexpr IndexRangeCyclic(int64_t start, int64_t end, IndexRange iterable_range, int64_t cycles)
- : start_(start),
- end_(end),
- range_start_(iterable_range.first()),
- range_end_(iterable_range.one_after_last()),
- cycles_(cycles)
+ constexpr IndexRangeCyclic(const int start,
+ const int end,
+ const int iterable_range_size,
+ const int cycles)
+ : start_(start), end_(end), range_size_(iterable_range_size), cycles_(cycles)
{
}
/**
* Create an iterator over the cyclical interval [start_index, end_index).
*/
- constexpr IndexRangeCyclic(int64_t start, int64_t end, IndexRange iterable_range)
+ constexpr IndexRangeCyclic(const int start, const int end, const int iterable_range_size)
: start_(start),
- end_(end == iterable_range.one_after_last() ? iterable_range.first() : end),
- range_start_(iterable_range.first()),
- range_end_(iterable_range.one_after_last()),
+ end_(end == iterable_range_size ? 0 : end),
+ range_size_(iterable_range_size),
cycles_(end < start)
{
}
/**
- * Increment the range by adding the given number of indices to the beginning of the range.
+ * Create a cyclical iterator of the specified size.
+ *
+ * \param start_point: Point on the curve that define the starting point of the interval.
+ * \param iterator_size: Number of elements to iterate (size of the iterated cyclical range).
+ * \param iterable_range_size: Size of the underlying range (superset to the cyclical range).
+ */
+ static IndexRangeCyclic get_range_from_size(const int start_index,
+ const int iterator_size,
+ const int iterable_range_size)
+ {
+ BLI_assert(start_index >= 0);
+ BLI_assert(iterator_size >= 0);
+ BLI_assert(iterable_range_size > 0);
+ const int num_until_loop = iterable_range_size - start_index;
+ if (iterator_size < num_until_loop) {
+ return IndexRangeCyclic(start_index, start_index + iterator_size, iterable_range_size, 0);
+ }
+
+ const int num_remaining = iterator_size - num_until_loop;
+ const int num_full_cycles = num_remaining /
+ iterable_range_size; /* Integer division (rounded down). */
+ const int end_index = num_remaining - num_full_cycles * iterable_range_size;
+ return IndexRangeCyclic(start_index, end_index, iterable_range_size, num_full_cycles + 1);
+ }
+
+ /**
+ * Create a cyclical iterator for all control points within the interval [start_point, end_point]
+ * including any control point at the start or end point.
+ *
+ * \param start_point: Point on the curve that define the starting point of the interval.
+ * \param end_point: Point on the curve that define the end point of the interval (included).
+ * \param iterable_range_size: Size of the underlying range (superset to the cyclical range).
+ */
+ static IndexRangeCyclic get_range_between_endpoints(const CurvePoint start_point,
+ const CurvePoint end_point,
+ const int iterable_range_size)
+ {
+ BLI_assert(iterable_range_size > 0);
+ const int start_index = start_point.parameter == 0.0 ? start_point.index :
+ start_point.next_index;
+ int end_index = end_point.parameter == 0.0 ? end_point.index : end_point.next_index;
+ int cycles;
+
+ if (end_point.is_controlpoint()) {
+ BLI_assert(end_index < iterable_range_size);
+ ++end_index;
+ if (end_index == iterable_range_size) {
+ end_index = 0;
+ }
+ /* end_point < start_point but parameter is irrelevant (end_point is controlpoint), and loop
+ * when equal due to increment. */
+ cycles = end_index <= start_index;
+ }
+ else {
+ cycles = end_point < start_point || end_index < start_index;
+ }
+ return IndexRangeCyclic(start_index, end_index, iterable_range_size, cycles);
+ }
+
+ /**
+ * Next index within the iterable range.
+ */
+ template<typename IndexT> constexpr IndexT next_index(const IndexT index, const bool cyclic)
+ {
+ static_assert((is_same_any_v<IndexT, int, int>), "Expected signed integer type.");
+ const IndexT next_index = index + 1;
+ if (next_index == this->size_range()) {
+ return cyclic ? 0 : index;
+ }
+ return next_index;
+ }
+
+ /**
+ * Previous index within the iterable range.
+ */
+ template<typename IndexT> constexpr IndexT previous_index(const IndexT index, const bool cyclic)
+ {
+ static_assert((is_same_any_v<IndexT, int, int64_t>), "Expected signed integer type.");
+ const IndexT prev_index = index - 1;
+ if (prev_index < 0) {
+ return cyclic ? this->size_range() - 1 : 0;
+ }
+ return prev_index;
+ }
+
+ /**
+ * Increment the range by adding `n` loops to the range. This invokes undefined behavior when n
+ * is negative.
+ */
+ constexpr IndexRangeCyclic push_loop(const int n = 1) const
+ {
+ return {this->start_, this->end_, this->range_size_, this->cycles_ + n};
+ }
+
+ /**
+ * Increment the range by adding the given number of indices to the beginning of the iterated
+ * range. This invokes undefined behavior when n is negative.
*/
- constexpr IndexRangeCyclic push_forward(int n)
+ constexpr IndexRangeCyclic push_front(const int n = 1) const
{
BLI_assert(n >= 0);
- int64_t nstart = start_ - n;
- int64_t cycles = cycles_;
- if (nstart < range_start_) {
+ int new_start = this->start_ - n;
+ int num_cycles = this->cycles_;
+ if (new_start < 0) {
+ const int new_cycles = n / this->size_range(); /* Integer division (floor) */
+ const int remainder = new_start + this->size_range() * new_cycles;
+ const bool underflow = remainder < 0;
+ new_start = remainder + (underflow ? this->size_range() : 0);
+ num_cycles += new_cycles + int(underflow);
+ }
+ BLI_assert(num_cycles >= 0);
+ BLI_assert(num_cycles > 0 ||
+ (new_start <= this->end_ || (this->end_ == 0 && new_start < this->size_range())));
+ return {new_start, this->end_, this->range_size_, num_cycles};
+ }
- cycles += (int64_t)(n / (range_end_ - range_start_)) + (end_ < nstart) - (end_ < start_);
+ /**
+ * Increment the range by adding the given number of indices to the end of the iterated range.
+ * This invokes undefined behavior when n is negative.
+ */
+ constexpr IndexRangeCyclic push_back(const int n = 1) const
+ {
+ BLI_assert(n >= 0);
+ int new_end = this->end_ + n;
+ int num_cycles = this->cycles_;
+ if (this->size_range() <= new_end) {
+ const int new_cycles = n / this->size_range(); /* Integer division (floor) */
+ const int remainder = new_end - this->size_range() * new_cycles;
+ const bool overflow = remainder >= this->size_range();
+ new_end = remainder - (overflow ? this->size_range() : 0);
+ num_cycles += new_cycles + int(overflow);
}
- return {nstart, end_, range_start_, range_end_, cycles};
+ BLI_assert(num_cycles >= 0);
+ BLI_assert(num_cycles > 0 || (this->start_ <= new_end || new_end == 0));
+ return {this->start_, new_end, this->range_size_, num_cycles};
}
+
/**
- * Increment the range by adding the given number of indices to the end of the range.
+ * Returns a new range with n indices removed from the beginning of the range.
+ * This invokes undefined behavior.
*/
- constexpr IndexRangeCyclic push_backward(int n)
+ constexpr IndexRangeCyclic drop_front(const int n = 1) const
{
BLI_assert(n >= 0);
- int64_t new_end = end_ + n;
- int64_t cycles = cycles_;
- if (range_end_ <= new_end) {
- cycles += (int64_t)(n / (range_end_ - range_start_)) + (new_end < start_) - (end_ < start_);
+ int new_start = this->start_ + n;
+ int num_cycles = this->cycles_;
+ if (this->size_range() <= new_start) {
+ const int dropped_cycles = n / this->size_range(); /* Integer division (floor) */
+ const int remainder = new_start - this->size_range() * dropped_cycles;
+ const bool overflow = remainder >= this->size_range();
+ new_start = remainder - (overflow ? this->size_range() : 0);
+ num_cycles -= dropped_cycles + int(overflow);
}
- return {start_, new_end, range_start_, range_end_, cycles};
+ BLI_assert(num_cycles >= 0);
+ BLI_assert(num_cycles > 0 ||
+ (new_start <= this->end_ || (this->end_ == 0 && new_start < this->size_range())));
+ return {new_start, this->end_, this->range_size_, num_cycles};
+ }
+
+ /**
+ * Returns a new range with n indices removed from the end of the range.
+ * This invokes undefined behavior when n is negative or n is larger then the underlying range.
+ */
+ constexpr IndexRangeCyclic drop_back(const int n = 1) const
+ {
+ BLI_assert(n >= 0);
+ int new_end = this->end_ - n;
+ int num_cycles = this->cycles_;
+ if (0 >= new_end) {
+ const int dropped_cycles = n / this->size_range(); /* Integer division (floor) */
+ const int remainder = new_end + this->size_range() * dropped_cycles;
+ const bool underflow = remainder < 0;
+ new_end = remainder + (underflow ? this->size_range() : 0);
+ num_cycles -= dropped_cycles + int(underflow);
+ }
+ BLI_assert(num_cycles >= 0);
+ BLI_assert(num_cycles > 0 || (this->start_ <= new_end || new_end == 0));
+ return {this->start_, new_end, this->range_size_, num_cycles};
}
/**
@@ -154,7 +296,7 @@ class IndexRangeCyclic {
*/
constexpr IndexRange curve_range() const
{
- return IndexRange(range_start_, total_size());
+ return IndexRange(0, this->size_range());
}
/**
@@ -162,7 +304,7 @@ class IndexRangeCyclic {
*/
constexpr IndexRange range_before_loop() const
{
- return IndexRange(start_, size_before_loop());
+ return IndexRange(this->start_, this->size_before_loop());
}
/**
@@ -170,88 +312,104 @@ class IndexRangeCyclic {
*/
constexpr IndexRange range_after_loop() const
{
- return IndexRange(range_start_, size_after_loop());
+ return IndexRange(0, this->size_after_loop());
}
/**
- * Size of the entire iterable range.
+ * Number of elements in the underlying iterable range.
*/
- constexpr int64_t total_size() const
+ constexpr int size_range() const
{
- return range_end_ - range_start_;
+ return this->range_size_;
}
/**
* Number of elements between the first element in the range up to the last element in the curve.
*/
- constexpr int64_t size_before_loop() const
+ constexpr int size_before_loop() const
{
- return range_end_ - start_;
+ return this->range_size_ - this->start_;
}
/**
* Number of elements between the first element in the iterable range up to the last element in
* the range.
*/
- constexpr int64_t size_after_loop() const
+ constexpr int size_after_loop() const
{
- return end_ - range_start_;
+ return this->end_;
}
/**
- * Get number of elements iterated by the cyclical index range.
+ * Number of elements iterated by the cyclical index range.
*/
- constexpr int64_t size() const
+ constexpr int size() const
{
- if (cycles_ > 0) {
- return size_before_loop() + end_ + (cycles_ - 1) * (range_end_ - range_start_);
+ if (this->cycles_ > 0) {
+ return this->size_before_loop() + this->end_ + (this->cycles_ - 1) * this->range_size_;
}
else {
- return end_ - start_;
+ return int(this->end_ - this->start_);
}
}
/**
* Return the number of times the iterator will cycle before ending.
*/
- constexpr int64_t cycles() const
+ constexpr int cycles() const
+ {
+ return this->cycles_;
+ }
+
+ constexpr int first() const
{
- return cycles_;
+ return this->start_;
}
- constexpr int64_t first() const
+ constexpr int last() const
{
- return start_;
+ BLI_assert(this->size() > 0);
+ return int(this->end_ - 1);
}
- constexpr int64_t one_after_last() const
+ constexpr int one_after_last() const
+ {
+ return this->end_;
+ }
+
+ constexpr bool operator==(const IndexRangeCyclic &other) const
+ {
+ return this->start_ == other.start_ && this->end_ == other.end_ &&
+ this->cycles_ == other.cycles_ && this->range_size_ == other.range_size_;
+ }
+ constexpr bool operator!=(const IndexRangeCyclic &other) const
{
- return end_;
+ return !this->operator==(other);
}
struct CyclicIterator; /* Forward declaration */
constexpr CyclicIterator begin() const
{
- return CyclicIterator(range_start_, range_end_, start_, 0);
+ return CyclicIterator(this->range_size_, this->start_, 0);
}
constexpr CyclicIterator end() const
{
- return CyclicIterator(range_start_, range_end_, end_, cycles_);
+ return CyclicIterator(this->range_size_, this->end_, this->cycles_);
}
struct CyclicIterator {
- int64_t index_, begin_, end_, cycles_;
+ int index_, range_end_, cycles_;
- constexpr CyclicIterator(int64_t range_begin, int64_t range_end, int64_t index, int64_t cycles)
- : index_(index), begin_(range_begin), end_(range_end), cycles_(cycles)
+ constexpr CyclicIterator(const int range_end, const int index, const int cycles)
+ : index_(index), range_end_(range_end), cycles_(cycles)
{
- BLI_assert(range_begin <= index && index <= range_end);
+ BLI_assert(0 <= index && index <= range_end);
}
constexpr CyclicIterator(const CyclicIterator &copy)
- : index_(copy.index_), begin_(copy.begin_), end_(copy.end_), cycles_(copy.cycles_)
+ : index_(copy.index_), range_end_(copy.range_end_), cycles_(copy.cycles_)
{
}
~CyclicIterator() = default;
@@ -261,37 +419,36 @@ class IndexRangeCyclic {
if (this == &copy) {
return *this;
}
- index_ = copy.index_;
- begin_ = copy.begin_;
- end_ = copy.end_;
- cycles_ = copy.cycles_;
+ this->index_ = copy.index_;
+ this->range_end_ = copy.range_end_;
+ this->cycles_ = copy.cycles_;
return *this;
}
constexpr CyclicIterator &operator++()
{
- index_++;
- if (index_ == end_) {
- index_ = begin_;
- cycles_++;
+ this->index_++;
+ if (this->index_ == this->range_end_) {
+ this->index_ = 0;
+ this->cycles_++;
}
return *this;
}
- void increment(int64_t n)
+ void increment(const int n)
{
for (int i = 0; i < n; i++) {
++*this;
}
}
- constexpr const int64_t &operator*() const
+ constexpr const int &operator*() const
{
- return index_;
+ return this->index_;
}
constexpr bool operator==(const CyclicIterator &other) const
{
- return index_ == other.index_ && cycles_ == other.cycles_;
+ return this->index_ == other.index_ && this->cycles_ == other.cycles_;
}
constexpr bool operator!=(const CyclicIterator &other) const
{
diff --git a/source/blender/blenkernel/BKE_fcurve.h b/source/blender/blenkernel/BKE_fcurve.h
index c11e6353bc0..b4de24e3b64 100644
--- a/source/blender/blenkernel/BKE_fcurve.h
+++ b/source/blender/blenkernel/BKE_fcurve.h
@@ -167,7 +167,7 @@ void set_active_fmodifier(ListBase *modifiers, struct FModifier *fcm);
* \param mtype: Type of modifier (if 0, doesn't matter).
* \param acttype: Type of action to perform (if -1, doesn't matter).
*/
-bool list_has_suitable_fmodifier(ListBase *modifiers, int mtype, short acttype);
+bool list_has_suitable_fmodifier(const ListBase *modifiers, int mtype, short acttype);
typedef struct FModifiersStackStorage {
uint modifier_count;
@@ -369,12 +369,12 @@ int BKE_fcurve_pathcache_find_array(struct FCurvePathCache *fcache,
* Calculate the extents of F-Curve's keyframes.
*/
bool BKE_fcurve_calc_range(
- struct FCurve *fcu, float *min, float *max, bool do_sel_only, bool do_min_length);
+ const struct FCurve *fcu, float *min, float *max, bool do_sel_only, bool do_min_length);
/**
* Calculate the extents of F-Curve's data.
*/
-bool BKE_fcurve_calc_bounds(struct FCurve *fcu,
+bool BKE_fcurve_calc_bounds(const struct FCurve *fcu,
float *xmin,
float *xmax,
float *ymin,
@@ -421,20 +421,25 @@ void BKE_fcurve_keyframe_move_value_with_handles(struct BezTriple *keyframe, flo
* Usability of keyframes refers to whether they should be displayed,
* and also whether they will have any influence on the final result.
*/
-bool BKE_fcurve_are_keyframes_usable(struct FCurve *fcu);
+bool BKE_fcurve_are_keyframes_usable(const struct FCurve *fcu);
/**
* Can keyframes be added to F-Curve?
* Keyframes can only be added if they are already visible.
*/
-bool BKE_fcurve_is_keyframable(struct FCurve *fcu);
-bool BKE_fcurve_is_protected(struct FCurve *fcu);
+bool BKE_fcurve_is_keyframable(const struct FCurve *fcu);
+bool BKE_fcurve_is_protected(const struct FCurve *fcu);
+
+/**
+ * Are any of the keyframe control points selected on the F-Curve?
+ */
+bool BKE_fcurve_has_selected_control_points(const struct FCurve *fcu);
/**
* Checks if the F-Curve has a Cycles modifier with simple settings
* that warrant transition smoothing.
*/
-bool BKE_fcurve_is_cyclic(struct FCurve *fcu);
+bool BKE_fcurve_is_cyclic(const struct FCurve *fcu);
/* Type of infinite cycle for a curve. */
typedef enum eFCU_Cycle_Type {
@@ -448,7 +453,7 @@ typedef enum eFCU_Cycle_Type {
/**
* Checks if the F-Curve has a Cycles modifier, and returns the type of the cycle behavior.
*/
-eFCU_Cycle_Type BKE_fcurve_get_cycle_type(struct FCurve *fcu);
+eFCU_Cycle_Type BKE_fcurve_get_cycle_type(const struct FCurve *fcu);
/**
* Recompute bezier handles of all three given BezTriples, so that `bezt` can be inserted between
@@ -539,7 +544,7 @@ float evaluate_fcurve_driver(struct PathResolvedRNA *anim_rna,
/**
* Checks if the curve has valid keys, drivers or modifiers that produce an actual curve.
*/
-bool BKE_fcurve_is_empty(struct FCurve *fcu);
+bool BKE_fcurve_is_empty(const struct FCurve *fcu);
/**
* Calculate the value of the given F-Curve at the given frame,
* and store it's value in #FCurve.curval.
diff --git a/source/blender/blenkernel/BKE_mesh_mapping.h b/source/blender/blenkernel/BKE_mesh_mapping.h
index a39953a9bd1..2f9d526f6fb 100644
--- a/source/blender/blenkernel/BKE_mesh_mapping.h
+++ b/source/blender/blenkernel/BKE_mesh_mapping.h
@@ -62,6 +62,10 @@ typedef struct UvElement {
* If islands are calculated, it also stores UvElements
* belonging to the same uv island in sequence and
* the number of uvs per island.
+ *
+ * \note in C++, #head_table and #unique_index_table would
+ * be `mutable`, as they are created on demand, and never
+ * changed after creation.
*/
typedef struct UvElementMap {
/** UvElement Storage. */
@@ -77,6 +81,9 @@ typedef struct UvElementMap {
/** If Non-NULL, pointer to local head of each unique UV. */
struct UvElement **head_table;
+ /** If Non-NULL, pointer to index of each unique UV. */
+ int *unique_index_table;
+
/** Number of islands, or zero if not calculated. */
int total_islands;
/** Array of starting index in #storage where each island begins. */
diff --git a/source/blender/blenkernel/BKE_node.h b/source/blender/blenkernel/BKE_node.h
index 4d883f9e31e..ae8eea4a6bf 100644
--- a/source/blender/blenkernel/BKE_node.h
+++ b/source/blender/blenkernel/BKE_node.h
@@ -746,7 +746,14 @@ struct bNode *nodeFindNodebyName(struct bNodeTree *ntree, const char *name);
/**
* Finds a node based on given socket and returns true on success.
*/
-bool nodeFindNode(struct bNodeTree *ntree,
+bool nodeFindNodeTry(struct bNodeTree *ntree,
+ struct bNodeSocket *sock,
+ struct bNode **r_node,
+ int *r_sockindex);
+/**
+ * Same as above but expects that the socket definitely is in the node tree.
+ */
+void nodeFindNode(struct bNodeTree *ntree,
struct bNodeSocket *sock,
struct bNode **r_node,
int *r_sockindex);
diff --git a/source/blender/blenkernel/BKE_paint.h b/source/blender/blenkernel/BKE_paint.h
index 9fc4aa5307d..434255b2d9c 100644
--- a/source/blender/blenkernel/BKE_paint.h
+++ b/source/blender/blenkernel/BKE_paint.h
@@ -119,6 +119,7 @@ typedef enum ePaintSymmetryAreas {
PAINT_SYMM_AREA_Y = (1 << 1),
PAINT_SYMM_AREA_Z = (1 << 2),
} ePaintSymmetryAreas;
+ENUM_OPERATORS(ePaintSymmetryAreas, PAINT_SYMM_AREA_Z);
#define PAINT_SYMM_AREAS 8
diff --git a/source/blender/blenkernel/BKE_particle.h b/source/blender/blenkernel/BKE_particle.h
index a797aef73f6..05b9aca7544 100644
--- a/source/blender/blenkernel/BKE_particle.h
+++ b/source/blender/blenkernel/BKE_particle.h
@@ -291,7 +291,11 @@ void psys_set_current_num(struct Object *ob, int index);
/* UNUSED */
// struct Object *psys_find_object(struct Scene *scene, struct ParticleSystem *psys);
-struct LatticeDeformData *psys_create_lattice_deform_data(struct ParticleSimulationData *sim);
+/**
+ * Initialize/free data for particle simulation evaluation.
+ */
+void psys_sim_data_init(struct ParticleSimulationData *sim);
+void psys_sim_data_free(struct ParticleSimulationData *sim);
/**
* For a given evaluated particle system get its original.
@@ -416,7 +420,7 @@ void psys_get_particle_on_path(struct ParticleSimulationData *sim,
struct ParticleKey *state,
bool vel);
/**
- * Gets particle's state at a time.
+ * Gets particle's state at a time. Must call psys_sim_data_init before this.
* \return true if particle exists and can be seen and false if not.
*/
bool psys_get_particle_state(struct ParticleSimulationData *sim,
diff --git a/source/blender/blenkernel/BKE_pbvh.h b/source/blender/blenkernel/BKE_pbvh.h
index b375d69b61c..4badd1bc269 100644
--- a/source/blender/blenkernel/BKE_pbvh.h
+++ b/source/blender/blenkernel/BKE_pbvh.h
@@ -416,6 +416,8 @@ typedef enum {
PBVH_Subdivide = 1,
PBVH_Collapse = 2,
} PBVHTopologyUpdateMode;
+ENUM_OPERATORS(PBVHTopologyUpdateMode, PBVH_Collapse);
+
/**
* Collapse short edges, subdivide long edges.
*/
diff --git a/source/blender/blenkernel/CMakeLists.txt b/source/blender/blenkernel/CMakeLists.txt
index 7d43fa7e6af..462ccc19601 100644
--- a/source/blender/blenkernel/CMakeLists.txt
+++ b/source/blender/blenkernel/CMakeLists.txt
@@ -75,6 +75,7 @@ set(SRC
intern/asset_catalog_path.cc
intern/asset_library.cc
intern/asset_library_service.cc
+ intern/asset_representation.cc
intern/attribute.cc
intern/attribute_access.cc
intern/attribute_math.cc
@@ -324,6 +325,7 @@ set(SRC
BKE_asset_catalog_path.hh
BKE_asset_library.h
BKE_asset_library.hh
+ BKE_asset_representation.hh
BKE_attribute.h
BKE_attribute.hh
BKE_attribute_math.hh
diff --git a/source/blender/blenkernel/intern/asset.cc b/source/blender/blenkernel/intern/asset.cc
index 67802b1d6b4..7103e017847 100644
--- a/source/blender/blenkernel/intern/asset.cc
+++ b/source/blender/blenkernel/intern/asset.cc
@@ -27,21 +27,31 @@ using namespace blender;
AssetMetaData *BKE_asset_metadata_create()
{
- AssetMetaData *asset_data = (AssetMetaData *)MEM_callocN(sizeof(*asset_data), __func__);
- memcpy(asset_data, DNA_struct_default_get(AssetMetaData), sizeof(*asset_data));
- return asset_data;
+ const AssetMetaData *default_metadata = DNA_struct_default_get(AssetMetaData);
+ return MEM_new<AssetMetaData>(__func__, *default_metadata);
}
void BKE_asset_metadata_free(AssetMetaData **asset_data)
{
- if ((*asset_data)->properties) {
- IDP_FreeProperty((*asset_data)->properties);
+ (*asset_data)->~AssetMetaData();
+ MEM_SAFE_FREE(*asset_data);
+}
+
+AssetMetaData::~AssetMetaData()
+{
+ if (properties) {
+ IDP_FreeProperty(properties);
}
- MEM_SAFE_FREE((*asset_data)->author);
- MEM_SAFE_FREE((*asset_data)->description);
- BLI_freelistN(&(*asset_data)->tags);
+ MEM_SAFE_FREE(author);
+ MEM_SAFE_FREE(description);
+ BLI_freelistN(&tags);
+}
- MEM_SAFE_FREE(*asset_data);
+std::unique_ptr<AssetMetaData> BKE_asset_metadata_move_to_unique_ptr(AssetMetaData *asset_data)
+{
+ std::unique_ptr unique_asset_data = std::make_unique<AssetMetaData>(*asset_data);
+ *asset_data = *DNA_struct_default_get(AssetMetaData);
+ return unique_asset_data;
}
static AssetTag *asset_metadata_tag_add(AssetMetaData *asset_data, const char *const name)
diff --git a/source/blender/blenkernel/intern/asset_catalog.cc b/source/blender/blenkernel/intern/asset_catalog.cc
index 62d03b2d79b..a9fe59eba64 100644
--- a/source/blender/blenkernel/intern/asset_catalog.cc
+++ b/source/blender/blenkernel/intern/asset_catalog.cc
@@ -508,14 +508,13 @@ CatalogFilePath AssetCatalogService::find_suitable_cdf_path_for_writing(
"catalog definition file should be put");
/* Ask the asset library API for an appropriate location. */
- char suitable_root_path[PATH_MAX];
- const bool asset_lib_root_found = BKE_asset_library_find_suitable_root_path_from_path(
- blend_file_path.c_str(), suitable_root_path);
- if (asset_lib_root_found) {
+ const std::string suitable_root_path = BKE_asset_library_find_suitable_root_path_from_path(
+ blend_file_path);
+ if (!suitable_root_path.empty()) {
char asset_lib_cdf_path[PATH_MAX];
BLI_path_join(asset_lib_cdf_path,
sizeof(asset_lib_cdf_path),
- suitable_root_path,
+ suitable_root_path.c_str(),
DEFAULT_CATALOG_FILENAME.c_str());
return asset_lib_cdf_path;
}
diff --git a/source/blender/blenkernel/intern/asset_library.cc b/source/blender/blenkernel/intern/asset_library.cc
index b8420af1168..4dccee425c6 100644
--- a/source/blender/blenkernel/intern/asset_library.cc
+++ b/source/blender/blenkernel/intern/asset_library.cc
@@ -7,11 +7,14 @@
#include <memory>
#include "BKE_asset_library.hh"
+#include "BKE_asset_representation.hh"
+#include "BKE_lib_remap.h"
#include "BKE_main.h"
#include "BKE_preferences.h"
#include "BLI_fileops.h"
#include "BLI_path_util.h"
+#include "BLI_set.hh"
#include "DNA_asset_types.h"
#include "DNA_userdef_types.h"
@@ -50,22 +53,22 @@ bool BKE_asset_library_has_any_unsaved_catalogs()
return service->has_any_unsaved_catalogs();
}
-bool BKE_asset_library_find_suitable_root_path_from_path(const char *input_path,
- char *r_library_path)
+std::string BKE_asset_library_find_suitable_root_path_from_path(
+ const blender::StringRefNull input_path)
{
if (bUserAssetLibrary *preferences_lib = BKE_preferences_asset_library_containing_path(
- &U, input_path)) {
- BLI_strncpy(r_library_path, preferences_lib->path, FILE_MAXDIR);
- return true;
+ &U, input_path.c_str())) {
+ return preferences_lib->path;
}
- BLI_split_dir_part(input_path, r_library_path, FILE_MAXDIR);
- return r_library_path[0] != '\0';
+ char buffer[FILE_MAXDIR];
+ BLI_split_dir_part(input_path.c_str(), buffer, FILE_MAXDIR);
+ return buffer;
}
-bool BKE_asset_library_find_suitable_root_path_from_main(const Main *bmain, char *r_library_path)
+std::string BKE_asset_library_find_suitable_root_path_from_main(const Main *bmain)
{
- return BKE_asset_library_find_suitable_root_path_from_path(bmain->filepath, r_library_path);
+ return BKE_asset_library_find_suitable_root_path_from_path(bmain->filepath);
}
blender::bke::AssetCatalogService *BKE_asset_library_get_catalog_service(
@@ -98,6 +101,13 @@ void BKE_asset_library_refresh_catalog_simplename(struct AssetLibrary *asset_lib
lib->refresh_catalog_simplename(asset_data);
}
+void BKE_asset_library_remap_ids(IDRemapper *mappings)
+{
+ blender::bke::AssetLibraryService *service = blender::bke::AssetLibraryService::get();
+ service->foreach_loaded_asset_library(
+ [mappings](blender::bke::AssetLibrary &library) { library.remap_ids(*mappings); });
+}
+
namespace blender::bke {
AssetLibrary::AssetLibrary() : catalog_service(std::make_unique<AssetCatalogService>())
@@ -111,7 +121,7 @@ AssetLibrary::~AssetLibrary()
}
}
-void AssetLibrary::load(StringRefNull library_root_directory)
+void AssetLibrary::load_catalogs(StringRefNull library_root_directory)
{
auto catalog_service = std::make_unique<AssetCatalogService>(library_root_directory);
catalog_service->load_from_disk();
@@ -123,6 +133,44 @@ void AssetLibrary::refresh()
this->catalog_service->reload_catalogs();
}
+AssetRepresentation &AssetLibrary::add_external_asset(StringRef name,
+ std::unique_ptr<AssetMetaData> metadata)
+{
+ asset_storage_.append(std::make_unique<AssetRepresentation>(name, std::move(metadata)));
+ return *asset_storage_.last();
+}
+
+AssetRepresentation &AssetLibrary::add_local_id_asset(ID &id)
+{
+ asset_storage_.append(std::make_unique<AssetRepresentation>(id));
+ return *asset_storage_.last();
+}
+
+std::optional<int> AssetLibrary::find_asset_index(const AssetRepresentation &asset)
+{
+ int index = 0;
+ /* Find index of asset. */
+ for (auto &asset_uptr : asset_storage_) {
+ if (&asset == asset_uptr.get()) {
+ return index;
+ }
+ index++;
+ }
+
+ return {};
+}
+
+bool AssetLibrary::remove_asset(AssetRepresentation &asset)
+{
+ std::optional<int> asset_index = find_asset_index(asset);
+ if (!asset_index) {
+ return false;
+ }
+
+ asset_storage_.remove_and_reorder(*asset_index);
+ return true;
+}
+
namespace {
void asset_library_on_save_post(struct Main *main,
struct PointerRNA **pointers,
@@ -166,6 +214,28 @@ void AssetLibrary::on_blend_save_post(struct Main *main,
}
}
+void AssetLibrary::remap_ids(IDRemapper &mappings)
+{
+ Set<AssetRepresentation *> removed_id_assets;
+
+ for (auto &asset_uptr : asset_storage_) {
+ if (!asset_uptr->is_local_id()) {
+ continue;
+ }
+
+ IDRemapperApplyResult result = BKE_id_remapper_apply(
+ &mappings, &asset_uptr->local_asset_id_, ID_REMAP_APPLY_DEFAULT);
+ if (result == ID_REMAP_RESULT_SOURCE_UNASSIGNED) {
+ removed_id_assets.add(asset_uptr.get());
+ }
+ }
+
+ /* Remove the assets from storage. */
+ for (AssetRepresentation *asset : removed_id_assets) {
+ remove_asset(*asset);
+ }
+}
+
void AssetLibrary::refresh_catalog_simplename(struct AssetMetaData *asset_data)
{
if (BLI_uuid_is_nil(asset_data->catalog_id)) {
diff --git a/source/blender/blenkernel/intern/asset_library_service.cc b/source/blender/blenkernel/intern/asset_library_service.cc
index cd8de7908bf..35441b9b795 100644
--- a/source/blender/blenkernel/intern/asset_library_service.cc
+++ b/source/blender/blenkernel/intern/asset_library_service.cc
@@ -6,6 +6,7 @@
#include "asset_library_service.hh"
+#include "BKE_asset_library.hh"
#include "BKE_blender.h"
#include "BKE_preferences.h"
@@ -47,15 +48,10 @@ AssetLibrary *AssetLibraryService::get_asset_library(
{
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';
- }
+ std::string root_path = bmain ? BKE_asset_library_find_suitable_root_path_from_main(bmain) :
+ "";
- if (root_path[0] == '\0') {
+ if (root_path.empty()) {
/* File wasn't saved yet. */
return get_asset_library_current_file();
}
@@ -104,7 +100,7 @@ AssetLibrary *AssetLibraryService::get_asset_library_on_disk(StringRefNull top_l
AssetLibrary *lib = lib_uptr.get();
lib->on_blend_save_handler_register();
- lib->load(top_dir_trailing_slash);
+ lib->load_catalogs(top_dir_trailing_slash);
on_disk_libraries_.add_new(top_dir_trailing_slash, std::move(lib_uptr));
CLOG_INFO(&LOG, 2, "get \"%s\" (loaded)", top_dir_trailing_slash.c_str());
@@ -180,4 +176,15 @@ bool AssetLibraryService::has_any_unsaved_catalogs() const
return false;
}
+void AssetLibraryService::foreach_loaded_asset_library(FunctionRef<void(AssetLibrary &)> fn) const
+{
+ if (current_file_library_) {
+ fn(*current_file_library_);
+ }
+
+ for (const auto &asset_lib_uptr : on_disk_libraries_.values()) {
+ fn(*asset_lib_uptr);
+ }
+}
+
} // namespace blender::bke
diff --git a/source/blender/blenkernel/intern/asset_library_service.hh b/source/blender/blenkernel/intern/asset_library_service.hh
index c22c6b182ce..6caaea72875 100644
--- a/source/blender/blenkernel/intern/asset_library_service.hh
+++ b/source/blender/blenkernel/intern/asset_library_service.hh
@@ -12,10 +12,13 @@
#include "BKE_asset_library.hh"
+#include "BLI_function_ref.hh"
#include "BLI_map.hh"
#include <memory>
+struct AssetLibraryReference;
+
namespace blender::bke {
/**
@@ -58,11 +61,16 @@ class AssetLibraryService {
/** Returns whether there are any known asset libraries with unsaved catalog edits. */
bool has_any_unsaved_catalogs() const;
+ void foreach_loaded_asset_library(FunctionRef<void(AssetLibrary &)> fn) const;
+
protected:
static std::unique_ptr<AssetLibraryService> instance_;
/* Mapping absolute path of the library's top-level directory to the AssetLibrary instance. */
Map<std::string, AssetLibraryPtr> on_disk_libraries_;
+ /** Library without a known path, i.e. the "Current File" library if the file isn't saved yet. If
+ * the file was saved, a valid path for the library can be determined and #on_disk_libraries_
+ * above should be used. */
AssetLibraryPtr current_file_library_;
/* Handlers for managing the life cycle of the AssetLibraryService instance. */
diff --git a/source/blender/blenkernel/intern/asset_library_service_test.cc b/source/blender/blenkernel/intern/asset_library_service_test.cc
index 7952e7ea3b0..18fdcb80155 100644
--- a/source/blender/blenkernel/intern/asset_library_service_test.cc
+++ b/source/blender/blenkernel/intern/asset_library_service_test.cc
@@ -8,6 +8,9 @@
#include "BKE_appdir.h"
#include "BKE_callbacks.h"
+#include "BKE_main.h"
+
+#include "DNA_asset_types.h"
#include "CLG_log.h"
@@ -102,6 +105,26 @@ TEST_F(AssetLibraryServiceTest, library_pointers)
* cannot be reliably tested by just pointer comparison, though. */
}
+TEST_F(AssetLibraryServiceTest, library_from_reference)
+{
+ AssetLibraryService *service = AssetLibraryService::get();
+ AssetLibrary *const lib = service->get_asset_library_on_disk(asset_library_root_);
+ AssetLibrary *const curfile_lib = service->get_asset_library_current_file();
+
+ AssetLibraryReference ref{};
+ ref.type = ASSET_LIBRARY_LOCAL;
+ EXPECT_EQ(curfile_lib, service->get_asset_library(nullptr, ref))
+ << "Getting the local (current file) reference without a main saved on disk should return "
+ "the current file library";
+
+ Main dummy_main{};
+ std::string dummy_filepath = asset_library_root_ + SEP + "dummy.blend";
+ BLI_strncpy(dummy_main.filepath, dummy_filepath.c_str(), sizeof(dummy_main.filepath));
+ EXPECT_EQ(lib, service->get_asset_library(&dummy_main, ref))
+ << "Getting the local (current file) reference with a main saved on disk should return "
+ "the an asset library for this directory";
+}
+
TEST_F(AssetLibraryServiceTest, library_path_trailing_slashes)
{
AssetLibraryService *service = AssetLibraryService::get();
diff --git a/source/blender/blenkernel/intern/asset_representation.cc b/source/blender/blenkernel/intern/asset_representation.cc
new file mode 100644
index 00000000000..bbaa634d5ad
--- /dev/null
+++ b/source/blender/blenkernel/intern/asset_representation.cc
@@ -0,0 +1,98 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+/** \file
+ * \ingroup bke
+ */
+
+#include <stdexcept>
+
+#include "DNA_ID.h"
+#include "DNA_asset_types.h"
+
+#include "BKE_asset.h"
+#include "BKE_asset_representation.hh"
+
+namespace blender::bke {
+
+AssetRepresentation::AssetRepresentation(StringRef name, std::unique_ptr<AssetMetaData> metadata)
+ : is_local_id_(false), external_asset_()
+{
+ external_asset_.name = name;
+ external_asset_.metadata_ = std::move(metadata);
+}
+
+AssetRepresentation::AssetRepresentation(ID &id) : is_local_id_(true), local_asset_id_(&id)
+{
+ if (!id.asset_data) {
+ throw std::invalid_argument("Passed ID is not an asset");
+ }
+}
+
+AssetRepresentation::AssetRepresentation(AssetRepresentation &&other)
+ : is_local_id_(other.is_local_id_)
+{
+ if (is_local_id_) {
+ local_asset_id_ = other.local_asset_id_;
+ other.local_asset_id_ = nullptr;
+ }
+ else {
+ external_asset_ = std::move(other.external_asset_);
+ }
+}
+
+AssetRepresentation::~AssetRepresentation()
+{
+ if (!is_local_id_) {
+ external_asset_.~ExternalAsset();
+ }
+}
+
+StringRefNull AssetRepresentation::get_name() const
+{
+ if (is_local_id_) {
+ return local_asset_id_->name + 2;
+ }
+
+ return external_asset_.name;
+}
+
+AssetMetaData &AssetRepresentation::get_metadata() const
+{
+ return is_local_id_ ? *local_asset_id_->asset_data : *external_asset_.metadata_;
+}
+
+bool AssetRepresentation::is_local_id() const
+{
+ return is_local_id_;
+}
+
+} // namespace blender::bke
+
+/* ---------------------------------------------------------------------- */
+/** \name C-API
+ * \{ */
+
+using namespace blender;
+
+const char *BKE_asset_representation_name_get(const AssetRepresentation *asset_handle)
+{
+ const bke::AssetRepresentation *asset = reinterpret_cast<const bke::AssetRepresentation *>(
+ asset_handle);
+ return asset->get_name().c_str();
+}
+
+AssetMetaData *BKE_asset_representation_metadata_get(const AssetRepresentation *asset_handle)
+{
+ const bke::AssetRepresentation *asset = reinterpret_cast<const bke::AssetRepresentation *>(
+ asset_handle);
+ return &asset->get_metadata();
+}
+
+bool BKE_asset_representation_is_local_id(const AssetRepresentation *asset_handle)
+{
+ const bke::AssetRepresentation *asset = reinterpret_cast<const bke::AssetRepresentation *>(
+ asset_handle);
+ return asset->is_local_id();
+}
+
+/** \} */
diff --git a/source/blender/blenkernel/intern/asset_test.cc b/source/blender/blenkernel/intern/asset_test.cc
index fa8769862a8..5ff65054926 100644
--- a/source/blender/blenkernel/intern/asset_test.cc
+++ b/source/blender/blenkernel/intern/asset_test.cc
@@ -13,7 +13,7 @@ namespace blender::bke::tests {
TEST(AssetMetadataTest, set_catalog_id)
{
- AssetMetaData meta;
+ AssetMetaData meta{};
const bUUID uuid = BLI_uuid_generate_random();
/* Test trivial values. */
diff --git a/source/blender/blenkernel/intern/attribute.cc b/source/blender/blenkernel/intern/attribute.cc
index a8eea24cdb6..d9f8baeda1a 100644
--- a/source/blender/blenkernel/intern/attribute.cc
+++ b/source/blender/blenkernel/intern/attribute.cc
@@ -515,29 +515,14 @@ CustomDataLayer *BKE_id_attributes_active_get(ID *id)
return nullptr;
}
-void BKE_id_attributes_active_set(ID *id, CustomDataLayer *active_layer)
+void BKE_id_attributes_active_set(ID *id, const char *name)
{
- DomainInfo info[ATTR_DOMAIN_NUM];
- get_domains(id, info);
-
- int index = 0;
+ const CustomDataLayer *layer = BKE_id_attribute_search(
+ id, name, CD_MASK_PROP_ALL, ATTR_DOMAIN_MASK_ALL);
+ BLI_assert(layer != nullptr);
- for (const int domain : IndexRange(ATTR_DOMAIN_NUM)) {
- const CustomData *customdata = info[domain].customdata;
- if (customdata == nullptr) {
- continue;
- }
- for (int i = 0; i < customdata->totlayer; i++) {
- const CustomDataLayer *layer = &customdata->layers[i];
- if (layer == active_layer) {
- *BKE_id_attributes_active_index_p(id) = index;
- return;
- }
- if (CD_MASK_PROP_ALL & CD_TYPE_AS_MASK(layer->type)) {
- index++;
- }
- }
- }
+ const int index = BKE_id_attribute_to_index(id, layer, ATTR_DOMAIN_MASK_ALL, CD_MASK_PROP_ALL);
+ *BKE_id_attributes_active_index_p(id) = index;
}
int *BKE_id_attributes_active_index_p(ID *id)
diff --git a/source/blender/blenkernel/intern/context.c b/source/blender/blenkernel/intern/context.c
index 1d6092849cc..0ddd53ccb99 100644
--- a/source/blender/blenkernel/intern/context.c
+++ b/source/blender/blenkernel/intern/context.c
@@ -1495,7 +1495,7 @@ AssetHandle CTX_wm_asset_handle(const bContext *C, bool *r_is_valid)
* require returning a non-owning pointer, which we don't have in the Asset Browser (yet). */
FileDirEntry *file =
(FileDirEntry *)CTX_data_pointer_get_type(C, "active_file", &RNA_FileSelectEntry).data;
- if (file && file->asset_data) {
+ if (file && file->asset) {
*r_is_valid = true;
return (AssetHandle){.file_data = file};
}
diff --git a/source/blender/blenkernel/intern/customdata.cc b/source/blender/blenkernel/intern/customdata.cc
index 9cbe4a79b82..b09ee75f1c6 100644
--- a/source/blender/blenkernel/intern/customdata.cc
+++ b/source/blender/blenkernel/intern/customdata.cc
@@ -2721,6 +2721,14 @@ static CustomDataLayer *customData_add_layer__internal(CustomData *data,
const LayerTypeInfo *typeInfo = layerType_getInfo(type);
int flag = 0;
+ /* Some layer types only support a single layer. */
+ if (!typeInfo->defaultname && CustomData_has_layer(data, type)) {
+ /* This function doesn't support dealing with existing layer data for these layer types when
+ * the layer already exists. */
+ BLI_assert(layerdata == nullptr);
+ return &data->layers[CustomData_get_layer_index(data, type)];
+ }
+
void *newlayerdata = nullptr;
switch (alloctype) {
case CD_SET_DEFAULT:
@@ -2773,21 +2781,6 @@ static CustomDataLayer *customData_add_layer__internal(CustomData *data,
break;
}
- /* Some layer types only support a single layer. */
- const bool reuse_existing_layer = !typeInfo->defaultname && CustomData_has_layer(data, type);
- if (reuse_existing_layer) {
- CustomDataLayer &layer = data->layers[CustomData_get_layer_index(data, type)];
- if (layer.data != nullptr) {
- if (typeInfo->free) {
- typeInfo->free(layer.data, totelem, typeInfo->size);
- }
- MEM_SAFE_FREE(layer.data);
- }
- layer.data = newlayerdata;
- layer.flag = flag;
- return &layer;
- }
-
int index = data->totlayer;
if (index >= data->maxlayer) {
if (!customData_resize(data, CUSTOMDATA_GROW)) {
diff --git a/source/blender/blenkernel/intern/fcurve.c b/source/blender/blenkernel/intern/fcurve.c
index beea3217126..aa99a5f605a 100644
--- a/source/blender/blenkernel/intern/fcurve.c
+++ b/source/blender/blenkernel/intern/fcurve.c
@@ -571,7 +571,7 @@ int BKE_fcurve_bezt_binarysearch_index(const BezTriple array[],
/* ...................................... */
/* Helper for calc_fcurve_* functions -> find first and last BezTriple to be used. */
-static short get_fcurve_end_keyframes(FCurve *fcu,
+static short get_fcurve_end_keyframes(const FCurve *fcu,
BezTriple **first,
BezTriple **last,
const bool do_sel_only)
@@ -621,7 +621,7 @@ static short get_fcurve_end_keyframes(FCurve *fcu,
return found;
}
-bool BKE_fcurve_calc_bounds(FCurve *fcu,
+bool BKE_fcurve_calc_bounds(const FCurve *fcu,
float *xmin,
float *xmax,
float *ymin,
@@ -752,7 +752,7 @@ bool BKE_fcurve_calc_bounds(FCurve *fcu,
}
bool BKE_fcurve_calc_range(
- FCurve *fcu, float *start, float *end, const bool do_sel_only, const bool do_min_length)
+ const FCurve *fcu, float *start, float *end, const bool do_sel_only, const bool do_min_length)
{
float min = 999999999.0f, max = -999999999.0f;
bool foundvert = false;
@@ -900,7 +900,7 @@ void BKE_fcurve_keyframe_move_value_with_handles(struct BezTriple *keyframe, con
/** \name Status Checks
* \{ */
-bool BKE_fcurve_are_keyframes_usable(FCurve *fcu)
+bool BKE_fcurve_are_keyframes_usable(const FCurve *fcu)
{
/* F-Curve must exist. */
if (fcu == NULL) {
@@ -960,12 +960,24 @@ bool BKE_fcurve_are_keyframes_usable(FCurve *fcu)
return true;
}
-bool BKE_fcurve_is_protected(FCurve *fcu)
+bool BKE_fcurve_is_protected(const FCurve *fcu)
{
return ((fcu->flag & FCURVE_PROTECTED) || ((fcu->grp) && (fcu->grp->flag & AGRP_PROTECTED)));
}
-bool BKE_fcurve_is_keyframable(FCurve *fcu)
+bool BKE_fcurve_has_selected_control_points(const FCurve *fcu)
+{
+ int i;
+ BezTriple *bezt;
+ for (bezt = fcu->bezt, i = 0; i < fcu->totvert; ++i, ++bezt) {
+ if ((bezt->f2 & SELECT) != 0) {
+ return true;
+ }
+ }
+ return false;
+}
+
+bool BKE_fcurve_is_keyframable(const FCurve *fcu)
{
/* F-Curve's keyframes must be "usable" (i.e. visible + have an effect on final result) */
if (BKE_fcurve_are_keyframes_usable(fcu) == 0) {
@@ -1156,7 +1168,7 @@ void fcurve_samples_to_keyframes(FCurve *fcu, const int start, const int end)
* that the handles are correct.
*/
-eFCU_Cycle_Type BKE_fcurve_get_cycle_type(FCurve *fcu)
+eFCU_Cycle_Type BKE_fcurve_get_cycle_type(const FCurve *fcu)
{
FModifier *fcm = fcu->modifiers.first;
@@ -1189,7 +1201,7 @@ eFCU_Cycle_Type BKE_fcurve_get_cycle_type(FCurve *fcu)
return FCU_CYCLE_NONE;
}
-bool BKE_fcurve_is_cyclic(FCurve *fcu)
+bool BKE_fcurve_is_cyclic(const FCurve *fcu)
{
return BKE_fcurve_get_cycle_type(fcu) != FCU_CYCLE_NONE;
}
@@ -2195,7 +2207,7 @@ float evaluate_fcurve_driver(PathResolvedRNA *anim_rna,
return evaluate_fcurve_ex(fcu, evaltime, cvalue);
}
-bool BKE_fcurve_is_empty(FCurve *fcu)
+bool BKE_fcurve_is_empty(const FCurve *fcu)
{
return (fcu->totvert == 0) && (fcu->driver == NULL) &&
!list_has_suitable_fmodifier(&fcu->modifiers, 0, FMI_TYPE_GENERATE_CURVE);
diff --git a/source/blender/blenkernel/intern/fluid.c b/source/blender/blenkernel/intern/fluid.c
index 32f8031a884..7409435e54a 100644
--- a/source/blender/blenkernel/intern/fluid.c
+++ b/source/blender/blenkernel/intern/fluid.c
@@ -1532,18 +1532,8 @@ static void emit_from_particles(Object *flow_ob,
sim.scene = scene;
sim.ob = flow_ob;
sim.psys = psys;
- sim.psys->lattice_deform_data = psys_create_lattice_deform_data(&sim);
- /* prepare curvemapping tables */
- if ((psys->part->child_flag & PART_CHILD_USE_CLUMP_CURVE) && psys->part->clumpcurve) {
- BKE_curvemapping_changed_all(psys->part->clumpcurve);
- }
- if ((psys->part->child_flag & PART_CHILD_USE_ROUGH_CURVE) && psys->part->roughcurve) {
- BKE_curvemapping_changed_all(psys->part->roughcurve);
- }
- if ((psys->part->child_flag & PART_CHILD_USE_TWIST_CURVE) && psys->part->twistcurve) {
- BKE_curvemapping_changed_all(psys->part->twistcurve);
- }
+ psys_sim_data_init(&sim);
/* initialize particle cache */
if (psys->part->type == PART_HAIR) {
@@ -1684,6 +1674,8 @@ static void emit_from_particles(Object *flow_ob,
if (particle_vel) {
MEM_freeN(particle_vel);
}
+
+ psys_sim_data_free(&sim);
}
}
diff --git a/source/blender/blenkernel/intern/fmodifier.c b/source/blender/blenkernel/intern/fmodifier.c
index 551bab75d4b..46dc01edbff 100644
--- a/source/blender/blenkernel/intern/fmodifier.c
+++ b/source/blender/blenkernel/intern/fmodifier.c
@@ -1283,7 +1283,7 @@ void set_active_fmodifier(ListBase *modifiers, FModifier *fcm)
}
}
-bool list_has_suitable_fmodifier(ListBase *modifiers, int mtype, short acttype)
+bool list_has_suitable_fmodifier(const ListBase *modifiers, int mtype, short acttype)
{
FModifier *fcm;
diff --git a/source/blender/blenkernel/intern/lib_id_delete.c b/source/blender/blenkernel/intern/lib_id_delete.c
index c7643c56212..92b34b9e1af 100644
--- a/source/blender/blenkernel/intern/lib_id_delete.c
+++ b/source/blender/blenkernel/intern/lib_id_delete.c
@@ -21,6 +21,7 @@
#include "BKE_anim_data.h"
#include "BKE_asset.h"
+#include "BKE_asset_library.h"
#include "BKE_idprop.h"
#include "BKE_idtype.h"
#include "BKE_key.h"
@@ -137,16 +138,16 @@ void BKE_id_free_ex(Main *bmain, void *idv, int flag, const bool use_flag_from_i
BKE_main_lock(bmain);
}
+ struct IDRemapper *remapper = BKE_id_remapper_create();
+ BKE_id_remapper_add(remapper, id, NULL);
+
if ((flag & LIB_ID_FREE_NO_UI_USER) == 0) {
if (free_notifier_reference_cb) {
free_notifier_reference_cb(id);
}
if (remap_editor_id_reference_cb) {
- struct IDRemapper *remapper = BKE_id_remapper_create();
- BKE_id_remapper_add(remapper, id, NULL);
remap_editor_id_reference_cb(remapper);
- BKE_id_remapper_free(remapper);
}
}
@@ -158,6 +159,9 @@ void BKE_id_free_ex(Main *bmain, void *idv, int flag, const bool use_flag_from_i
}
}
+ BKE_asset_library_remap_ids(remapper);
+ BKE_id_remapper_free(remapper);
+
BKE_libblock_free_data(id, (flag & LIB_ID_FREE_NO_USER_REFCOUNT) == 0);
if ((flag & LIB_ID_FREE_NO_MAIN) == 0) {
diff --git a/source/blender/blenkernel/intern/material.c b/source/blender/blenkernel/intern/material.c
index 59530a6d6a6..796ed4f8316 100644
--- a/source/blender/blenkernel/intern/material.c
+++ b/source/blender/blenkernel/intern/material.c
@@ -653,38 +653,29 @@ Material **BKE_object_material_get_p(Object *ob, short act)
/* if object cannot have material, (totcolp == NULL) */
totcolp = BKE_object_material_len_p(ob);
- if (totcolp == NULL || ob->totcol == 0) {
+ if (totcolp == NULL || *totcolp == 0) {
return NULL;
}
- /* return NULL for invalid 'act', can happen for mesh face indices */
- if (act > ob->totcol) {
- return NULL;
- }
- if (act <= 0) {
- if (act < 0) {
- CLOG_ERROR(&LOG, "Negative material index!");
- }
- return NULL;
- }
+ /* Clamp to number of slots if index is out of range, same convention as used for rendering. */
+ const int slot_index = clamp_i(act - 1, 0, *totcolp - 1);
- if (ob->matbits && ob->matbits[act - 1]) { /* in object */
- ma_p = &ob->mat[act - 1];
+ /* Fix inconsistency which may happen when library linked data reduces the number of
+ * slots but object was not updated. Ideally should be fixed elsewhere. */
+ if (*totcolp < ob->totcol) {
+ ob->totcol = *totcolp;
}
- else { /* in data */
-
- /* check for inconsistency */
- if (*totcolp < ob->totcol) {
- ob->totcol = *totcolp;
- }
- if (act > ob->totcol) {
- act = ob->totcol;
- }
+ if (slot_index < ob->totcol && ob->matbits && ob->matbits[slot_index]) {
+ /* Use object material slot. */
+ ma_p = &ob->mat[slot_index];
+ }
+ else {
+ /* Use data material slot. */
matarar = BKE_object_material_array_p(ob);
if (matarar && *matarar) {
- ma_p = &(*matarar)[act - 1];
+ ma_p = &(*matarar)[slot_index];
}
else {
ma_p = NULL;
@@ -717,17 +708,17 @@ static ID *get_evaluated_object_data_with_materials(Object *ob)
Material *BKE_object_material_get_eval(Object *ob, short act)
{
BLI_assert(DEG_is_evaluated_object(ob));
- const int slot_index = act - 1;
- if (slot_index < 0) {
- return NULL;
- }
ID *data = get_evaluated_object_data_with_materials(ob);
const short *tot_slots_data_ptr = BKE_id_material_len_p(data);
const int tot_slots_data = tot_slots_data_ptr ? *tot_slots_data_ptr : 0;
- if (slot_index >= tot_slots_data) {
+
+ if (tot_slots_data == 0) {
return NULL;
}
+
+ /* Clamp to number of slots if index is out of range, same convention as used for rendering. */
+ const int slot_index = clamp_i(act - 1, 0, tot_slots_data - 1);
const int tot_slots_object = ob->totcol;
Material ***materials_data_ptr = BKE_id_material_array_p(data);
diff --git a/source/blender/blenkernel/intern/node.cc b/source/blender/blenkernel/intern/node.cc
index 31fc8afea84..5400fd78ddb 100644
--- a/source/blender/blenkernel/intern/node.cc
+++ b/source/blender/blenkernel/intern/node.cc
@@ -2019,7 +2019,7 @@ bNode *nodeFindNodebyName(bNodeTree *ntree, const char *name)
return (bNode *)BLI_findstring(&ntree->nodes, name, offsetof(bNode, name));
}
-bool nodeFindNode(bNodeTree *ntree, bNodeSocket *sock, bNode **r_node, int *r_sockindex)
+void nodeFindNode(bNodeTree *ntree, bNodeSocket *sock, bNode **r_node, int *r_sockindex)
{
*r_node = nullptr;
if (!ntree->runtime->topology_cache_is_dirty) {
@@ -2029,9 +2029,15 @@ bool nodeFindNode(bNodeTree *ntree, bNodeSocket *sock, bNode **r_node, int *r_so
ListBase *sockets = (sock->in_out == SOCK_IN) ? &node->inputs : &node->outputs;
*r_sockindex = BLI_findindex(sockets, sock);
}
- return true;
+ return;
}
+ const bool success = nodeFindNodeTry(ntree, sock, r_node, r_sockindex);
+ BLI_assert(success);
+ UNUSED_VARS_NDEBUG(success);
+}
+bool nodeFindNodeTry(bNodeTree *ntree, bNodeSocket *sock, bNode **r_node, int *r_sockindex)
+{
LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
ListBase *sockets = (sock->in_out == SOCK_IN) ? &node->inputs : &node->outputs;
int i;
diff --git a/source/blender/blenkernel/intern/object_dupli.cc b/source/blender/blenkernel/intern/object_dupli.cc
index cf4f2cd27a4..2979a3cf1ff 100644
--- a/source/blender/blenkernel/intern/object_dupli.cc
+++ b/source/blender/blenkernel/intern/object_dupli.cc
@@ -80,6 +80,8 @@ namespace geo_log = blender::nodes::geo_eval_log;
/** \name Internal Duplicate Context
* \{ */
+static constexpr short GEOMETRY_SET_DUPLI_GENERATOR_TYPE = 1;
+
struct DupliContext {
Depsgraph *depsgraph;
/** XXX child objects are selected from this group if set, could be nicer. */
@@ -88,6 +90,9 @@ struct DupliContext {
Object *obedit;
Scene *scene;
+ /** Root parent object at the scene level. */
+ Object *root_object;
+ /** Immediate parent object in the context. */
Object *object;
float space_mat[4][4];
/**
@@ -107,6 +112,14 @@ struct DupliContext {
*/
Vector<Object *> *instance_stack;
+ /**
+ * Older code relies on the "dupli generator type" for various visibility or processing
+ * decisions. However, new code uses geometry instances in places that weren't using the dupli
+ * system previously. To fix this, keep track of the last dupli generator type that wasn't a
+ * geometry set instance.
+ * */
+ Vector<short> *dupli_gen_type_stack;
+
int persistent_id[MAX_DUPLI_RECUR];
int64_t instance_idx[MAX_DUPLI_RECUR];
const GeometrySet *instance_data[MAX_DUPLI_RECUR];
@@ -133,15 +146,18 @@ static void init_context(DupliContext *r_ctx,
Scene *scene,
Object *ob,
const float space_mat[4][4],
- Vector<Object *> &instance_stack)
+ Vector<Object *> &instance_stack,
+ Vector<short> &dupli_gen_type_stack)
{
r_ctx->depsgraph = depsgraph;
r_ctx->scene = scene;
r_ctx->collection = nullptr;
+ r_ctx->root_object = ob;
r_ctx->object = ob;
r_ctx->obedit = OBEDIT_FROM_OBACT(ob);
r_ctx->instance_stack = &instance_stack;
+ r_ctx->dupli_gen_type_stack = &dupli_gen_type_stack;
if (space_mat) {
copy_m4_m4(r_ctx->space_mat, space_mat);
}
@@ -151,6 +167,9 @@ static void init_context(DupliContext *r_ctx,
r_ctx->level = 0;
r_ctx->gen = get_dupli_generator(r_ctx);
+ if (r_ctx->gen && r_ctx->gen->type != GEOMETRY_SET_DUPLI_GENERATOR_TYPE) {
+ r_ctx->dupli_gen_type_stack->append(r_ctx->gen->type);
+ }
r_ctx->duplilist = nullptr;
r_ctx->preview_instance_index = -1;
@@ -192,6 +211,9 @@ static bool copy_dupli_context(DupliContext *r_ctx,
}
r_ctx->gen = get_dupli_generator(r_ctx);
+ if (r_ctx->gen && r_ctx->gen->type != GEOMETRY_SET_DUPLI_GENERATOR_TYPE) {
+ r_ctx->dupli_gen_type_stack->append(r_ctx->gen->type);
+ }
return true;
}
@@ -224,7 +246,7 @@ static DupliObject *make_dupli(const DupliContext *ctx,
dob->ob = ob;
dob->ob_data = const_cast<ID *>(object_data);
mul_m4_m4m4(dob->mat, (float(*)[4])ctx->space_mat, mat);
- dob->type = ctx->gen == nullptr ? 0 : ctx->gen->type;
+ dob->type = ctx->gen == nullptr ? 0 : ctx->dupli_gen_type_stack->last();
dob->preview_base_geometry = ctx->preview_base_geometry;
dob->preview_instance_index = ctx->preview_instance_index;
@@ -265,8 +287,9 @@ static DupliObject *make_dupli(const DupliContext *ctx,
dob->no_draw = true;
}
- /* Random number.
- * The logic here is designed to match Cycles. */
+ /* Random number per instance.
+ * The root object in the scene, persistent ID up to the instance object, and the instance object
+ * name together result in a unique random number. */
dob->random_id = BLI_hash_string(dob->ob->id.name + 2);
if (dob->persistent_id[0] != INT_MAX) {
@@ -278,8 +301,8 @@ static DupliObject *make_dupli(const DupliContext *ctx,
dob->random_id = BLI_hash_int_2d(dob->random_id, 0);
}
- if (ctx->object != ob) {
- dob->random_id ^= BLI_hash_int(BLI_hash_string(ctx->object->id.name + 2));
+ if (ctx->root_object != ob) {
+ dob->random_id ^= BLI_hash_int(BLI_hash_string(ctx->root_object->id.name + 2));
}
return dob;
@@ -992,7 +1015,7 @@ static void make_duplis_geometry_set(const DupliContext *ctx)
}
static const DupliGenerator gen_dupli_geometry_set = {
- 0,
+ GEOMETRY_SET_DUPLI_GENERATOR_TYPE,
make_duplis_geometry_set,
};
@@ -1391,7 +1414,7 @@ static void make_duplis_particle_system(const DupliContext *ctx, ParticleSystem
RNG *rng = BLI_rng_new_srandom(31415926u + uint(psys->seed));
- psys->lattice_deform_data = psys_create_lattice_deform_data(&sim);
+ psys_sim_data_init(&sim);
/* Gather list of objects or single object. */
int totcollection = 0;
@@ -1613,17 +1636,13 @@ static void make_duplis_particle_system(const DupliContext *ctx, ParticleSystem
}
BLI_rng_free(rng);
+ psys_sim_data_free(&sim);
}
/* Clean up. */
if (oblist) {
MEM_freeN(oblist);
}
-
- if (psys->lattice_deform_data) {
- BKE_lattice_deform_data_destroy(psys->lattice_deform_data);
- psys->lattice_deform_data = nullptr;
- }
}
static void make_duplis_particles(const DupliContext *ctx)
@@ -1717,8 +1736,9 @@ ListBase *object_duplilist(Depsgraph *depsgraph, Scene *sce, Object *ob)
ListBase *duplilist = MEM_cnew<ListBase>("duplilist");
DupliContext ctx;
Vector<Object *> instance_stack;
+ Vector<short> dupli_gen_type_stack({0});
instance_stack.append(ob);
- init_context(&ctx, depsgraph, sce, ob, nullptr, instance_stack);
+ init_context(&ctx, depsgraph, sce, ob, nullptr, instance_stack, dupli_gen_type_stack);
if (ctx.gen) {
ctx.duplilist = duplilist;
ctx.gen->make_duplis(&ctx);
@@ -1735,8 +1755,9 @@ ListBase *object_duplilist_preview(Depsgraph *depsgraph,
ListBase *duplilist = MEM_cnew<ListBase>("duplilist");
DupliContext ctx;
Vector<Object *> instance_stack;
+ Vector<short> dupli_gen_type_stack({0});
instance_stack.append(ob_eval);
- init_context(&ctx, depsgraph, sce, ob_eval, nullptr, instance_stack);
+ init_context(&ctx, depsgraph, sce, ob_eval, nullptr, instance_stack, dupli_gen_type_stack);
ctx.duplilist = duplilist;
Object *ob_orig = DEG_get_original_object(ob_eval);
diff --git a/source/blender/blenkernel/intern/particle.c b/source/blender/blenkernel/intern/particle.c
index 4a0a09bcf56..6a277295efd 100644
--- a/source/blender/blenkernel/intern/particle.c
+++ b/source/blender/blenkernel/intern/particle.c
@@ -684,10 +684,13 @@ void psys_set_current_num(Object *ob, int index)
}
}
-struct LatticeDeformData *psys_create_lattice_deform_data(ParticleSimulationData *sim)
+void psys_sim_data_init(ParticleSimulationData *sim)
{
- struct LatticeDeformData *lattice_deform_data = NULL;
+ ParticleSystem *psys = sim->psys;
+ ParticleSettings *part = psys->part;
+ /* Prepare lattice deform. */
+ psys->lattice_deform_data = NULL;
if (psys_in_edit_mode(sim->depsgraph, sim->psys) == 0) {
Object *lattice = NULL;
ModifierData *md = (ModifierData *)psys_get_modifier(sim->ob, sim->psys);
@@ -699,19 +702,39 @@ struct LatticeDeformData *psys_create_lattice_deform_data(ParticleSimulationData
if (md->mode & mode) {
LatticeModifierData *lmd = (LatticeModifierData *)md;
lattice = lmd->object;
- sim->psys->lattice_strength = lmd->strength;
+ psys->lattice_strength = lmd->strength;
}
break;
}
}
if (lattice) {
- lattice_deform_data = BKE_lattice_deform_data_create(lattice, NULL);
+ psys->lattice_deform_data = BKE_lattice_deform_data_create(lattice, NULL);
}
}
- return lattice_deform_data;
+ /* Prepare curvemapping tables. */
+ if ((part->child_flag & PART_CHILD_USE_CLUMP_CURVE) && part->clumpcurve) {
+ BKE_curvemapping_init(part->clumpcurve);
+ }
+ if ((part->child_flag & PART_CHILD_USE_ROUGH_CURVE) && part->roughcurve) {
+ BKE_curvemapping_init(part->roughcurve);
+ }
+ if ((part->child_flag & PART_CHILD_USE_TWIST_CURVE) && part->twistcurve) {
+ BKE_curvemapping_init(part->twistcurve);
+ }
}
+
+void psys_sim_data_free(ParticleSimulationData *sim)
+{
+ ParticleSystem *psys = sim->psys;
+
+ if (psys->lattice_deform_data) {
+ BKE_lattice_deform_data_destroy(psys->lattice_deform_data);
+ psys->lattice_deform_data = NULL;
+ }
+}
+
void psys_disable_all(Object *ob)
{
ParticleSystem *psys = ob->particlesystem.first;
@@ -2784,7 +2807,7 @@ static bool psys_thread_context_init_path(ParticleThreadContext *ctx,
ctx->cfra = cfra;
ctx->editupdate = editupdate;
- psys->lattice_deform_data = psys_create_lattice_deform_data(&ctx->sim);
+ psys_sim_data_init(&ctx->sim);
/* cache all relevant vertex groups if they exist */
ctx->vg_length = psys_cache_vgroup(ctx->mesh, psys, PSYS_VG_LENGTH);
@@ -3340,7 +3363,7 @@ void psys_cache_paths(ParticleSimulationData *sim, float cfra, const bool use_re
cache = psys->pathcache = psys_alloc_path_cache_buffers(
&psys->pathcachebufs, totpart, segments + 1);
- psys->lattice_deform_data = psys_create_lattice_deform_data(sim);
+ psys_sim_data_init(sim);
ma = BKE_object_material_get(sim->ob, psys->part->omat);
if (ma && (psys->part->draw_col == PART_DRAW_COL_MAT)) {
copy_v3_v3(col, &ma->r);
@@ -3507,10 +3530,7 @@ void psys_cache_paths(ParticleSimulationData *sim, float cfra, const bool use_re
psys->totcached = totpart;
- if (psys->lattice_deform_data) {
- BKE_lattice_deform_data_destroy(psys->lattice_deform_data);
- psys->lattice_deform_data = NULL;
- }
+ psys_sim_data_free(sim);
if (vg_effector) {
MEM_freeN(vg_effector);
@@ -4867,6 +4887,7 @@ void psys_get_particle_on_path(ParticleSimulationData *sim,
}
}
}
+
bool psys_get_particle_state(ParticleSimulationData *sim,
int p,
ParticleKey *state,
@@ -5225,7 +5246,7 @@ void psys_apply_hair_lattice(Depsgraph *depsgraph, Scene *scene, Object *ob, Par
sim.psys = psys;
sim.psmd = psys_get_modifier(ob, psys);
- psys->lattice_deform_data = psys_create_lattice_deform_data(&sim);
+ psys_sim_data_init(&sim);
if (psys->lattice_deform_data) {
ParticleData *pa = psys->particles;
@@ -5246,12 +5267,11 @@ void psys_apply_hair_lattice(Depsgraph *depsgraph, Scene *scene, Object *ob, Par
}
}
- BKE_lattice_deform_data_destroy(psys->lattice_deform_data);
- psys->lattice_deform_data = NULL;
-
/* protect the applied shape */
psys->flag |= PSYS_EDITED;
}
+
+ psys_sim_data_free(&sim);
}
/* Draw Engine */
diff --git a/source/blender/blenkernel/intern/particle_system.c b/source/blender/blenkernel/intern/particle_system.c
index 72094f8cf04..d97a217a734 100644
--- a/source/blender/blenkernel/intern/particle_system.c
+++ b/source/blender/blenkernel/intern/particle_system.c
@@ -516,10 +516,7 @@ void psys_thread_context_free(ParticleThreadContext *ctx)
MEM_freeN(ctx->vg_twist);
}
- if (ctx->sim.psys->lattice_deform_data) {
- BKE_lattice_deform_data_destroy(ctx->sim.psys->lattice_deform_data);
- ctx->sim.psys->lattice_deform_data = NULL;
- }
+ psys_sim_data_free(&ctx->sim);
/* distribution */
if (ctx->jit) {
@@ -3557,12 +3554,12 @@ static void save_hair(ParticleSimulationData *sim, float UNUSED(cfra))
invert_m4_m4(ob->world_to_object, ob->object_to_world);
- psys->lattice_deform_data = psys_create_lattice_deform_data(sim);
-
if (psys->totpart == 0) {
return;
}
+ psys_sim_data_init(sim);
+
/* save new keys for elements if needed */
LOOP_PARTICLES
{
@@ -3596,6 +3593,8 @@ static void save_hair(ParticleSimulationData *sim, float UNUSED(cfra))
zero_v3(root->co);
}
}
+
+ psys_sim_data_free(sim);
}
/* Code for an adaptive time step based on the Courant-Friedrichs-Lewy
@@ -4099,6 +4098,8 @@ static void cached_step(ParticleSimulationData *sim, float cfra, const bool use_
disp = psys_get_current_display_percentage(psys, use_render_params);
+ psys_sim_data_init(sim);
+
LOOP_PARTICLES
{
psys_get_texture(sim, pa, &ptex, PAMAP_SIZE, cfra);
@@ -4107,8 +4108,6 @@ static void cached_step(ParticleSimulationData *sim, float cfra, const bool use_
pa->size *= 1.0f - part->randsize * psys_frand(psys, p + 1);
}
- psys->lattice_deform_data = psys_create_lattice_deform_data(sim);
-
dietime = pa->dietime;
/* update alive status and push events */
@@ -4125,11 +4124,6 @@ static void cached_step(ParticleSimulationData *sim, float cfra, const bool use_
pa->alive = PARS_ALIVE;
}
- if (psys->lattice_deform_data) {
- BKE_lattice_deform_data_destroy(psys->lattice_deform_data);
- psys->lattice_deform_data = NULL;
- }
-
if (psys_frand(psys, p) > disp) {
pa->flag |= PARS_NO_DISP;
}
@@ -4137,6 +4131,8 @@ static void cached_step(ParticleSimulationData *sim, float cfra, const bool use_
pa->flag &= ~PARS_NO_DISP;
}
}
+
+ psys_sim_data_free(sim);
}
static bool particles_has_flip(short parttype)
@@ -4609,10 +4605,7 @@ static void system_step(ParticleSimulationData *sim, float cfra, const bool use_
update_children(sim, use_render_params);
/* cleanup */
- if (psys->lattice_deform_data) {
- BKE_lattice_deform_data_destroy(psys->lattice_deform_data);
- psys->lattice_deform_data = NULL;
- }
+ psys_sim_data_free(sim);
}
void psys_changed_type(Object *ob, ParticleSystem *psys)
diff --git a/source/blender/blenkernel/intern/pbvh.c b/source/blender/blenkernel/intern/pbvh.c
index 98e89b09060..24ea2de98f6 100644
--- a/source/blender/blenkernel/intern/pbvh.c
+++ b/source/blender/blenkernel/intern/pbvh.c
@@ -833,7 +833,12 @@ void BKE_pbvh_build_grids(PBVH *pbvh,
pbvh->gridkey = *key;
pbvh->grid_hidden = grid_hidden;
pbvh->subdiv_ccg = subdiv_ccg;
- pbvh->leaf_limit = max_ii(LEAF_LIMIT / (gridsize * gridsize), 1);
+
+ /* Ensure leaf limit is at least 4 so there's room
+ * to split at original face boundaries.
+ * Fixes T102209.
+ */
+ pbvh->leaf_limit = max_ii(LEAF_LIMIT / (gridsize * gridsize), 4);
/* We need the base mesh attribute layout for PBVH draw. */
pbvh->vdata = &me->vdata;
diff --git a/source/blender/blenkernel/intern/pbvh_bmesh.c b/source/blender/blenkernel/intern/pbvh_bmesh.c
index 3b0f35263d3..d03f12b98bd 100644
--- a/source/blender/blenkernel/intern/pbvh_bmesh.c
+++ b/source/blender/blenkernel/intern/pbvh_bmesh.c
@@ -1527,8 +1527,8 @@ bool pbvh_bmesh_node_raycast(PBVHNode *node,
float location[3] = {0.0f};
madd_v3_v3v3fl(location, ray_start, ray_normal, *depth);
for (int j = 0; j < 3; j++) {
- if (len_squared_v3v3(location, cos[j]) <
- len_squared_v3v3(location, nearest_vertex_co)) {
+ if (j == 0 || len_squared_v3v3(location, cos[j]) <
+ len_squared_v3v3(location, nearest_vertex_co)) {
copy_v3_v3(nearest_vertex_co, cos[j]);
r_active_vertex->i = (intptr_t)node->bm_orvert[node->bm_ortri[i][j]];
}
@@ -1559,8 +1559,8 @@ bool pbvh_bmesh_node_raycast(PBVHNode *node,
float location[3] = {0.0f};
madd_v3_v3v3fl(location, ray_start, ray_normal, *depth);
for (int j = 0; j < 3; j++) {
- if (len_squared_v3v3(location, v_tri[j]->co) <
- len_squared_v3v3(location, nearest_vertex_co)) {
+ if (j == 0 || len_squared_v3v3(location, v_tri[j]->co) <
+ len_squared_v3v3(location, nearest_vertex_co)) {
copy_v3_v3(nearest_vertex_co, v_tri[j]->co);
r_active_vertex->i = (intptr_t)v_tri[j];
}
diff --git a/source/blender/blenlib/BLI_string.h b/source/blender/blenlib/BLI_string.h
index fb02ea5fb17..ed15e0871b9 100644
--- a/source/blender/blenlib/BLI_string.h
+++ b/source/blender/blenlib/BLI_string.h
@@ -206,11 +206,12 @@ char *BLI_sprintfN(const char *__restrict format, ...) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL(1) ATTR_MALLOC ATTR_PRINTF_FORMAT(1, 2);
/**
- * A wrapper around ::sprintf() which does not generate security warnings.
+ * A wrapper around `::sprintf()` which does not generate security warnings.
*
- * \note Use BLI_snprintf for cases when the string size is known.
+ * \note Use #BLI_snprintf for cases when the string size is known.
*/
-int BLI_sprintf(char *__restrict str, const char *__restrict format, ...);
+int BLI_sprintf(char *__restrict str, const char *__restrict format, ...) ATTR_NONNULL(1, 2)
+ ATTR_PRINTF_FORMAT(2, 3);
/**
* This roughly matches C and Python's string escaping with double quotes - `"`.
diff --git a/source/blender/blenlib/intern/math_rotation.c b/source/blender/blenlib/intern/math_rotation.c
index ff45bbee5c9..180412c4a14 100644
--- a/source/blender/blenlib/intern/math_rotation.c
+++ b/source/blender/blenlib/intern/math_rotation.c
@@ -275,64 +275,83 @@ void mat3_normalized_to_quat_fast(float q[4], const float mat[3][3])
/* Caller must ensure matrices aren't negative for valid results, see: T24291, T94231. */
BLI_assert(!is_negative_m3(mat));
- /* Check the trace of the matrix - bad precision if close to -1. */
- const float trace = mat[0][0] + mat[1][1] + mat[2][2];
-
- if (trace > 0) {
- float s = 2.0f * sqrtf(1.0f + trace);
-
- q[0] = 0.25f * s;
-
- s = 1.0f / s;
-
- q[1] = (mat[1][2] - mat[2][1]) * s;
- q[2] = (mat[2][0] - mat[0][2]) * s;
- q[3] = (mat[0][1] - mat[1][0]) * s;
- }
- else {
- /* Find the biggest diagonal element to choose the best formula.
- * Here trace should also be always >= 0, avoiding bad precision. */
- if (mat[0][0] > mat[1][1] && mat[0][0] > mat[2][2]) {
- float s = 2.0f * sqrtf(1.0f + mat[0][0] - mat[1][1] - mat[2][2]);
-
+ /* Method outlined by Mike Day, ref: https://math.stackexchange.com/a/3183435/220949
+ * with an additional `sqrtf(..)` for higher precision result.
+ * Removing the `sqrt` causes tests to fail unless the precision is set to 1e-6 or larger. */
+
+ if (mat[2][2] < 0.0f) {
+ if (mat[0][0] > mat[1][1]) {
+ const float trace = 1.0f + mat[0][0] - mat[1][1] - mat[2][2];
+ float s = 2.0f * sqrtf(trace);
+ if (mat[1][2] < mat[2][1]) {
+ /* Ensure W is non-negative for a canonical result. */
+ s = -s;
+ }
q[1] = 0.25f * s;
-
s = 1.0f / s;
-
q[0] = (mat[1][2] - mat[2][1]) * s;
- q[2] = (mat[1][0] + mat[0][1]) * s;
+ q[2] = (mat[0][1] + mat[1][0]) * s;
q[3] = (mat[2][0] + mat[0][2]) * s;
+ if (UNLIKELY((trace == 1.0f) && (q[0] == 0.0f && q[2] == 0.0f && q[3] == 0.0f))) {
+ /* Avoids the need to normalize the degenerate case. */
+ q[1] = 1.0f;
+ }
}
- else if (mat[1][1] > mat[2][2]) {
- float s = 2.0f * sqrtf(1.0f + mat[1][1] - mat[0][0] - mat[2][2]);
-
+ else {
+ const float trace = 1.0f - mat[0][0] + mat[1][1] - mat[2][2];
+ float s = 2.0f * sqrtf(trace);
+ if (mat[2][0] < mat[0][2]) {
+ /* Ensure W is non-negative for a canonical result. */
+ s = -s;
+ }
q[2] = 0.25f * s;
-
s = 1.0f / s;
-
q[0] = (mat[2][0] - mat[0][2]) * s;
- q[1] = (mat[1][0] + mat[0][1]) * s;
- q[3] = (mat[2][1] + mat[1][2]) * s;
+ q[1] = (mat[0][1] + mat[1][0]) * s;
+ q[3] = (mat[1][2] + mat[2][1]) * s;
+ if (UNLIKELY((trace == 1.0f) && (q[0] == 0.0f && q[1] == 0.0f && q[3] == 0.0f))) {
+ /* Avoids the need to normalize the degenerate case. */
+ q[2] = 1.0f;
+ }
}
- else {
- float s = 2.0f * sqrtf(1.0f + mat[2][2] - mat[0][0] - mat[1][1]);
-
+ }
+ else {
+ if (mat[0][0] < -mat[1][1]) {
+ const float trace = 1.0f - mat[0][0] - mat[1][1] + mat[2][2];
+ float s = 2.0f * sqrtf(trace);
+ if (mat[0][1] < mat[1][0]) {
+ /* Ensure W is non-negative for a canonical result. */
+ s = -s;
+ }
q[3] = 0.25f * s;
-
s = 1.0f / s;
-
q[0] = (mat[0][1] - mat[1][0]) * s;
q[1] = (mat[2][0] + mat[0][2]) * s;
- q[2] = (mat[2][1] + mat[1][2]) * s;
+ q[2] = (mat[1][2] + mat[2][1]) * s;
+ if (UNLIKELY((trace == 1.0f) && (q[0] == 0.0f && q[1] == 0.0f && q[2] == 0.0f))) {
+ /* Avoids the need to normalize the degenerate case. */
+ q[3] = 1.0f;
+ }
}
-
- /* Make sure W is non-negative for a canonical result. */
- if (q[0] < 0) {
- negate_v4(q);
+ else {
+ /* NOTE(@campbellbarton): A zero matrix will fall through to this block,
+ * needed so a zero scaled matrices to return a quaternion without rotation, see: T101848. */
+ const float trace = 1.0f + mat[0][0] + mat[1][1] + mat[2][2];
+ float s = 2.0f * sqrtf(trace);
+ q[0] = 0.25f * s;
+ s = 1.0f / s;
+ q[1] = (mat[1][2] - mat[2][1]) * s;
+ q[2] = (mat[2][0] - mat[0][2]) * s;
+ q[3] = (mat[0][1] - mat[1][0]) * s;
+ if (UNLIKELY((trace == 1.0f) && (q[1] == 0.0f && q[2] == 0.0f && q[3] == 0.0f))) {
+ /* Avoids the need to normalize the degenerate case. */
+ q[0] = 1.0f;
+ }
}
}
- normalize_qt(q);
+ BLI_assert(!(q[0] < 0.0f));
+ BLI_ASSERT_UNIT_QUAT(q);
}
static void mat3_normalized_to_quat_with_checks(float q[4], float mat[3][3])
diff --git a/source/blender/blenlib/tests/BLI_math_rotation_test.cc b/source/blender/blenlib/tests/BLI_math_rotation_test.cc
index e37b212e1df..0c8ae38c386 100644
--- a/source/blender/blenlib/tests/BLI_math_rotation_test.cc
+++ b/source/blender/blenlib/tests/BLI_math_rotation_test.cc
@@ -3,6 +3,7 @@
#include "testing/testing.h"
#include "BLI_math_base.h"
+#include "BLI_math_matrix.h"
#include "BLI_math_rotation.h"
#include "BLI_math_rotation.hh"
#include "BLI_math_vector.hh"
@@ -138,6 +139,21 @@ TEST(math_rotation, quat_to_mat_to_quat_near_0001)
test_quat_to_mat_to_quat(0.30f, -0.030f, -0.30f, 0.95f);
}
+/* A zeroed matrix converted to a quaternion and back should not add rotation, see: T101848 */
+TEST(math_rotation, quat_to_mat_to_quat_zeroed_matrix)
+{
+ float matrix_zeroed[3][3] = {{0.0f}};
+ float matrix_result[3][3];
+ float matrix_unit[3][3];
+ float out_quat[4];
+
+ unit_m3(matrix_unit);
+ mat3_normalized_to_quat(out_quat, matrix_zeroed);
+ quat_to_mat3(matrix_result, out_quat);
+
+ EXPECT_M3_NEAR(matrix_unit, matrix_result, FLT_EPSILON);
+}
+
TEST(math_rotation, quat_split_swing_and_twist_negative)
{
const float input[4] = {-0.5f, 0, sqrtf(3) / 2, 0};
diff --git a/source/blender/blenloader/intern/versioning_260.c b/source/blender/blenloader/intern/versioning_260.c
index cdb63bd8075..47a1f7f7241 100644
--- a/source/blender/blenloader/intern/versioning_260.c
+++ b/source/blender/blenloader/intern/versioning_260.c
@@ -280,10 +280,9 @@ static void do_versions_nodetree_multi_file_output_format_2_62_1(Scene *sce, bNo
BLI_strncpy(filename, old_image->name, sizeof(filename));
}
- /* if z buffer is saved, change the image type to multilayer exr.
- * XXX this is slightly messy, Z buffer was ignored before for anything but EXR and IRIS ...
- * I'm just assuming here that IRIZ means IRIS with z buffer ...
- */
+ /* If Z buffer is saved, change the image type to multi-layer EXR.
+ * XXX: this is slightly messy, Z buffer was ignored before for anything but EXR and IRIS ...
+ * I'm just assuming here that IRIZ means IRIS with z buffer. */
if (old_data && ELEM(old_data->im_format.imtype, R_IMF_IMTYPE_IRIZ, R_IMF_IMTYPE_OPENEXR)) {
char sockpath[FILE_MAX];
@@ -393,9 +392,8 @@ static void do_versions_nodetree_file_output_layers_2_64_5(bNodeTree *ntree)
for (sock = node->inputs.first; sock; sock = sock->next) {
NodeImageMultiFileSocket *input = sock->storage;
- /* multilayer names are stored as separate strings now,
- * used the path string before, so copy it over.
- */
+ /* Multi-layer names are stored as separate strings now,
+ * used the path string before, so copy it over. */
BLI_strncpy(input->layer, input->path, sizeof(input->layer));
/* paths/layer names also have to be unique now, initial check */
diff --git a/source/blender/compositor/nodes/COM_OutputFileNode.cc b/source/blender/compositor/nodes/COM_OutputFileNode.cc
index fc4270cc222..50989f73986 100644
--- a/source/blender/compositor/nodes/COM_OutputFileNode.cc
+++ b/source/blender/compositor/nodes/COM_OutputFileNode.cc
@@ -65,7 +65,7 @@ void OutputFileNode::convert_to_operations(NodeConverter &converter,
if (storage->format.imtype == R_IMF_IMTYPE_MULTILAYER) {
const bool use_half_float = (storage->format.depth == R_IMF_CHAN_DEPTH_16);
- /* single output operation for the multilayer file */
+ /* Single output operation for the multi-layer file. */
OutputOpenExrMultiLayerOperation *output_operation;
if (is_multiview && storage->format.views_format == R_IMF_VIEWS_MULTIVIEW) {
diff --git a/source/blender/compositor/operations/COM_MovieDistortionOperation.cc b/source/blender/compositor/operations/COM_MovieDistortionOperation.cc
index b89a48f2a39..353f3da14d7 100644
--- a/source/blender/compositor/operations/COM_MovieDistortionOperation.cc
+++ b/source/blender/compositor/operations/COM_MovieDistortionOperation.cc
@@ -78,34 +78,41 @@ void MovieDistortionOperation::execute_pixel_sampled(float output[4],
float y,
PixelSampler /*sampler*/)
{
- if (distortion_ != nullptr) {
- /* float overscan = 0.0f; */
- const float pixel_aspect = pixel_aspect_;
- const float w = float(this->get_width()) /* / (1 + overscan) */;
- const float h = float(this->get_height()) /* / (1 + overscan) */;
- const float aspx = w / float(calibration_width_);
- const float aspy = h / float(calibration_height_);
- float in[2];
- float out[2];
-
- in[0] = (x /* - 0.5 * overscan * w */) / aspx;
- in[1] = (y /* - 0.5 * overscan * h */) / aspy / pixel_aspect;
+ const int width = this->get_width();
+ const int height = this->get_height();
+ if (distortion_ == nullptr || width == 0 || height == 0) {
+ /* When there is no precomputed distortion pass-through the coordinate as-is to the input
+ * samples.
+ * If the frame size is zero do the same and bypass any math. In theory it is probably more
+ * correct to zero the output but it is easier and safe to let the input to do so than to deal
+ * with possible different number of channels here. */
+ input_operation_->read_sampled(output, x, y, PixelSampler::Bilinear);
+ return;
+ }
- if (apply_) {
- BKE_tracking_distortion_undistort_v2(distortion_, in, out);
- }
- else {
- BKE_tracking_distortion_distort_v2(distortion_, in, out);
- }
+ /* float overscan = 0.0f; */
+ const float w = float(width) /* / (1 + overscan) */;
+ const float h = float(height) /* / (1 + overscan) */;
+ const float pixel_aspect = pixel_aspect_;
+ const float aspx = w / float(calibration_width_);
+ const float aspy = h / float(calibration_height_);
+ float in[2];
+ float out[2];
- float u = out[0] * aspx /* + 0.5 * overscan * w */,
- v = (out[1] * aspy /* + 0.5 * overscan * h */) * pixel_aspect;
+ in[0] = (x /* - 0.5 * overscan * w */) / aspx;
+ in[1] = (y /* - 0.5 * overscan * h */) / aspy / pixel_aspect;
- input_operation_->read_sampled(output, u, v, PixelSampler::Bilinear);
+ if (apply_) {
+ BKE_tracking_distortion_undistort_v2(distortion_, in, out);
}
else {
- input_operation_->read_sampled(output, x, y, PixelSampler::Bilinear);
+ BKE_tracking_distortion_distort_v2(distortion_, in, out);
}
+
+ float u = out[0] * aspx /* + 0.5 * overscan * w */,
+ v = (out[1] * aspy /* + 0.5 * overscan * h */) * pixel_aspect;
+
+ input_operation_->read_sampled(output, u, v, PixelSampler::Bilinear);
}
bool MovieDistortionOperation::determine_depending_area_of_interest(
diff --git a/source/blender/compositor/operations/COM_OutputFileMultiViewOperation.h b/source/blender/compositor/operations/COM_OutputFileMultiViewOperation.h
index e36999e5cf1..70773c1a559 100644
--- a/source/blender/compositor/operations/COM_OutputFileMultiViewOperation.h
+++ b/source/blender/compositor/operations/COM_OutputFileMultiViewOperation.h
@@ -31,7 +31,7 @@ class OutputOpenExrSingleLayerMultiViewOperation : public OutputSingleLayerOpera
void deinit_execution() override;
};
-/* Writes inputs into OpenEXR multilayer channels. */
+/** Writes inputs into OpenEXR multi-layer channels. */
class OutputOpenExrMultiLayerMultiViewOperation : public OutputOpenExrMultiLayerOperation {
private:
public:
diff --git a/source/blender/compositor/operations/COM_OutputFileOperation.h b/source/blender/compositor/operations/COM_OutputFileOperation.h
index df1d68838d9..716bede8035 100644
--- a/source/blender/compositor/operations/COM_OutputFileOperation.h
+++ b/source/blender/compositor/operations/COM_OutputFileOperation.h
@@ -71,7 +71,7 @@ struct OutputOpenExrLayer {
SocketReader *image_input;
};
-/* Writes inputs into OpenEXR multilayer channels. */
+/* Writes inputs into OpenEXR multi-layer channels. */
class OutputOpenExrMultiLayerOperation : public MultiThreadedOperation {
protected:
const Scene *scene_;
diff --git a/source/blender/compositor/realtime_compositor/COM_scheduler.hh b/source/blender/compositor/realtime_compositor/COM_scheduler.hh
index 4f778b32145..9f3bc14ae17 100644
--- a/source/blender/compositor/realtime_compositor/COM_scheduler.hh
+++ b/source/blender/compositor/realtime_compositor/COM_scheduler.hh
@@ -16,6 +16,6 @@ using Schedule = VectorSet<DNode>;
/* Computes the execution schedule of the node tree. This is essentially a post-order depth first
* traversal of the node tree from the output node to the leaf input nodes, with informed order of
* traversal of dependencies based on a heuristic estimation of the number of needed buffers. */
-Schedule compute_schedule(DerivedNodeTree &tree);
+Schedule compute_schedule(const DerivedNodeTree &tree);
} // namespace blender::realtime_compositor
diff --git a/source/blender/compositor/realtime_compositor/intern/realize_on_domain_operation.cc b/source/blender/compositor/realtime_compositor/intern/realize_on_domain_operation.cc
index 817293c0fa6..e5c448d0e33 100644
--- a/source/blender/compositor/realtime_compositor/intern/realize_on_domain_operation.cc
+++ b/source/blender/compositor/realtime_compositor/intern/realize_on_domain_operation.cc
@@ -38,8 +38,8 @@ void RealizeOnDomainOperation::execute()
GPU_shader_bind(shader);
/* Transform the input space into the domain space. */
- const float3x3 local_transformation = input.domain().transformation *
- domain_.transformation.inverted();
+ const float3x3 local_transformation = domain_.transformation.inverted() *
+ input.domain().transformation;
/* Set the origin of the transformation to be the center of the domain. */
const float3x3 transformation = float3x3::from_origin_transformation(
diff --git a/source/blender/compositor/realtime_compositor/intern/scheduler.cc b/source/blender/compositor/realtime_compositor/intern/scheduler.cc
index ac5cc55a73f..0d3cce7af39 100644
--- a/source/blender/compositor/realtime_compositor/intern/scheduler.cc
+++ b/source/blender/compositor/realtime_compositor/intern/scheduler.cc
@@ -8,6 +8,7 @@
#include "NOD_derived_node_tree.hh"
+#include "BKE_node.h"
#include "BKE_node_runtime.hh"
#include "COM_scheduler.hh"
@@ -17,36 +18,103 @@ namespace blender::realtime_compositor {
using namespace nodes::derived_node_tree_types;
-/* Compute the output node whose result should be computed. The output node is the node marked as
- * NODE_DO_OUTPUT. If multiple types of output nodes are marked, then the preference will be
- * CMP_NODE_COMPOSITE > CMP_NODE_VIEWER > CMP_NODE_SPLITVIEWER. If no output node exists, a null
- * node will be returned. */
-static DNode compute_output_node(DerivedNodeTree &tree)
+/* Find the active context from the given context and its descendants contexts. The active context
+ * is the one whose node instance key matches the active_viewer_key stored in the root node tree.
+ * The instance key of each context is computed by calling BKE_node_instance_key given the key of
+ * the parent as well as the group node making the context. */
+static const DTreeContext *find_active_context_recursive(const DTreeContext *context,
+ bNodeInstanceKey key)
{
- const bNodeTree &root_tree = tree.root_context().btree();
+ /* The instance key of the given context matches the active viewer instance key, so this is the
+ * active context, return it. */
+ if (key.value == context->derived_tree().root_context().btree().active_viewer_key.value) {
+ return context;
+ }
+
+ /* For each of the group nodes, compute their instance key and contexts and call this function
+ * recursively. */
+ for (const bNode *group_node : context->btree().group_nodes()) {
+ const bNodeInstanceKey child_key = BKE_node_instance_key(key, &context->btree(), group_node);
+ const DTreeContext *child_context = context->child_context(*group_node);
+ const DTreeContext *found_context = find_active_context_recursive(child_context, child_key);
+
+ /* If the found context is null, that means neither the child context nor one of its descendant
+ * contexts is active. */
+ if (!found_context) {
+ continue;
+ }
+
+ /* Otherwise, we have found our active context, return it. */
+ return found_context;
+ }
+
+ /* Neither the given context nor one of its descendant contexts is active, so return null. */
+ return nullptr;
+}
+
+/* Find the active context for the given node tree. The active context represents the node tree
+ * currently being edited. In most cases, that would be the top level node tree itself, but in the
+ * case where the user is editing the node tree of a node group, the active context would be a
+ * representation of the node tree of that node group. Note that the context also stores the group
+ * node that the user selected to edit the node tree, so the context fully represents a particular
+ * instance of the node group. */
+static const DTreeContext *find_active_context(const DerivedNodeTree &tree)
+{
+ /* The root context has an instance key of NODE_INSTANCE_KEY_BASE by definition. */
+ return find_active_context_recursive(&tree.root_context(), NODE_INSTANCE_KEY_BASE);
+}
+
+/* Return the output node which is marked as NODE_DO_OUTPUT. If multiple types of output nodes are
+ * marked, then the preference will be CMP_NODE_COMPOSITE > CMP_NODE_VIEWER > CMP_NODE_SPLITVIEWER.
+ * If no output node exists, a null node will be returned. */
+static DNode find_output_in_context(const DTreeContext *context)
+{
+ const bNodeTree &tree = context->btree();
- for (const bNode *node : root_tree.nodes_by_type("CompositorNodeComposite")) {
+ for (const bNode *node : tree.nodes_by_type("CompositorNodeComposite")) {
if (node->flag & NODE_DO_OUTPUT) {
- return DNode(&tree.root_context(), node);
+ return DNode(context, node);
}
}
- for (const bNode *node : root_tree.nodes_by_type("CompositorNodeViewer")) {
+ for (const bNode *node : tree.nodes_by_type("CompositorNodeViewer")) {
if (node->flag & NODE_DO_OUTPUT) {
- return DNode(&tree.root_context(), node);
+ return DNode(context, node);
}
}
- for (const bNode *node : root_tree.nodes_by_type("CompositorNodeSplitViewer")) {
+ for (const bNode *node : tree.nodes_by_type("CompositorNodeSplitViewer")) {
if (node->flag & NODE_DO_OUTPUT) {
- return DNode(&tree.root_context(), node);
+ return DNode(context, node);
}
}
- /* No output node found, return a null node. */
return DNode();
}
+/* Compute the output node whose result should be computed. This node is the output node that
+ * satisfies the requirements in the find_output_in_context function. First, the active context is
+ * searched for an output node, if non was found, the root context is search. For more information
+ * on what contexts mean here, see the find_active_context function. */
+static DNode compute_output_node(const DerivedNodeTree &tree)
+{
+ const DTreeContext *active_context = find_active_context(tree);
+
+ const DNode node = find_output_in_context(active_context);
+ if (node) {
+ return node;
+ }
+
+ /* If the active context is the root one and no output node was found, we consider this node tree
+ * to have no output node, even if one of the non-active descendants have an output node. */
+ if (active_context->is_root()) {
+ return DNode();
+ }
+
+ /* The active context doesn't have an output node, search in the root context as a fallback. */
+ return find_output_in_context(&tree.root_context());
+}
+
/* A type representing a mapping that associates each node with a heuristic estimation of the
* number of intermediate buffers needed to compute it and all of its dependencies. See the
* compute_number_of_needed_buffers function for more information. */
@@ -225,7 +293,7 @@ static NeededBuffers compute_number_of_needed_buffers(DNode output_node)
* doesn't always guarantee an optimal evaluation order, as the optimal evaluation order is very
* difficult to compute, however, this method works well in most cases. Moreover it assumes that
* all buffers will have roughly the same size, which may not always be the case. */
-Schedule compute_schedule(DerivedNodeTree &tree)
+Schedule compute_schedule(const DerivedNodeTree &tree)
{
Schedule schedule;
diff --git a/source/blender/depsgraph/DEG_depsgraph.h b/source/blender/depsgraph/DEG_depsgraph.h
index a8b21e4c153..48a6a5cda74 100644
--- a/source/blender/depsgraph/DEG_depsgraph.h
+++ b/source/blender/depsgraph/DEG_depsgraph.h
@@ -221,6 +221,14 @@ bool DEG_is_active(const struct Depsgraph *depsgraph);
void DEG_make_active(struct Depsgraph *depsgraph);
void DEG_make_inactive(struct Depsgraph *depsgraph);
+/**
+ * Disable the visibility optimization making it so IDs which affect hidden objects or disabled
+ * modifiers are still evaluated.
+ *
+ * For example, this ensures that an object which is needed by a modifier is ignoring checks about
+ * whether the object is hidden or the modifier is disabled. */
+void DEG_disable_visibility_optimization(struct Depsgraph *depsgraph);
+
/** \} */
/* -------------------------------------------------------------------- */
diff --git a/source/blender/depsgraph/DEG_depsgraph_build.h b/source/blender/depsgraph/DEG_depsgraph_build.h
index 201a534f535..ffeb5e897ab 100644
--- a/source/blender/depsgraph/DEG_depsgraph_build.h
+++ b/source/blender/depsgraph/DEG_depsgraph_build.h
@@ -56,6 +56,9 @@ void DEG_graph_build_for_render_pipeline(struct Depsgraph *graph);
*/
void DEG_graph_build_for_compositor_preview(struct Depsgraph *graph, struct bNodeTree *nodetree);
+/**
+ * Builds the minimal dependency graph needed for evaluation of the given IDs.
+ */
void DEG_graph_build_from_ids(struct Depsgraph *graph, struct ID **ids, int num_ids);
/** Tag relations from the given graph for update. */
diff --git a/source/blender/depsgraph/intern/depsgraph.cc b/source/blender/depsgraph/intern/depsgraph.cc
index 316d0b615c6..4d7d537b450 100644
--- a/source/blender/depsgraph/intern/depsgraph.cc
+++ b/source/blender/depsgraph/intern/depsgraph.cc
@@ -58,6 +58,7 @@ Depsgraph::Depsgraph(Main *bmain, Scene *scene, ViewLayer *view_layer, eEvaluati
ctime(BKE_scene_ctime_get(scene)),
scene_cow(nullptr),
is_active(false),
+ use_visibility_optimization(true),
is_evaluating(false),
is_render_pipeline_depsgraph(false),
use_editors_update(false)
@@ -334,3 +335,9 @@ void DEG_make_inactive(struct Depsgraph *depsgraph)
deg::Depsgraph *deg_graph = reinterpret_cast<deg::Depsgraph *>(depsgraph);
deg_graph->is_active = false;
}
+
+void DEG_disable_visibility_optimization(struct Depsgraph *depsgraph)
+{
+ deg::Depsgraph *deg_graph = reinterpret_cast<deg::Depsgraph *>(depsgraph);
+ deg_graph->use_visibility_optimization = false;
+} \ No newline at end of file
diff --git a/source/blender/depsgraph/intern/depsgraph.h b/source/blender/depsgraph/intern/depsgraph.h
index 2f88199384d..042cb045c6f 100644
--- a/source/blender/depsgraph/intern/depsgraph.h
+++ b/source/blender/depsgraph/intern/depsgraph.h
@@ -147,6 +147,9 @@ struct Depsgraph {
* to read stuff from. */
bool is_active;
+ /* Optimize out evaluation of operations which affect hidden objects or disabled modifiers. */
+ bool use_visibility_optimization;
+
DepsgraphDebug debug;
bool is_evaluating;
diff --git a/source/blender/depsgraph/intern/depsgraph_build.cc b/source/blender/depsgraph/intern/depsgraph_build.cc
index 6da290d6c4e..9eeb074bbaa 100644
--- a/source/blender/depsgraph/intern/depsgraph_build.cc
+++ b/source/blender/depsgraph/intern/depsgraph_build.cc
@@ -138,9 +138,14 @@ void DEG_add_node_tree_output_relation(DepsNodeHandle *node_handle,
{
deg::OperationKey ntree_output_key(
&node_tree->id, deg::NodeType::NTREE_OUTPUT, deg::OperationCode::NTREE_OUTPUT);
+ deg::OperationKey ntree_preprocess_key(&node_tree->id,
+ deg::NodeType::NTREE_GEOMETRY_PREPROCESS,
+ deg::OperationCode::NTREE_GEOMETRY_PREPROCESS);
deg::DepsNodeHandle *deg_node_handle = get_node_handle(node_handle);
deg_node_handle->builder->add_node_handle_relation(
ntree_output_key, deg_node_handle, description);
+ deg_node_handle->builder->add_node_handle_relation(
+ ntree_preprocess_key, deg_node_handle, description, deg::RELATION_FLAG_NO_FLUSH);
}
void DEG_add_object_cache_relation(DepsNodeHandle *node_handle,
diff --git a/source/blender/depsgraph/intern/eval/deg_eval.cc b/source/blender/depsgraph/intern/eval/deg_eval.cc
index 45a13b807af..5ca32d00ba5 100644
--- a/source/blender/depsgraph/intern/eval/deg_eval.cc
+++ b/source/blender/depsgraph/intern/eval/deg_eval.cc
@@ -12,6 +12,7 @@
#include "PIL_time.h"
#include "BLI_compiler_attrs.h"
+#include "BLI_function_ref.hh"
#include "BLI_gsqueue.h"
#include "BLI_task.h"
#include "BLI_utildefines.h"
@@ -52,16 +53,9 @@ struct DepsgraphEvalState;
void deg_task_run_func(TaskPool *pool, void *taskdata);
-template<typename ScheduleFunction, typename... ScheduleFunctionArgs>
void schedule_children(DepsgraphEvalState *state,
OperationNode *node,
- ScheduleFunction *schedule_function,
- ScheduleFunctionArgs... schedule_function_args);
-
-void schedule_node_to_pool(OperationNode *node, const int /*thread_id*/, TaskPool *pool)
-{
- BLI_task_pool_push(pool, deg_task_run_func, node, false, nullptr);
-}
+ FunctionRef<void(OperationNode *node)> schedule_fn);
/* Denotes which part of dependency graph is being evaluated. */
enum class EvaluationStage {
@@ -125,7 +119,9 @@ void deg_task_run_func(TaskPool *pool, void *taskdata)
evaluate_node(state, operation_node);
/* Schedule children. */
- schedule_children(state, operation_node, schedule_node_to_pool, pool);
+ schedule_children(state, operation_node, [&](OperationNode *node) {
+ BLI_task_pool_push(pool, deg_task_run_func, node, false, nullptr);
+ });
}
bool check_operation_node_visible(const DepsgraphEvalState *state, OperationNode *op_node)
@@ -241,12 +237,10 @@ bool need_evaluate_operation_at_stage(DepsgraphEvalState *state,
* dec_parents: Decrement pending parents count, true when child nodes are
* scheduled after a task has been completed.
*/
-template<typename ScheduleFunction, typename... ScheduleFunctionArgs>
void schedule_node(DepsgraphEvalState *state,
OperationNode *node,
bool dec_parents,
- ScheduleFunction *schedule_function,
- ScheduleFunctionArgs... schedule_function_args)
+ const FunctionRef<void(OperationNode *node)> schedule_fn)
{
/* No need to schedule nodes of invisible ID. */
if (!check_operation_node_visible(state, node)) {
@@ -277,30 +271,26 @@ void schedule_node(DepsgraphEvalState *state,
if (!is_scheduled) {
if (node->is_noop()) {
/* skip NOOP node, schedule children right away */
- schedule_children(state, node, schedule_function, schedule_function_args...);
+ schedule_children(state, node, schedule_fn);
}
else {
/* children are scheduled once this task is completed */
- schedule_function(node, 0, schedule_function_args...);
+ schedule_fn(node);
}
}
}
-template<typename ScheduleFunction, typename... ScheduleFunctionArgs>
void schedule_graph(DepsgraphEvalState *state,
- ScheduleFunction *schedule_function,
- ScheduleFunctionArgs... schedule_function_args)
+ const FunctionRef<void(OperationNode *node)> schedule_fn)
{
for (OperationNode *node : state->graph->operations) {
- schedule_node(state, node, false, schedule_function, schedule_function_args...);
+ schedule_node(state, node, false, schedule_fn);
}
}
-template<typename ScheduleFunction, typename... ScheduleFunctionArgs>
void schedule_children(DepsgraphEvalState *state,
OperationNode *node,
- ScheduleFunction *schedule_function,
- ScheduleFunctionArgs... schedule_function_args)
+ const FunctionRef<void(OperationNode *node)> schedule_fn)
{
for (Relation *rel : node->outlinks) {
OperationNode *child = (OperationNode *)rel->to;
@@ -309,21 +299,10 @@ void schedule_children(DepsgraphEvalState *state,
/* Happens when having cyclic dependencies. */
continue;
}
- schedule_node(state,
- child,
- (rel->flag & RELATION_FLAG_CYCLIC) == 0,
- schedule_function,
- schedule_function_args...);
+ schedule_node(state, child, (rel->flag & RELATION_FLAG_CYCLIC) == 0, schedule_fn);
}
}
-void schedule_node_to_queue(OperationNode *node,
- const int /*thread_id*/,
- GSQueue *evaluation_queue)
-{
- BLI_gsqueue_push(evaluation_queue, &node);
-}
-
/* Evaluate given stage of the dependency graph evaluation using multiple threads.
*
* NOTE: Will assign the `state->stage` to the given stage. */
@@ -335,7 +314,9 @@ void evaluate_graph_threaded_stage(DepsgraphEvalState *state,
calculate_pending_parents_if_needed(state);
- schedule_graph(state, schedule_node_to_pool, task_pool);
+ schedule_graph(state, [&](OperationNode *node) {
+ BLI_task_pool_push(task_pool, deg_task_run_func, node, false, nullptr);
+ });
BLI_task_pool_work_and_wait(task_pool);
}
@@ -351,14 +332,17 @@ void evaluate_graph_single_threaded_if_needed(DepsgraphEvalState *state)
state->stage = EvaluationStage::SINGLE_THREADED_WORKAROUND;
GSQueue *evaluation_queue = BLI_gsqueue_new(sizeof(OperationNode *));
- schedule_graph(state, schedule_node_to_queue, evaluation_queue);
+ auto schedule_node_to_queue = [&](OperationNode *node) {
+ BLI_gsqueue_push(evaluation_queue, &node);
+ };
+ schedule_graph(state, schedule_node_to_queue);
while (!BLI_gsqueue_is_empty(evaluation_queue)) {
OperationNode *operation_node;
BLI_gsqueue_pop(evaluation_queue, &operation_node);
evaluate_node(state, operation_node);
- schedule_children(state, operation_node, schedule_node_to_queue, evaluation_queue);
+ schedule_children(state, operation_node, schedule_node_to_queue);
}
BLI_gsqueue_free(evaluation_queue);
diff --git a/source/blender/depsgraph/intern/eval/deg_eval_visibility.cc b/source/blender/depsgraph/intern/eval/deg_eval_visibility.cc
index a056ba1dfa7..0ee4052eff3 100644
--- a/source/blender/depsgraph/intern/eval/deg_eval_visibility.cc
+++ b/source/blender/depsgraph/intern/eval/deg_eval_visibility.cc
@@ -37,7 +37,8 @@ void deg_evaluate_object_node_visibility(::Depsgraph *depsgraph, IDNode *id_node
const int required_flags = (graph->mode == DAG_EVAL_VIEWPORT) ? BASE_ENABLED_VIEWPORT :
BASE_ENABLED_RENDER;
- const bool is_enabled = object->base_flag & required_flags;
+ const bool is_enabled = !graph->use_visibility_optimization ||
+ object->base_flag & required_flags;
if (id_node->is_enabled_on_eval != is_enabled) {
id_node->is_enabled_on_eval = is_enabled;
@@ -73,7 +74,8 @@ void deg_evaluate_object_modifiers_mode_node_visibility(::Depsgraph *depsgraph,
"Modifier node in depsgraph is not found. Likely due to missing "
"DEG_relations_tag_update().");
- const bool modifier_enabled = modifier->mode & modifier_mode;
+ const bool modifier_enabled = !graph->use_visibility_optimization ||
+ (modifier->mode & modifier_mode);
const int mute_flag = modifier_enabled ? 0 : DEPSOP_FLAG_MUTE;
if ((modifier_node->flag & DEPSOP_FLAG_MUTE) != mute_flag) {
modifier_node->flag &= ~DEPSOP_FLAG_MUTE;
diff --git a/source/blender/draw/engines/eevee_next/eevee_camera.cc b/source/blender/draw/engines/eevee_next/eevee_camera.cc
index ad22219f0ae..4331db4bc4c 100644
--- a/source/blender/draw/engines/eevee_next/eevee_camera.cc
+++ b/source/blender/draw/engines/eevee_next/eevee_camera.cc
@@ -32,7 +32,7 @@ void Camera::init()
CameraData &data = data_;
- if (camera_eval) {
+ if (camera_eval && camera_eval->type == OB_CAMERA) {
const ::Camera *cam = reinterpret_cast<const ::Camera *>(camera_eval->data);
switch (cam->type) {
default:
@@ -112,7 +112,7 @@ void Camera::sync()
data.uv_bias = float2(0.0f);
}
- if (camera_eval) {
+ if (camera_eval && camera_eval->type == OB_CAMERA) {
const ::Camera *cam = reinterpret_cast<const ::Camera *>(camera_eval->data);
data.clip_near = cam->clip_start;
data.clip_far = cam->clip_end;
diff --git a/source/blender/draw/engines/eevee_next/eevee_depth_of_field.cc b/source/blender/draw/engines/eevee_next/eevee_depth_of_field.cc
index e4c4f6f3f6f..8672cce80b6 100644
--- a/source/blender/draw/engines/eevee_next/eevee_depth_of_field.cc
+++ b/source/blender/draw/engines/eevee_next/eevee_depth_of_field.cc
@@ -44,7 +44,7 @@ void DepthOfField::init()
{
const SceneEEVEE &sce_eevee = inst_.scene->eevee;
const Object *camera_object_eval = inst_.camera_eval_object;
- const ::Camera *camera = (camera_object_eval) ?
+ const ::Camera *camera = (camera_object_eval && camera_object_eval->type == OB_CAMERA) ?
reinterpret_cast<const ::Camera *>(camera_object_eval->data) :
nullptr;
if (camera == nullptr) {
@@ -70,7 +70,7 @@ void DepthOfField::sync()
{
const Camera &camera = inst_.camera;
const Object *camera_object_eval = inst_.camera_eval_object;
- const ::Camera *camera_data = (camera_object_eval) ?
+ const ::Camera *camera_data = (camera_object_eval && camera_object_eval->type == OB_CAMERA) ?
reinterpret_cast<const ::Camera *>(camera_object_eval->data) :
nullptr;
diff --git a/source/blender/draw/intern/draw_cache_impl_particles.c b/source/blender/draw/intern/draw_cache_impl_particles.c
index 15fe569abae..6f3ad687441 100644
--- a/source/blender/draw/intern/draw_cache_impl_particles.c
+++ b/source/blender/draw/intern/draw_cache_impl_particles.c
@@ -1346,7 +1346,7 @@ static void particle_batch_cache_ensure_pos(Object *object,
sim.ob = object;
sim.psys = psys;
sim.psmd = psys_get_modifier(object, psys);
- sim.psys->lattice_deform_data = psys_create_lattice_deform_data(&sim);
+ psys_sim_data_init(&sim);
GPU_VERTBUF_DISCARD_SAFE(point_cache->pos);
@@ -1392,6 +1392,8 @@ static void particle_batch_cache_ensure_pos(Object *object,
if (curr_point != psys->totpart) {
GPU_vertbuf_data_resize(point_cache->pos, curr_point);
}
+
+ psys_sim_data_free(&sim);
}
static void drw_particle_update_ptcache_edit(Object *object_eval,
diff --git a/source/blender/draw/intern/draw_manager.c b/source/blender/draw/intern/draw_manager.c
index 4fcfec833eb..c8f0fdde62d 100644
--- a/source/blender/draw/intern/draw_manager.c
+++ b/source/blender/draw/intern/draw_manager.c
@@ -2039,6 +2039,7 @@ void DRW_render_to_image(RenderEngine *engine, struct Depsgraph *depsgraph)
DRW_smoke_exit(DST.vmempool);
drw_manager_exit(&DST);
+ DRW_cache_free_old_subdiv();
/* Reset state after drawing */
DRW_state_reset();
diff --git a/source/blender/editors/asset/intern/asset_handle.cc b/source/blender/editors/asset/intern/asset_handle.cc
index 00fffd595c0..0b2cd352d77 100644
--- a/source/blender/editors/asset/intern/asset_handle.cc
+++ b/source/blender/editors/asset/intern/asset_handle.cc
@@ -8,6 +8,9 @@
#include "DNA_space_types.h"
+#include "BKE_asset.h"
+#include "BKE_asset_representation.hh"
+
#include "BLO_readfile.h"
#include "ED_asset_handle.h"
@@ -17,12 +20,12 @@
const char *ED_asset_handle_get_name(const AssetHandle *asset)
{
- return asset->file_data->name;
+ return BKE_asset_representation_name_get(asset->file_data->asset);
}
-AssetMetaData *ED_asset_handle_get_metadata(const AssetHandle *asset)
+AssetMetaData *ED_asset_handle_get_metadata(const AssetHandle *asset_handle)
{
- return asset->file_data->asset_data;
+ return BKE_asset_representation_metadata_get(asset_handle->file_data->asset);
}
ID *ED_asset_handle_get_local_id(const AssetHandle *asset)
diff --git a/source/blender/editors/asset/intern/asset_temp_id_consumer.cc b/source/blender/editors/asset/intern/asset_temp_id_consumer.cc
index 376454d62b6..d1fd48d966c 100644
--- a/source/blender/editors/asset/intern/asset_temp_id_consumer.cc
+++ b/source/blender/editors/asset/intern/asset_temp_id_consumer.cc
@@ -72,7 +72,7 @@ AssetTempIDConsumer *ED_asset_temp_id_consumer_create(const AssetHandle *handle)
if (!handle) {
return nullptr;
}
- BLI_assert(handle->file_data->asset_data != nullptr);
+ BLI_assert(handle->file_data->asset != nullptr);
return reinterpret_cast<AssetTempIDConsumer *>(
MEM_new<AssetTemporaryIDConsumer>(__func__, *handle));
}
diff --git a/source/blender/editors/geometry/geometry_attributes.cc b/source/blender/editors/geometry/geometry_attributes.cc
index 1a4c93afcdc..5b0202dcbe1 100644
--- a/source/blender/editors/geometry/geometry_attributes.cc
+++ b/source/blender/editors/geometry/geometry_attributes.cc
@@ -98,7 +98,7 @@ static int geometry_attribute_add_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
- BKE_id_attributes_active_set(id, layer);
+ BKE_id_attributes_active_set(id, layer->name);
DEG_id_tag_update(id, ID_RECALC_GEOMETRY);
WM_main_add_notifier(NC_GEOM | ND_DATA, id);
@@ -274,15 +274,14 @@ static int geometry_attribute_convert_exec(bContext *C, wmOperator *op)
{
Object *ob = ED_object_context(C);
ID *ob_data = static_cast<ID *>(ob->data);
- const CustomDataLayer *layer = BKE_id_attributes_active_get(ob_data);
- const std::string name = layer->name;
-
+ CustomDataLayer *layer = BKE_id_attributes_active_get(ob_data);
const ConvertAttributeMode mode = static_cast<ConvertAttributeMode>(
RNA_enum_get(op->ptr, "mode"));
-
Mesh *mesh = reinterpret_cast<Mesh *>(ob_data);
bke::MutableAttributeAccessor attributes = mesh->attributes_for_write();
+ const std::string name = layer->name;
+
/* General conversion steps are always the same:
* 1. Convert old data to right domain and data type.
* 2. Copy the data into a new array so that it does not depend on the old attribute anymore.
@@ -290,21 +289,13 @@ static int geometry_attribute_convert_exec(bContext *C, wmOperator *op)
* 4. Create a new attribute based on the previously copied data. */
switch (mode) {
case ConvertAttributeMode::Generic: {
- const eAttrDomain dst_domain = static_cast<eAttrDomain>(RNA_enum_get(op->ptr, "domain"));
- const eCustomDataType dst_type = static_cast<eCustomDataType>(
- RNA_enum_get(op->ptr, "data_type"));
-
- if (ELEM(dst_type, CD_PROP_STRING)) {
- BKE_report(op->reports, RPT_ERROR, "Cannot convert to the selected type");
+ if (!ED_geometry_attribute_convert(mesh,
+ name.c_str(),
+ eCustomDataType(RNA_enum_get(op->ptr, "data_type")),
+ eAttrDomain(RNA_enum_get(op->ptr, "domain")),
+ op->reports)) {
return OPERATOR_CANCELLED;
}
-
- GVArray src_varray = attributes.lookup_or_default(name, dst_domain, dst_type);
- const CPPType &cpp_type = src_varray.type();
- void *new_data = MEM_malloc_arrayN(src_varray.size(), cpp_type.size(), __func__);
- src_varray.materialize_to_uninitialized(new_data);
- attributes.remove(name);
- attributes.add(name, dst_domain, dst_type, blender::bke::AttributeInitMoveArray(new_data));
break;
}
case ConvertAttributeMode::VertexGroup: {
@@ -323,18 +314,16 @@ static int geometry_attribute_convert_exec(bContext *C, wmOperator *op)
BKE_defvert_add_index_notest(dverts + i, defgroup_index, weight);
}
}
+ int *active_index = BKE_id_attributes_active_index_p(&mesh->id);
+ if (*active_index > 0) {
+ *active_index -= 1;
+ }
break;
}
}
- int *active_index = BKE_id_attributes_active_index_p(&mesh->id);
- if (*active_index > 0) {
- *active_index -= 1;
- }
-
DEG_id_tag_update(&mesh->id, ID_RECALC_GEOMETRY);
WM_main_add_notifier(NC_GEOM | ND_DATA, &mesh->id);
-
return OPERATOR_FINISHED;
}
@@ -576,6 +565,79 @@ static int geometry_attribute_convert_invoke(bContext *C,
return WM_operator_props_dialog_popup(C, op, 300);
}
+static bool geometry_color_attribute_convert_poll(bContext *C)
+{
+ if (!geometry_attributes_poll(C)) {
+ return false;
+ }
+
+ Object *ob = ED_object_context(C);
+ ID *id = static_cast<ID *>(ob->data);
+ if (GS(id->name) != ID_ME) {
+ return false;
+ }
+ CustomDataLayer *layer = BKE_id_attributes_active_color_get(id);
+ if (layer == nullptr) {
+ return false;
+ }
+ return true;
+}
+
+static int geometry_color_attribute_convert_exec(bContext *C, wmOperator *op)
+{
+ Object *ob = ED_object_context(C);
+ ID *ob_data = static_cast<ID *>(ob->data);
+ CustomDataLayer *layer = BKE_id_attributes_active_color_get(ob_data);
+ ED_geometry_attribute_convert(static_cast<Mesh *>(ob->data),
+ layer->name,
+ eCustomDataType(RNA_enum_get(op->ptr, "data_type")),
+ eAttrDomain(RNA_enum_get(op->ptr, "domain")),
+ op->reports);
+ return OPERATOR_FINISHED;
+}
+
+static void geometry_color_attribute_convert_ui(bContext *UNUSED(C), wmOperator *op)
+{
+ uiLayout *layout = op->layout;
+ uiLayoutSetPropSep(layout, true);
+ uiLayoutSetPropDecorate(layout, false);
+
+ uiItemR(layout, op->ptr, "domain", UI_ITEM_R_EXPAND, nullptr, ICON_NONE);
+ uiItemR(layout, op->ptr, "data_type", UI_ITEM_R_EXPAND, nullptr, ICON_NONE);
+}
+
+void GEOMETRY_OT_color_attribute_convert(wmOperatorType *ot)
+{
+ ot->name = "Convert Color Attribute";
+ ot->description = "Change how the color attribute is stored";
+ ot->idname = "GEOMETRY_OT_color_attribute_convert";
+
+ ot->invoke = geometry_attribute_convert_invoke;
+ ot->exec = geometry_color_attribute_convert_exec;
+ ot->poll = geometry_color_attribute_convert_poll;
+ ot->ui = geometry_color_attribute_convert_ui;
+
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ PropertyRNA *prop;
+
+ prop = RNA_def_enum(ot->srna,
+ "domain",
+ rna_enum_color_attribute_domain_items,
+ ATTR_DOMAIN_POINT,
+ "Domain",
+ "Type of element that attribute is stored on");
+ RNA_def_property_flag(prop, PROP_SKIP_SAVE);
+
+ prop = RNA_def_enum(ot->srna,
+ "data_type",
+ rna_enum_color_attribute_type_items,
+ CD_PROP_COLOR,
+ "Data Type",
+ "Type of data stored in attribute");
+ RNA_def_property_flag(prop, PROP_SKIP_SAVE);
+}
+
void GEOMETRY_OT_attribute_convert(wmOperatorType *ot)
{
ot->name = "Convert Attribute";
@@ -613,37 +675,31 @@ void GEOMETRY_OT_attribute_convert(wmOperatorType *ot)
} // namespace blender::ed::geometry
-using blender::CPPType;
-using blender::GVArray;
-
bool ED_geometry_attribute_convert(Mesh *mesh,
- const char *layer_name,
- eCustomDataType old_type,
- eAttrDomain old_domain,
- eCustomDataType new_type,
- eAttrDomain new_domain)
+ const char *name,
+ const eCustomDataType dst_type,
+ const eAttrDomain dst_domain,
+ ReportList *reports)
{
- CustomDataLayer *layer = BKE_id_attribute_find(&mesh->id, layer_name, old_type, old_domain);
- const std::string name = layer->name;
-
- if (!layer) {
+ using namespace blender;
+ bke::MutableAttributeAccessor attributes = mesh->attributes_for_write();
+ BLI_assert(mesh->attributes().contains(name));
+ BLI_assert(mesh->edit_mesh == nullptr);
+ if (ELEM(dst_type, CD_PROP_STRING)) {
+ if (reports) {
+ BKE_report(reports, RPT_ERROR, "Cannot convert to the selected type");
+ }
return false;
}
- blender::bke::MutableAttributeAccessor attributes = mesh->attributes_for_write();
+ const std::string name_copy = name;
+ const GVArray varray = attributes.lookup_or_default(name_copy, dst_domain, dst_type);
- GVArray src_varray = attributes.lookup_or_default(name, new_domain, new_type);
-
- const CPPType &cpp_type = src_varray.type();
- void *new_data = MEM_malloc_arrayN(src_varray.size(), cpp_type.size(), __func__);
- src_varray.materialize_to_uninitialized(new_data);
- attributes.remove(name);
- attributes.add(name, new_domain, new_type, blender::bke::AttributeInitMoveArray(new_data));
-
- int *active_index = BKE_id_attributes_active_index_p(&mesh->id);
- if (*active_index > 0) {
- *active_index -= 1;
- }
+ const CPPType &cpp_type = varray.type();
+ void *new_data = MEM_malloc_arrayN(varray.size(), cpp_type.size(), __func__);
+ varray.materialize_to_uninitialized(new_data);
+ attributes.remove(name_copy);
+ attributes.add(name_copy, dst_domain, dst_type, bke::AttributeInitMoveArray(new_data));
return true;
}
diff --git a/source/blender/editors/geometry/geometry_intern.hh b/source/blender/editors/geometry/geometry_intern.hh
index a1000a5d01f..0ae63d07c6d 100644
--- a/source/blender/editors/geometry/geometry_intern.hh
+++ b/source/blender/editors/geometry/geometry_intern.hh
@@ -19,5 +19,6 @@ void GEOMETRY_OT_color_attribute_remove(struct wmOperatorType *ot);
void GEOMETRY_OT_color_attribute_render_set(struct wmOperatorType *ot);
void GEOMETRY_OT_color_attribute_duplicate(struct wmOperatorType *ot);
void GEOMETRY_OT_attribute_convert(struct wmOperatorType *ot);
+void GEOMETRY_OT_color_attribute_convert(struct wmOperatorType *ot);
} // namespace blender::ed::geometry
diff --git a/source/blender/editors/geometry/geometry_ops.cc b/source/blender/editors/geometry/geometry_ops.cc
index acac757ecf1..79a0468f51a 100644
--- a/source/blender/editors/geometry/geometry_ops.cc
+++ b/source/blender/editors/geometry/geometry_ops.cc
@@ -24,4 +24,5 @@ void ED_operatortypes_geometry(void)
WM_operatortype_append(GEOMETRY_OT_color_attribute_render_set);
WM_operatortype_append(GEOMETRY_OT_color_attribute_duplicate);
WM_operatortype_append(GEOMETRY_OT_attribute_convert);
+ WM_operatortype_append(GEOMETRY_OT_color_attribute_convert);
}
diff --git a/source/blender/editors/include/ED_geometry.h b/source/blender/editors/include/ED_geometry.h
index 4620181894a..8436df73d10 100644
--- a/source/blender/editors/include/ED_geometry.h
+++ b/source/blender/editors/include/ED_geometry.h
@@ -15,14 +15,21 @@ extern "C" {
#endif
struct Mesh;
+struct ReportList;
void ED_operatortypes_geometry(void);
+
+/**
+ * Convert an attribute with the given name to a new type and domain.
+ * The attribute must already exist.
+ *
+ * \note Does not support meshes in edit mode.
+ */
bool ED_geometry_attribute_convert(struct Mesh *mesh,
- const char *layer_name,
- eCustomDataType old_type,
- eAttrDomain old_domain,
- eCustomDataType new_type,
- eAttrDomain new_domain);
+ const char *name,
+ eCustomDataType dst_type,
+ eAttrDomain dst_domain,
+ ReportList *reports);
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/editors/include/ED_mesh.h b/source/blender/editors/include/ED_mesh.h
index 44a8d0718cb..76f7e3b2c3e 100644
--- a/source/blender/editors/include/ED_mesh.h
+++ b/source/blender/editors/include/ED_mesh.h
@@ -142,12 +142,15 @@ struct UvElementMap *BM_uv_element_map_create(struct BMesh *bm,
bool use_seams,
bool do_islands);
void BM_uv_element_map_free(struct UvElementMap *element_map);
-struct UvElement *BM_uv_element_get(const struct UvElementMap *map,
+struct UvElement *BM_uv_element_get(const struct UvElementMap *element_map,
const struct BMFace *efa,
const struct BMLoop *l);
-struct UvElement *BM_uv_element_get_head(struct UvElementMap *map, struct UvElement *child);
+struct UvElement *BM_uv_element_get_head(struct UvElementMap *element_map,
+ struct UvElement *child);
+int BM_uv_element_get_unique_index(struct UvElementMap *element_map, struct UvElement *child);
struct UvElement **BM_uv_element_map_ensure_head_table(struct UvElementMap *element_map);
+int *BM_uv_element_map_ensure_unique_index(struct UvElementMap *element_map);
/**
* Can we edit UV's for this mesh?
diff --git a/source/blender/editors/include/ED_sculpt.h b/source/blender/editors/include/ED_sculpt.h
index 1c1ce41ef7a..bc4e3b88586 100644
--- a/source/blender/editors/include/ED_sculpt.h
+++ b/source/blender/editors/include/ED_sculpt.h
@@ -22,7 +22,7 @@ struct wmMsgSubscribeValue;
struct wmRegionMessageSubscribeParams;
struct wmOperator;
-/* sculpt.c */
+/* sculpt.cc */
void ED_operatortypes_sculpt(void);
void ED_sculpt_redraw_planes_get(float planes[4][4], struct ARegion *region, struct Object *ob);
diff --git a/source/blender/editors/include/UI_interface.h b/source/blender/editors/include/UI_interface.h
index 66b3d9fba6b..415356d1d71 100644
--- a/source/blender/editors/include/UI_interface.h
+++ b/source/blender/editors/include/UI_interface.h
@@ -1789,7 +1789,6 @@ void UI_but_drag_attach_image(uiBut *but, struct ImBuf *imb, float scale);
void UI_but_drag_set_asset(uiBut *but,
const struct AssetHandle *asset,
const char *path,
- struct AssetMetaData *metadata,
int import_type, /* eFileAssetImportType */
int icon,
struct ImBuf *imb,
diff --git a/source/blender/editors/interface/interface_drag.cc b/source/blender/editors/interface/interface_drag.cc
index 4bf2dac4151..e959986d19e 100644
--- a/source/blender/editors/interface/interface_drag.cc
+++ b/source/blender/editors/interface/interface_drag.cc
@@ -27,15 +27,14 @@ void UI_but_drag_attach_image(uiBut *but, struct ImBuf *imb, const float scale)
}
void UI_but_drag_set_asset(uiBut *but,
- const AssetHandle *asset,
+ const AssetHandle *asset_handle,
const char *path,
- struct AssetMetaData *metadata,
int import_type,
int icon,
struct ImBuf *imb,
float scale)
{
- wmDragAsset *asset_drag = WM_drag_create_asset_data(asset, metadata, path, import_type);
+ wmDragAsset *asset_drag = WM_drag_create_asset_data(asset_handle, path, import_type);
/* FIXME: This is temporary evil solution to get scene/view-layer/etc in the copy callback of the
* #wmDropBox.
diff --git a/source/blender/editors/interface/interface_ops.cc b/source/blender/editors/interface/interface_ops.cc
index 2d06dd2c465..1b576583291 100644
--- a/source/blender/editors/interface/interface_ops.cc
+++ b/source/blender/editors/interface/interface_ops.cc
@@ -1165,7 +1165,7 @@ bool UI_context_copy_to_selected_list(bContext *C,
if (RNA_struct_is_a(ptr->type, &RNA_NodeSocket)) {
bNodeTree *ntree = (bNodeTree *)ptr->owner_id;
bNodeSocket *sock = static_cast<bNodeSocket *>(ptr->data);
- if (nodeFindNode(ntree, sock, &node, nullptr)) {
+ if (nodeFindNodeTry(ntree, sock, &node, nullptr)) {
if ((path = RNA_path_resolve_from_type_to_property(ptr, prop, &RNA_Node)) != nullptr) {
/* we're good! */
}
diff --git a/source/blender/editors/interface/interface_region_color_picker.cc b/source/blender/editors/interface/interface_region_color_picker.cc
index 0b2c538331a..8b28e9fece1 100644
--- a/source/blender/editors/interface/interface_region_color_picker.cc
+++ b/source/blender/editors/interface/interface_region_color_picker.cc
@@ -199,7 +199,7 @@ static void ui_update_color_picker_buts_rgb(uiBut *from_but,
* push, so disable it on RNA buttons in the color picker block */
UI_but_flag_disable(bt, UI_BUT_UNDO);
}
- else if (STREQ(bt->str, "Hex: ")) {
+ else if (STREQ(bt->str, "Hex:")) {
float rgb_hex[3];
uchar rgb_hex_uchar[3];
char col[16];
@@ -613,7 +613,7 @@ static void ui_block_colorpicker(uiBlock *block,
bt = uiDefButR_prop(block,
UI_BTYPE_NUM_SLIDER,
0,
- IFACE_("R:"),
+ IFACE_("Red:"),
0,
yco,
butwidth,
@@ -623,7 +623,7 @@ static void ui_block_colorpicker(uiBlock *block,
0,
0.0,
0.0,
- 0,
+ 10,
3,
TIP_("Red"));
UI_but_func_set(bt, ui_colorpicker_rgba_update_cb, bt, nullptr);
@@ -631,7 +631,7 @@ static void ui_block_colorpicker(uiBlock *block,
bt = uiDefButR_prop(block,
UI_BTYPE_NUM_SLIDER,
0,
- IFACE_("G:"),
+ IFACE_("Green:"),
0,
yco -= UI_UNIT_Y,
butwidth,
@@ -641,7 +641,7 @@ static void ui_block_colorpicker(uiBlock *block,
1,
0.0,
0.0,
- 0,
+ 10,
3,
TIP_("Green"));
UI_but_func_set(bt, ui_colorpicker_rgba_update_cb, bt, nullptr);
@@ -649,7 +649,7 @@ static void ui_block_colorpicker(uiBlock *block,
bt = uiDefButR_prop(block,
UI_BTYPE_NUM_SLIDER,
0,
- IFACE_("B:"),
+ IFACE_("Blue:"),
0,
yco -= UI_UNIT_Y,
butwidth,
@@ -659,7 +659,7 @@ static void ui_block_colorpicker(uiBlock *block,
2,
0.0,
0.0,
- 0,
+ 10,
3,
TIP_("Blue"));
UI_but_func_set(bt, ui_colorpicker_rgba_update_cb, bt, nullptr);
@@ -675,7 +675,7 @@ static void ui_block_colorpicker(uiBlock *block,
bt = uiDefButF(block,
UI_BTYPE_NUM_SLIDER,
0,
- IFACE_("H:"),
+ IFACE_("Hue:"),
0,
yco,
butwidth,
@@ -692,7 +692,7 @@ static void ui_block_colorpicker(uiBlock *block,
bt = uiDefButF(block,
UI_BTYPE_NUM_SLIDER,
0,
- IFACE_("S:"),
+ IFACE_("Saturation:"),
0,
yco -= UI_UNIT_Y,
butwidth,
@@ -710,7 +710,7 @@ static void ui_block_colorpicker(uiBlock *block,
bt = uiDefButF(block,
UI_BTYPE_NUM_SLIDER,
0,
- IFACE_("L:"),
+ IFACE_("Lightness:"),
0,
yco -= UI_UNIT_Y,
butwidth,
@@ -726,7 +726,7 @@ static void ui_block_colorpicker(uiBlock *block,
bt = uiDefButF(block,
UI_BTYPE_NUM_SLIDER,
0,
- IFACE_("V:"),
+ IFACE_("Value:"),
0,
yco -= UI_UNIT_Y,
butwidth,
@@ -750,7 +750,7 @@ static void ui_block_colorpicker(uiBlock *block,
bt = uiDefButR_prop(block,
UI_BTYPE_NUM_SLIDER,
0,
- IFACE_("A: "),
+ IFACE_("Alpha:"),
0,
yco -= UI_UNIT_Y,
butwidth,
@@ -760,7 +760,7 @@ static void ui_block_colorpicker(uiBlock *block,
3,
0.0,
0.0,
- 0,
+ 10,
3,
TIP_("Alpha"));
UI_but_func_set(bt, ui_colorpicker_rgba_update_cb, bt, nullptr);
@@ -788,7 +788,7 @@ static void ui_block_colorpicker(uiBlock *block,
bt = uiDefBut(block,
UI_BTYPE_TEXT,
0,
- IFACE_("Hex: "),
+ IFACE_("Hex:"),
0,
yco,
butwidth,
diff --git a/source/blender/editors/interface/interface_template_asset_view.cc b/source/blender/editors/interface/interface_template_asset_view.cc
index 11fe653724c..9a3f7800c64 100644
--- a/source/blender/editors/interface/interface_template_asset_view.cc
+++ b/source/blender/editors/interface/interface_template_asset_view.cc
@@ -57,7 +57,6 @@ static void asset_view_item_but_drag_set(uiBut *but,
UI_but_drag_set_asset(but,
asset_handle,
BLI_strdup(blend_path),
- ED_asset_handle_get_metadata(asset_handle),
FILE_ASSET_IMPORT_APPEND,
ED_asset_handle_get_preview_icon_id(asset_handle),
imbuf,
diff --git a/source/blender/editors/interface/view2d_gizmo_navigate.cc b/source/blender/editors/interface/view2d_gizmo_navigate.cc
index 78549a33fc5..f754b2ab088 100644
--- a/source/blender/editors/interface/view2d_gizmo_navigate.cc
+++ b/source/blender/editors/interface/view2d_gizmo_navigate.cc
@@ -110,7 +110,6 @@ struct NavigateWidgetGroup {
struct {
rcti rect_visible;
} state;
- int region_size[2];
};
static bool WIDGETGROUP_navigate_poll(const bContext *C, wmGizmoGroupType * /*gzgt*/)
@@ -145,9 +144,6 @@ static void WIDGETGROUP_navigate_setup(const bContext * /*C*/, wmGizmoGroup *gzg
{
NavigateWidgetGroup *navgroup = MEM_cnew<NavigateWidgetGroup>(__func__);
- navgroup->region_size[0] = -1;
- navgroup->region_size[1] = -1;
-
const struct NavigateGizmoInfo *navigate_params = navigate_params_from_space_type(
gzgroup->type->gzmap_params.spaceid);
diff --git a/source/blender/editors/mesh/editmesh_utils.c b/source/blender/editors/mesh/editmesh_utils.c
index 38d0a42ae92..3f1981b1e75 100644
--- a/source/blender/editors/mesh/editmesh_utils.c
+++ b/source/blender/editors/mesh/editmesh_utils.c
@@ -617,6 +617,44 @@ struct UvElement **BM_uv_element_map_ensure_head_table(struct UvElementMap *elem
return element_map->head_table;
}
+int *BM_uv_element_map_ensure_unique_index(struct UvElementMap *element_map)
+{
+ if (!element_map->unique_index_table) {
+ element_map->unique_index_table = MEM_callocN(
+ element_map->total_uvs * sizeof(*element_map->unique_index_table), __func__);
+
+ int j = 0;
+ for (int i = 0; i < element_map->total_uvs; i++) {
+ UvElement *element = element_map->storage + i;
+ if (!element->separate) {
+ continue;
+ }
+ BLI_assert(0 <= j);
+ BLI_assert(j < element_map->total_unique_uvs);
+ while (element) {
+ element_map->unique_index_table[element - element_map->storage] = j;
+ element = element->next;
+ if (!element || element->separate) {
+ break;
+ }
+ }
+ j++;
+ }
+ BLI_assert(j == element_map->total_unique_uvs);
+ }
+
+ return element_map->unique_index_table;
+}
+
+int BM_uv_element_get_unique_index(struct UvElementMap *element_map, struct UvElement *child)
+{
+ int *unique_index = BM_uv_element_map_ensure_unique_index(element_map);
+ int index = child - element_map->storage;
+ BLI_assert(0 <= index);
+ BLI_assert(index < element_map->total_uvs);
+ return unique_index[index];
+}
+
#define INVALID_ISLAND ((uint)-1)
static void bm_uv_assign_island(UvElementMap *element_map,
@@ -1162,6 +1200,7 @@ void BM_uv_element_map_free(UvElementMap *element_map)
MEM_SAFE_FREE(element_map->storage);
MEM_SAFE_FREE(element_map->vertex);
MEM_SAFE_FREE(element_map->head_table);
+ MEM_SAFE_FREE(element_map->unique_index_table);
MEM_SAFE_FREE(element_map->island_indices);
MEM_SAFE_FREE(element_map->island_total_uvs);
MEM_SAFE_FREE(element_map->island_total_unique_uvs);
diff --git a/source/blender/editors/object/object_modifier.cc b/source/blender/editors/object/object_modifier.cc
index a87e52db129..67399717c72 100644
--- a/source/blender/editors/object/object_modifier.cc
+++ b/source/blender/editors/object/object_modifier.cc
@@ -942,31 +942,56 @@ bool ED_object_modifier_apply(Main *bmain,
Object *ob_eval = DEG_get_evaluated_object(depsgraph, ob);
ModifierData *md_eval = (ob_eval) ? BKE_modifiers_findby_name(ob_eval, md->name) : md;
- /* Allow apply of a non-real-time modifier, by first re-enabling real-time. */
- int prev_mode = md_eval->mode;
- md_eval->mode |= eModifierMode_Realtime;
+ Depsgraph *apply_depsgraph = depsgraph;
+ Depsgraph *local_depsgraph = nullptr;
+
+ /* If the object is hidden or the modifier is not enabled for the viewport is disabled a special
+ * handling is required. This is because the viewport dependency graph optimizes out evaluation
+ * of objects which are used by hidden objects and disabled modifiers.
+ *
+ * The idea is to create a dependency graph which does not perform those optimizations. */
+ if ((ob_eval->base_flag & BASE_ENABLED_VIEWPORT) == 0 ||
+ (md_eval->mode & eModifierMode_Realtime) == 0) {
+ ViewLayer *view_layer = DEG_get_input_view_layer(depsgraph);
+
+ local_depsgraph = DEG_graph_new(bmain, scene, view_layer, DAG_EVAL_VIEWPORT);
+ DEG_disable_visibility_optimization(local_depsgraph);
+
+ ID *ids[] = {&ob->id};
+
+ DEG_graph_build_from_ids(local_depsgraph, ids, 1);
+ DEG_evaluate_on_refresh(local_depsgraph);
+
+ apply_depsgraph = local_depsgraph;
+
+ /* The evaluated object and modifier are now from the different dependency graph. */
+ ob_eval = DEG_get_evaluated_object(local_depsgraph, ob);
+ md_eval = BKE_modifiers_findby_name(ob_eval, md->name);
+
+ /* Force mode on the evaluated modifier, enforcing the modifier evaluation in the apply()
+ * functions. */
+ md_eval->mode |= eModifierMode_Realtime;
+ }
+ bool did_apply = false;
if (mode == MODIFIER_APPLY_SHAPE) {
- if (!modifier_apply_shape(bmain, reports, depsgraph, scene, ob, md_eval)) {
- md_eval->mode = prev_mode;
- return false;
- }
+ did_apply = modifier_apply_shape(bmain, reports, apply_depsgraph, scene, ob, md_eval);
}
else {
- if (!modifier_apply_obdata(reports, depsgraph, scene, ob, md_eval)) {
- md_eval->mode = prev_mode;
- return false;
- }
+ did_apply = modifier_apply_obdata(reports, apply_depsgraph, scene, ob, md_eval);
}
- md_eval->mode = prev_mode;
-
- if (!keep_modifier) {
- BKE_modifier_remove_from_list(ob, md);
- BKE_modifier_free(md);
+ if (did_apply) {
+ if (!keep_modifier) {
+ BKE_modifier_remove_from_list(ob, md);
+ BKE_modifier_free(md);
+ }
+ BKE_object_free_derived_caches(ob);
}
- BKE_object_free_derived_caches(ob);
+ if (local_depsgraph != nullptr) {
+ DEG_graph_free(local_depsgraph);
+ }
return true;
}
diff --git a/source/blender/editors/sculpt_paint/CMakeLists.txt b/source/blender/editors/sculpt_paint/CMakeLists.txt
index 2709ac3fd91..b29fc0e9e7d 100644
--- a/source/blender/editors/sculpt_paint/CMakeLists.txt
+++ b/source/blender/editors/sculpt_paint/CMakeLists.txt
@@ -60,7 +60,7 @@ set(SRC
paint_vertex_proj.c
paint_vertex_weight_ops.c
paint_vertex_weight_utils.c
- sculpt.c
+ sculpt.cc
sculpt_automasking.cc
sculpt_boundary.c
sculpt_brush_types.c
diff --git a/source/blender/editors/sculpt_paint/curves_sculpt_ops.cc b/source/blender/editors/sculpt_paint/curves_sculpt_ops.cc
index df7dd871a94..df23bdf0079 100644
--- a/source/blender/editors/sculpt_paint/curves_sculpt_ops.cc
+++ b/source/blender/editors/sculpt_paint/curves_sculpt_ops.cc
@@ -76,7 +76,7 @@ namespace blender::ed::sculpt_paint {
using blender::bke::CurvesGeometry;
/* -------------------------------------------------------------------- */
-/** \name * SCULPT_CURVES_OT_brush_stroke
+/** \name Brush Stroke Operator
* \{ */
float brush_radius_factor(const Brush &brush, const StrokeExtension &stroke_extension)
@@ -271,7 +271,7 @@ static void SCULPT_CURVES_OT_brush_stroke(struct wmOperatorType *ot)
/** \} */
/* -------------------------------------------------------------------- */
-/** \name * CURVES_OT_sculptmode_toggle
+/** \name Toggle Sculpt Mode
* \{ */
static void curves_sculptmode_enter(bContext *C)
@@ -1269,7 +1269,7 @@ static void SCULPT_CURVES_OT_min_distance_edit(wmOperatorType *ot)
} // namespace blender::ed::sculpt_paint
/* -------------------------------------------------------------------- */
-/** \name * Registration
+/** \name Registration
* \{ */
void ED_operatortypes_sculpt_curves()
diff --git a/source/blender/editors/sculpt_paint/paint_vertex.cc b/source/blender/editors/sculpt_paint/paint_vertex.cc
index 8e790ac435e..8758d3fa83f 100644
--- a/source/blender/editors/sculpt_paint/paint_vertex.cc
+++ b/source/blender/editors/sculpt_paint/paint_vertex.cc
@@ -1162,7 +1162,7 @@ static void do_weight_paint_vertex(
}
}
-/* Toggle operator for turning vertex paint mode on or off (copied from sculpt.c) */
+/* Toggle operator for turning vertex paint mode on or off (copied from sculpt.cc) */
static void vertex_paint_init_session(Depsgraph *depsgraph,
Scene *scene,
Object *ob,
@@ -2388,7 +2388,7 @@ static void wpaint_do_paint(bContext *C,
WeightPaintInfo *wpi,
Mesh *me,
Brush *brush,
- const char symm,
+ const ePaintSymmetryFlags symm,
const int axis,
const int i,
const float angle)
@@ -2415,7 +2415,7 @@ static void wpaint_do_radial_symmetry(bContext *C,
WeightPaintInfo *wpi,
Mesh *me,
Brush *brush,
- const char symm,
+ const ePaintSymmetryFlags symm,
const int axis)
{
for (int i = 1; i < wp->radial_symm[axis - 'X']; i++) {
@@ -2424,7 +2424,7 @@ static void wpaint_do_radial_symmetry(bContext *C,
}
}
-/* near duplicate of: sculpt.c's,
+/* near duplicate of: sculpt.cc's,
* 'do_symmetrical_brush_actions' and 'vpaint_do_symmetrical_brush_actions'. */
static void wpaint_do_symmetrical_brush_actions(
bContext *C, Object *ob, VPaint *wp, Sculpt *sd, WPaintData *wpd, WeightPaintInfo *wpi)
@@ -2437,11 +2437,11 @@ static void wpaint_do_symmetrical_brush_actions(
int i = 0;
/* initial stroke */
- cache->mirror_symmetry_pass = 0;
- wpaint_do_paint(C, ob, wp, sd, wpd, wpi, me, brush, 0, 'X', 0, 0);
- wpaint_do_radial_symmetry(C, ob, wp, sd, wpd, wpi, me, brush, 0, 'X');
- wpaint_do_radial_symmetry(C, ob, wp, sd, wpd, wpi, me, brush, 0, 'Y');
- wpaint_do_radial_symmetry(C, ob, wp, sd, wpd, wpi, me, brush, 0, 'Z');
+ cache->mirror_symmetry_pass = ePaintSymmetryFlags(0);
+ wpaint_do_paint(C, ob, wp, sd, wpd, wpi, me, brush, ePaintSymmetryFlags(0), 'X', 0, 0);
+ wpaint_do_radial_symmetry(C, ob, wp, sd, wpd, wpi, me, brush, ePaintSymmetryFlags(0), 'X');
+ wpaint_do_radial_symmetry(C, ob, wp, sd, wpd, wpi, me, brush, ePaintSymmetryFlags(0), 'Y');
+ wpaint_do_radial_symmetry(C, ob, wp, sd, wpd, wpi, me, brush, ePaintSymmetryFlags(0), 'Z');
cache->symmetry = symm;
@@ -2456,21 +2456,22 @@ static void wpaint_do_symmetrical_brush_actions(
* X; 2 is Y; 3 is XY; 4 is Z; 5 is XZ; 6 is YZ; 7 is XYZ */
for (i = 1; i <= symm; i++) {
if (symm & i && (symm != 5 || i != 3) && (symm != 6 || !ELEM(i, 3, 5))) {
- cache->mirror_symmetry_pass = i;
+ const ePaintSymmetryFlags symm = ePaintSymmetryFlags(i);
+ cache->mirror_symmetry_pass = symm;
cache->radial_symmetry_pass = 0;
- SCULPT_cache_calc_brushdata_symm(cache, i, 0, 0);
+ SCULPT_cache_calc_brushdata_symm(cache, symm, 0, 0);
if (i & (1 << 0)) {
- wpaint_do_paint(C, ob, wp, sd, wpd, wpi, me, brush, i, 'X', 0, 0);
- wpaint_do_radial_symmetry(C, ob, wp, sd, wpd, wpi, me, brush, i, 'X');
+ wpaint_do_paint(C, ob, wp, sd, wpd, wpi, me, brush, symm, 'X', 0, 0);
+ wpaint_do_radial_symmetry(C, ob, wp, sd, wpd, wpi, me, brush, symm, 'X');
}
if (i & (1 << 1)) {
- wpaint_do_paint(C, ob, wp, sd, wpd, wpi, me, brush, i, 'Y', 0, 0);
- wpaint_do_radial_symmetry(C, ob, wp, sd, wpd, wpi, me, brush, i, 'Y');
+ wpaint_do_paint(C, ob, wp, sd, wpd, wpi, me, brush, symm, 'Y', 0, 0);
+ wpaint_do_radial_symmetry(C, ob, wp, sd, wpd, wpi, me, brush, symm, 'Y');
}
if (i & (1 << 2)) {
- wpaint_do_paint(C, ob, wp, sd, wpd, wpi, me, brush, i, 'Z', 0, 0);
- wpaint_do_radial_symmetry(C, ob, wp, sd, wpd, wpi, me, brush, i, 'Z');
+ wpaint_do_paint(C, ob, wp, sd, wpd, wpi, me, brush, symm, 'Z', 0, 0);
+ wpaint_do_radial_symmetry(C, ob, wp, sd, wpd, wpi, me, brush, symm, 'Z');
}
}
}
@@ -3738,7 +3739,7 @@ static void vpaint_do_paint(bContext *C,
Object *ob,
Mesh *me,
Brush *brush,
- const char symm,
+ const ePaintSymmetryFlags symm,
const int axis,
const int i,
const float angle)
@@ -3769,7 +3770,7 @@ static void vpaint_do_radial_symmetry(bContext *C,
Object *ob,
Mesh *me,
Brush *brush,
- const char symm,
+ const ePaintSymmetryFlags symm,
const int axis)
{
for (int i = 1; i < vp->radial_symm[axis - 'X']; i++) {
@@ -3778,7 +3779,7 @@ static void vpaint_do_radial_symmetry(bContext *C,
}
}
-/* near duplicate of: sculpt.c's,
+/* near duplicate of: sculpt.cc's,
* 'do_symmetrical_brush_actions' and 'wpaint_do_symmetrical_brush_actions'. */
template<typename Color, typename Traits, eAttrDomain domain>
static void vpaint_do_symmetrical_brush_actions(
@@ -3792,11 +3793,15 @@ static void vpaint_do_symmetrical_brush_actions(
int i = 0;
/* initial stroke */
- cache->mirror_symmetry_pass = 0;
- vpaint_do_paint<Color, Traits, domain>(C, sd, vp, vpd, ob, me, brush, i, 'X', 0, 0);
- vpaint_do_radial_symmetry<Color, Traits, domain>(C, sd, vp, vpd, ob, me, brush, i, 'X');
- vpaint_do_radial_symmetry<Color, Traits, domain>(C, sd, vp, vpd, ob, me, brush, i, 'Y');
- vpaint_do_radial_symmetry<Color, Traits, domain>(C, sd, vp, vpd, ob, me, brush, i, 'Z');
+ const ePaintSymmetryFlags initial_symm = ePaintSymmetryFlags(0);
+ cache->mirror_symmetry_pass = ePaintSymmetryFlags(0);
+ vpaint_do_paint<Color, Traits, domain>(C, sd, vp, vpd, ob, me, brush, initial_symm, 'X', 0, 0);
+ vpaint_do_radial_symmetry<Color, Traits, domain>(
+ C, sd, vp, vpd, ob, me, brush, initial_symm, 'X');
+ vpaint_do_radial_symmetry<Color, Traits, domain>(
+ C, sd, vp, vpd, ob, me, brush, initial_symm, 'Y');
+ vpaint_do_radial_symmetry<Color, Traits, domain>(
+ C, sd, vp, vpd, ob, me, brush, initial_symm, 'Z');
cache->symmetry = symm;
@@ -3804,21 +3809,28 @@ static void vpaint_do_symmetrical_brush_actions(
* X; 2 is Y; 3 is XY; 4 is Z; 5 is XZ; 6 is YZ; 7 is XYZ */
for (i = 1; i <= symm; i++) {
if (symm & i && (symm != 5 || i != 3) && (symm != 6 || !ELEM(i, 3, 5))) {
- cache->mirror_symmetry_pass = i;
+ const ePaintSymmetryFlags symm_pass = ePaintSymmetryFlags(i);
+ cache->mirror_symmetry_pass = symm_pass;
cache->radial_symmetry_pass = 0;
- SCULPT_cache_calc_brushdata_symm(cache, i, 0, 0);
+ SCULPT_cache_calc_brushdata_symm(cache, symm_pass, 0, 0);
if (i & (1 << 0)) {
- vpaint_do_paint<Color, Traits, domain>(C, sd, vp, vpd, ob, me, brush, i, 'X', 0, 0);
- vpaint_do_radial_symmetry<Color, Traits, domain>(C, sd, vp, vpd, ob, me, brush, i, 'X');
+ vpaint_do_paint<Color, Traits, domain>(
+ C, sd, vp, vpd, ob, me, brush, symm_pass, 'X', 0, 0);
+ vpaint_do_radial_symmetry<Color, Traits, domain>(
+ C, sd, vp, vpd, ob, me, brush, symm_pass, 'X');
}
if (i & (1 << 1)) {
- vpaint_do_paint<Color, Traits, domain>(C, sd, vp, vpd, ob, me, brush, i, 'Y', 0, 0);
- vpaint_do_radial_symmetry<Color, Traits, domain>(C, sd, vp, vpd, ob, me, brush, i, 'Y');
+ vpaint_do_paint<Color, Traits, domain>(
+ C, sd, vp, vpd, ob, me, brush, symm_pass, 'Y', 0, 0);
+ vpaint_do_radial_symmetry<Color, Traits, domain>(
+ C, sd, vp, vpd, ob, me, brush, symm_pass, 'Y');
}
if (i & (1 << 2)) {
- vpaint_do_paint<Color, Traits, domain>(C, sd, vp, vpd, ob, me, brush, i, 'Z', 0, 0);
- vpaint_do_radial_symmetry<Color, Traits, domain>(C, sd, vp, vpd, ob, me, brush, i, 'Z');
+ vpaint_do_paint<Color, Traits, domain>(
+ C, sd, vp, vpd, ob, me, brush, symm_pass, 'Z', 0, 0);
+ vpaint_do_radial_symmetry<Color, Traits, domain>(
+ C, sd, vp, vpd, ob, me, brush, symm_pass, 'Z');
}
}
}
diff --git a/source/blender/editors/sculpt_paint/paint_vertex_weight_ops.c b/source/blender/editors/sculpt_paint/paint_vertex_weight_ops.c
index fca25ee2e4b..816e779cd06 100644
--- a/source/blender/editors/sculpt_paint/paint_vertex_weight_ops.c
+++ b/source/blender/editors/sculpt_paint/paint_vertex_weight_ops.c
@@ -587,6 +587,7 @@ typedef struct WPGradient_userData {
Scene *scene;
Mesh *me;
MDeformVert *dvert;
+ const bool *select_vert;
Brush *brush;
const float *sco_start; /* [2] */
const float *sco_end; /* [2] */
@@ -683,7 +684,7 @@ static void gradientVertInit__mapFunc(void *userData,
WPGradient_userData *grad_data = userData;
WPGradient_vertStore *vs = &grad_data->vert_cache->elem[index];
- if (grad_data->use_select && !(grad_data->dvert[index].flag & SELECT)) {
+ if (grad_data->use_select && (grad_data->select_vert && !grad_data->select_vert[index])) {
copy_v2_fl(vs->sco, FLT_MAX);
return;
}
@@ -811,6 +812,8 @@ static int paint_weight_gradient_exec(bContext *C, wmOperator *op)
data.scene = scene;
data.me = ob->data;
data.dvert = dverts;
+ data.select_vert = (const bool *)CustomData_get_layer_named(
+ &me->vdata, CD_PROP_BOOL, ".select_vert");
data.sco_start = sco_start;
data.sco_end = sco_end;
data.sco_line_div = 1.0f / len_v2v2(sco_start, sco_end);
diff --git a/source/blender/editors/sculpt_paint/sculpt.c b/source/blender/editors/sculpt_paint/sculpt.cc
index 3477285814e..684fcdbff9e 100644
--- a/source/blender/editors/sculpt_paint/sculpt.c
+++ b/source/blender/editors/sculpt_paint/sculpt.cc
@@ -6,6 +6,10 @@
* Implements the Sculpt Mode tools.
*/
+#include <cmath>
+#include <cstdlib>
+#include <cstring>
+
#include "MEM_guardedalloc.h"
#include "BLI_blenlib.h"
@@ -65,10 +69,6 @@
#include "bmesh.h"
-#include <math.h>
-#include <stdlib.h>
-#include <string.h>
-
/* -------------------------------------------------------------------- */
/** \name Sculpt PBVH Abstraction API
*
@@ -121,7 +121,7 @@ const float *SCULPT_vertex_co_get(SculptSession *ss, PBVHVertRef vertex)
return CCG_elem_co(key, CCG_elem_offset(key, elem, vertex_index));
}
}
- return NULL;
+ return nullptr;
}
bool SCULPT_has_loop_colors(const Object *ob)
@@ -209,9 +209,10 @@ void SCULPT_vertex_limit_surface_get(SculptSession *ss, PBVHVertRef vertex, floa
const int grid_index = vertex.i / key->grid_area;
const int vertex_index = vertex.i - grid_index * key->grid_area;
- SubdivCCGCoord coord = {.grid_index = grid_index,
- .x = vertex_index % key->grid_size,
- .y = vertex_index / key->grid_size};
+ SubdivCCGCoord coord{};
+ coord.grid_index = grid_index;
+ coord.x = vertex_index % key->grid_size;
+ coord.y = vertex_index / key->grid_size;
BKE_subdiv_ccg_eval_limit_point(ss->subdiv_ccg, &coord, r_co);
break;
}
@@ -280,9 +281,9 @@ MVert *SCULPT_mesh_deformed_mverts_get(SculptSession *ss)
return ss->mvert;
case PBVH_BMESH:
case PBVH_GRIDS:
- return NULL;
+ return nullptr;
}
- return NULL;
+ return nullptr;
}
float *SCULPT_brush_deform_target_vertex_co_get(SculptSession *ss,
@@ -351,7 +352,7 @@ bool SCULPT_vertex_visible_get(SculptSession *ss, PBVHVertRef vertex)
switch (BKE_pbvh_type(ss->pbvh)) {
case PBVH_FACES: {
const bool *hide_vert = BKE_pbvh_get_vert_hide(ss->pbvh);
- return hide_vert == NULL || !hide_vert[vertex.i];
+ return hide_vert == nullptr || !hide_vert[vertex.i];
}
case PBVH_BMESH:
return !BM_elem_flag_test((BMVert *)vertex.i, BM_ELEM_HIDDEN);
@@ -370,8 +371,8 @@ bool SCULPT_vertex_visible_get(SculptSession *ss, PBVHVertRef vertex)
void SCULPT_face_set_visibility_set(SculptSession *ss, int face_set, bool visible)
{
- BLI_assert(ss->face_sets != NULL);
- BLI_assert(ss->hide_poly != NULL);
+ BLI_assert(ss->face_sets != nullptr);
+ BLI_assert(ss->hide_poly != nullptr);
switch (BKE_pbvh_type(ss->pbvh)) {
case PBVH_FACES:
case PBVH_GRIDS:
@@ -389,8 +390,8 @@ void SCULPT_face_set_visibility_set(SculptSession *ss, int face_set, bool visibl
void SCULPT_face_visibility_all_invert(SculptSession *ss)
{
- BLI_assert(ss->face_sets != NULL);
- BLI_assert(ss->hide_poly != NULL);
+ BLI_assert(ss->face_sets != nullptr);
+ BLI_assert(ss->hide_poly != nullptr);
switch (BKE_pbvh_type(ss->pbvh)) {
case PBVH_FACES:
case PBVH_GRIDS:
@@ -415,7 +416,7 @@ void SCULPT_face_visibility_all_set(SculptSession *ss, bool visible)
switch (BKE_pbvh_type(ss->pbvh)) {
case PBVH_FACES:
case PBVH_GRIDS:
- BLI_assert(ss->hide_poly != NULL);
+ BLI_assert(ss->hide_poly != nullptr);
memset(ss->hide_poly, !visible, sizeof(bool) * ss->totfaces);
break;
case PBVH_BMESH: {
@@ -509,7 +510,7 @@ void SCULPT_vertex_face_set_set(SculptSession *ss, PBVHVertRef vertex, int face_
{
switch (BKE_pbvh_type(ss->pbvh)) {
case PBVH_FACES: {
- BLI_assert(ss->face_sets != NULL);
+ BLI_assert(ss->face_sets != nullptr);
const MeshElemMap *vert_map = &ss->pmap[vertex.i];
for (int j = 0; j < vert_map->count; j++) {
const int poly_index = vert_map->indices[j];
@@ -524,7 +525,7 @@ void SCULPT_vertex_face_set_set(SculptSession *ss, PBVHVertRef vertex, int face_
case PBVH_BMESH:
break;
case PBVH_GRIDS: {
- BLI_assert(ss->face_sets != NULL);
+ BLI_assert(ss->face_sets != nullptr);
const CCGKey *key = BKE_pbvh_get_grid_key(ss->pbvh);
const int grid_index = vertex.i / key->grid_area;
const int face_index = BKE_subdiv_ccg_grid_to_face_index(ss->subdiv_ccg, grid_index);
@@ -715,9 +716,10 @@ bool SCULPT_vertex_has_unique_face_set(SculptSession *ss, PBVHVertRef vertex)
const CCGKey *key = BKE_pbvh_get_grid_key(ss->pbvh);
const int grid_index = vertex.i / key->grid_area;
const int vertex_index = vertex.i - grid_index * key->grid_area;
- const SubdivCCGCoord coord = {.grid_index = grid_index,
- .x = vertex_index % key->grid_size,
- .y = vertex_index / key->grid_size};
+ SubdivCCGCoord coord{};
+ coord.grid_index = grid_index;
+ coord.x = vertex_index % key->grid_size;
+ coord.y = vertex_index / key->grid_size;
int v1, v2;
const SubdivCCGAdjacencyType adjacency = BKE_subdiv_ccg_coarse_mesh_adjacency_info_get(
ss->subdiv_ccg, &coord, ss->mloop, ss->mpoly, &v1, &v2);
@@ -775,21 +777,23 @@ static void sculpt_vertex_neighbor_add(SculptVertexNeighborIter *iter,
iter->capacity += SCULPT_VERTEX_NEIGHBOR_FIXED_CAPACITY;
if (iter->neighbors == iter->neighbors_fixed) {
- iter->neighbors = MEM_mallocN(iter->capacity * sizeof(PBVHVertRef), "neighbor array");
+ iter->neighbors = static_cast<PBVHVertRef *>(
+ MEM_mallocN(iter->capacity * sizeof(PBVHVertRef), "neighbor array"));
memcpy(iter->neighbors, iter->neighbors_fixed, sizeof(PBVHVertRef) * iter->size);
}
else {
- iter->neighbors = MEM_reallocN_id(
- iter->neighbors, iter->capacity * sizeof(PBVHVertRef), "neighbor array");
+ iter->neighbors = static_cast<PBVHVertRef *>(MEM_reallocN_id(
+ iter->neighbors, iter->capacity * sizeof(PBVHVertRef), "neighbor array"));
}
if (iter->neighbor_indices == iter->neighbor_indices_fixed) {
- iter->neighbor_indices = MEM_mallocN(iter->capacity * sizeof(int), "neighbor array");
+ iter->neighbor_indices = static_cast<int *>(
+ MEM_mallocN(iter->capacity * sizeof(int), "neighbor array"));
memcpy(iter->neighbor_indices, iter->neighbor_indices_fixed, sizeof(int) * iter->size);
}
else {
- iter->neighbor_indices = MEM_reallocN_id(
- iter->neighbor_indices, iter->capacity * sizeof(int), "neighbor array");
+ iter->neighbor_indices = static_cast<int *>(
+ MEM_reallocN_id(iter->neighbor_indices, iter->capacity * sizeof(int), "neighbor array"));
}
}
@@ -849,7 +853,7 @@ static void sculpt_vertex_neighbors_get_faces(SculptSession *ss,
}
if (ss->fake_neighbors.use_fake_neighbors) {
- BLI_assert(ss->fake_neighbors.fake_neighbor_index != NULL);
+ BLI_assert(ss->fake_neighbors.fake_neighbor_index != nullptr);
if (ss->fake_neighbors.fake_neighbor_index[vertex.i] != FAKE_NEIGHBOR_NONE) {
sculpt_vertex_neighbor_add(
iter,
@@ -871,9 +875,10 @@ static void sculpt_vertex_neighbors_get_grids(SculptSession *ss,
const int grid_index = vertex.i / key->grid_area;
const int vertex_index = vertex.i - grid_index * key->grid_area;
- SubdivCCGCoord coord = {.grid_index = grid_index,
- .x = vertex_index % key->grid_size,
- .y = vertex_index / key->grid_size};
+ SubdivCCGCoord coord{};
+ coord.grid_index = grid_index;
+ coord.x = vertex_index % key->grid_size;
+ coord.y = vertex_index / key->grid_size;
SubdivCCGNeighbors neighbors;
BKE_subdiv_ccg_neighbor_coords_get(ss->subdiv_ccg, &coord, include_duplicates, &neighbors);
@@ -892,7 +897,7 @@ static void sculpt_vertex_neighbors_get_grids(SculptSession *ss,
}
if (ss->fake_neighbors.use_fake_neighbors) {
- BLI_assert(ss->fake_neighbors.fake_neighbor_index != NULL);
+ BLI_assert(ss->fake_neighbors.fake_neighbor_index != nullptr);
if (ss->fake_neighbors.fake_neighbor_index[vertex.i] != FAKE_NEIGHBOR_NONE) {
int v = ss->fake_neighbors.fake_neighbor_index[vertex.i];
sculpt_vertex_neighbor_add(iter, BKE_pbvh_make_vref(v), v);
@@ -946,9 +951,10 @@ bool SCULPT_vertex_is_boundary(const SculptSession *ss, const PBVHVertRef vertex
const CCGKey *key = BKE_pbvh_get_grid_key(ss->pbvh);
const int grid_index = vertex.i / key->grid_area;
const int vertex_index = vertex.i - grid_index * key->grid_area;
- const SubdivCCGCoord coord = {.grid_index = grid_index,
- .x = vertex_index % key->grid_size,
- .y = vertex_index / key->grid_size};
+ SubdivCCGCoord coord{};
+ coord.grid_index = grid_index;
+ coord.x = vertex_index % key->grid_size;
+ coord.y = vertex_index / key->grid_size;
int v1, v2;
const SubdivCCGAdjacencyType adjacency = BKE_subdiv_ccg_coarse_mesh_adjacency_info_get(
ss->subdiv_ccg, &coord, ss->mloop, ss->mpoly, &v1, &v2);
@@ -1005,18 +1011,18 @@ bool SCULPT_check_vertex_pivot_symmetry(const float vco[3], const float pco[3],
return is_in_symmetry_area;
}
-typedef struct NearestVertexTLSData {
+struct NearestVertexTLSData {
PBVHVertRef nearest_vertex;
float nearest_vertex_distance_squared;
-} NearestVertexTLSData;
+};
static void do_nearest_vertex_get_task_cb(void *__restrict userdata,
const int n,
const TaskParallelTLS *__restrict tls)
{
- SculptThreadedTaskData *data = userdata;
+ SculptThreadedTaskData *data = static_cast<SculptThreadedTaskData *>(userdata);
SculptSession *ss = data->ob->sculpt;
- NearestVertexTLSData *nvtd = tls->userdata_chunk;
+ NearestVertexTLSData *nvtd = static_cast<NearestVertexTLSData *>(tls->userdata_chunk);
PBVHVertexIter vd;
BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
@@ -1030,12 +1036,12 @@ static void do_nearest_vertex_get_task_cb(void *__restrict userdata,
BKE_pbvh_vertex_iter_end;
}
-static void nearest_vertex_get_reduce(const void *__restrict UNUSED(userdata),
+static void nearest_vertex_get_reduce(const void *__restrict /*userdata*/,
void *__restrict chunk_join,
void *__restrict chunk)
{
- NearestVertexTLSData *join = chunk_join;
- NearestVertexTLSData *nvtd = chunk;
+ NearestVertexTLSData *join = static_cast<NearestVertexTLSData *>(chunk_join);
+ NearestVertexTLSData *nvtd = static_cast<NearestVertexTLSData *>(chunk);
if (join->nearest_vertex.i == PBVH_REF_NONE) {
join->nearest_vertex = nvtd->nearest_vertex;
join->nearest_vertex_distance_squared = nvtd->nearest_vertex_distance_squared;
@@ -1050,26 +1056,24 @@ PBVHVertRef SCULPT_nearest_vertex_get(
Sculpt *sd, Object *ob, const float co[3], float max_distance, bool use_original)
{
SculptSession *ss = ob->sculpt;
- PBVHNode **nodes = NULL;
+ PBVHNode **nodes = nullptr;
int totnode;
- SculptSearchSphereData data = {
- .ss = ss,
- .sd = sd,
- .radius_squared = max_distance * max_distance,
- .original = use_original,
- .center = co,
- };
+ SculptSearchSphereData data{};
+ data.sd = sd;
+ data.radius_squared = max_distance * max_distance;
+ data.original = use_original;
+ data.center = co;
+
BKE_pbvh_search_gather(ss->pbvh, SCULPT_search_sphere_cb, &data, &nodes, &totnode);
if (totnode == 0) {
return BKE_pbvh_make_vref(PBVH_REF_NONE);
}
- SculptThreadedTaskData task_data = {
- .sd = sd,
- .ob = ob,
- .nodes = nodes,
- .max_distance_squared = max_distance * max_distance,
- };
+ SculptThreadedTaskData task_data{};
+ task_data.sd = sd;
+ task_data.ob = ob;
+ task_data.nodes = nodes;
+ task_data.max_distance_squared = max_distance * max_distance;
copy_v3_v3(task_data.nearest_vertex_search_co, co);
NearestVertexTLSData nvtd;
@@ -1103,7 +1107,7 @@ bool SCULPT_is_vertex_inside_brush_radius_symm(const float vertex[3],
continue;
}
float location[3];
- flip_v3_v3(location, br_co, (char)i);
+ flip_v3_v3(location, br_co, ePaintSymmetryFlags(i));
if (len_squared_v3v3(location, vertex) < radius * radius) {
return true;
}
@@ -1176,7 +1180,7 @@ void SCULPT_floodfill_add_initial_with_symmetry(Sculpt *sd,
else if (radius > 0.0f) {
float radius_squared = (radius == FLT_MAX) ? FLT_MAX : radius * radius;
float location[3];
- flip_v3_v3(location, SCULPT_vertex_co_get(ss, vertex), i);
+ flip_v3_v3(location, SCULPT_vertex_co_get(ss, vertex), ePaintSymmetryFlags(i));
v = SCULPT_nearest_vertex_get(sd, ob, location, radius_squared, false);
}
@@ -1203,7 +1207,7 @@ void SCULPT_floodfill_add_active(
}
else if (radius > 0.0f) {
float location[3];
- flip_v3_v3(location, SCULPT_active_vertex_co_get(ss), i);
+ flip_v3_v3(location, SCULPT_active_vertex_co_get(ss), ePaintSymmetryFlags(i));
v = SCULPT_nearest_vertex_get(sd, ob, location, radius, false);
}
@@ -1253,7 +1257,7 @@ void SCULPT_floodfill_free(SculptFloodFill *flood)
{
MEM_SAFE_FREE(flood->visited_verts);
BLI_gsqueue_free(flood->queue);
- flood->queue = NULL;
+ flood->queue = nullptr;
}
/** \} */
@@ -1302,7 +1306,7 @@ static bool sculpt_tool_is_proxy_used(const char sculpt_tool)
static bool sculpt_brush_use_topology_rake(const SculptSession *ss, const Brush *brush)
{
return SCULPT_TOOL_HAS_TOPOLOGY_RAKE(brush->sculpt_tool) &&
- (brush->topology_rake_factor > 0.0f) && (ss->bm != NULL);
+ (brush->topology_rake_factor > 0.0f) && (ss->bm != nullptr);
}
/**
@@ -1340,11 +1344,11 @@ static bool sculpt_brush_needs_rake_rotation(const Brush *brush)
/** \name Sculpt Init/Update
* \{ */
-typedef enum StrokeFlags {
+enum StrokeFlags {
CLIP_X = 1,
CLIP_Y = 2,
CLIP_Z = 4,
-} StrokeFlags;
+};
void SCULPT_orig_vert_data_unode_init(SculptOrigVertData *data, Object *ob, SculptUndoNode *unode)
{
@@ -1399,7 +1403,7 @@ void SCULPT_orig_vert_data_update(SculptOrigVertData *orig_data, PBVHVertexIter
}
}
-static void sculpt_rake_data_update(struct SculptRakeData *srd, const float co[3])
+static void sculpt_rake_data_update(SculptRakeData *srd, const float co[3])
{
float rake_dist = len_v3v3(srd->follow_co, co);
if (rake_dist > srd->follow_dist) {
@@ -1434,9 +1438,9 @@ bool SCULPT_stroke_is_dynamic_topology(const SculptSession *ss, const Brush *bru
static void paint_mesh_restore_co_task_cb(void *__restrict userdata,
const int n,
- const TaskParallelTLS *__restrict UNUSED(tls))
+ const TaskParallelTLS *__restrict /*tls*/)
{
- SculptThreadedTaskData *data = userdata;
+ SculptThreadedTaskData *data = static_cast<SculptThreadedTaskData *>(userdata);
SculptSession *ss = data->ob->sculpt;
SculptUndoNode *unode;
@@ -1518,19 +1522,18 @@ static void paint_mesh_restore_co(Sculpt *sd, Object *ob)
PBVHNode **nodes;
int totnode;
- BKE_pbvh_search_gather(ss->pbvh, NULL, NULL, &nodes, &totnode);
+ BKE_pbvh_search_gather(ss->pbvh, nullptr, nullptr, &nodes, &totnode);
/**
* Disable multi-threading when dynamic-topology is enabled. Otherwise,
* new entries might be inserted by #SCULPT_undo_push_node() into the #GHash
* used internally by #BM_log_original_vert_co() by a different thread. See T33787.
*/
- SculptThreadedTaskData data = {
- .sd = sd,
- .ob = ob,
- .brush = brush,
- .nodes = nodes,
- };
+ SculptThreadedTaskData data{};
+ data.sd = sd;
+ data.ob = ob;
+ data.brush = brush;
+ data.nodes = nodes;
TaskParallelSettings settings;
BKE_pbvh_parallel_range_settings(&settings, true && !ss->bm, totnode);
@@ -1624,7 +1627,7 @@ void SCULPT_brush_test_init(SculptSession *ss, SculptBrushTest *test)
}
else {
copy_v3_v3(test->location, ss->cursor_location);
- test->mirror_symmetry_pass = 0;
+ test->mirror_symmetry_pass = ePaintSymmetryFlags(0);
test->radial_symmetry_pass = 0;
unit_m4(test->symm_rot_mat_inv);
}
@@ -1640,7 +1643,7 @@ void SCULPT_brush_test_init(SculptSession *ss, SculptBrushTest *test)
test->clip_rv3d = rv3d;
}
else {
- test->clip_rv3d = NULL;
+ test->clip_rv3d = nullptr;
}
}
@@ -1837,7 +1840,10 @@ static bool sculpt_brush_test_cyl(SculptBrushTest *test,
/* ===== Sculpting =====
*/
-static float calc_overlap(StrokeCache *cache, const char symm, const char axis, const float angle)
+static float calc_overlap(StrokeCache *cache,
+ const ePaintSymmetryFlags symm,
+ const char axis,
+ const float angle)
{
float mirror[3];
float distsq;
@@ -1860,7 +1866,7 @@ static float calc_overlap(StrokeCache *cache, const char symm, const char axis,
static float calc_radial_symmetry_feather(Sculpt *sd,
StrokeCache *cache,
- const char symm,
+ const ePaintSymmetryFlags symm,
const char axis)
{
float overlap = 0.0f;
@@ -1887,11 +1893,11 @@ static float calc_symmetry_feather(Sculpt *sd, StrokeCache *cache)
continue;
}
- overlap += calc_overlap(cache, i, 0, 0);
+ overlap += calc_overlap(cache, ePaintSymmetryFlags(i), 0, 0);
- overlap += calc_radial_symmetry_feather(sd, cache, i, 'X');
- overlap += calc_radial_symmetry_feather(sd, cache, i, 'Y');
- overlap += calc_radial_symmetry_feather(sd, cache, i, 'Z');
+ overlap += calc_radial_symmetry_feather(sd, cache, ePaintSymmetryFlags(i), 'X');
+ overlap += calc_radial_symmetry_feather(sd, cache, ePaintSymmetryFlags(i), 'Y');
+ overlap += calc_radial_symmetry_feather(sd, cache, ePaintSymmetryFlags(i), 'Z');
}
return 1.0f / overlap;
}
@@ -1912,26 +1918,26 @@ static float calc_symmetry_feather(Sculpt *sd, StrokeCache *cache)
* \note These are all _very_ similar, when changing one, check others.
* \{ */
-typedef struct AreaNormalCenterTLSData {
+struct AreaNormalCenterTLSData {
/* 0 = towards view, 1 = flipped */
float area_cos[2][3];
float area_nos[2][3];
int count_no[2];
int count_co[2];
-} AreaNormalCenterTLSData;
+};
static void calc_area_normal_and_center_task_cb(void *__restrict userdata,
const int n,
const TaskParallelTLS *__restrict tls)
{
- SculptThreadedTaskData *data = userdata;
+ SculptThreadedTaskData *data = static_cast<SculptThreadedTaskData *>(userdata);
SculptSession *ss = data->ob->sculpt;
- AreaNormalCenterTLSData *anctd = tls->userdata_chunk;
+ AreaNormalCenterTLSData *anctd = static_cast<AreaNormalCenterTLSData *>(tls->userdata_chunk);
const bool use_area_nos = data->use_area_nos;
const bool use_area_cos = data->use_area_cos;
PBVHVertexIter vd;
- SculptUndoNode *unode = NULL;
+ SculptUndoNode *unode = nullptr;
bool use_original = false;
bool normal_test_r, area_test_r;
@@ -1982,7 +1988,8 @@ static void calc_area_normal_and_center_task_cb(void *__restrict userdata,
int(*orco_tris)[3];
int orco_tris_num;
- BKE_pbvh_node_get_bm_orco_data(data->nodes[n], &orco_tris, &orco_tris_num, &orco_coords, NULL);
+ BKE_pbvh_node_get_bm_orco_data(
+ data->nodes[n], &orco_tris, &orco_tris_num, &orco_coords, nullptr);
for (int i = 0; i < orco_tris_num; i++) {
const float *co_tri[3] = {
@@ -2109,12 +2116,12 @@ static void calc_area_normal_and_center_task_cb(void *__restrict userdata,
}
}
-static void calc_area_normal_and_center_reduce(const void *__restrict UNUSED(userdata),
+static void calc_area_normal_and_center_reduce(const void *__restrict /*userdata*/,
void *__restrict chunk_join,
void *__restrict chunk)
{
- AreaNormalCenterTLSData *join = chunk_join;
- AreaNormalCenterTLSData *anctd = chunk;
+ AreaNormalCenterTLSData *join = static_cast<AreaNormalCenterTLSData *>(chunk_join);
+ AreaNormalCenterTLSData *anctd = static_cast<AreaNormalCenterTLSData *>(chunk);
/* For flatten center. */
add_v3_v3(join->area_cos[0], anctd->area_cos[0]);
@@ -2137,16 +2144,15 @@ void SCULPT_calc_area_center(
const bool has_bm_orco = ss->bm && SCULPT_stroke_is_dynamic_topology(ss, brush);
int n;
- /* Intentionally set 'sd' to NULL since we share logic with vertex paint. */
- SculptThreadedTaskData data = {
- .sd = NULL,
- .ob = ob,
- .brush = brush,
- .nodes = nodes,
- .totnode = totnode,
- .has_bm_orco = has_bm_orco,
- .use_area_cos = true,
- };
+ /* Intentionally set 'sd' to nullptr since we share logic with vertex paint. */
+ SculptThreadedTaskData data{};
+ data.sd = nullptr;
+ data.ob = ob;
+ data.brush = brush;
+ data.nodes = nodes;
+ data.totnode = totnode;
+ data.has_bm_orco = has_bm_orco;
+ data.use_area_cos = true;
AreaNormalCenterTLSData anctd = {{{0}}};
@@ -2195,17 +2201,16 @@ bool SCULPT_pbvh_calc_area_normal(const Brush *brush,
SculptSession *ss = ob->sculpt;
const bool has_bm_orco = ss->bm && SCULPT_stroke_is_dynamic_topology(ss, brush);
- /* Intentionally set 'sd' to NULL since this is used for vertex paint too. */
- SculptThreadedTaskData data = {
- .sd = NULL,
- .ob = ob,
- .brush = brush,
- .nodes = nodes,
- .totnode = totnode,
- .has_bm_orco = has_bm_orco,
- .use_area_nos = true,
- .any_vertex_sampled = false,
- };
+ /* Intentionally set 'sd' to nullptr since this is used for vertex paint too. */
+ SculptThreadedTaskData data{};
+ data.sd = nullptr;
+ data.ob = ob;
+ data.brush = brush;
+ data.nodes = nodes;
+ data.totnode = totnode;
+ data.has_bm_orco = has_bm_orco;
+ data.use_area_nos = true;
+ data.any_vertex_sampled = false;
AreaNormalCenterTLSData anctd = {{{0}}};
@@ -2234,17 +2239,16 @@ void SCULPT_calc_area_normal_and_center(
const bool has_bm_orco = ss->bm && SCULPT_stroke_is_dynamic_topology(ss, brush);
int n;
- /* Intentionally set 'sd' to NULL since this is used for vertex paint too. */
- SculptThreadedTaskData data = {
- .sd = NULL,
- .ob = ob,
- .brush = brush,
- .nodes = nodes,
- .totnode = totnode,
- .has_bm_orco = has_bm_orco,
- .use_area_cos = true,
- .use_area_nos = true,
- };
+ /* Intentionally set 'sd' to nullptr since this is used for vertex paint too. */
+ SculptThreadedTaskData data{};
+ data.sd = nullptr;
+ data.ob = ob;
+ data.brush = brush;
+ data.nodes = nodes;
+ data.totnode = totnode;
+ data.has_bm_orco = has_bm_orco;
+ data.use_area_cos = true;
+ data.use_area_nos = true;
AreaNormalCenterTLSData anctd = {{{0}}};
@@ -2298,7 +2302,7 @@ static float brush_strength(const Sculpt *sd,
const StrokeCache *cache,
const float feather,
const UnifiedPaintSettings *ups,
- const PaintModeSettings *UNUSED(paint_mode_settings))
+ const PaintModeSettings * /*paint_mode_settings*/)
{
const Scene *scene = cache->vc->scene;
const Brush *brush = BKE_paint_brush((Paint *)&sd->paint);
@@ -2545,7 +2549,7 @@ float SCULPT_brush_strength_factor(SculptSession *ss,
bool SCULPT_search_sphere_cb(PBVHNode *node, void *data_v)
{
- SculptSearchSphereData *data = data_v;
+ SculptSearchSphereData *data = static_cast<SculptSearchSphereData *>(data_v);
const float *center;
float nearest[3];
if (data->center) {
@@ -2591,7 +2595,7 @@ bool SCULPT_search_sphere_cb(PBVHNode *node, void *data_v)
bool SCULPT_search_circle_cb(PBVHNode *node, void *data_v)
{
- SculptSearchCircleData *data = data_v;
+ SculptSearchCircleData *data = static_cast<SculptSearchCircleData *>(data_v);
float bb_min[3], bb_max[3];
if (data->ignore_fully_ineffective) {
@@ -2653,15 +2657,14 @@ static PBVHNode **sculpt_pbvh_gather_cursor_update(Object *ob,
int *r_totnode)
{
SculptSession *ss = ob->sculpt;
- PBVHNode **nodes = NULL;
- SculptSearchSphereData data = {
- .ss = ss,
- .sd = sd,
- .radius_squared = ss->cursor_radius,
- .original = use_original,
- .ignore_fully_ineffective = false,
- .center = NULL,
- };
+ PBVHNode **nodes = nullptr;
+ SculptSearchSphereData data{};
+ data.ss = ss;
+ data.sd = sd;
+ data.radius_squared = ss->cursor_radius;
+ data.original = use_original;
+ data.ignore_fully_ineffective = false;
+ data.center = nullptr;
BKE_pbvh_search_gather(ss->pbvh, SCULPT_search_sphere_cb, &data, &nodes, r_totnode);
return nodes;
}
@@ -2674,34 +2677,32 @@ static PBVHNode **sculpt_pbvh_gather_generic(Object *ob,
int *r_totnode)
{
SculptSession *ss = ob->sculpt;
- PBVHNode **nodes = NULL;
+ PBVHNode **nodes = nullptr;
/* Build a list of all nodes that are potentially within the cursor or brush's area of influence.
*/
if (brush->falloff_shape == PAINT_FALLOFF_SHAPE_SPHERE) {
- SculptSearchSphereData data = {
- .ss = ss,
- .sd = sd,
- .radius_squared = square_f(ss->cache->radius * radius_scale),
- .original = use_original,
- .ignore_fully_ineffective = brush->sculpt_tool != SCULPT_TOOL_MASK,
- .center = NULL,
- };
+ SculptSearchSphereData data{};
+ data.ss = ss;
+ data.sd = sd;
+ data.radius_squared = square_f(ss->cache->radius * radius_scale);
+ data.original = use_original;
+ data.ignore_fully_ineffective = brush->sculpt_tool != SCULPT_TOOL_MASK;
+ data.center = nullptr;
BKE_pbvh_search_gather(ss->pbvh, SCULPT_search_sphere_cb, &data, &nodes, r_totnode);
}
else {
- struct DistRayAABB_Precalc dist_ray_to_aabb_precalc;
+ DistRayAABB_Precalc dist_ray_to_aabb_precalc;
dist_squared_ray_to_aabb_v3_precalc(
&dist_ray_to_aabb_precalc, ss->cache->location, ss->cache->view_normal);
- SculptSearchCircleData data = {
- .ss = ss,
- .sd = sd,
- .radius_squared = ss->cache ? square_f(ss->cache->radius * radius_scale) :
- ss->cursor_radius,
- .original = use_original,
- .dist_ray_to_aabb_precalc = &dist_ray_to_aabb_precalc,
- .ignore_fully_ineffective = brush->sculpt_tool != SCULPT_TOOL_MASK,
- };
+ SculptSearchCircleData data{};
+ data.ss = ss;
+ data.sd = sd;
+ data.radius_squared = ss->cache ? square_f(ss->cache->radius * radius_scale) :
+ ss->cursor_radius;
+ data.original = use_original;
+ data.dist_ray_to_aabb_precalc = &dist_ray_to_aabb_precalc;
+ data.ignore_fully_ineffective = brush->sculpt_tool != SCULPT_TOOL_MASK;
BKE_pbvh_search_gather(ss->pbvh, SCULPT_search_circle_cb, &data, &nodes, r_totnode);
}
return nodes;
@@ -2899,7 +2900,7 @@ static void sculpt_pbvh_update_pixels(PaintModeSettings *paint_mode_settings,
/** \name Generic Brush Plane & Symmetry Utilities
* \{ */
-typedef struct {
+struct SculptRaycastData {
SculptSession *ss;
const float *ray_start;
const float *ray_normal;
@@ -2912,21 +2913,21 @@ typedef struct {
int active_face_grid_index;
- struct IsectRayPrecalc isect_precalc;
-} SculptRaycastData;
+ IsectRayPrecalc isect_precalc;
+};
-typedef struct {
+struct SculptFindNearestToRayData {
SculptSession *ss;
const float *ray_start, *ray_normal;
bool hit;
float depth;
float dist_sq_to_ray;
bool original;
-} SculptFindNearestToRayData;
+};
ePaintSymmetryAreas SCULPT_get_vertex_symm_area(const float co[3])
{
- ePaintSymmetryAreas symm_area = PAINT_SYMM_AREA_DEFAULT;
+ ePaintSymmetryAreas symm_area = ePaintSymmetryAreas(PAINT_SYMM_AREA_DEFAULT);
if (co[0] < 0.0f) {
symm_area |= PAINT_SYMM_AREA_X;
}
@@ -2945,7 +2946,7 @@ void SCULPT_flip_v3_by_symm_area(float v[3],
const float pivot[3])
{
for (int i = 0; i < 3; i++) {
- ePaintSymmetryFlags symm_it = 1 << i;
+ ePaintSymmetryFlags symm_it = ePaintSymmetryFlags(1 << i);
if (!(symm & symm_it)) {
continue;
}
@@ -2964,7 +2965,7 @@ void SCULPT_flip_quat_by_symm_area(float quat[4],
const float pivot[3])
{
for (int i = 0; i < 3; i++) {
- ePaintSymmetryFlags symm_it = 1 << i;
+ ePaintSymmetryFlags symm_it = ePaintSymmetryFlags(1 << i);
if (!(symm & symm_it)) {
continue;
}
@@ -3101,7 +3102,7 @@ static void do_gravity_task_cb_ex(void *__restrict userdata,
const int n,
const TaskParallelTLS *__restrict tls)
{
- SculptThreadedTaskData *data = userdata;
+ SculptThreadedTaskData *data = static_cast<SculptThreadedTaskData *>(userdata);
SculptSession *ss = data->ob->sculpt;
const Brush *brush = data->brush;
float *offset = data->offset;
@@ -3129,7 +3130,7 @@ static void do_gravity_task_cb_ex(void *__restrict userdata,
vd.mask ? *vd.mask : 0.0f,
vd.vertex,
thread_id,
- NULL);
+ nullptr);
mul_v3_v3fl(proxy[vd.i], offset, fade);
@@ -3155,13 +3156,12 @@ static void do_gravity(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode, fl
mul_v3_fl(offset, bstrength);
/* Threaded loop over nodes. */
- SculptThreadedTaskData data = {
- .sd = sd,
- .ob = ob,
- .brush = brush,
- .nodes = nodes,
- .offset = offset,
- };
+ SculptThreadedTaskData data{};
+ data.sd = sd;
+ data.ob = ob;
+ data.brush = brush;
+ data.nodes = nodes;
+ data.offset = offset;
TaskParallelSettings settings;
BKE_pbvh_parallel_range_settings(&settings, true, totnode);
@@ -3177,10 +3177,9 @@ static void do_gravity(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode, fl
void SCULPT_vertcos_to_key(Object *ob, KeyBlock *kb, const float (*vertCos)[3])
{
Mesh *me = (Mesh *)ob->data;
- float(*ofs)[3] = NULL;
+ float(*ofs)[3] = nullptr;
int a;
const int kb_act_idx = ob->shapenr - 1;
- KeyBlock *currkey;
/* For relative keys editing of base should update other keys. */
if (BKE_keyblock_is_basis(me->key, kb_act_idx)) {
@@ -3192,7 +3191,7 @@ void SCULPT_vertcos_to_key(Object *ob, KeyBlock *kb, const float (*vertCos)[3])
}
/* Apply offsets on other keys. */
- for (currkey = me->key->block.first; currkey; currkey = currkey->next) {
+ LISTBASE_FOREACH (KeyBlock *, currkey, &me->key->block) {
if ((currkey != kb) && (currkey->relative == kb_act_idx)) {
BKE_keyblock_update_from_offset(ob, currkey, ofs);
}
@@ -3221,8 +3220,8 @@ void SCULPT_vertcos_to_key(Object *ob, KeyBlock *kb, const float (*vertCos)[3])
static void sculpt_topology_update(Sculpt *sd,
Object *ob,
Brush *brush,
- UnifiedPaintSettings *UNUSED(ups),
- PaintModeSettings *UNUSED(paint_mode_settings))
+ UnifiedPaintSettings * /*ups*/,
+ PaintModeSettings * /*paint_mode_settings*/)
{
SculptSession *ss = ob->sculpt;
@@ -3244,7 +3243,7 @@ static void sculpt_topology_update(Sculpt *sd,
MEM_SAFE_FREE(ss->vertex_info.boundary);
MEM_SAFE_FREE(ss->vertex_info.connected_component);
- PBVHTopologyUpdateMode mode = 0;
+ PBVHTopologyUpdateMode mode = PBVHTopologyUpdateMode(0);
float location[3];
if (!(sd->flags & SCULPT_DYNTOPO_DETAIL_MANUAL)) {
@@ -3289,9 +3288,9 @@ static void sculpt_topology_update(Sculpt *sd,
static void do_brush_action_task_cb(void *__restrict userdata,
const int n,
- const TaskParallelTLS *__restrict UNUSED(tls))
+ const TaskParallelTLS *__restrict /*tls*/)
{
- SculptThreadedTaskData *data = userdata;
+ SculptThreadedTaskData *data = static_cast<SculptThreadedTaskData *>(userdata);
SculptSession *ss = data->ob->sculpt;
bool need_coords = ss->cache->supports_gravity;
@@ -3347,7 +3346,7 @@ static void do_brush_action(Sculpt *sd,
if (SCULPT_tool_needs_all_pbvh_nodes(brush)) {
/* These brushes need to update all nodes as they are not constrained by the brush radius */
- BKE_pbvh_search_gather(ss->pbvh, NULL, NULL, &nodes, &totnode);
+ BKE_pbvh_search_gather(ss->pbvh, nullptr, nullptr, &nodes, &totnode);
}
else if (brush->sculpt_tool == SCULPT_TOOL_CLOTH) {
nodes = SCULPT_cloth_brush_affected_nodes_gather(ss, brush, &totnode);
@@ -3385,7 +3384,7 @@ static void do_brush_action(Sculpt *sd,
/* TODO(pablodp606): This check should be done in the undo code and not here, but the rest of
* the sculpt code is not checking for unsupported undo types that may return a null node. */
if (BKE_pbvh_type(ss->pbvh) != PBVH_BMESH) {
- SCULPT_undo_push_node(ob, NULL, SCULPT_UNDO_FACE_SETS);
+ SCULPT_undo_push_node(ob, nullptr, SCULPT_UNDO_FACE_SETS);
}
if (ss->cache->invert) {
@@ -3412,9 +3411,9 @@ static void do_brush_action(Sculpt *sd,
/* Initialize surface smooth cache. */
if ((brush->sculpt_tool == SCULPT_TOOL_SMOOTH) &&
(brush->smooth_deform_type == BRUSH_SMOOTH_DEFORM_SURFACE)) {
- BLI_assert(ss->cache->surface_smooth_laplacian_disp == NULL);
- ss->cache->surface_smooth_laplacian_disp = MEM_callocN(
- sizeof(float[3]) * SCULPT_vertex_count_get(ss), "HC smooth laplacian b");
+ BLI_assert(ss->cache->surface_smooth_laplacian_disp == nullptr);
+ ss->cache->surface_smooth_laplacian_disp = static_cast<float(*)[3]>(
+ MEM_callocN(sizeof(float[3]) * SCULPT_vertex_count_get(ss), "HC smooth laplacian b"));
}
}
}
@@ -3426,12 +3425,11 @@ static void do_brush_action(Sculpt *sd,
float location[3];
if (!use_pixels) {
- SculptThreadedTaskData task_data = {
- .sd = sd,
- .ob = ob,
- .brush = brush,
- .nodes = nodes,
- };
+ SculptThreadedTaskData task_data{};
+ task_data.sd = sd;
+ task_data.ob = ob;
+ task_data.brush = brush;
+ task_data.nodes = nodes;
TaskParallelSettings settings;
BKE_pbvh_parallel_range_settings(&settings, true, totnode);
@@ -3627,7 +3625,7 @@ static void do_brush_action(Sculpt *sd,
static void sculpt_flush_pbvhvert_deform(Object *ob, PBVHVertexIter *vd)
{
SculptSession *ss = ob->sculpt;
- Mesh *me = ob->data;
+ Mesh *me = static_cast<Mesh *>(ob->data);
float disp[3], newco[3];
int index = vd->vert_indices[vd->i];
@@ -3646,9 +3644,9 @@ static void sculpt_flush_pbvhvert_deform(Object *ob, PBVHVertexIter *vd)
static void sculpt_combine_proxies_task_cb(void *__restrict userdata,
const int n,
- const TaskParallelTLS *__restrict UNUSED(tls))
+ const TaskParallelTLS *__restrict /*tls*/)
{
- SculptThreadedTaskData *data = userdata;
+ SculptThreadedTaskData *data = static_cast<SculptThreadedTaskData *>(userdata);
SculptSession *ss = data->ob->sculpt;
Sculpt *sd = data->sd;
Object *ob = data->ob;
@@ -3657,7 +3655,7 @@ static void sculpt_combine_proxies_task_cb(void *__restrict userdata,
PBVHVertexIter vd;
PBVHProxyNode *proxies;
int proxy_count;
- float(*orco)[3] = NULL;
+ float(*orco)[3] = nullptr;
if (use_orco && !ss->bm) {
orco = SCULPT_undo_push_node(data->ob, data->nodes[n], SCULPT_UNDO_COORDS)->co;
@@ -3718,13 +3716,12 @@ static void sculpt_combine_proxies(Sculpt *sd, Object *ob)
BKE_pbvh_gather_proxies(ss->pbvh, &nodes, &totnode);
- SculptThreadedTaskData data = {
- .sd = sd,
- .ob = ob,
- .brush = brush,
- .nodes = nodes,
- .use_proxies_orco = use_orco,
- };
+ SculptThreadedTaskData data{};
+ data.sd = sd;
+ data.ob = ob;
+ data.brush = brush;
+ data.nodes = nodes;
+ data.use_proxies_orco = use_orco;
TaskParallelSettings settings;
BKE_pbvh_parallel_range_settings(&settings, true, totnode);
@@ -3739,12 +3736,11 @@ void SCULPT_combine_transform_proxies(Sculpt *sd, Object *ob)
int totnode;
BKE_pbvh_gather_proxies(ss->pbvh, &nodes, &totnode);
- SculptThreadedTaskData data = {
- .sd = sd,
- .ob = ob,
- .nodes = nodes,
- .use_proxies_orco = false,
- };
+ SculptThreadedTaskData data{};
+ data.sd = sd;
+ data.ob = ob;
+ data.nodes = nodes;
+ data.use_proxies_orco = false;
TaskParallelSettings settings;
BKE_pbvh_parallel_range_settings(&settings, true, totnode);
@@ -3783,9 +3779,9 @@ static void sculpt_update_keyblock(Object *ob)
static void SCULPT_flush_stroke_deform_task_cb(void *__restrict userdata,
const int n,
- const TaskParallelTLS *__restrict UNUSED(tls))
+ const TaskParallelTLS *__restrict /*tls*/)
{
- SculptThreadedTaskData *data = userdata;
+ SculptThreadedTaskData *data = static_cast<SculptThreadedTaskData *>(userdata);
SculptSession *ss = data->ob->sculpt;
Object *ob = data->ob;
float(*vertCos)[3] = data->vertCos;
@@ -3817,25 +3813,25 @@ void SCULPT_flush_stroke_deform(Sculpt *sd, Object *ob, bool is_proxy_used)
int totnode;
Mesh *me = (Mesh *)ob->data;
PBVHNode **nodes;
- float(*vertCos)[3] = NULL;
+ float(*vertCos)[3] = nullptr;
if (ss->shapekey_active) {
- vertCos = MEM_mallocN(sizeof(*vertCos) * me->totvert, "flushStrokeDeofrm keyVerts");
+ vertCos = static_cast<float(*)[3]>(
+ MEM_mallocN(sizeof(*vertCos) * me->totvert, "flushStrokeDeofrm keyVerts"));
/* Mesh could have isolated verts which wouldn't be in BVH, to deal with this we copy old
* coordinates over new ones and then update coordinates for all vertices from BVH. */
memcpy(vertCos, ss->orig_cos, sizeof(*vertCos) * me->totvert);
}
- BKE_pbvh_search_gather(ss->pbvh, NULL, NULL, &nodes, &totnode);
+ BKE_pbvh_search_gather(ss->pbvh, nullptr, nullptr, &nodes, &totnode);
- SculptThreadedTaskData data = {
- .sd = sd,
- .ob = ob,
- .brush = brush,
- .nodes = nodes,
- .vertCos = vertCos,
- };
+ SculptThreadedTaskData data{};
+ data.sd = sd;
+ data.ob = ob;
+ data.brush = brush;
+ data.nodes = nodes;
+ data.vertCos = vertCos;
TaskParallelSettings settings;
BKE_pbvh_parallel_range_settings(&settings, true, totnode);
@@ -3854,7 +3850,7 @@ void SCULPT_flush_stroke_deform(Sculpt *sd, Object *ob, bool is_proxy_used)
}
void SCULPT_cache_calc_brushdata_symm(StrokeCache *cache,
- const char symm,
+ const ePaintSymmetryFlags symm,
const char axis,
const float angle)
{
@@ -3904,11 +3900,11 @@ void SCULPT_cache_calc_brushdata_symm(StrokeCache *cache,
}
}
-typedef void (*BrushActionFunc)(Sculpt *sd,
- Object *ob,
- Brush *brush,
- UnifiedPaintSettings *ups,
- PaintModeSettings *paint_mode_settings);
+using BrushActionFunc = void (*)(Sculpt *sd,
+ Object *ob,
+ Brush *brush,
+ UnifiedPaintSettings *ups,
+ PaintModeSettings *paint_mode_settings);
static void do_tiled(Sculpt *sd,
Object *ob,
@@ -3980,9 +3976,9 @@ static void do_radial_symmetry(Sculpt *sd,
UnifiedPaintSettings *ups,
PaintModeSettings *paint_mode_settings,
BrushActionFunc action,
- const char symm,
+ const ePaintSymmetryFlags symm,
const int axis,
- const float UNUSED(feather))
+ const float /*feather*/)
{
SculptSession *ss = ob->sculpt;
@@ -4031,15 +4027,16 @@ static void do_symmetrical_brush_actions(Sculpt *sd,
if (!SCULPT_is_symmetry_iteration_valid(i, symm)) {
continue;
}
- cache->mirror_symmetry_pass = i;
+ const ePaintSymmetryFlags symm = ePaintSymmetryFlags(i);
+ cache->mirror_symmetry_pass = symm;
cache->radial_symmetry_pass = 0;
- SCULPT_cache_calc_brushdata_symm(cache, i, 0, 0);
+ SCULPT_cache_calc_brushdata_symm(cache, symm, 0, 0);
do_tiled(sd, ob, brush, ups, paint_mode_settings, action);
- do_radial_symmetry(sd, ob, brush, ups, paint_mode_settings, action, i, 'X', feather);
- do_radial_symmetry(sd, ob, brush, ups, paint_mode_settings, action, i, 'Y', feather);
- do_radial_symmetry(sd, ob, brush, ups, paint_mode_settings, action, i, 'Z', feather);
+ do_radial_symmetry(sd, ob, brush, ups, paint_mode_settings, action, symm, 'X', feather);
+ do_radial_symmetry(sd, ob, brush, ups, paint_mode_settings, action, symm, 'Y', feather);
+ do_radial_symmetry(sd, ob, brush, ups, paint_mode_settings, action, symm, 'Z', feather);
}
}
@@ -4172,11 +4169,9 @@ void SCULPT_cache_free(StrokeCache *cache)
/* Initialize mirror modifier clipping. */
static void sculpt_init_mirror_clipping(Object *ob, SculptSession *ss)
{
- ModifierData *md;
-
unit_m4(ss->cache->clip_mirror_mtx);
- for (md = ob->modifiers.first; md; md = md->next) {
+ LISTBASE_FOREACH (ModifierData *, md, &ob->modifiers) {
if (!(md->type == eModifierType_Mirror && (md->mode & eModifierMode_Realtime))) {
continue;
}
@@ -4272,11 +4267,12 @@ static void smooth_brush_toggle_off(const bContext *C, Paint *paint, StrokeCache
static void sculpt_update_cache_invariants(
bContext *C, Sculpt *sd, SculptSession *ss, wmOperator *op, const float mval[2])
{
- StrokeCache *cache = MEM_callocN(sizeof(StrokeCache), "stroke cache");
+ StrokeCache *cache = static_cast<StrokeCache *>(
+ MEM_callocN(sizeof(StrokeCache), "stroke cache"));
ToolSettings *tool_settings = CTX_data_tool_settings(C);
UnifiedPaintSettings *ups = &tool_settings->unified_paint_settings;
Brush *brush = BKE_paint_brush(&sd->paint);
- ViewContext *vc = paint_stroke_view_context(op->customdata);
+ ViewContext *vc = paint_stroke_view_context(static_cast<PaintStroke *>(op->customdata));
Object *ob = CTX_data_active_object(C);
float mat[3][3];
float viewDir[3] = {0.0f, 0.0f, 1.0f};
@@ -4830,8 +4826,8 @@ static void sculpt_raycast_cb(PBVHNode *node, void *data_v, float *tmin)
if (BKE_pbvh_node_get_tmin(node) >= *tmin) {
return;
}
- SculptRaycastData *srd = data_v;
- float(*origco)[3] = NULL;
+ SculptRaycastData *srd = static_cast<SculptRaycastData *>(data_v);
+ float(*origco)[3] = nullptr;
bool use_origco = false;
if (srd->original && srd->ss->cache) {
@@ -4841,7 +4837,7 @@ static void sculpt_raycast_cb(PBVHNode *node, void *data_v, float *tmin)
else {
/* Intersect with coordinates from before we started stroke. */
SculptUndoNode *unode = SCULPT_undo_get_node(node, SCULPT_UNDO_COORDS);
- origco = (unode) ? unode->co : NULL;
+ origco = (unode) ? unode->co : nullptr;
use_origco = origco ? true : false;
}
}
@@ -4867,8 +4863,8 @@ static void sculpt_find_nearest_to_ray_cb(PBVHNode *node, void *data_v, float *t
if (BKE_pbvh_node_get_tmin(node) >= *tmin) {
return;
}
- SculptFindNearestToRayData *srd = data_v;
- float(*origco)[3] = NULL;
+ SculptFindNearestToRayData *srd = static_cast<SculptFindNearestToRayData *>(data_v);
+ float(*origco)[3] = nullptr;
bool use_origco = false;
if (srd->original && srd->ss->cache) {
@@ -4878,7 +4874,7 @@ static void sculpt_find_nearest_to_ray_cb(PBVHNode *node, void *data_v, float *t
else {
/* Intersect with coordinates from before we started stroke. */
SculptUndoNode *unode = SCULPT_undo_get_node(node, SCULPT_UNDO_COORDS);
- origco = (unode) ? unode->co : NULL;
+ origco = (unode) ? unode->co : nullptr;
use_origco = origco ? true : false;
}
}
@@ -4906,7 +4902,7 @@ float SCULPT_raycast_init(ViewContext *vc,
float obimat[4][4];
float dist;
Object *ob = vc->obact;
- RegionView3D *rv3d = vc->region->regiondata;
+ RegionView3D *rv3d = static_cast<RegionView3D *>(vc->region->regiondata);
View3D *v3d = vc->v3d;
/* TODO: what if the segment is totally clipped? (return == 0). */
@@ -4967,15 +4963,15 @@ bool SCULPT_cursor_geometry_info_update(bContext *C,
depth = SCULPT_raycast_init(&vc, mval, ray_start, ray_end, ray_normal, original);
SCULPT_stroke_modifiers_check(C, ob, brush);
- SculptRaycastData srd = {
- .original = original,
- .ss = ob->sculpt,
- .hit = false,
- .ray_start = ray_start,
- .ray_normal = ray_normal,
- .depth = depth,
- .face_normal = face_normal,
- };
+ SculptRaycastData srd{};
+ srd.original = original;
+ srd.ss = ob->sculpt;
+ srd.hit = false;
+ srd.ray_start = ray_start;
+ srd.ray_normal = ray_normal;
+ srd.depth = depth;
+ srd.face_normal = face_normal;
+
isect_ray_tri_watertight_v3_precalc(&srd.isect_precalc, ray_normal);
BKE_pbvh_raycast(ss->pbvh, sculpt_raycast_cb, &srd, ray_start, ray_normal, srd.original);
@@ -5123,15 +5119,15 @@ bool SCULPT_stroke_get_location(bContext *C,
return hit;
}
- SculptFindNearestToRayData srd = {
- .original = original,
- .ss = ob->sculpt,
- .hit = false,
- .ray_start = ray_start,
- .ray_normal = ray_normal,
- .depth = FLT_MAX,
- .dist_sq_to_ray = FLT_MAX,
- };
+ SculptFindNearestToRayData srd{};
+ srd.original = original;
+ srd.ss = ob->sculpt;
+ srd.hit = false;
+ srd.ray_start = ray_start;
+ srd.ray_normal = ray_normal;
+ srd.depth = FLT_MAX;
+ srd.dist_sq_to_ray = FLT_MAX;
+
BKE_pbvh_find_nearest_to_ray(
ss->pbvh, sculpt_find_nearest_to_ray_cb, &srd, ray_start, ray_normal, srd.original);
if (srd.hit) {
@@ -5155,7 +5151,7 @@ static void sculpt_brush_init_tex(Sculpt *sd, SculptSession *ss)
ntreeTexBeginExecTree(mtex->tex->nodetree);
}
- if (ss->tex_pool == NULL) {
+ if (ss->tex_pool == nullptr) {
ss->tex_pool = BKE_image_pool_new();
}
}
@@ -5256,7 +5252,7 @@ void SCULPT_flush_update_step(bContext *C, SculptUpdateType update_flags)
rv3d->rflag |= RV3D_PAINTING;
}
- if (mmd != NULL) {
+ if (mmd != nullptr) {
multires_mark_as_modified(depsgraph, ob, MULTIRES_COORDS_MODIFIED);
}
@@ -5317,7 +5313,7 @@ void SCULPT_flush_update_done(const bContext *C, Object *ob, SculptUpdateType up
wmWindowManager *wm = CTX_wm_manager(C);
RegionView3D *current_rv3d = CTX_wm_region_view3d(C);
SculptSession *ss = ob->sculpt;
- Mesh *mesh = ob->data;
+ Mesh *mesh = static_cast<Mesh *>(ob->data);
/* Always needed for linked duplicates. */
bool need_tag = (ID_REAL_USERS(&mesh->id) > 1);
@@ -5329,7 +5325,7 @@ void SCULPT_flush_update_done(const bContext *C, Object *ob, SculptUpdateType up
LISTBASE_FOREACH (wmWindow *, win, &wm->windows) {
bScreen *screen = WM_window_get_active_screen(win);
LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
- SpaceLink *sl = area->spacedata.first;
+ SpaceLink *sl = static_cast<SpaceLink *>(area->spacedata.first);
if (sl->spacetype != SPACE_VIEW3D) {
continue;
}
@@ -5339,7 +5335,7 @@ void SCULPT_flush_update_done(const bContext *C, Object *ob, SculptUpdateType up
* current viewport was deactivated. */
LISTBASE_FOREACH (ARegion *, region, &area->regionbase) {
if (region->regiontype == RGN_TYPE_WINDOW) {
- RegionView3D *rv3d = region->regiondata;
+ RegionView3D *rv3d = static_cast<RegionView3D *>(region->regiondata);
if (rv3d != current_rv3d) {
need_tag |= !BKE_sculptsession_use_pbvh_draw(ob, rv3d);
}
@@ -5351,7 +5347,7 @@ void SCULPT_flush_update_done(const bContext *C, Object *ob, SculptUpdateType up
if (update_flags & SCULPT_UPDATE_IMAGE) {
LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
- SpaceLink *sl = area->spacedata.first;
+ SpaceLink *sl = static_cast<SpaceLink *>(area->spacedata.first);
if (sl->spacetype != SPACE_IMAGE) {
continue;
}
@@ -5397,7 +5393,7 @@ void SCULPT_flush_update_done(const bContext *C, Object *ob, SculptUpdateType up
/* Returns whether the mouse/stylus is over the mesh (1)
* or over the background (0). */
-static bool over_mesh(bContext *C, struct wmOperator *UNUSED(op), const float mval[2])
+static bool over_mesh(bContext *C, wmOperator * /*op*/, const float mval[2])
{
float co_dummy[3];
return SCULPT_stroke_get_location(C, co_dummy, mval, false);
@@ -5453,13 +5449,13 @@ bool SCULPT_handles_colors_report(SculptSession *ss, ReportList *reports)
return false;
}
-static bool sculpt_stroke_test_start(bContext *C, struct wmOperator *op, const float mval[2])
+static bool sculpt_stroke_test_start(bContext *C, wmOperator *op, const float mval[2])
{
/* Don't start the stroke until `mval` goes over the mesh.
* NOTE: `mval` will only be null when re-executing the saved stroke.
* We have exception for 'exec' strokes since they may not set `mval`,
* only 'location', see: T52195. */
- if (((op->flag & OP_IS_INVOKE) == 0) || (mval == NULL) || over_mesh(C, op, mval)) {
+ if (((op->flag & OP_IS_INVOKE) == 0) || (mval == nullptr) || over_mesh(C, op, mval)) {
Object *ob = CTX_data_active_object(C);
SculptSession *ss = ob->sculpt;
Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
@@ -5494,8 +5490,8 @@ static bool sculpt_stroke_test_start(bContext *C, struct wmOperator *op, const f
}
static void sculpt_stroke_update_step(bContext *C,
- wmOperator *UNUSED(op),
- struct PaintStroke *stroke,
+ wmOperator * /*op*/,
+ PaintStroke *stroke,
PointerRNA *itemptr)
{
UnifiedPaintSettings *ups = &CTX_data_tool_settings(C)->unified_paint_settings;
@@ -5582,7 +5578,7 @@ static void sculpt_brush_exit_tex(Sculpt *sd)
}
}
-static void sculpt_stroke_done(const bContext *C, struct PaintStroke *UNUSED(stroke))
+static void sculpt_stroke_done(const bContext *C, PaintStroke * /*stroke*/)
{
Object *ob = CTX_data_active_object(C);
SculptSession *ss = ob->sculpt;
@@ -5614,7 +5610,7 @@ static void sculpt_stroke_done(const bContext *C, struct PaintStroke *UNUSED(str
BKE_pbvh_node_color_buffer_free(ss->pbvh);
SCULPT_cache_free(ss->cache);
- ss->cache = NULL;
+ ss->cache = nullptr;
sculpt_stroke_undo_end(C, brush);
@@ -5640,7 +5636,7 @@ static void sculpt_stroke_done(const bContext *C, struct PaintStroke *UNUSED(str
static int sculpt_brush_stroke_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
- struct PaintStroke *stroke;
+ PaintStroke *stroke;
int ignore_background_click;
int retval;
Object *ob = CTX_data_active_object(C);
@@ -5682,7 +5678,7 @@ static int sculpt_brush_stroke_invoke(bContext *C, wmOperator *op, const wmEvent
SCULPT_stroke_get_location,
sculpt_stroke_test_start,
sculpt_stroke_update_step,
- NULL,
+ nullptr,
sculpt_stroke_done,
event->type);
@@ -5690,15 +5686,15 @@ static int sculpt_brush_stroke_invoke(bContext *C, wmOperator *op, const wmEvent
/* For tablet rotation. */
ignore_background_click = RNA_boolean_get(op->ptr, "ignore_background_click");
-
- if (ignore_background_click && !over_mesh(C, op, (const float[2]){UNPACK2(event->mval)})) {
- paint_stroke_free(C, op, op->customdata);
+ const float mval[2] = {float(event->mval[0]), float(event->mval[1])};
+ if (ignore_background_click && !over_mesh(C, op, mval)) {
+ paint_stroke_free(C, op, static_cast<PaintStroke *>(op->customdata));
return OPERATOR_PASS_THROUGH;
}
retval = op->type->modal(C, op, event);
if (ELEM(retval, OPERATOR_FINISHED, OPERATOR_CANCELLED)) {
- paint_stroke_free(C, op, op->customdata);
+ paint_stroke_free(C, op, static_cast<PaintStroke *>(op->customdata));
return retval;
}
/* Add modal handler. */
@@ -5719,12 +5715,12 @@ static int sculpt_brush_stroke_exec(bContext *C, wmOperator *op)
SCULPT_stroke_get_location,
sculpt_stroke_test_start,
sculpt_stroke_update_step,
- NULL,
+ nullptr,
sculpt_stroke_done,
0);
/* Frees op->customdata. */
- paint_stroke_exec(C, op, op->customdata);
+ paint_stroke_exec(C, op, static_cast<PaintStroke *>(op->customdata));
return OPERATOR_FINISHED;
}
@@ -5742,11 +5738,11 @@ static void sculpt_brush_stroke_cancel(bContext *C, wmOperator *op)
paint_mesh_restore_co(sd, ob);
}
- paint_stroke_cancel(C, op, op->customdata);
+ paint_stroke_cancel(C, op, static_cast<PaintStroke *>(op->customdata));
if (ss->cache) {
SCULPT_cache_free(ss->cache);
- ss->cache = NULL;
+ ss->cache = nullptr;
}
sculpt_brush_exit_tex(sd);
@@ -5754,9 +5750,9 @@ static void sculpt_brush_stroke_cancel(bContext *C, wmOperator *op)
static int sculpt_brush_stroke_modal(bContext *C, wmOperator *op, const wmEvent *event)
{
- bool started = op->customdata && paint_stroke_started((struct PaintStroke *)op->customdata);
+ bool started = op->customdata && paint_stroke_started((PaintStroke *)op->customdata);
- int retval = paint_stroke_modal(C, op, event, (struct PaintStroke **)&op->customdata);
+ int retval = paint_stroke_modal(C, op, event, (PaintStroke **)&op->customdata);
if (!started && ELEM(retval, OPERATOR_FINISHED, OPERATOR_CANCELLED)) {
/* Did the stroke never start? If so push a blank sculpt undo
@@ -5779,7 +5775,7 @@ static int sculpt_brush_stroke_modal(bContext *C, wmOperator *op, const wmEvent
return retval;
}
-static void sculpt_redo_empty_ui(bContext *UNUSED(C), wmOperator *UNUSED(op))
+static void sculpt_redo_empty_ui(bContext * /*C*/, wmOperator * /*op*/)
{
}
@@ -5850,8 +5846,8 @@ static int SCULPT_vertex_get_connected_component(SculptSession *ss, PBVHVertRef
static void SCULPT_fake_neighbor_init(SculptSession *ss, const float max_dist)
{
const int totvert = SCULPT_vertex_count_get(ss);
- ss->fake_neighbors.fake_neighbor_index = MEM_malloc_arrayN(
- totvert, sizeof(int), "fake neighbor");
+ ss->fake_neighbors.fake_neighbor_index = static_cast<int *>(
+ MEM_malloc_arrayN(totvert, sizeof(int), "fake neighbor"));
for (int i = 0; i < totvert; i++) {
ss->fake_neighbors.fake_neighbor_index[i] = FAKE_NEIGHBOR_NONE;
}
@@ -5875,19 +5871,20 @@ static void sculpt_pose_fake_neighbors_free(SculptSession *ss)
MEM_SAFE_FREE(ss->fake_neighbors.fake_neighbor_index);
}
-typedef struct NearestVertexFakeNeighborTLSData {
+struct NearestVertexFakeNeighborTLSData {
PBVHVertRef nearest_vertex;
float nearest_vertex_distance_squared;
int current_topology_id;
-} NearestVertexFakeNeighborTLSData;
+};
static void do_fake_neighbor_search_task_cb(void *__restrict userdata,
const int n,
const TaskParallelTLS *__restrict tls)
{
- SculptThreadedTaskData *data = userdata;
+ SculptThreadedTaskData *data = static_cast<SculptThreadedTaskData *>(userdata);
SculptSession *ss = data->ob->sculpt;
- NearestVertexFakeNeighborTLSData *nvtd = tls->userdata_chunk;
+ NearestVertexFakeNeighborTLSData *nvtd = static_cast<NearestVertexFakeNeighborTLSData *>(
+ tls->userdata_chunk);
PBVHVertexIter vd;
BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
@@ -5905,12 +5902,13 @@ static void do_fake_neighbor_search_task_cb(void *__restrict userdata,
BKE_pbvh_vertex_iter_end;
}
-static void fake_neighbor_search_reduce(const void *__restrict UNUSED(userdata),
+static void fake_neighbor_search_reduce(const void *__restrict /*userdata*/,
void *__restrict chunk_join,
void *__restrict chunk)
{
- NearestVertexFakeNeighborTLSData *join = chunk_join;
- NearestVertexFakeNeighborTLSData *nvtd = chunk;
+ NearestVertexFakeNeighborTLSData *join = static_cast<NearestVertexFakeNeighborTLSData *>(
+ chunk_join);
+ NearestVertexFakeNeighborTLSData *nvtd = static_cast<NearestVertexFakeNeighborTLSData *>(chunk);
if (join->nearest_vertex.i == PBVH_REF_NONE) {
join->nearest_vertex = nvtd->nearest_vertex;
join->nearest_vertex_distance_squared = nvtd->nearest_vertex_distance_squared;
@@ -5927,27 +5925,26 @@ static PBVHVertRef SCULPT_fake_neighbor_search(Sculpt *sd,
float max_distance)
{
SculptSession *ss = ob->sculpt;
- PBVHNode **nodes = NULL;
+ PBVHNode **nodes = nullptr;
int totnode;
- SculptSearchSphereData data = {
- .ss = ss,
- .sd = sd,
- .radius_squared = max_distance * max_distance,
- .original = false,
- .center = SCULPT_vertex_co_get(ss, vertex),
- };
+ SculptSearchSphereData data{};
+ data.ss = ss;
+ data.sd = sd;
+ data.radius_squared = max_distance * max_distance;
+ data.original = false;
+ data.center = SCULPT_vertex_co_get(ss, vertex);
+
BKE_pbvh_search_gather(ss->pbvh, SCULPT_search_sphere_cb, &data, &nodes, &totnode);
if (totnode == 0) {
return BKE_pbvh_make_vref(PBVH_REF_NONE);
}
- SculptThreadedTaskData task_data = {
- .sd = sd,
- .ob = ob,
- .nodes = nodes,
- .max_distance_squared = max_distance * max_distance,
- };
+ SculptThreadedTaskData task_data{};
+ task_data.sd = sd;
+ task_data.ob = ob;
+ task_data.nodes = nodes;
+ task_data.max_distance_squared = max_distance * max_distance;
copy_v3_v3(task_data.nearest_vertex_search_co, SCULPT_vertex_co_get(ss, vertex));
@@ -5968,17 +5965,14 @@ static PBVHVertRef SCULPT_fake_neighbor_search(Sculpt *sd,
return nvtd.nearest_vertex;
}
-typedef struct SculptTopologyIDFloodFillData {
+struct SculptTopologyIDFloodFillData {
int next_id;
-} SculptTopologyIDFloodFillData;
+};
-static bool SCULPT_connected_components_floodfill_cb(SculptSession *ss,
- PBVHVertRef from_v,
- PBVHVertRef to_v,
- bool UNUSED(is_duplicate),
- void *userdata)
+static bool SCULPT_connected_components_floodfill_cb(
+ SculptSession *ss, PBVHVertRef from_v, PBVHVertRef to_v, bool /*is_duplicate*/, void *userdata)
{
- SculptTopologyIDFloodFillData *data = userdata;
+ SculptTopologyIDFloodFillData *data = static_cast<SculptTopologyIDFloodFillData *>(userdata);
int from_v_i = BKE_pbvh_vertex_to_index(ss->pbvh, from_v);
int to_v_i = BKE_pbvh_vertex_to_index(ss->pbvh, to_v);
@@ -6000,7 +5994,8 @@ void SCULPT_connected_components_ensure(Object *ob)
}
const int totvert = SCULPT_vertex_count_get(ss);
- ss->vertex_info.connected_component = MEM_malloc_arrayN(totvert, sizeof(int), "topology ID");
+ ss->vertex_info.connected_component = static_cast<int *>(
+ MEM_malloc_arrayN(totvert, sizeof(int), "topology ID"));
for (int i = 0; i < totvert; i++) {
ss->vertex_info.connected_component[i] = SCULPT_TOPOLOGY_ID_NONE;
@@ -6036,8 +6031,8 @@ void SCULPT_boundary_info_ensure(Object *object)
const MLoop *loops = BKE_mesh_loops(base_mesh);
ss->vertex_info.boundary = BLI_BITMAP_NEW(base_mesh->totvert, "Boundary info");
- int *adjacent_faces_edge_count = MEM_calloc_arrayN(
- base_mesh->totedge, sizeof(int), "Adjacent face edge count");
+ int *adjacent_faces_edge_count = static_cast<int *>(
+ MEM_calloc_arrayN(base_mesh->totedge, sizeof(int), "Adjacent face edge count"));
for (int p = 0; p < base_mesh->totpoly; p++) {
const MPoly *poly = &polys[p];
@@ -6091,14 +6086,14 @@ void SCULPT_fake_neighbors_ensure(Sculpt *sd, Object *ob, const float max_dist)
void SCULPT_fake_neighbors_enable(Object *ob)
{
SculptSession *ss = ob->sculpt;
- BLI_assert(ss->fake_neighbors.fake_neighbor_index != NULL);
+ BLI_assert(ss->fake_neighbors.fake_neighbor_index != nullptr);
ss->fake_neighbors.use_fake_neighbors = true;
}
void SCULPT_fake_neighbors_disable(Object *ob)
{
SculptSession *ss = ob->sculpt;
- BLI_assert(ss->fake_neighbors.fake_neighbor_index != NULL);
+ BLI_assert(ss->fake_neighbors.fake_neighbor_index != nullptr);
ss->fake_neighbors.use_fake_neighbors = false;
}
@@ -6109,7 +6104,7 @@ void SCULPT_fake_neighbors_free(Object *ob)
}
void SCULPT_automasking_node_begin(Object *ob,
- const SculptSession *UNUSED(ss),
+ const SculptSession * /*ss*/,
AutomaskingCache *automasking,
AutomaskingNodeData *automask_data,
PBVHNode *node)
@@ -6131,7 +6126,7 @@ void SCULPT_automasking_node_begin(Object *ob,
}
}
-void SCULPT_automasking_node_update(SculptSession *UNUSED(ss),
+void SCULPT_automasking_node_update(SculptSession * /*ss*/,
AutomaskingNodeData *automask_data,
PBVHVertexIter *vd)
{
@@ -6177,7 +6172,7 @@ void SCULPT_stroke_id_next(Object *ob)
/* Manually wrap in int32 space to avoid tripping up undefined behavior
* sanitizers.
*/
- ob->sculpt->stroke_id = (uchar)(((int)ob->sculpt->stroke_id + 1) & 255);
+ ob->sculpt->stroke_id = uchar((int(ob->sculpt->stroke_id) + 1) & 255);
}
void SCULPT_stroke_id_ensure(Object *ob)
diff --git a/source/blender/editors/sculpt_paint/sculpt_intern.h b/source/blender/editors/sculpt_paint/sculpt_intern.h
index bf47b64d176..852b3c2719a 100644
--- a/source/blender/editors/sculpt_paint/sculpt_intern.h
+++ b/source/blender/editors/sculpt_paint/sculpt_intern.h
@@ -341,7 +341,7 @@ typedef struct SculptBrushTest {
float radius;
float location[3];
float dist;
- int mirror_symmetry_pass;
+ ePaintSymmetryFlags mirror_symmetry_pass;
int radial_symmetry_pass;
float symm_rot_mat_inv[4][4];
@@ -556,7 +556,8 @@ typedef struct StrokeCache {
/* Symmetry index between 0 and 7 bit combo 0 is Brush only;
* 1 is X mirror; 2 is Y mirror; 3 is XY; 4 is Z; 5 is XZ; 6 is YZ; 7 is XYZ */
int symmetry;
- int mirror_symmetry_pass; /* The symmetry pass we are currently on between 0 and 7. */
+ ePaintSymmetryFlags
+ mirror_symmetry_pass; /* The symmetry pass we are currently on between 0 and 7. */
float true_view_normal[3];
float view_normal[3];
@@ -1526,7 +1527,10 @@ bool SCULPT_pbvh_calc_area_normal(const struct Brush *brush,
* Flip all the edit-data across the axis/axes specified by \a symm.
* Used to calculate multiple modifications to the mesh when symmetry is enabled.
*/
-void SCULPT_cache_calc_brushdata_symm(StrokeCache *cache, char symm, char axis, float angle);
+void SCULPT_cache_calc_brushdata_symm(StrokeCache *cache,
+ ePaintSymmetryFlags symm,
+ char axis,
+ float angle);
void SCULPT_cache_free(StrokeCache *cache);
/* -------------------------------------------------------------------- */
diff --git a/source/blender/editors/sculpt_paint/sculpt_ops.c b/source/blender/editors/sculpt_paint/sculpt_ops.c
index 8affb0e9d53..0e7873bc652 100644
--- a/source/blender/editors/sculpt_paint/sculpt_ops.c
+++ b/source/blender/editors/sculpt_paint/sculpt_ops.c
@@ -246,15 +246,17 @@ static void SCULPT_OT_symmetrize(wmOperatorType *ot)
ot->exec = sculpt_symmetrize_exec;
ot->poll = sculpt_no_multires_poll;
- RNA_def_float(ot->srna,
- "merge_tolerance",
- 0.001f,
- 0.0f,
- FLT_MAX,
- "Merge Distance",
- "Distance within which symmetrical vertices are merged",
- 0.0f,
- 1.0f);
+ PropertyRNA *prop = RNA_def_float(ot->srna,
+ "merge_tolerance",
+ 0.0005f,
+ 0.0f,
+ FLT_MAX,
+ "Merge Distance",
+ "Distance within which symmetrical vertices are merged",
+ 0.0f,
+ 1.0f);
+
+ RNA_def_property_ui_range(prop, 0.0, FLT_MAX, 0.001, 5);
}
/**** Toggle operator for turning sculpt mode on or off ****/
@@ -1202,7 +1204,7 @@ static void SCULPT_OT_mask_from_cavity(wmOperatorType *ot)
RNA_def_boolean(ot->srna,
"use_automask_settings",
false,
- "Use Automask Settings",
+ "Automask Settings",
"Use default settings from Options panel in sculpt mode");
RNA_def_float(ot->srna,
@@ -1210,7 +1212,7 @@ static void SCULPT_OT_mask_from_cavity(wmOperatorType *ot)
0.5f,
0.0f,
5.0f,
- "Cavity Factor",
+ "Factor",
"The contrast of the cavity mask",
0.0f,
1.0f);
@@ -1219,11 +1221,11 @@ static void SCULPT_OT_mask_from_cavity(wmOperatorType *ot)
2,
0,
25,
- "Cavity Blur",
+ "Blur",
"The number of times the cavity mask is blurred",
0,
25);
- RNA_def_boolean(ot->srna, "use_curve", false, "Use Curve", "");
+ RNA_def_boolean(ot->srna, "use_curve", false, "Custom Curve", "");
RNA_def_boolean(ot->srna, "invert", false, "Cavity (Inverted)", "");
}
diff --git a/source/blender/editors/sculpt_paint/sculpt_undo.c b/source/blender/editors/sculpt_paint/sculpt_undo.c
index eb92c865f18..833f62d4955 100644
--- a/source/blender/editors/sculpt_paint/sculpt_undo.c
+++ b/source/blender/editors/sculpt_paint/sculpt_undo.c
@@ -1823,9 +1823,7 @@ static void sculpt_undo_set_active_layer(struct bContext *C, SculptAttrRef *attr
if (!layer) {
layer = BKE_id_attribute_search(&me->id, attr->name, CD_MASK_PROP_ALL, ATTR_DOMAIN_MASK_ALL);
if (layer) {
- const eAttrDomain domain = BKE_id_attribute_domain(&me->id, layer);
- if (ED_geometry_attribute_convert(
- me, attr->name, layer->type, domain, attr->type, attr->domain)) {
+ if (ED_geometry_attribute_convert(me, attr->name, attr->type, attr->domain, NULL)) {
layer = BKE_id_attribute_find(&me->id, attr->name, attr->type, attr->domain);
}
}
diff --git a/source/blender/editors/space_file/CMakeLists.txt b/source/blender/editors/space_file/CMakeLists.txt
index 688aa846c30..76564f38da8 100644
--- a/source/blender/editors/space_file/CMakeLists.txt
+++ b/source/blender/editors/space_file/CMakeLists.txt
@@ -46,6 +46,10 @@ set(LIB
bf_blenkernel
)
+if(WIN32)
+ add_definitions(-DNOMINMAX)
+endif()
+
if(WITH_HEADLESS)
add_definitions(-DWITH_HEADLESS)
else()
diff --git a/source/blender/editors/space_file/asset_catalog_tree_view.cc b/source/blender/editors/space_file/asset_catalog_tree_view.cc
index 4eb2958f5a2..fe2e46fc056 100644
--- a/source/blender/editors/space_file/asset_catalog_tree_view.cc
+++ b/source/blender/editors/space_file/asset_catalog_tree_view.cc
@@ -708,12 +708,11 @@ bool file_set_asset_catalog_filter_settings(
void file_ensure_updated_catalog_filter_data(
FileAssetCatalogFilterSettingsHandle *filter_settings_handle,
- const ::AssetLibrary *asset_library)
+ const bke::AssetLibrary *asset_library)
{
AssetCatalogFilterSettings *filter_settings = reinterpret_cast<AssetCatalogFilterSettings *>(
filter_settings_handle);
- const AssetCatalogService *catalog_service = BKE_asset_library_get_catalog_service(
- asset_library);
+ const AssetCatalogService *catalog_service = asset_library->catalog_service.get();
if (filter_settings->asset_catalog_visibility != FILE_SHOW_ASSETS_ALL_CATALOGS) {
filter_settings->catalog_filter = std::make_unique<AssetCatalogFilter>(
diff --git a/source/blender/editors/space_file/file_draw.c b/source/blender/editors/space_file/file_draw.c
index 240901318b5..ed0132c6990 100644
--- a/source/blender/editors/space_file/file_draw.c
+++ b/source/blender/editors/space_file/file_draw.c
@@ -171,7 +171,6 @@ static void file_draw_icon(const SpaceFile *sfile,
UI_but_drag_set_asset(but,
&(AssetHandle){.file_data = file},
BLI_strdup(blend_path),
- file->asset_data,
asset_params->import_type,
icon,
preview_image,
@@ -565,7 +564,6 @@ static void file_draw_preview(const SpaceFile *sfile,
UI_but_drag_set_asset(but,
&(AssetHandle){.file_data = file},
BLI_strdup(blend_path),
- file->asset_data,
asset_params->import_type,
icon,
imb,
diff --git a/source/blender/editors/space_file/file_indexer.cc b/source/blender/editors/space_file/file_indexer.cc
index ec631eb48b3..8520ac34122 100644
--- a/source/blender/editors/space_file/file_indexer.cc
+++ b/source/blender/editors/space_file/file_indexer.cc
@@ -67,8 +67,9 @@ void ED_file_indexer_entries_extend_from_datablock_infos(
}
}
-static void ED_file_indexer_entry_free(void *indexer_entry)
+static void ED_file_indexer_entry_free(void *indexer_entry_ptr)
{
+ FileIndexerEntry *indexer_entry = static_cast<FileIndexerEntry *>(indexer_entry_ptr);
MEM_freeN(indexer_entry);
}
diff --git a/source/blender/editors/space_file/file_intern.h b/source/blender/editors/space_file/file_intern.h
index eac72af00ab..0ca09487507 100644
--- a/source/blender/editors/space_file/file_intern.h
+++ b/source/blender/editors/space_file/file_intern.h
@@ -218,6 +218,17 @@ void file_path_to_ui_path(const char *path, char *r_pathi, int max_size);
/* C-handle for #ed::asset_browser::AssetCatalogFilterSettings. */
typedef struct FileAssetCatalogFilterSettingsHandle FileAssetCatalogFilterSettingsHandle;
+void file_create_asset_catalog_tree_view_in_layout(struct AssetLibrary *asset_library,
+ struct uiLayout *layout,
+ SpaceFile *space_file,
+ FileAssetSelectParams *params);
+
+#ifdef __cplusplus
+
+namespace blender::bke {
+struct AssetLibrary;
+}
+
FileAssetCatalogFilterSettingsHandle *file_create_asset_catalog_filter_settings(void);
void file_delete_asset_catalog_filter_settings(
FileAssetCatalogFilterSettingsHandle **filter_settings_handle);
@@ -231,15 +242,12 @@ bool file_set_asset_catalog_filter_settings(
bUUID catalog_id);
void file_ensure_updated_catalog_filter_data(
FileAssetCatalogFilterSettingsHandle *filter_settings_handle,
- const struct AssetLibrary *asset_library);
+ const blender::bke::AssetLibrary *asset_library);
bool file_is_asset_visible_in_catalog_filter_settings(
const FileAssetCatalogFilterSettingsHandle *filter_settings_handle,
const AssetMetaData *asset_data);
-void file_create_asset_catalog_tree_view_in_layout(struct AssetLibrary *asset_library,
- struct uiLayout *layout,
- struct SpaceFile *space_file,
- struct FileAssetSelectParams *params);
+#endif
#ifdef __cplusplus
}
diff --git a/source/blender/editors/space_file/filelist.cc b/source/blender/editors/space_file/filelist.cc
index 9ca5b1da7da..c4d99d41a60 100644
--- a/source/blender/editors/space_file/filelist.cc
+++ b/source/blender/editors/space_file/filelist.cc
@@ -43,6 +43,8 @@
#include "BKE_asset.h"
#include "BKE_asset_library.h"
+#include "BKE_asset_library.hh"
+#include "BKE_asset_representation.hh"
#include "BKE_context.h"
#include "BKE_global.h"
#include "BKE_icons.h"
@@ -78,6 +80,8 @@
#include "file_intern.h"
#include "filelist.h"
+using namespace blender;
+
#define FILEDIR_NBR_ENTRIES_UNSET -1
/* ------------------FILELIST------------------------ */
@@ -95,7 +99,7 @@ struct FileListInternEntry {
/** Optional argument for shortcuts, aliases etc. */
char *redirection_path;
/** not strictly needed, but used during sorting, avoids to have to recompute it there... */
- char *name;
+ const char *name;
bool free_name;
/**
@@ -112,9 +116,8 @@ struct FileListInternEntry {
PreviewImage *preview_image;
} local_data;
- /** When the file represents an asset read from another file, it is stored here.
- * Owning pointer. */
- AssetMetaData *imported_asset_data;
+ /* References an asset in the asset library storage. */
+ bke::AssetRepresentation *asset; /* Non-owning. */
/* See #FILE_ENTRY_BLENDERLIB_NO_PREVIEW. */
bool blenderlib_has_no_preview;
@@ -210,7 +213,7 @@ struct FileList {
eFileSelectType type;
/* The library this list was created for. Stored here so we know when to re-read. */
AssetLibraryReference *asset_library_ref;
- AssetLibrary *asset_library; /* Non-owning pointer. */
+ bke::AssetLibrary *asset_library; /* Non-owning. */
short flags;
@@ -776,8 +779,10 @@ static bool is_filtered_id_file_type(const FileListInternEntry *file,
*/
static AssetMetaData *filelist_file_internal_get_asset_data(const FileListInternEntry *file)
{
- const ID *local_id = file->local_data.id;
- return local_id ? local_id->asset_data : file->imported_asset_data;
+ if (!file->asset) {
+ return nullptr;
+ }
+ return &file->asset->get_metadata();
}
static void prepare_filter_asset_library(const FileList *filelist, FileListFilter *filter)
@@ -1016,7 +1021,7 @@ void filelist_setindexer(FileList *filelist, const FileIndexerType *indexer)
void filelist_set_asset_catalog_filter_options(
FileList *filelist,
eFileSel_Params_AssetCatalogVisibility catalog_visibility,
- const bUUID *catalog_id)
+ const ::bUUID *catalog_id)
{
if (!filelist->filter_data.asset_catalog_filter) {
/* There's no filter data yet. */
@@ -1362,7 +1367,7 @@ static bool filelist_checkdir_main_assets(struct FileList * /*filelist*/,
static void filelist_entry_clear(FileDirEntry *entry)
{
if (entry->name && ((entry->flags & FILE_ENTRY_NAME_FREE) != 0)) {
- MEM_freeN(entry->name);
+ MEM_freeN((char *)entry->name);
}
if (entry->relpath) {
MEM_freeN(entry->relpath);
@@ -1399,8 +1404,13 @@ static void filelist_direntryarr_free(FileDirEntryArr *array)
array->entries_filtered_num = FILEDIR_NBR_ENTRIES_UNSET;
}
-static void filelist_intern_entry_free(FileListInternEntry *entry)
+static void filelist_intern_entry_free(FileList *filelist, FileListInternEntry *entry)
{
+ if (entry->asset) {
+ BLI_assert(filelist->asset_library);
+ filelist->asset_library->remove_asset(*entry->asset);
+ }
+
if (entry->relpath) {
MEM_freeN(entry->relpath);
}
@@ -1408,19 +1418,16 @@ static void filelist_intern_entry_free(FileListInternEntry *entry)
MEM_freeN(entry->redirection_path);
}
if (entry->name && entry->free_name) {
- MEM_freeN(entry->name);
- }
- /* If we own the asset-data (it was generated from external file data), free it. */
- if (entry->imported_asset_data) {
- BKE_asset_metadata_free(&entry->imported_asset_data);
+ MEM_freeN((char *)entry->name);
}
MEM_freeN(entry);
}
-static void filelist_intern_free(FileListIntern *filelist_intern)
+static void filelist_intern_free(FileList *filelist)
{
+ FileListIntern *filelist_intern = &filelist->filelist_intern;
LISTBASE_FOREACH_MUTABLE (FileListInternEntry *, entry, &filelist_intern->entries) {
- filelist_intern_entry_free(entry);
+ filelist_intern_entry_free(filelist, entry);
}
BLI_listbase_clear(&filelist_intern->entries);
@@ -1430,8 +1437,9 @@ static void filelist_intern_free(FileListIntern *filelist_intern)
/**
* \return the number of main files removed.
*/
-static int filelist_intern_free_main_files(FileListIntern *filelist_intern)
+static int filelist_intern_free_main_files(FileList *filelist)
{
+ FileListIntern *filelist_intern = &filelist->filelist_intern;
int removed_counter = 0;
LISTBASE_FOREACH_MUTABLE (FileListInternEntry *, entry, &filelist_intern->entries) {
if (!filelist_intern_entry_is_main_file(entry)) {
@@ -1439,7 +1447,7 @@ static int filelist_intern_free_main_files(FileListIntern *filelist_intern)
}
BLI_remlink(&filelist_intern->entries, entry);
- filelist_intern_entry_free(entry);
+ filelist_intern_entry_free(filelist, entry);
removed_counter++;
}
@@ -1794,7 +1802,7 @@ void filelist_clear_ex(struct FileList *filelist,
filelist_cache_clear(&filelist->filelist_cache, filelist->filelist_cache.size);
}
- filelist_intern_free(&filelist->filelist_intern);
+ filelist_intern_free(filelist);
filelist_direntryarr_free(&filelist->filelist);
@@ -1822,7 +1830,7 @@ static void filelist_clear_main_files(FileList *filelist,
filelist_cache_clear(&filelist->filelist_cache, filelist->filelist_cache.size);
}
- const int removed_files = filelist_intern_free_main_files(&filelist->filelist_intern);
+ const int removed_files = filelist_intern_free_main_files(filelist);
filelist->filelist.entries_num -= removed_files;
filelist->filelist.entries_filtered_num = FILEDIR_NBR_ENTRIES_UNSET;
@@ -1881,7 +1889,7 @@ void filelist_free(struct FileList *filelist)
AssetLibrary *filelist_asset_library(FileList *filelist)
{
- return filelist->asset_library;
+ return reinterpret_cast<::AssetLibrary *>(filelist->asset_library);
}
void filelist_freelib(struct FileList *filelist)
@@ -1897,11 +1905,15 @@ BlendHandle *filelist_lib(struct FileList *filelist)
return filelist->libfiledata;
}
-static char *fileentry_uiname(const char *root,
- const char *relpath,
- const eFileSel_File_Types typeflag,
- char *buff)
+static const char *fileentry_uiname(const char *root, FileListInternEntry *entry, char *buff)
{
+ if (entry->asset) {
+ const StringRefNull asset_name = entry->asset->get_name();
+ return BLI_strdupn(asset_name.c_str(), asset_name.size());
+ }
+
+ const char *relpath = entry->relpath;
+ const eFileSel_File_Types typeflag = entry->typeflag;
char *name = nullptr;
if (typeflag & FILE_TYPE_FTFONT && !(typeflag & FILE_TYPE_BLENDERLIB)) {
@@ -2042,10 +2054,7 @@ static FileDirEntry *filelist_file_create_entry(FileList *filelist, const int in
ret->redirection_path = BLI_strdup(entry->redirection_path);
}
ret->id = entry->local_data.id;
- ret->asset_data = entry->imported_asset_data ? entry->imported_asset_data : nullptr;
- if (ret->id && (ret->asset_data == nullptr)) {
- ret->asset_data = ret->id->asset_data;
- }
+ ret->asset = reinterpret_cast<::AssetRepresentation *>(entry->asset);
/* For some file types the preview is already available. */
if (entry->local_data.preview_image &&
BKE_previewimg_is_finished(entry->local_data.preview_image, ICON_SIZE_PREVIEW)) {
@@ -2996,8 +3005,13 @@ static FileListInternEntry *filelist_readjob_list_lib_group_create(const int idc
return entry;
}
-static void filelist_readjob_list_lib_add_datablock(ListBase *entries,
- const BLODataBlockInfo *datablock_info,
+/**
+ * \warning: This "steals" the asset metadata from \a datablock_info. Not great design but fixing
+ * this requires redesigning things on the caller side for proper ownership management.
+ */
+static void filelist_readjob_list_lib_add_datablock(FileList *filelist,
+ ListBase *entries,
+ BLODataBlockInfo *datablock_info,
const bool prefix_relpath_with_group_name,
const int idcode,
const char *group_name)
@@ -3010,21 +3024,29 @@ 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) {
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;
+
+ if (filelist->asset_library) {
+ /** XXX Moving out the asset metadata like this isn't great. */
+ std::unique_ptr metadata = BKE_asset_metadata_move_to_unique_ptr(
+ datablock_info->asset_data);
+ BKE_asset_metadata_free(&datablock_info->asset_data);
+
+ entry->asset = &filelist->asset_library->add_external_asset(datablock_info->name,
+ std::move(metadata));
+ }
}
}
entry->blentype = idcode;
BLI_addtail(entries, entry);
}
-static void filelist_readjob_list_lib_add_datablocks(ListBase *entries,
+static void filelist_readjob_list_lib_add_datablocks(FileList *filelist,
+ ListBase *entries,
LinkNode *datablock_infos,
const bool prefix_relpath_with_group_name,
const int idcode,
@@ -3033,19 +3055,21 @@ static void filelist_readjob_list_lib_add_datablocks(ListBase *entries,
for (LinkNode *ln = datablock_infos; ln; ln = ln->next) {
struct BLODataBlockInfo *datablock_info = static_cast<BLODataBlockInfo *>(ln->link);
filelist_readjob_list_lib_add_datablock(
- entries, datablock_info, prefix_relpath_with_group_name, idcode, group_name);
+ filelist, entries, datablock_info, prefix_relpath_with_group_name, idcode, group_name);
}
}
static void filelist_readjob_list_lib_add_from_indexer_entries(
+ FileList *filelist,
ListBase *entries,
const FileIndexerEntries *indexer_entries,
const bool prefix_relpath_with_group_name)
{
for (const LinkNode *ln = indexer_entries->entries; ln; ln = ln->next) {
- const FileIndexerEntry *indexer_entry = (const FileIndexerEntry *)ln->link;
+ FileIndexerEntry *indexer_entry = static_cast<FileIndexerEntry *>(ln->link);
const char *group_name = BKE_idtype_idcode_to_name(indexer_entry->idcode);
- filelist_readjob_list_lib_add_datablock(entries,
+ filelist_readjob_list_lib_add_datablock(filelist,
+ entries,
&indexer_entry->datablock_info,
prefix_relpath_with_group_name,
indexer_entry->idcode,
@@ -3073,7 +3097,8 @@ typedef struct FileIndexer {
void *user_data;
} FileIndexer;
-static int filelist_readjob_list_lib_populate_from_index(ListBase *entries,
+static int filelist_readjob_list_lib_populate_from_index(FileList *filelist,
+ ListBase *entries,
const ListLibOptions options,
const int read_from_index,
const FileIndexerEntries *indexer_entries)
@@ -3085,11 +3110,12 @@ static int filelist_readjob_list_lib_populate_from_index(ListBase *entries,
navigate_to_parent_len = 1;
}
- filelist_readjob_list_lib_add_from_indexer_entries(entries, indexer_entries, true);
+ filelist_readjob_list_lib_add_from_indexer_entries(filelist, entries, indexer_entries, true);
return read_from_index + navigate_to_parent_len;
}
-static int filelist_readjob_list_lib(const char *root,
+static int filelist_readjob_list_lib(FileList *filelist,
+ const char *root,
ListBase *entries,
const ListLibOptions options,
FileIndexer *indexer_runtime)
@@ -3128,7 +3154,7 @@ static int filelist_readjob_list_lib(const char *root,
dir, &indexer_entries, &read_from_index, indexer_runtime->user_data);
if (indexer_result == FILE_INDEXER_ENTRIES_LOADED) {
int entries_read = filelist_readjob_list_lib_populate_from_index(
- entries, options, read_from_index, &indexer_entries);
+ filelist, entries, options, read_from_index, &indexer_entries);
ED_file_indexer_entries_clear(&indexer_entries);
return entries_read;
}
@@ -3158,7 +3184,8 @@ static int filelist_readjob_list_lib(const char *root,
const int idcode = groupname_to_code(group);
LinkNode *datablock_infos = BLO_blendhandle_get_datablock_info(
libfiledata, idcode, options & LIST_LIB_ASSETS_ONLY, &datablock_len);
- filelist_readjob_list_lib_add_datablocks(entries, datablock_infos, false, idcode, group);
+ filelist_readjob_list_lib_add_datablocks(
+ filelist, entries, datablock_infos, false, idcode, group);
BLI_linklist_freeN(datablock_infos);
}
else {
@@ -3177,7 +3204,7 @@ static int filelist_readjob_list_lib(const char *root,
LinkNode *group_datablock_infos = BLO_blendhandle_get_datablock_info(
libfiledata, idcode, options & LIST_LIB_ASSETS_ONLY, &group_datablock_len);
filelist_readjob_list_lib_add_datablocks(
- entries, group_datablock_infos, true, idcode, group_name);
+ filelist, entries, group_datablock_infos, true, idcode, group_name);
if (use_indexer) {
ED_file_indexer_entries_extend_from_datablock_infos(
&indexer_entries, group_datablock_infos, idcode);
@@ -3529,7 +3556,7 @@ static void filelist_readjob_recursive_dir_add_items(const bool do_lib,
list_lib_options |= LIST_LIB_ASSETS_ONLY;
}
entries_num = filelist_readjob_list_lib(
- subdir, &entries, list_lib_options, &indexer_runtime);
+ filelist, subdir, &entries, list_lib_options, &indexer_runtime);
if (entries_num > 0) {
is_lib = true;
}
@@ -3550,7 +3577,7 @@ static void filelist_readjob_recursive_dir_add_items(const bool do_lib,
MEM_freeN(entry->relpath);
entry->relpath = BLI_strdup(dir + 2); /* + 2 to remove '//'
* added by BLI_path_rel to rel_subdir. */
- entry->name = fileentry_uiname(root, entry->relpath, entry->typeflag, dir);
+ entry->name = fileentry_uiname(root, entry, dir);
entry->free_name = true;
if (filelist_readjob_should_recurse_into_entry(
@@ -3626,20 +3653,6 @@ static void filelist_readjob_lib(FileListReadJob *job_params,
filelist_readjob_do(true, job_params, stop, do_update, progress);
}
-static void filelist_asset_library_path(const FileListReadJob *job_params,
- char r_library_root_path[FILE_MAX])
-{
- if (job_params->filelist->type == FILE_MAIN_ASSET) {
- /* For the "Current File" library (#FILE_MAIN_ASSET) we get the asset library root path based
- * on main. */
- BKE_asset_library_find_suitable_root_path_from_main(job_params->current_main,
- r_library_root_path);
- }
- else {
- BLI_strncpy(r_library_root_path, job_params->tmp_filelist->filelist.root, FILE_MAX);
- }
-}
-
/**
* Load asset library data, which currently means loading the asset catalogs for the library.
*/
@@ -3657,12 +3670,10 @@ static void filelist_readjob_load_asset_library_data(FileListReadJob *job_params
return;
}
- char library_root_path[FILE_MAX];
- filelist_asset_library_path(job_params, library_root_path);
-
/* Load asset catalogs, into the temp filelist for thread-safety.
* #filelist_readjob_endjob() will move it into the real filelist. */
- tmp_filelist->asset_library = BKE_asset_library_load(library_root_path);
+ tmp_filelist->asset_library = BKE_asset_library_load(job_params->current_main,
+ *job_params->filelist->asset_library_ref);
*do_update = true;
}
@@ -3699,6 +3710,9 @@ static void filelist_readjob_main_assets_add_items(FileListReadJob *job_params,
entry->local_data.preview_image = BKE_asset_metadata_preview_get_from_id(id_iter->asset_data,
id_iter);
entry->local_data.id = id_iter;
+ if (filelist->asset_library) {
+ entry->asset = &filelist->asset_library->add_local_id_asset(*id_iter);
+ }
entries_num++;
BLI_addtail(&tmp_entries, entry);
}
diff --git a/source/blender/editors/space_file/space_file.c b/source/blender/editors/space_file/space_file.c
index 74f1b8e838a..95b87f06d96 100644
--- a/source/blender/editors/space_file/space_file.c
+++ b/source/blender/editors/space_file/space_file.c
@@ -950,7 +950,7 @@ static int /*eContextResult*/ file_context(const bContext *C,
for (int file_index = 0; file_index < num_files_filtered; file_index++) {
if (filelist_entry_is_selected(sfile->files, file_index)) {
FileDirEntry *entry = filelist_file(sfile->files, file_index);
- if (entry->asset_data) {
+ if (entry->asset) {
CTX_data_list_add(result, &screen->id, &RNA_FileSelectEntry, entry);
}
}
diff --git a/source/blender/editors/space_graph/graph_edit.c b/source/blender/editors/space_graph/graph_edit.c
index a23b33dde95..cb01b0d9dc8 100644
--- a/source/blender/editors/space_graph/graph_edit.c
+++ b/source/blender/editors/space_graph/graph_edit.c
@@ -2333,6 +2333,48 @@ static int graphkeys_snap_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
+static bool graph_has_selected_control_points(struct bContext *C)
+{
+ bAnimContext ac;
+ ListBase anim_data = {NULL, NULL};
+
+ /* Get editor data. */
+ if (ANIM_animdata_get_context(C, &ac) == 0) {
+ return OPERATOR_CANCELLED;
+ }
+
+ /* Filter data. */
+ const int filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_FCURVESONLY |
+ ANIMFILTER_FOREDIT | ANIMFILTER_NODUPLIS);
+ ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
+
+ /* Check if any of the visible and editable f-curves have at least one selected control point. */
+ bool has_selected_control_points = false;
+ LISTBASE_FOREACH (bAnimListElem *, ale, &anim_data) {
+ const FCurve *fcu = ale->key_data;
+ if (BKE_fcurve_has_selected_control_points(fcu)) {
+ has_selected_control_points = true;
+ break;
+ }
+ }
+
+ ANIM_animdata_freelist(&anim_data);
+
+ return has_selected_control_points;
+}
+
+static int graphkeys_selected_control_points_invoke(struct bContext *C,
+ struct wmOperator *op,
+ const struct wmEvent *event)
+{
+ if (!graph_has_selected_control_points(C)) {
+ BKE_report(op->reports, RPT_ERROR, "No control points are selected");
+ return OPERATOR_CANCELLED;
+ }
+
+ return WM_menu_invoke(C, op, event);
+}
+
void GRAPH_OT_snap(wmOperatorType *ot)
{
/* Identifiers */
@@ -2341,7 +2383,7 @@ void GRAPH_OT_snap(wmOperatorType *ot)
ot->description = "Snap selected keyframes to the chosen times/values";
/* API callbacks */
- ot->invoke = WM_menu_invoke;
+ ot->invoke = graphkeys_selected_control_points_invoke;
ot->exec = graphkeys_snap_exec;
ot->poll = graphop_editable_keyframes_poll;
@@ -2418,7 +2460,7 @@ void GRAPH_OT_equalize_handles(wmOperatorType *ot)
"Ensure selected keyframes' handles have equal length, optionally making them horizontal. "
"Automatic, Automatic Clamped, or Vector handle types will be converted to Aligned";
/* API callbacks */
- ot->invoke = WM_menu_invoke;
+ ot->invoke = graphkeys_selected_control_points_invoke;
ot->exec = graphkeys_equalize_handles_exec;
ot->poll = graphop_editable_keyframes_poll;
diff --git a/source/blender/editors/space_graph/graph_slider_ops.c b/source/blender/editors/space_graph/graph_slider_ops.c
index f3d92911155..62aecf930d3 100644
--- a/source/blender/editors/space_graph/graph_slider_ops.c
+++ b/source/blender/editors/space_graph/graph_slider_ops.c
@@ -458,16 +458,13 @@ static bool decimate_poll_property(const bContext *UNUSED(C),
const PropertyRNA *prop)
{
const char *prop_id = RNA_property_identifier(prop);
+ const int mode = RNA_enum_get(op->ptr, "mode");
- if (STRPREFIX(prop_id, "remove")) {
- int mode = RNA_enum_get(op->ptr, "mode");
-
- if (STREQ(prop_id, "factor") && mode != DECIM_RATIO) {
- return false;
- }
- if (STREQ(prop_id, "remove_error_margin") && mode != DECIM_ERROR) {
- return false;
- }
+ if (STREQ(prop_id, "factor") && mode != DECIM_RATIO) {
+ return false;
+ }
+ if (STREQ(prop_id, "remove_error_margin") && mode != DECIM_ERROR) {
+ return false;
}
return true;
diff --git a/source/blender/editors/space_node/node_relationships.cc b/source/blender/editors/space_node/node_relationships.cc
index 637c795d4d7..8eeba8727dc 100644
--- a/source/blender/editors/space_node/node_relationships.cc
+++ b/source/blender/editors/space_node/node_relationships.cc
@@ -1678,6 +1678,7 @@ static int node_join_exec(bContext *C, wmOperator * /*op*/)
const Set<bNode *> selected_nodes = get_selected_nodes(ntree);
bNode *frame_node = nodeAddStaticNode(C, &ntree, NODE_FRAME);
+ nodeSetActive(&ntree, frame_node);
/* reset tags */
LISTBASE_FOREACH (bNode *, node, &ntree.nodes) {
diff --git a/source/blender/editors/space_node/space_node.cc b/source/blender/editors/space_node/space_node.cc
index ce0273eec81..c993fa57d76 100644
--- a/source/blender/editors/space_node/space_node.cc
+++ b/source/blender/editors/space_node/space_node.cc
@@ -5,6 +5,7 @@
* \ingroup spnode
*/
+#include "DNA_ID.h"
#include "DNA_gpencil_types.h"
#include "DNA_light_types.h"
#include "DNA_material_types.h"
@@ -28,6 +29,8 @@
#include "UI_resources.h"
#include "UI_view2d.h"
+#include "DEG_depsgraph.h"
+
#include "BLO_read_write.h"
#include "RNA_access.h"
@@ -191,6 +194,13 @@ void ED_node_set_active_viewer_key(SpaceNode *snode)
{
bNodeTreePath *path = (bNodeTreePath *)snode->treepath.last;
if (snode->nodetree && path) {
+ /* A change in active viewer may result in the change of the output node used by the
+ * compositor, so we need to get notified about such changes. */
+ if (snode->nodetree->active_viewer_key.value != path->parent_key.value) {
+ DEG_id_tag_update(&snode->nodetree->id, ID_RECALC_NTREE_OUTPUT);
+ WM_main_add_notifier(NC_NODE, nullptr);
+ }
+
snode->nodetree->active_viewer_key = path->parent_key;
}
}
diff --git a/source/blender/editors/space_text/text_ops.c b/source/blender/editors/space_text/text_ops.c
index f0196bf8e00..0ddd06ead62 100644
--- a/source/blender/editors/space_text/text_ops.c
+++ b/source/blender/editors/space_text/text_ops.c
@@ -3487,10 +3487,10 @@ static int text_insert_invoke(bContext *C, wmOperator *op, const wmEvent *event)
/* NOTE: the "text" property is always set from key-map,
* so we can't use #RNA_struct_property_is_set, check the length instead. */
if (!RNA_string_length(op->ptr, "text")) {
- /* if alt/ctrl/super are pressed pass through except for utf8 character event
+ /* If Alt/Control/Super are pressed pass through except for utf8 character event
* (when input method are used for utf8 inputs, the user may assign key event
- * including alt/ctrl/super like ctrl+m to commit utf8 string. in such case,
- * the modifiers in the utf8 character event make no sense.) */
+ * including Alt/Control/Super like Control-M to commit utf8 string.
+ * In such case, the modifiers in the utf8 character event make no sense). */
if ((event->modifier & (KM_CTRL | KM_OSKEY)) && !event->utf8_buf[0]) {
return OPERATOR_PASS_THROUGH;
}
diff --git a/source/blender/editors/space_view3d/view3d_draw.cc b/source/blender/editors/space_view3d/view3d_draw.cc
index b69b0d910ab..61f66150ce4 100644
--- a/source/blender/editors/space_view3d/view3d_draw.cc
+++ b/source/blender/editors/space_view3d/view3d_draw.cc
@@ -1717,6 +1717,7 @@ void ED_view3d_draw_offscreen(Depsgraph *depsgraph,
do_color_management,
ofs,
viewport);
+ DRW_cache_free_old_subdiv();
GPU_matrix_pop_projection();
GPU_matrix_pop();
diff --git a/source/blender/editors/space_view3d/view3d_gizmo_navigate.c b/source/blender/editors/space_view3d/view3d_gizmo_navigate.c
index 22ab6636c47..35ae745bab3 100644
--- a/source/blender/editors/space_view3d/view3d_gizmo_navigate.c
+++ b/source/blender/editors/space_view3d/view3d_gizmo_navigate.c
@@ -106,7 +106,6 @@ struct NavigateWidgetGroup {
char viewlock;
} rv3d;
} state;
- int region_size[2];
};
static bool WIDGETGROUP_navigate_poll(const bContext *C, wmGizmoGroupType *UNUSED(gzgt))
@@ -124,9 +123,6 @@ static void WIDGETGROUP_navigate_setup(const bContext *C, wmGizmoGroup *gzgroup)
{
struct NavigateWidgetGroup *navgroup = MEM_callocN(sizeof(struct NavigateWidgetGroup), __func__);
- navgroup->region_size[0] = -1;
- navgroup->region_size[1] = -1;
-
wmOperatorType *ot_view_axis = WM_operatortype_find("VIEW3D_OT_view_axis", true);
wmOperatorType *ot_view_camera = WM_operatortype_find("VIEW3D_OT_view_camera", true);
diff --git a/source/blender/editors/transform/transform_convert.c b/source/blender/editors/transform/transform_convert.c
index a5b2442f11c..d71a3897cbc 100644
--- a/source/blender/editors/transform/transform_convert.c
+++ b/source/blender/editors/transform/transform_convert.c
@@ -1109,7 +1109,7 @@ static TransConvertTypeInfo *convert_type_get(const TransInfo *t, Object **r_obj
PE_start_edit(PE_get_current(t->depsgraph, t->scene, ob))) {
return &TransConvertType_Particle;
}
- if (ob && (ob->mode & OB_MODE_ALL_PAINT)) {
+ if (ob && ((ob->mode & OB_MODE_ALL_PAINT) || (ob->mode & OB_MODE_SCULPT_CURVES))) {
if ((t->options & CTX_PAINT_CURVE) && !ELEM(t->mode, TFM_SHEAR, TFM_SHRINKFATTEN)) {
return &TransConvertType_PaintCurve;
}
diff --git a/source/blender/editors/transform/transform_generics.c b/source/blender/editors/transform/transform_generics.c
index e1f93bf881b..e7ef408b848 100644
--- a/source/blender/editors/transform/transform_generics.c
+++ b/source/blender/editors/transform/transform_generics.c
@@ -309,7 +309,7 @@ void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve
t->flag |= T_V3D_ALIGN;
}
- if (object_mode & OB_MODE_ALL_PAINT) {
+ if ((object_mode & OB_MODE_ALL_PAINT) || (object_mode & OB_MODE_SCULPT_CURVES)) {
Paint *p = BKE_paint_get_active_from_context(C);
if (p && p->brush && (p->brush->flag & BRUSH_CURVE)) {
t->options |= CTX_PAINT_CURVE;
diff --git a/source/blender/geometry/GEO_trim_curves.hh b/source/blender/geometry/GEO_trim_curves.hh
index d2ff770f225..197ef79c25b 100644
--- a/source/blender/geometry/GEO_trim_curves.hh
+++ b/source/blender/geometry/GEO_trim_curves.hh
@@ -3,6 +3,7 @@
#pragma once
#include "BLI_span.hh"
+#include "DNA_node_types.h"
#include "BKE_curves.hh"
#include "BKE_curves_utils.hh"
@@ -16,21 +17,8 @@ namespace blender::geometry {
*/
bke::CurvesGeometry trim_curves(const bke::CurvesGeometry &src_curves,
IndexMask selection,
- Span<bke::curves::CurvePoint> start_points,
- Span<bke::curves::CurvePoint> end_points);
-
-/**
- * Find the point(s) and piecewise segment corresponding to the given distance along the length of
- * the curve. Returns points on the evaluated curve for Catmull-Rom and NURBS splines.
- *
- * \param curves: Curve geometry to sample.
- * \param lengths: Distance along the curve on form [0.0, length] to determine the point for.
- * \param curve_indices: Curve index to lookup for each 'length', negative index are set to 0.
- * \param normalized_factors: If true, 'lengths' are normalized to the interval [0.0, 1.0].
- */
-Array<bke::curves::CurvePoint, 12> lookup_curve_points(const bke::CurvesGeometry &curves,
- Span<float> lengths,
- Span<int64_t> curve_indices,
- bool normalized_factors);
+ const VArray<float> &starts,
+ const VArray<float> &ends,
+ GeometryNodeCurveSampleMode mode);
} // namespace blender::geometry
diff --git a/source/blender/geometry/intern/set_curve_type.cc b/source/blender/geometry/intern/set_curve_type.cc
index 4233c62c7b3..e069732ca9b 100644
--- a/source/blender/geometry/intern/set_curve_type.cc
+++ b/source/blender/geometry/intern/set_curve_type.cc
@@ -257,7 +257,7 @@ static int to_bezier_size(const CurveType src_type,
switch (src_type) {
case CURVE_TYPE_NURBS: {
if (is_nurbs_to_bezier_one_to_one(knots_mode)) {
- return cyclic ? src_size : src_size - 2;
+ return cyclic ? src_size : std::max(1, src_size - 2);
}
return (src_size + 1) / 3;
}
@@ -392,6 +392,13 @@ static bke::CurvesGeometry convert_curves_to_bezier(const bke::CurvesGeometry &s
const IndexRange src_points = src_curves.points_for_curve(i);
const IndexRange dst_points = dst_curves.points_for_curve(i);
const Span<float3> src_curve_positions = src_positions.slice(src_points);
+ if (dst_points.size() == 1) {
+ const float3 &position = src_positions[src_points.first()];
+ dst_positions[dst_points.first()] = position;
+ dst_handles_l[dst_points.first()] = position;
+ dst_handles_r[dst_points.first()] = position;
+ continue;
+ }
KnotsMode knots_mode = KnotsMode(src_knot_modes[i]);
Span<float3> nurbs_positions = src_curve_positions;
diff --git a/source/blender/geometry/intern/trim_curves.cc b/source/blender/geometry/intern/trim_curves.cc
index f2adc3b58d3..1aff07f2b4e 100644
--- a/source/blender/geometry/intern/trim_curves.cc
+++ b/source/blender/geometry/intern/trim_curves.cc
@@ -18,61 +18,6 @@
namespace blender::geometry {
/* -------------------------------------------------------------------- */
-/** \name Curve Enums
- * \{ */
-
-#define CURVE_TYPE_AS_MASK(curve_type) ((CurveTypeMask)(1 << int(curve_type)))
-
-enum CurveTypeMask {
- CURVE_TYPE_MASK_CATMULL_ROM = (1 << 0),
- CURVE_TYPE_MASK_POLY = (1 << 1),
- CURVE_TYPE_MASK_BEZIER = (1 << 2),
- CURVE_TYPE_MASK_NURBS = (1 << 3),
- CURVE_TYPE_MASK_ALL = (1 << 4) - 1
-};
-
-/** \} */
-
-/* -------------------------------------------------------------------- */
-/** \name #IndexRangeCyclic Utilities
- * \{ */
-
-/**
- * Create a cyclical iterator for all control points within the interval [start_point, end_point]
- * including any control point at the start or end point.
- *
- * \param start_point: Point on the curve that define the starting point of the interval.
- * \param end_point: Point on the curve that define the end point of the interval (included).
- * \param points: #IndexRange for the curve points.
- */
-static bke::curves::IndexRangeCyclic get_range_between_endpoints(
- const bke::curves::CurvePoint start_point,
- const bke::curves::CurvePoint end_point,
- const IndexRange points)
-{
- const int64_t start_index = start_point.parameter == 0.0 ? start_point.index :
- start_point.next_index;
- int64_t end_index = end_point.parameter == 0.0 ? end_point.index : end_point.next_index;
- int64_t cycles;
-
- if (end_point.is_controlpoint()) {
- ++end_index;
- if (end_index > points.last()) {
- end_index = points.one_after_last();
- }
- /* end_point < start_point but parameter is irrelevant (end_point is controlpoint), and loop
- * when equal due to increment. */
- cycles = end_index <= start_index;
- }
- else {
- cycles = end_point < start_point || end_index < start_index;
- }
- return bke::curves::IndexRangeCyclic(start_index, end_index, points, cycles);
-}
-
-/** \} */
-
-/* -------------------------------------------------------------------- */
/** \name Lookup Curve Points
* \{ */
@@ -88,11 +33,11 @@ static bke::curves::IndexRangeCyclic get_range_between_endpoints(
* \param num_curve_points: Total number of control points in the curve.
* \return: Point on the piecewise segment matching the given distance.
*/
-static bke::curves::CurvePoint lookup_curve_point(const Span<float> lengths,
- const float sample_length,
- const bool cyclic,
- const int resolution,
- const int num_curve_points)
+static bke::curves::CurvePoint lookup_point_uniform_spacing(const Span<float> lengths,
+ const float sample_length,
+ const bool cyclic,
+ const int resolution,
+ const int num_curve_points)
{
BLI_assert(!cyclic || lengths.size() / resolution >= 2);
const int last_index = num_curve_points - 1;
@@ -117,7 +62,7 @@ static bke::curves::CurvePoint lookup_curve_point(const Span<float> lengths,
/**
* Find the point on the 'evaluated' polygonal curve.
*/
-static bke::curves::CurvePoint lookup_evaluated_point(const Span<float> lengths,
+static bke::curves::CurvePoint lookup_point_polygonal(const Span<float> lengths,
const float sample_length,
const bool cyclic,
const int evaluated_size)
@@ -142,7 +87,7 @@ static bke::curves::CurvePoint lookup_evaluated_point(const Span<float> lengths,
/**
* Find the point on a Bezier curve using the 'bezier_offsets' cache.
*/
-static bke::curves::CurvePoint lookup_bezier_point(const Span<int> bezier_offsets,
+static bke::curves::CurvePoint lookup_point_bezier(const Span<int> bezier_offsets,
const Span<float> lengths,
const float sample_length,
const bool cyclic,
@@ -166,197 +111,73 @@ static bke::curves::CurvePoint lookup_bezier_point(const Span<int> bezier_offset
const int right = left == last_index ? 0 : left + 1;
const int prev_offset = left == 0 ? 0 : bezier_offsets[int64_t(left) - 1];
- const float offset_in_segment = eval_factor + eval_index - prev_offset;
+ const float offset_in_segment = eval_factor + (eval_index - prev_offset);
const int segment_resolution = bezier_offsets[left] - prev_offset;
const float parameter = std::clamp(offset_in_segment / segment_resolution, 0.0f, 1.0f);
return {{left, right}, parameter};
}
-Array<bke::curves::CurvePoint, 12> lookup_curve_points(const bke::CurvesGeometry &curves,
- const Span<float> lengths,
- const Span<int64_t> curve_indices,
- const bool normalized_factors)
-{
- BLI_assert(lengths.size() == curve_indices.size());
- BLI_assert(*std::max_element(curve_indices.begin(), curve_indices.end()) < curves.curves_num());
-
- const VArray<bool> cyclic = curves.cyclic();
- const VArray<int> resolution = curves.resolution();
- const VArray<int8_t> curve_types = curves.curve_types();
-
- /* Compute curve lengths! */
- curves.ensure_evaluated_lengths();
- curves.ensure_evaluated_offsets();
-
- /* Find the curve points referenced by the input! */
- Array<bke::curves::CurvePoint, 12> lookups(curve_indices.size());
- threading::parallel_for(curve_indices.index_range(), 128, [&](const IndexRange range) {
- for (const int64_t lookup_index : range) {
- const int64_t curve_i = curve_indices[lookup_index];
-
- const int point_count = curves.points_num_for_curve(curve_i);
- if (curve_i < 0 || point_count == 1) {
- lookups[lookup_index] = {{0, 0}, 0.0f};
- continue;
- }
-
- const Span<float> accumulated_lengths = curves.evaluated_lengths_for_curve(curve_i,
- cyclic[curve_i]);
- BLI_assert(accumulated_lengths.size() > 0);
-
- const float sample_length = normalized_factors ?
- lengths[lookup_index] * accumulated_lengths.last() :
- lengths[lookup_index];
-
- const CurveType curve_type = (CurveType)curve_types[curve_i];
-
- switch (curve_type) {
- case CURVE_TYPE_BEZIER: {
- if (bke::curves::bezier::has_vector_handles(
- point_count,
- curves.evaluated_points_for_curve(curve_i).size(),
- cyclic[curve_i],
- resolution[curve_i])) {
- const Span<int> bezier_offsets = curves.bezier_evaluated_offsets_for_curve(curve_i);
- lookups[lookup_index] = lookup_bezier_point(
- bezier_offsets, accumulated_lengths, sample_length, cyclic[curve_i], point_count);
- }
- else {
- lookups[lookup_index] = lookup_curve_point(accumulated_lengths,
- sample_length,
- cyclic[curve_i],
- resolution[curve_i],
- point_count);
- }
- break;
- }
- case CURVE_TYPE_CATMULL_ROM: {
- lookups[lookup_index] = lookup_curve_point(accumulated_lengths,
- sample_length,
- cyclic[curve_i],
- resolution[curve_i],
- point_count);
- break;
- }
- case CURVE_TYPE_NURBS:
- case CURVE_TYPE_POLY:
- default: {
- /* Handle general case as an "evaluated" or polygonal curve. */
- BLI_assert(resolution[curve_i] > 0);
- lookups[lookup_index] = lookup_evaluated_point(
- accumulated_lengths,
- sample_length,
- cyclic[curve_i],
- curves.evaluated_points_for_curve(curve_i).size());
- break;
- }
- }
- }
- });
- return lookups;
-}
-
-/** \} */
-
-/* -------------------------------------------------------------------- */
-/** \name Transfer Curve Domain
- * \{ */
-
-/**
- * Determine curve type(s) for the copied curves given the supported set of types and knot modes.
- * If a curve type is not supported the default type is set.
- */
-static void determine_copyable_curve_types(
- const bke::CurvesGeometry &src_curves,
- bke::CurvesGeometry &dst_curves,
- const IndexMask selection,
- const IndexMask selection_inverse,
- const CurveTypeMask supported_curve_type_mask,
- const int8_t default_curve_type = int8_t(CURVE_TYPE_POLY))
-{
- const VArray<int8_t> src_curve_types = src_curves.curve_types();
- const VArray<int8_t> src_knot_modes = src_curves.nurbs_knots_modes();
- MutableSpan<int8_t> dst_curve_types = dst_curves.curve_types_for_write();
-
- threading::parallel_for(selection.index_range(), 4096, [&](const IndexRange selection_range) {
- for (const int64_t curve_i : selection.slice(selection_range)) {
- if (supported_curve_type_mask & CURVE_TYPE_AS_MASK(src_curve_types[curve_i])) {
- dst_curve_types[curve_i] = src_curve_types[curve_i];
- }
- else {
- dst_curve_types[curve_i] = default_curve_type;
- }
- }
- });
-
- array_utils::copy(src_curve_types, selection_inverse, dst_curve_types);
-}
-
-/**
- * Determine if a curve is treated as an evaluated curve. Curves which inherently do not support
- * trimming are discretized (e.g. NURBS).
- */
-static bool copy_as_evaluated_curve(const int8_t src_type, const int8_t dst_type)
+static bke::curves::CurvePoint lookup_point_bezier(const bke::CurvesGeometry &src_curves,
+ const int64_t curve_index,
+ const Span<float> accumulated_lengths,
+ const float sample_length,
+ const bool cyclic,
+ const int resolution,
+ const int num_curve_points)
{
- return src_type != CURVE_TYPE_POLY && dst_type == CURVE_TYPE_POLY;
+ if (bke::curves::bezier::has_vector_handles(
+ num_curve_points,
+ src_curves.evaluated_points_for_curve(curve_index).size(),
+ cyclic,
+ resolution)) {
+ const Span<int> bezier_offsets = src_curves.bezier_evaluated_offsets_for_curve(curve_index);
+ return lookup_point_bezier(
+ bezier_offsets, accumulated_lengths, sample_length, cyclic, num_curve_points);
+ }
+ else {
+ return lookup_point_uniform_spacing(
+ accumulated_lengths, sample_length, cyclic, resolution, num_curve_points);
+ }
}
-/** \} */
-
-/* -------------------------------------------------------------------- */
-/** \name Specialized Curve Constructors
- * \{ */
-
-static void compute_trim_result_offsets(const bke::CurvesGeometry &src_curves,
- const IndexMask selection,
- const IndexMask inverse_selection,
- const Span<bke::curves::CurvePoint> start_points,
- const Span<bke::curves::CurvePoint> end_points,
- const VArray<int8_t> dst_curve_types,
- MutableSpan<int> dst_curve_offsets,
- Vector<int64_t> &r_curve_indices,
- Vector<int64_t> &r_point_curve_indices)
+static bke::curves::CurvePoint lookup_curve_point(const bke::CurvesGeometry &src_curves,
+ const CurveType curve_type,
+ const int64_t curve_index,
+ const Span<float> accumulated_lengths,
+ const float sample_length,
+ const bool cyclic,
+ const int resolution,
+ const int num_curve_points)
{
- BLI_assert(r_curve_indices.size() == 0);
- BLI_assert(r_point_curve_indices.size() == 0);
- const VArray<bool> cyclic = src_curves.cyclic();
- const VArray<int8_t> curve_types = src_curves.curve_types();
- r_curve_indices.reserve(selection.size());
-
- for (const int64_t curve_i : selection) {
-
- int64_t src_point_count;
-
- if (copy_as_evaluated_curve(curve_types[curve_i], dst_curve_types[curve_i])) {
- src_point_count = src_curves.evaluated_points_for_curve(curve_i).size();
- }
- else {
- src_point_count = int64_t(src_curves.points_num_for_curve(curve_i));
- }
- BLI_assert(src_point_count > 0);
+ if (num_curve_points == 1) {
+ return {{0, 0}, 0.0f};
+ }
- if (start_points[curve_i] == end_points[curve_i]) {
- dst_curve_offsets[curve_i] = 1;
- r_point_curve_indices.append(curve_i);
- }
- else {
- const bke::curves::IndexRangeCyclic point_range = get_range_between_endpoints(
- start_points[curve_i], end_points[curve_i], {0, src_point_count});
- const int count = point_range.size() + !start_points[curve_i].is_controlpoint() +
- !end_points[curve_i].is_controlpoint();
- dst_curve_offsets[curve_i] = count;
- r_curve_indices.append(curve_i);
- }
- BLI_assert(dst_curve_offsets[curve_i] > 0);
+ if (curve_type == CURVE_TYPE_CATMULL_ROM) {
+ return lookup_point_uniform_spacing(
+ accumulated_lengths, sample_length, cyclic, resolution, num_curve_points);
+ }
+ else if (curve_type == CURVE_TYPE_BEZIER) {
+ return lookup_point_bezier(src_curves,
+ curve_index,
+ accumulated_lengths,
+ sample_length,
+ cyclic,
+ resolution,
+ num_curve_points);
+ }
+ else if (curve_type == CURVE_TYPE_POLY) {
+ return lookup_point_polygonal(accumulated_lengths, sample_length, cyclic, num_curve_points);
+ }
+ else {
+ /* Handle evaluated curve. */
+ BLI_assert(resolution > 0);
+ return lookup_point_polygonal(accumulated_lengths,
+ sample_length,
+ cyclic,
+ src_curves.evaluated_points_for_curve(curve_index).size());
}
- threading::parallel_for(
- inverse_selection.index_range(), 4096, [&](const IndexRange selection_range) {
- for (const int64_t curve_i : inverse_selection.slice(selection_range)) {
- dst_curve_offsets[curve_i] = src_curves.points_num_for_curve(curve_i);
- }
- });
- bke::curves::accumulate_counts_to_offsets(dst_curve_offsets);
}
/** \} */
@@ -367,41 +188,42 @@ static void compute_trim_result_offsets(const bke::CurvesGeometry &src_curves,
static void fill_bezier_data(bke::CurvesGeometry &dst_curves, const IndexMask selection)
{
- if (dst_curves.has_curve_with_type(CURVE_TYPE_BEZIER)) {
- MutableSpan<float3> handle_positions_left = dst_curves.handle_positions_left_for_write();
- MutableSpan<float3> handle_positions_right = dst_curves.handle_positions_right_for_write();
- MutableSpan<int8_t> handle_types_left = dst_curves.handle_types_left_for_write();
- MutableSpan<int8_t> handle_types_right = dst_curves.handle_types_right_for_write();
-
- threading::parallel_for(selection.index_range(), 4096, [&](const IndexRange range) {
- for (const int64_t curve_i : selection.slice(range)) {
- const IndexRange points = dst_curves.points_for_curve(curve_i);
- handle_types_right.slice(points).fill(int8_t(BEZIER_HANDLE_FREE));
- handle_types_left.slice(points).fill(int8_t(BEZIER_HANDLE_FREE));
- handle_positions_left.slice(points).fill({0.0f, 0.0f, 0.0f});
- handle_positions_right.slice(points).fill({0.0f, 0.0f, 0.0f});
- }
- });
+ if (!dst_curves.has_curve_with_type(CURVE_TYPE_BEZIER)) {
+ return;
}
+ MutableSpan<float3> handle_positions_left = dst_curves.handle_positions_left_for_write();
+ MutableSpan<float3> handle_positions_right = dst_curves.handle_positions_right_for_write();
+ MutableSpan<int8_t> handle_types_left = dst_curves.handle_types_left_for_write();
+ MutableSpan<int8_t> handle_types_right = dst_curves.handle_types_right_for_write();
+
+ threading::parallel_for(selection.index_range(), 4096, [&](const IndexRange range) {
+ for (const int64_t curve_i : selection.slice(range)) {
+ const IndexRange points = dst_curves.points_for_curve(curve_i);
+ handle_types_right.slice(points).fill(int8_t(BEZIER_HANDLE_FREE));
+ handle_types_left.slice(points).fill(int8_t(BEZIER_HANDLE_FREE));
+ handle_positions_left.slice(points).fill({0.0f, 0.0f, 0.0f});
+ handle_positions_right.slice(points).fill({0.0f, 0.0f, 0.0f});
+ }
+ });
}
static void fill_nurbs_data(bke::CurvesGeometry &dst_curves, const IndexMask selection)
{
- if (dst_curves.has_curve_with_type(CURVE_TYPE_NURBS)) {
- bke::curves::fill_points(dst_curves, selection, 0.0f, dst_curves.nurbs_weights_for_write());
+ if (!dst_curves.has_curve_with_type(CURVE_TYPE_NURBS)) {
+ return;
}
+ bke::curves::fill_points(dst_curves, selection, 0.0f, dst_curves.nurbs_weights_for_write());
}
template<typename T>
static int64_t copy_point_data_between_endpoints(const Span<T> src_data,
MutableSpan<T> dst_data,
const bke::curves::IndexRangeCyclic src_range,
- const int64_t src_index,
int64_t dst_index)
{
int64_t increment;
if (src_range.cycles()) {
increment = src_range.size_before_loop();
- dst_data.slice(dst_index, increment).copy_from(src_data.slice(src_index, increment));
+ dst_data.slice(dst_index, increment).copy_from(src_data.slice(src_range.first(), increment));
dst_index += increment;
increment = src_range.size_after_loop();
@@ -411,7 +233,7 @@ static int64_t copy_point_data_between_endpoints(const Span<T> src_data,
}
else {
increment = src_range.one_after_last() - src_range.first();
- dst_data.slice(dst_index, increment).copy_from(src_data.slice(src_index, increment));
+ dst_data.slice(dst_index, increment).copy_from(src_data.slice(src_range.first(), increment));
dst_index += increment;
}
return dst_index;
@@ -466,82 +288,6 @@ static bke::curves::bezier::Insertion knot_insert_bezier(
/** \} */
/* -------------------------------------------------------------------- */
-/** \name Sample Single Point
- * \{ */
-
-template<typename T>
-static void sample_linear(const Span<T> src_data,
- MutableSpan<T> dst_data,
- const IndexRange dst_range,
- const bke::curves::CurvePoint sample_point)
-{
- BLI_assert(dst_range.size() == 1);
- if (sample_point.is_controlpoint()) {
- /* Resolves cases where the source curve consist of a single control point. */
- const int index = sample_point.parameter == 1.0 ? sample_point.next_index : sample_point.index;
- dst_data[dst_range.first()] = src_data[index];
- }
- else {
- dst_data[dst_range.first()] = attribute_math::mix2(
- sample_point.parameter, src_data[sample_point.index], src_data[sample_point.next_index]);
- }
-}
-
-template<typename T>
-static void sample_catmull_rom(const Span<T> src_data,
- MutableSpan<T> dst_data,
- const IndexRange dst_range,
- const bke::curves::CurvePoint sample_point,
- const bool src_cyclic)
-{
- BLI_assert(dst_range.size() == 1);
- if (sample_point.is_controlpoint()) {
- /* Resolves cases where the source curve consist of a single control point. */
- const int index = sample_point.parameter == 1.0 ? sample_point.next_index : sample_point.index;
- dst_data[dst_range.first()] = src_data[index];
- }
- else {
- dst_data[dst_range.first()] = interpolate_catmull_rom(src_data, sample_point, src_cyclic);
- }
-}
-
-static void sample_bezier(const Span<float3> src_positions,
- const Span<float3> src_handles_l,
- const Span<float3> src_handles_r,
- const Span<int8_t> src_types_l,
- const Span<int8_t> src_types_r,
- MutableSpan<float3> dst_positions,
- MutableSpan<float3> dst_handles_l,
- MutableSpan<float3> dst_handles_r,
- MutableSpan<int8_t> dst_types_l,
- MutableSpan<int8_t> dst_types_r,
- const IndexRange dst_range,
- const bke::curves::CurvePoint sample_point)
-{
- BLI_assert(dst_range.size() == 1);
- if (sample_point.is_controlpoint()) {
- /* Resolves cases where the source curve consist of a single control point. */
- const int index = sample_point.parameter == 1.0 ? sample_point.next_index : sample_point.index;
- dst_positions[dst_range.first()] = src_positions[index];
- dst_handles_l[dst_range.first()] = src_handles_l[index];
- dst_handles_r[dst_range.first()] = src_handles_r[index];
- dst_types_l[dst_range.first()] = src_types_l[index];
- dst_types_r[dst_range.first()] = src_types_r[index];
- }
- else {
- bke::curves::bezier::Insertion insertion_point = knot_insert_bezier(
- src_positions, src_handles_l, src_handles_r, sample_point);
- dst_positions[dst_range.first()] = insertion_point.position;
- dst_handles_l[dst_range.first()] = insertion_point.left_handle;
- dst_handles_r[dst_range.first()] = insertion_point.right_handle;
- dst_types_l[dst_range.first()] = BEZIER_HANDLE_FREE;
- dst_types_r[dst_range.first()] = BEZIER_HANDLE_FREE;
- }
-}
-
-/** \} */
-
-/* -------------------------------------------------------------------- */
/** \name Sample Curve Interval (Trim)
* \{ */
@@ -561,19 +307,18 @@ static void sample_bezier(const Span<float3> src_positions,
template<typename T, bool include_start_point = true>
static void sample_interval_linear(const Span<T> src_data,
MutableSpan<T> dst_data,
- const bke::curves::IndexRangeCyclic src_range,
+ bke::curves::IndexRangeCyclic src_range,
const IndexRange dst_range,
const bke::curves::CurvePoint start_point,
const bke::curves::CurvePoint end_point)
{
- int64_t src_index = src_range.first();
int64_t dst_index = dst_range.first();
if (start_point.is_controlpoint()) {
/* 'start_point' is included in the copy iteration. */
if constexpr (!include_start_point) {
/* Skip first. */
- ++src_index;
+ src_range = src_range.drop_front();
}
}
else if constexpr (!include_start_point) {
@@ -586,8 +331,11 @@ static void sample_interval_linear(const Span<T> src_data,
++dst_index;
}
- dst_index = copy_point_data_between_endpoints(
- src_data, dst_data, src_range, src_index, dst_index);
+ dst_index = copy_point_data_between_endpoints(src_data, dst_data, src_range, dst_index);
+ if (dst_range.size() == 1) {
+ BLI_assert(dst_index == dst_range.one_after_last());
+ return;
+ }
/* Handle last case */
if (end_point.is_controlpoint()) {
@@ -603,27 +351,18 @@ static void sample_interval_linear(const Span<T> src_data,
BLI_assert(dst_index == dst_range.one_after_last());
}
-template<typename T, bool include_start_point = true>
+template<typename T>
static void sample_interval_catmull_rom(const Span<T> src_data,
MutableSpan<T> dst_data,
- const bke::curves::IndexRangeCyclic src_range,
+ bke::curves::IndexRangeCyclic src_range,
const IndexRange dst_range,
const bke::curves::CurvePoint start_point,
const bke::curves::CurvePoint end_point,
const bool src_cyclic)
{
- int64_t src_index = src_range.first();
int64_t dst_index = dst_range.first();
if (start_point.is_controlpoint()) {
- /* 'start_point' is included in the copy iteration. */
- if constexpr (!include_start_point) {
- /* Skip first. */
- ++src_index;
- }
- }
- else if constexpr (!include_start_point) {
- /* Do nothing (excluded). */
}
else {
/* General case, sample 'start_point' */
@@ -631,8 +370,11 @@ static void sample_interval_catmull_rom(const Span<T> src_data,
++dst_index;
}
- dst_index = copy_point_data_between_endpoints(
- src_data, dst_data, src_range, src_index, dst_index);
+ dst_index = copy_point_data_between_endpoints(src_data, dst_data, src_range, dst_index);
+ if (dst_range.size() == 1) {
+ BLI_assert(dst_index == dst_range.one_after_last());
+ return;
+ }
/* Handle last case */
if (end_point.is_controlpoint()) {
@@ -658,20 +400,19 @@ static void sample_interval_bezier(const Span<float3> src_positions,
MutableSpan<float3> dst_handles_r,
MutableSpan<int8_t> dst_types_l,
MutableSpan<int8_t> dst_types_r,
- const bke::curves::IndexRangeCyclic src_range,
+ bke::curves::IndexRangeCyclic src_range,
const IndexRange dst_range,
const bke::curves::CurvePoint start_point,
const bke::curves::CurvePoint end_point)
{
bke::curves::bezier::Insertion start_point_insert;
- int64_t src_index = src_range.first();
int64_t dst_index = dst_range.first();
bool start_point_trimmed = false;
if (start_point.is_controlpoint()) {
/* The 'start_point' control point is included in the copy iteration. */
if constexpr (!include_start_point) {
- ++src_index; /* Skip first! */
+ src_range = src_range.drop_front();
}
}
else if constexpr (!include_start_point) {
@@ -696,7 +437,7 @@ static void sample_interval_bezier(const Span<float3> src_positions,
src_range.one_after_last() - src_range.first();
const IndexRange dst_range_to_end(dst_index, increment);
- const IndexRange src_range_to_end(src_index, increment);
+ const IndexRange src_range_to_end(src_range.first(), increment);
dst_positions.slice(dst_range_to_end).copy_from(src_positions.slice(src_range_to_end));
dst_handles_l.slice(dst_range_to_end).copy_from(src_handles_l.slice(src_range_to_end));
dst_handles_r.slice(dst_range_to_end).copy_from(src_handles_r.slice(src_range_to_end));
@@ -704,6 +445,11 @@ static void sample_interval_bezier(const Span<float3> src_positions,
dst_types_r.slice(dst_range_to_end).copy_from(src_types_r.slice(src_range_to_end));
dst_index += increment;
+ if (dst_range.size() == 1) {
+ BLI_assert(dst_index == dst_range.one_after_last());
+ return;
+ }
+
increment = src_range.size_after_loop();
if (src_range.cycles() && increment > 0) {
const IndexRange dst_range_looped(dst_index, increment);
@@ -769,174 +515,6 @@ static void sample_interval_bezier(const Span<float3> src_positions,
/** \} */
/* -------------------------------------------------------------------- */
-/** \name Convert to Point Curves
- * \{ */
-
-static void convert_point_polygonal_curves(
- const bke::CurvesGeometry &src_curves,
- bke::CurvesGeometry &dst_curves,
- const IndexMask selection,
- const Span<bke::curves::CurvePoint> sample_points,
- MutableSpan<bke::AttributeTransferData> transfer_attributes)
-{
- const Span<float3> src_positions = src_curves.positions();
- MutableSpan<float3> dst_positions = dst_curves.positions_for_write();
-
- threading::parallel_for(selection.index_range(), 4096, [&](const IndexRange range) {
- for (const int64_t curve_i : selection.slice(range)) {
- const IndexRange src_points = src_curves.points_for_curve(curve_i);
- const IndexRange dst_points = dst_curves.points_for_curve(curve_i);
-
- sample_linear<float3>(
- src_positions.slice(src_points), dst_positions, dst_points, sample_points[curve_i]);
-
- for (bke::AttributeTransferData &attribute : transfer_attributes) {
- attribute_math::convert_to_static_type(attribute.meta_data.data_type, [&](auto dummy) {
- using T = decltype(dummy);
- sample_linear<T>(attribute.src.template typed<T>().slice(src_points),
- attribute.dst.span.typed<T>(),
- dst_curves.points_for_curve(curve_i),
- sample_points[curve_i]);
- });
- }
- }
- });
-
- fill_bezier_data(dst_curves, selection);
- fill_nurbs_data(dst_curves, selection);
-}
-
-static void convert_point_catmull_curves(
- const bke::CurvesGeometry &src_curves,
- bke::CurvesGeometry &dst_curves,
- const IndexMask selection,
- const Span<bke::curves::CurvePoint> sample_points,
- MutableSpan<bke::AttributeTransferData> transfer_attributes)
-{
- const Span<float3> src_positions = src_curves.positions();
- const VArray<bool> src_cyclic = src_curves.cyclic();
-
- MutableSpan<float3> dst_positions = dst_curves.positions_for_write();
-
- threading::parallel_for(selection.index_range(), 4096, [&](const IndexRange range) {
- for (const int64_t curve_i : selection.slice(range)) {
- const IndexRange src_points = src_curves.points_for_curve(curve_i);
- const IndexRange dst_points = dst_curves.points_for_curve(curve_i);
-
- sample_catmull_rom<float3>(src_positions.slice(src_points),
- dst_positions,
- dst_points,
- sample_points[curve_i],
- src_cyclic[curve_i]);
- for (bke::AttributeTransferData &attribute : transfer_attributes) {
- attribute_math::convert_to_static_type(attribute.meta_data.data_type, [&](auto dummy) {
- using T = decltype(dummy);
- sample_catmull_rom<T>(attribute.src.template typed<T>().slice(src_points),
- attribute.dst.span.typed<T>(),
- dst_points,
- sample_points[curve_i],
- src_cyclic[curve_i]);
- });
- }
- }
- });
- fill_bezier_data(dst_curves, selection);
- fill_nurbs_data(dst_curves, selection);
-}
-
-static void convert_point_bezier_curves(
- const bke::CurvesGeometry &src_curves,
- bke::CurvesGeometry &dst_curves,
- const IndexMask selection,
- const Span<bke::curves::CurvePoint> sample_points,
- MutableSpan<bke::AttributeTransferData> transfer_attributes)
-{
- const Span<float3> src_positions = src_curves.positions();
- const VArraySpan<int8_t> src_types_l{src_curves.handle_types_left()};
- const VArraySpan<int8_t> src_types_r{src_curves.handle_types_right()};
- const Span<float3> src_handles_l = src_curves.handle_positions_left();
- const Span<float3> src_handles_r = src_curves.handle_positions_right();
-
- MutableSpan<float3> dst_positions = dst_curves.positions_for_write();
- MutableSpan<int8_t> dst_types_l = dst_curves.handle_types_left_for_write();
- MutableSpan<int8_t> dst_types_r = dst_curves.handle_types_right_for_write();
- MutableSpan<float3> dst_handles_l = dst_curves.handle_positions_left_for_write();
- MutableSpan<float3> dst_handles_r = dst_curves.handle_positions_right_for_write();
-
- threading::parallel_for(selection.index_range(), 4096, [&](const IndexRange range) {
- for (const int64_t curve_i : selection.slice(range)) {
- const IndexRange src_points = src_curves.points_for_curve(curve_i);
- const IndexRange dst_points = dst_curves.points_for_curve(curve_i);
-
- sample_bezier(src_positions.slice(src_points),
- src_handles_l.slice(src_points),
- src_handles_r.slice(src_points),
- src_types_l.slice(src_points),
- src_types_r.slice(src_points),
- dst_positions,
- dst_handles_l,
- dst_handles_r,
- dst_types_l,
- dst_types_r,
- dst_points,
- sample_points[curve_i]);
-
- for (bke::AttributeTransferData &attribute : transfer_attributes) {
- attribute_math::convert_to_static_type(attribute.meta_data.data_type, [&](auto dummy) {
- using T = decltype(dummy);
- sample_linear<T>(attribute.src.template typed<T>().slice(src_points),
- attribute.dst.span.typed<T>(),
- dst_points,
- sample_points[curve_i]);
- });
- }
- }
- });
- fill_nurbs_data(dst_curves, selection);
-}
-
-static void convert_point_evaluated_curves(
- const bke::CurvesGeometry &src_curves,
- bke::CurvesGeometry &dst_curves,
- const IndexMask selection,
- const Span<bke::curves::CurvePoint> evaluated_sample_points,
- MutableSpan<bke::AttributeTransferData> transfer_attributes)
-{
- const Span<float3> src_eval_positions = src_curves.evaluated_positions();
- MutableSpan<float3> dst_positions = dst_curves.positions_for_write();
-
- threading::parallel_for(selection.index_range(), 4096, [&](const IndexRange range) {
- for (const int64_t curve_i : selection.slice(range)) {
- const IndexRange dst_points = dst_curves.points_for_curve(curve_i);
- const IndexRange src_evaluated_points = src_curves.evaluated_points_for_curve(curve_i);
-
- sample_linear<float3>(src_eval_positions.slice(src_evaluated_points),
- dst_positions,
- dst_points,
- evaluated_sample_points[curve_i]);
-
- for (bke::AttributeTransferData &attribute : transfer_attributes) {
- attribute_math::convert_to_static_type(attribute.meta_data.data_type, [&](auto dummy) {
- using T = decltype(dummy);
- GArray evaluated_data(CPPType::get<T>(), src_evaluated_points.size());
- GMutableSpan evaluated_span = evaluated_data.as_mutable_span();
- src_curves.interpolate_to_evaluated(
- curve_i, attribute.src.slice(src_curves.points_for_curve(curve_i)), evaluated_span);
- sample_linear<T>(evaluated_span.typed<T>(),
- attribute.dst.span.typed<T>(),
- dst_points,
- evaluated_sample_points[curve_i]);
- });
- }
- }
- });
- fill_bezier_data(dst_curves, selection);
- fill_nurbs_data(dst_curves, selection);
-}
-
-/** \} */
-
-/* -------------------------------------------------------------------- */
/** \name Trim Curves
* \{ */
@@ -945,6 +523,7 @@ static void trim_attribute_linear(const bke::CurvesGeometry &src_curves,
const IndexMask selection,
const Span<bke::curves::CurvePoint> start_points,
const Span<bke::curves::CurvePoint> end_points,
+ const Span<bke::curves::IndexRangeCyclic> src_ranges,
MutableSpan<bke::AttributeTransferData> transfer_attributes)
{
for (bke::AttributeTransferData &attribute : transfer_attributes) {
@@ -955,11 +534,9 @@ static void trim_attribute_linear(const bke::CurvesGeometry &src_curves,
for (const int64_t curve_i : selection.slice(range)) {
const IndexRange src_points = src_curves.points_for_curve(curve_i);
- bke::curves::IndexRangeCyclic src_sample_range = get_range_between_endpoints(
- start_points[curve_i], end_points[curve_i], {0, src_points.size()});
sample_interval_linear<T>(attribute.src.template typed<T>().slice(src_points),
attribute.dst.span.typed<T>(),
- src_sample_range,
+ src_ranges[curve_i],
dst_curves.points_for_curve(curve_i),
start_points[curve_i],
end_points[curve_i]);
@@ -974,6 +551,7 @@ static void trim_polygonal_curves(const bke::CurvesGeometry &src_curves,
const IndexMask selection,
const Span<bke::curves::CurvePoint> start_points,
const Span<bke::curves::CurvePoint> end_points,
+ const Span<bke::curves::IndexRangeCyclic> src_ranges,
MutableSpan<bke::AttributeTransferData> transfer_attributes)
{
const Span<float3> src_positions = src_curves.positions();
@@ -984,11 +562,9 @@ static void trim_polygonal_curves(const bke::CurvesGeometry &src_curves,
const IndexRange src_points = src_curves.points_for_curve(curve_i);
const IndexRange dst_points = dst_curves.points_for_curve(curve_i);
- bke::curves::IndexRangeCyclic src_sample_range = get_range_between_endpoints(
- start_points[curve_i], end_points[curve_i], {0, src_points.size()});
sample_interval_linear<float3>(src_positions.slice(src_points),
dst_positions,
- src_sample_range,
+ src_ranges[curve_i],
dst_points,
start_points[curve_i],
end_points[curve_i]);
@@ -996,8 +572,13 @@ static void trim_polygonal_curves(const bke::CurvesGeometry &src_curves,
});
fill_bezier_data(dst_curves, selection);
fill_nurbs_data(dst_curves, selection);
- trim_attribute_linear(
- src_curves, dst_curves, selection, start_points, end_points, transfer_attributes);
+ trim_attribute_linear(src_curves,
+ dst_curves,
+ selection,
+ start_points,
+ end_points,
+ src_ranges,
+ transfer_attributes);
}
static void trim_catmull_rom_curves(const bke::CurvesGeometry &src_curves,
@@ -1005,6 +586,7 @@ static void trim_catmull_rom_curves(const bke::CurvesGeometry &src_curves,
const IndexMask selection,
const Span<bke::curves::CurvePoint> start_points,
const Span<bke::curves::CurvePoint> end_points,
+ const Span<bke::curves::IndexRangeCyclic> src_ranges,
MutableSpan<bke::AttributeTransferData> transfer_attributes)
{
const Span<float3> src_positions = src_curves.positions();
@@ -1016,11 +598,9 @@ static void trim_catmull_rom_curves(const bke::CurvesGeometry &src_curves,
const IndexRange src_points = src_curves.points_for_curve(curve_i);
const IndexRange dst_points = dst_curves.points_for_curve(curve_i);
- bke::curves::IndexRangeCyclic src_sample_range = get_range_between_endpoints(
- start_points[curve_i], end_points[curve_i], {0, src_points.size()});
sample_interval_catmull_rom<float3>(src_positions.slice(src_points),
dst_positions,
- src_sample_range,
+ src_ranges[curve_i],
dst_points,
start_points[curve_i],
end_points[curve_i],
@@ -1039,11 +619,9 @@ static void trim_catmull_rom_curves(const bke::CurvesGeometry &src_curves,
const IndexRange src_points = src_curves.points_for_curve(curve_i);
const IndexRange dst_points = dst_curves.points_for_curve(curve_i);
- bke::curves::IndexRangeCyclic src_sample_range = get_range_between_endpoints(
- start_points[curve_i], end_points[curve_i], {0, src_points.size()});
sample_interval_catmull_rom<T>(attribute.src.template typed<T>().slice(src_points),
attribute.dst.span.typed<T>(),
- src_sample_range,
+ src_ranges[curve_i],
dst_points,
start_points[curve_i],
end_points[curve_i],
@@ -1059,6 +637,7 @@ static void trim_bezier_curves(const bke::CurvesGeometry &src_curves,
const IndexMask selection,
const Span<bke::curves::CurvePoint> start_points,
const Span<bke::curves::CurvePoint> end_points,
+ const Span<bke::curves::IndexRangeCyclic> src_ranges,
MutableSpan<bke::AttributeTransferData> transfer_attributes)
{
const Span<float3> src_positions = src_curves.positions();
@@ -1078,8 +657,6 @@ static void trim_bezier_curves(const bke::CurvesGeometry &src_curves,
const IndexRange src_points = src_curves.points_for_curve(curve_i);
const IndexRange dst_points = dst_curves.points_for_curve(curve_i);
- bke::curves::IndexRangeCyclic src_sample_range = get_range_between_endpoints(
- start_points[curve_i], end_points[curve_i], {0, src_points.size()});
sample_interval_bezier(src_positions.slice(src_points),
src_handles_l.slice(src_points),
src_handles_r.slice(src_points),
@@ -1090,15 +667,20 @@ static void trim_bezier_curves(const bke::CurvesGeometry &src_curves,
dst_handles_r,
dst_types_l,
dst_types_r,
- src_sample_range,
+ src_ranges[curve_i],
dst_points,
start_points[curve_i],
end_points[curve_i]);
}
});
fill_nurbs_data(dst_curves, selection);
- trim_attribute_linear(
- src_curves, dst_curves, selection, start_points, end_points, transfer_attributes);
+ trim_attribute_linear(src_curves,
+ dst_curves,
+ selection,
+ start_points,
+ end_points,
+ src_ranges,
+ transfer_attributes);
}
static void trim_evaluated_curves(const bke::CurvesGeometry &src_curves,
@@ -1106,6 +688,7 @@ static void trim_evaluated_curves(const bke::CurvesGeometry &src_curves,
const IndexMask selection,
const Span<bke::curves::CurvePoint> start_points,
const Span<bke::curves::CurvePoint> end_points,
+ const Span<bke::curves::IndexRangeCyclic> src_ranges,
MutableSpan<bke::AttributeTransferData> transfer_attributes)
{
const Span<float3> src_eval_positions = src_curves.evaluated_positions();
@@ -1116,11 +699,9 @@ static void trim_evaluated_curves(const bke::CurvesGeometry &src_curves,
const IndexRange dst_points = dst_curves.points_for_curve(curve_i);
const IndexRange src_evaluated_points = src_curves.evaluated_points_for_curve(curve_i);
- bke::curves::IndexRangeCyclic src_sample_range = get_range_between_endpoints(
- start_points[curve_i], end_points[curve_i], {0, src_evaluated_points.size()});
sample_interval_linear<float3>(src_eval_positions.slice(src_evaluated_points),
dst_positions,
- src_sample_range,
+ src_ranges[curve_i],
dst_points,
start_points[curve_i],
end_points[curve_i]);
@@ -1141,11 +722,9 @@ static void trim_evaluated_curves(const bke::CurvesGeometry &src_curves,
GMutableSpan evaluated_span = evaluated_data.as_mutable_span();
src_curves.interpolate_to_evaluated(
curve_i, attribute.src.slice(src_curves.points_for_curve(curve_i)), evaluated_span);
- bke::curves::IndexRangeCyclic src_sample_range = get_range_between_endpoints(
- start_points[curve_i], end_points[curve_i], {0, src_evaluated_points.size()});
sample_interval_linear<T>(evaluated_span.typed<T>(),
attribute.dst.span.typed<T>(),
- src_sample_range,
+ src_ranges[curve_i],
dst_curves.points_for_curve(curve_i),
start_points[curve_i],
end_points[curve_i]);
@@ -1155,52 +734,204 @@ static void trim_evaluated_curves(const bke::CurvesGeometry &src_curves,
}
}
+/* -------------------------------------------------------------------- */
+/** \name Compute trim parameters
+ * \{ */
+
+static float trim_sample_length(const Span<float> accumulated_lengths,
+ const float sample_length,
+ const GeometryNodeCurveSampleMode mode)
+{
+ float length = mode == GEO_NODE_CURVE_SAMPLE_FACTOR ?
+ sample_length * accumulated_lengths.last() :
+ sample_length;
+ return std::clamp(length, 0.0f, accumulated_lengths.last());
+}
+
+/**
+ * Compute the selection for the given curve type. Tracks indices for splitting the selection if
+ * there are curves reduced to a single point.
+ */
+static void compute_curve_trim_parameters(const bke::CurvesGeometry &curves,
+ const IndexMask selection,
+ const VArray<float> &starts,
+ const VArray<float> &ends,
+ const GeometryNodeCurveSampleMode mode,
+ MutableSpan<int> dst_curve_size,
+ MutableSpan<int8_t> dst_curve_types,
+ MutableSpan<bke::curves::CurvePoint> start_points,
+ MutableSpan<bke::curves::CurvePoint> end_points,
+ MutableSpan<bke::curves::IndexRangeCyclic> src_ranges)
+{
+ const VArray<bool> src_cyclic = curves.cyclic();
+ const VArray<int> resolution = curves.resolution();
+ const VArray<int8_t> curve_types = curves.curve_types();
+
+ /* Compute. */
+ threading::parallel_for(selection.index_range(), 128, [&](const IndexRange selection_range) {
+ for (const int64_t curve_i : selection.slice(selection_range)) {
+ CurveType curve_type = CurveType(curve_types[curve_i]);
+
+ int point_count;
+ if (curve_type == CURVE_TYPE_NURBS) {
+ dst_curve_types[curve_i] = CURVE_TYPE_POLY;
+ point_count = curves.evaluated_points_for_curve(curve_i).size();
+ }
+ else {
+ dst_curve_types[curve_i] = curve_type;
+ point_count = curves.points_num_for_curve(curve_i);
+ }
+ if (point_count == 1) {
+ /* Single point. */
+ dst_curve_size[curve_i] = 1;
+ src_ranges[curve_i] = bke::curves::IndexRangeCyclic(0, 0, 1, 1);
+ start_points[curve_i] = {{0, 0}, 0.0f};
+ end_points[curve_i] = {{0, 0}, 0.0f};
+ continue;
+ }
+
+ const bool cyclic = src_cyclic[curve_i];
+ const Span<float> lengths = curves.evaluated_lengths_for_curve(curve_i, cyclic);
+ BLI_assert(lengths.size() > 0);
+
+ const float start_length = trim_sample_length(lengths, starts[curve_i], mode);
+ float end_length;
+
+ bool equal_sample_point;
+ if (cyclic) {
+ end_length = trim_sample_length(lengths, ends[curve_i], mode);
+ const float cyclic_start = start_length == lengths.last() ? 0.0f : start_length;
+ const float cyclic_end = end_length == lengths.last() ? 0.0f : end_length;
+ equal_sample_point = cyclic_start == cyclic_end;
+ }
+ else {
+ end_length = ends[curve_i] <= starts[curve_i] ?
+ start_length :
+ trim_sample_length(lengths, ends[curve_i], mode);
+ equal_sample_point = start_length == end_length;
+ }
+
+ start_points[curve_i] = lookup_curve_point(curves,
+ curve_type,
+ curve_i,
+ lengths,
+ start_length,
+ cyclic,
+ resolution[curve_i],
+ point_count);
+ if (equal_sample_point) {
+ end_points[curve_i] = start_points[curve_i];
+ if (end_length <= start_length) {
+ /* Single point. */
+ dst_curve_size[curve_i] = 1;
+ src_ranges[curve_i] = bke::curves::IndexRangeCyclic::get_range_from_size(
+ start_points[curve_i].index,
+ start_points[curve_i].is_controlpoint(), /* Only iterate if control point. */
+ point_count);
+ }
+ else {
+ /* Split. */
+ src_ranges[curve_i] = bke::curves::IndexRangeCyclic::get_range_between_endpoints(
+ start_points[curve_i], end_points[curve_i], point_count)
+ .push_loop();
+ const int count = 1 + !start_points[curve_i].is_controlpoint() + point_count;
+ BLI_assert(count > 1);
+ dst_curve_size[curve_i] = count;
+ }
+ }
+ else {
+ /* General case. */
+ end_points[curve_i] = lookup_curve_point(curves,
+ curve_type,
+ curve_i,
+ lengths,
+ end_length,
+ cyclic,
+ resolution[curve_i],
+ point_count);
+
+ src_ranges[curve_i] = bke::curves::IndexRangeCyclic::get_range_between_endpoints(
+ start_points[curve_i], end_points[curve_i], point_count);
+ const int count = src_ranges[curve_i].size() + !start_points[curve_i].is_controlpoint() +
+ !end_points[curve_i].is_controlpoint();
+ BLI_assert(count > 1);
+ dst_curve_size[curve_i] = count;
+ }
+ BLI_assert(dst_curve_size[curve_i] > 0);
+ }
+ });
+}
+
+/** \} */
+
bke::CurvesGeometry trim_curves(const bke::CurvesGeometry &src_curves,
const IndexMask selection,
- const Span<bke::curves::CurvePoint> start_points,
- const Span<bke::curves::CurvePoint> end_points)
+ const VArray<float> &starts,
+ const VArray<float> &ends,
+ const GeometryNodeCurveSampleMode mode)
{
BLI_assert(selection.size() > 0);
- BLI_assert(selection.last() <= start_points.size());
- BLI_assert(start_points.size() == end_points.size());
+ BLI_assert(selection.last() <= src_curves.curves_num());
+ BLI_assert(starts.size() == src_curves.curves_num());
+ BLI_assert(starts.size() == ends.size());
+ src_curves.ensure_evaluated_lengths();
- src_curves.ensure_evaluated_offsets();
Vector<int64_t> inverse_selection_indices;
const IndexMask inverse_selection = selection.invert(src_curves.curves_range(),
inverse_selection_indices);
- /* Create trim curves. */
+ /* Create destination curves. */
bke::CurvesGeometry dst_curves(0, src_curves.curves_num());
- determine_copyable_curve_types(src_curves,
- dst_curves,
- selection,
- inverse_selection,
- (CurveTypeMask)(CURVE_TYPE_MASK_CATMULL_ROM |
- CURVE_TYPE_MASK_POLY | CURVE_TYPE_MASK_BEZIER));
-
- Vector<int64_t> curve_indices;
- Vector<int64_t> point_curve_indices;
- compute_trim_result_offsets(src_curves,
- selection,
- inverse_selection,
- start_points,
- end_points,
- dst_curves.curve_types(),
- dst_curves.offsets_for_write(),
- curve_indices,
- point_curve_indices);
- /* Finalize by updating the geometry container. */
+ MutableSpan<int> dst_curve_offsets = dst_curves.offsets_for_write();
+ MutableSpan<int8_t> dst_curve_types = dst_curves.curve_types_for_write();
+ Array<bke::curves::CurvePoint, 12> start_points(src_curves.curves_num());
+ Array<bke::curves::CurvePoint, 12> end_points(src_curves.curves_num());
+ Array<bke::curves::IndexRangeCyclic, 12> src_ranges(src_curves.curves_num());
+
+ if (src_curves.has_curve_with_type({CURVE_TYPE_BEZIER, CURVE_TYPE_NURBS})) {
+ src_curves.ensure_evaluated_offsets();
+ if (src_curves.has_curve_with_type(CURVE_TYPE_NURBS)) {
+ src_curves.evaluated_positions();
+ }
+ }
+
+ /* Compute destination curves. */
+ compute_curve_trim_parameters(src_curves,
+ selection,
+ starts,
+ ends,
+ mode,
+ dst_curve_offsets,
+ dst_curve_types,
+ start_points,
+ end_points,
+ src_ranges);
+
+ /* Transfer copied curves parameters. */
+ const VArray<int8_t> src_curve_types = src_curves.curve_types();
+ threading::parallel_for(
+ inverse_selection.index_range(), 4096, [&](const IndexRange selection_range) {
+ for (const int64_t curve_i : inverse_selection.slice(selection_range)) {
+ dst_curve_offsets[curve_i] = src_curves.points_num_for_curve(curve_i);
+ dst_curve_types[curve_i] = src_curve_types[curve_i];
+ }
+ });
+ /* Finalize and update the geometry container. */
+ bke::curves::accumulate_counts_to_offsets(dst_curve_offsets);
dst_curves.resize(dst_curves.offsets().last(), dst_curves.curves_num());
dst_curves.update_curve_types();
/* Populate curve domain. */
const bke::AttributeAccessor src_attributes = src_curves.attributes();
bke::MutableAttributeAccessor dst_attributes = dst_curves.attributes_for_write();
- bke::copy_attribute_domain(src_attributes,
- dst_attributes,
- selection,
- ATTR_DOMAIN_CURVE,
- {"cyclic", "curve_type", "nurbs_order", "knots_mode"});
+ Set<std::string> transfer_curve_skip = {"cyclic", "curve_type", "nurbs_order", "knots_mode"};
+ if (dst_curves.has_curve_with_type(CURVE_TYPE_NURBS)) {
+ /* If a NURBS curve is copied keep */
+ transfer_curve_skip.remove("nurbs_order");
+ transfer_curve_skip.remove("knots_mode");
+ }
+ bke::copy_attribute_domain(
+ src_attributes, dst_attributes, selection, ATTR_DOMAIN_CURVE, transfer_curve_skip);
/* Fetch custom point domain attributes for transfer (copy). */
Vector<bke::AttributeTransferData> transfer_attributes = bke::retrieve_attributes_for_transfer(
@@ -1214,61 +945,55 @@ bke::CurvesGeometry trim_curves(const bke::CurvesGeometry &src_curves,
"handle_type_right",
"nurbs_weight"});
- auto trim_catmull = [&](IndexMask selection) {
- trim_catmull_rom_curves(
- src_curves, dst_curves, selection, start_points, end_points, transfer_attributes);
+ auto trim_catmull = [&](const IndexMask selection) {
+ trim_catmull_rom_curves(src_curves,
+ dst_curves,
+ selection,
+ start_points,
+ end_points,
+ src_ranges,
+ transfer_attributes);
};
- auto trim_poly = [&](IndexMask selection) {
- trim_polygonal_curves(
- src_curves, dst_curves, selection, start_points, end_points, transfer_attributes);
+ auto trim_poly = [&](const IndexMask selection) {
+ trim_polygonal_curves(src_curves,
+ dst_curves,
+ selection,
+ start_points,
+ end_points,
+ src_ranges,
+ transfer_attributes);
};
- auto trim_bezier = [&](IndexMask selection) {
- trim_bezier_curves(
- src_curves, dst_curves, selection, start_points, end_points, transfer_attributes);
+ auto trim_bezier = [&](const IndexMask selection) {
+ trim_bezier_curves(src_curves,
+ dst_curves,
+ selection,
+ start_points,
+ end_points,
+ src_ranges,
+ transfer_attributes);
};
- auto trim_evaluated = [&](IndexMask selection) {
+ auto trim_evaluated = [&](const IndexMask selection) {
/* Ensure evaluated positions are available. */
src_curves.ensure_evaluated_offsets();
src_curves.evaluated_positions();
- trim_evaluated_curves(
- src_curves, dst_curves, selection, start_points, end_points, transfer_attributes);
- };
-
- auto single_point_catmull = [&](IndexMask selection) {
- convert_point_catmull_curves(
- src_curves, dst_curves, selection, start_points, transfer_attributes);
- };
- auto single_point_poly = [&](IndexMask selection) {
- convert_point_polygonal_curves(
- src_curves, dst_curves, selection, start_points, transfer_attributes);
- };
- auto single_point_bezier = [&](IndexMask selection) {
- convert_point_bezier_curves(
- src_curves, dst_curves, selection, start_points, transfer_attributes);
- };
- auto single_point_evaluated = [&](IndexMask selection) {
- convert_point_evaluated_curves(
- src_curves, dst_curves, selection, start_points, transfer_attributes);
+ trim_evaluated_curves(src_curves,
+ dst_curves,
+ selection,
+ start_points,
+ end_points,
+ src_ranges,
+ transfer_attributes);
};
/* Populate point domain. */
bke::curves::foreach_curve_by_type(src_curves.curve_types(),
src_curves.curve_type_counts(),
- curve_indices.as_span(),
+ selection,
trim_catmull,
trim_poly,
trim_bezier,
trim_evaluated);
- if (point_curve_indices.size()) {
- bke::curves::foreach_curve_by_type(src_curves.curve_types(),
- src_curves.curve_type_counts(),
- point_curve_indices.as_span(),
- single_point_catmull,
- single_point_poly,
- single_point_bezier,
- single_point_evaluated);
- }
/* Cleanup/close context */
for (bke::AttributeTransferData &attribute : transfer_attributes) {
attribute.dst.finish();
@@ -1276,14 +1001,21 @@ bke::CurvesGeometry trim_curves(const bke::CurvesGeometry &src_curves,
/* Copy unselected */
if (!inverse_selection.is_empty()) {
+ transfer_curve_skip.remove("cyclic");
bke::copy_attribute_domain(
- src_attributes, dst_attributes, inverse_selection, ATTR_DOMAIN_CURVE);
+ src_attributes, dst_attributes, inverse_selection, ATTR_DOMAIN_CURVE, transfer_curve_skip);
/* Trim curves are no longer cyclic. If all curves are trimmed, this will be set implicitly. */
dst_curves.cyclic_for_write().fill_indices(selection, false);
+ Set<std::string> copy_point_skip;
+ if (!dst_curves.has_curve_with_type(CURVE_TYPE_NURBS) &&
+ src_curves.has_curve_with_type(CURVE_TYPE_NURBS)) {
+ copy_point_skip.add("nurbs_weight");
+ }
+
/* Copy point domain. */
for (auto &attribute : bke::retrieve_attributes_for_transfer(
- src_attributes, dst_attributes, ATTR_DOMAIN_MASK_POINT)) {
+ src_attributes, dst_attributes, ATTR_DOMAIN_MASK_POINT, copy_point_skip)) {
bke::curves::copy_point_data(
src_curves, dst_curves, inverse_selection, attribute.src, attribute.dst.span);
attribute.dst.finish();
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpenciloutline.c b/source/blender/gpencil_modifiers/intern/MOD_gpenciloutline.c
index 455d8b0b528..dff8d14564a 100644
--- a/source/blender/gpencil_modifiers/intern/MOD_gpenciloutline.c
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpenciloutline.c
@@ -287,7 +287,7 @@ static void updateDepsgraph(GpencilModifierData *md,
DEG_add_object_relation(ctx->node, ctx->object, DEG_OB_COMP_TRANSFORM, "Outline Modifier");
}
-static void panel_draw(const bContext *UNUSED(C), Panel *panel)
+static void panel_draw(const bContext *C, Panel *panel)
{
uiLayout *layout = panel->layout;
@@ -302,6 +302,11 @@ static void panel_draw(const bContext *UNUSED(C), Panel *panel)
uiItemR(layout, ptr, "outline_material", 0, NULL, ICON_NONE);
uiItemR(layout, ptr, "object", 0, NULL, ICON_NONE);
+ Scene *scene = CTX_data_scene(C);
+ if (scene->camera == NULL) {
+ uiItemL(layout, IFACE_("Outline requires an active camera"), ICON_ERROR);
+ }
+
gpencil_modifier_panel_end(layout, ptr);
}
diff --git a/source/blender/gpu/intern/gpu_node_graph.h b/source/blender/gpu/intern/gpu_node_graph.h
index de0a0687b13..2f617713749 100644
--- a/source/blender/gpu/intern/gpu_node_graph.h
+++ b/source/blender/gpu/intern/gpu_node_graph.h
@@ -66,7 +66,7 @@ typedef enum {
GPU_NODE_TAG_COMPOSITOR = (1 << 6),
} eGPUNodeTag;
-ENUM_OPERATORS(eGPUNodeTag, GPU_NODE_TAG_FUNCTION)
+ENUM_OPERATORS(eGPUNodeTag, GPU_NODE_TAG_COMPOSITOR)
struct GPUNode {
struct GPUNode *next, *prev;
diff --git a/source/blender/gpu/intern/gpu_shader_builder.cc b/source/blender/gpu/intern/gpu_shader_builder.cc
index abb45ca074a..96e3eacd6f5 100644
--- a/source/blender/gpu/intern/gpu_shader_builder.cc
+++ b/source/blender/gpu/intern/gpu_shader_builder.cc
@@ -59,7 +59,7 @@ void ShaderBuilder::init()
break;
}
- ghost_system_ = GHOST_CreateSystem();
+ ghost_system_ = GHOST_CreateSystemBackground();
ghost_context_ = GHOST_CreateOpenGLContext(ghost_system_, glSettings);
GHOST_ActivateOpenGLContext(ghost_context_);
diff --git a/source/blender/imbuf/intern/jp2.c b/source/blender/imbuf/intern/jp2.c
index f3d6d19cb8d..4320f870d64 100644
--- a/source/blender/imbuf/intern/jp2.c
+++ b/source/blender/imbuf/intern/jp2.c
@@ -125,7 +125,7 @@ struct BufInfo {
static void opj_read_from_buffer_free(void *UNUSED(p_user_data))
{
- /* nop */
+ /* NOP. */
}
static OPJ_SIZE_T opj_read_from_buffer(void *p_buffer, OPJ_SIZE_T p_nb_bytes, void *p_user_data)
diff --git a/source/blender/imbuf/intern/openexr/openexr_api.cpp b/source/blender/imbuf/intern/openexr/openexr_api.cpp
index d4a89c9e1c9..d2bdb5041c5 100644
--- a/source/blender/imbuf/intern/openexr/openexr_api.cpp
+++ b/source/blender/imbuf/intern/openexr/openexr_api.cpp
@@ -811,7 +811,7 @@ static void imb_exr_get_views(MultiPartInputFile &file, StringVector &views)
}
}
-/* Multilayer Blender files have the view name in all the passes (even the default view one) */
+/* Multi-layer Blender files have the view name in all the passes (even the default view one). */
static void imb_exr_insert_view_name(char *name_full, const char *passname, const char *viewname)
{
BLI_assert(!ELEM(name_full, passname, viewname));
diff --git a/source/blender/io/alembic/exporter/abc_writer_points.cc b/source/blender/io/alembic/exporter/abc_writer_points.cc
index 6ec6f736818..9372bffc3ca 100644
--- a/source/blender/io/alembic/exporter/abc_writer_points.cc
+++ b/source/blender/io/alembic/exporter/abc_writer_points.cc
@@ -85,7 +85,7 @@ void ABCPointsWriter::do_write(HierarchyContext &context)
sim.ob = context.object;
sim.psys = psys;
- psys->lattice_deform_data = psys_create_lattice_deform_data(&sim);
+ psys_sim_data_init(&sim);
uint64_t index = 0;
for (int p = 0; p < psys->totpart; p++) {
@@ -113,10 +113,7 @@ void ABCPointsWriter::do_write(HierarchyContext &context)
ids.push_back(index++);
}
- if (psys->lattice_deform_data) {
- BKE_lattice_deform_data_destroy(psys->lattice_deform_data);
- psys->lattice_deform_data = nullptr;
- }
+ psys_sim_data_free(&sim);
Alembic::Abc::P3fArraySample psample(points);
Alembic::Abc::UInt64ArraySample idsample(ids);
diff --git a/source/blender/makesdna/DNA_asset_types.h b/source/blender/makesdna/DNA_asset_types.h
index 29795519719..d7e3bcfc919 100644
--- a/source/blender/makesdna/DNA_asset_types.h
+++ b/source/blender/makesdna/DNA_asset_types.h
@@ -42,6 +42,10 @@ typedef struct AssetFilterSettings {
* more than that from the file. So pointers to other IDs or ID data are strictly forbidden.
*/
typedef struct AssetMetaData {
+#ifdef __cplusplus
+ ~AssetMetaData();
+#endif
+
/** Runtime type, to reference event callbacks. Only valid for local assets. */
struct AssetTypeInfo *local_type_info;
@@ -114,6 +118,8 @@ typedef struct AssetLibraryReference {
} AssetLibraryReference;
/**
+ * To be replaced by #AssetRepresentation!
+ *
* Not part of the core design, we should try to get rid of it. Only needed to wrap FileDirEntry
* into a type with PropertyGroup as base, so we can have an RNA collection of #AssetHandle's to
* pass to the UI.
diff --git a/source/blender/makesdna/DNA_scene_types.h b/source/blender/makesdna/DNA_scene_types.h
index 8d02b274c65..274b2094ee7 100644
--- a/source/blender/makesdna/DNA_scene_types.h
+++ b/source/blender/makesdna/DNA_scene_types.h
@@ -2302,6 +2302,7 @@ typedef enum ePaintSymmetryFlags {
PAINT_TILE_Y = (1 << 5),
PAINT_TILE_Z = (1 << 6),
} ePaintSymmetryFlags;
+ENUM_OPERATORS(ePaintSymmetryFlags, PAINT_TILE_Z);
#define PAINT_SYMM_AXIS_ALL (PAINT_SYMM_X | PAINT_SYMM_Y | PAINT_SYMM_Z)
diff --git a/source/blender/makesdna/DNA_space_types.h b/source/blender/makesdna/DNA_space_types.h
index 4bb92e6fcc5..d6d5f64a6a6 100644
--- a/source/blender/makesdna/DNA_space_types.h
+++ b/source/blender/makesdna/DNA_space_types.h
@@ -1107,7 +1107,7 @@ typedef struct FileDirEntry {
uint32_t uid; /* FileUID */
/* Name needs freeing if FILE_ENTRY_NAME_FREE is set. Otherwise this is a direct pointer to a
* name buffer. */
- char *name;
+ const char *name;
uint64_t size;
int64_t time;
@@ -1134,7 +1134,7 @@ typedef struct FileDirEntry {
/** If this file represents an asset, its asset data is here. Note that we may show assets of
* external files in which case this is set but not the id above.
* Note comment for FileListInternEntry.local_data, the same applies here! */
- struct AssetMetaData *asset_data;
+ struct AssetRepresentation *asset;
/* The icon_id for the preview image. */
int preview_icon_id;
diff --git a/source/blender/makesrna/intern/rna_attribute.c b/source/blender/makesrna/intern/rna_attribute.c
index e1b6fb429a7..20c6e24b735 100644
--- a/source/blender/makesrna/intern/rna_attribute.c
+++ b/source/blender/makesrna/intern/rna_attribute.c
@@ -534,7 +534,7 @@ static void rna_AttributeGroup_active_set(PointerRNA *ptr,
{
ID *id = ptr->owner_id;
CustomDataLayer *layer = attribute_ptr.data;
- BKE_id_attributes_active_set(id, layer);
+ BKE_id_attributes_active_set(id, layer->name);
}
static void rna_AttributeGroup_active_index_set(PointerRNA *ptr, int value)
diff --git a/source/blender/makesrna/intern/rna_nodetree.c b/source/blender/makesrna/intern/rna_nodetree.c
index cfec020c739..c6115711c1a 100644
--- a/source/blender/makesrna/intern/rna_nodetree.c
+++ b/source/blender/makesrna/intern/rna_nodetree.c
@@ -1302,8 +1302,8 @@ static bNodeLink *rna_NodeTree_link_new(bNodeTree *ntree,
return NULL;
}
- nodeFindNode(ntree, fromsock, &fromnode, NULL);
- nodeFindNode(ntree, tosock, &tonode, NULL);
+ nodeFindNodeTry(ntree, fromsock, &fromnode, NULL);
+ nodeFindNodeTry(ntree, tosock, &tonode, NULL);
/* check validity of the sockets:
* if sockets from different trees are passed in this will fail!
*/
@@ -2417,6 +2417,11 @@ static void rna_Node_name_set(PointerRNA *ptr, const char *value)
BKE_animdata_fix_paths_rename_all(NULL, "nodes", oldname, node->name);
}
+static bool allow_changing_sockets(bNode *node)
+{
+ return ELEM(node->type, NODE_CUSTOM, SH_NODE_SCRIPT);
+}
+
static bNodeSocket *rna_Node_inputs_new(ID *id,
bNode *node,
Main *bmain,
@@ -2425,7 +2430,7 @@ static bNodeSocket *rna_Node_inputs_new(ID *id,
const char *name,
const char *identifier)
{
- if (node->type != NODE_CUSTOM) {
+ if (!allow_changing_sockets(node)) {
BKE_report(reports, RPT_ERROR, "Cannot add socket to built-in node");
return NULL;
}
@@ -2452,7 +2457,7 @@ static bNodeSocket *rna_Node_outputs_new(ID *id,
const char *name,
const char *identifier)
{
- if (node->type != NODE_CUSTOM) {
+ if (!allow_changing_sockets(node)) {
BKE_report(reports, RPT_ERROR, "Cannot add socket to built-in node");
return NULL;
}
@@ -2474,7 +2479,7 @@ static bNodeSocket *rna_Node_outputs_new(ID *id,
static void rna_Node_socket_remove(
ID *id, bNode *node, Main *bmain, ReportList *reports, bNodeSocket *sock)
{
- if (node->type != NODE_CUSTOM) {
+ if (!allow_changing_sockets(node)) {
BKE_report(reports, RPT_ERROR, "Unable to remove socket from built-in node");
return;
}
@@ -2494,7 +2499,7 @@ static void rna_Node_socket_remove(
static void rna_Node_inputs_clear(ID *id, bNode *node, Main *bmain, ReportList *reports)
{
- if (node->type != NODE_CUSTOM) {
+ if (!allow_changing_sockets(node)) {
BKE_report(reports, RPT_ERROR, "Unable to remove sockets from built-in node");
return;
}
@@ -2513,7 +2518,7 @@ static void rna_Node_inputs_clear(ID *id, bNode *node, Main *bmain, ReportList *
static void rna_Node_outputs_clear(ID *id, bNode *node, Main *bmain, ReportList *reports)
{
- if (node->type != NODE_CUSTOM) {
+ if (!allow_changing_sockets(node)) {
BKE_report(reports, RPT_ERROR, "Unable to remove socket from built-in node");
return;
}
@@ -2533,7 +2538,7 @@ static void rna_Node_outputs_clear(ID *id, bNode *node, Main *bmain, ReportList
static void rna_Node_inputs_move(
ID *id, bNode *node, Main *bmain, ReportList *reports, int from_index, int to_index)
{
- if (node->type != NODE_CUSTOM) {
+ if (!allow_changing_sockets(node)) {
BKE_report(reports, RPT_ERROR, "Unable to move sockets in built-in node");
return;
}
@@ -2571,7 +2576,7 @@ static void rna_Node_inputs_move(
static void rna_Node_outputs_move(
ID *id, bNode *node, Main *bmain, ReportList *reports, int from_index, int to_index)
{
- if (node->type != NODE_CUSTOM) {
+ if (!allow_changing_sockets(node)) {
BKE_report(reports, RPT_ERROR, "Unable to move sockets in built-in node");
return;
}
@@ -2784,9 +2789,7 @@ static char *rna_NodeSocket_path(const PointerRNA *ptr)
int socketindex;
char name_esc[sizeof(node->name) * 2];
- if (!nodeFindNode(ntree, sock, &node, &socketindex)) {
- return NULL;
- }
+ nodeFindNode(ntree, sock, &node, &socketindex);
BLI_str_escape(name_esc, node->name, sizeof(name_esc));
diff --git a/source/blender/makesrna/intern/rna_space.c b/source/blender/makesrna/intern/rna_space.c
index b2663b89333..b0311d63d44 100644
--- a/source/blender/makesrna/intern/rna_space.c
+++ b/source/blender/makesrna/intern/rna_space.c
@@ -540,6 +540,7 @@ static const EnumPropertyItem rna_enum_curve_display_handle_items[] = {
# include "BLI_string.h"
# include "BKE_anim_data.h"
+# include "BKE_asset.h"
# include "BKE_brush.h"
# include "BKE_colortools.h"
# include "BKE_context.h"
@@ -2761,18 +2762,24 @@ static PointerRNA rna_FileBrowser_FileSelectEntry_asset_data_get(PointerRNA *ptr
{
const FileDirEntry *entry = ptr->data;
+ if (!entry->asset) {
+ return PointerRNA_NULL;
+ }
+
+ AssetMetaData *asset_data = BKE_asset_representation_metadata_get(entry->asset);
+
/* Note that the owning ID of the RNA pointer (`ptr->owner_id`) has to be set carefully:
* Local IDs (`entry->id`) own their asset metadata themselves. Asset metadata from other blend
* files are owned by the file browser (`entry`). Only if this is set correctly, we can tell from
* the metadata RNA pointer if the metadata is stored locally and can thus be edited or not. */
- if (entry->id) {
+ if (BKE_asset_representation_is_local_id(entry->asset)) {
PointerRNA id_ptr;
RNA_id_pointer_create(entry->id, &id_ptr);
- return rna_pointer_inherit_refine(&id_ptr, &RNA_AssetMetaData, entry->asset_data);
+ return rna_pointer_inherit_refine(&id_ptr, &RNA_AssetMetaData, asset_data);
}
- return rna_pointer_inherit_refine(ptr, &RNA_AssetMetaData, entry->asset_data);
+ return rna_pointer_inherit_refine(ptr, &RNA_AssetMetaData, asset_data);
}
static int rna_FileBrowser_FileSelectEntry_name_editable(PointerRNA *ptr, const char **r_info)
@@ -2782,7 +2789,7 @@ static int rna_FileBrowser_FileSelectEntry_name_editable(PointerRNA *ptr, const
/* This actually always returns 0 (the name is never editable) but we want to get a disabled
* message returned to `r_info` in some cases. */
- if (entry->asset_data) {
+ if (entry->asset) {
PointerRNA asset_data_ptr = rna_FileBrowser_FileSelectEntry_asset_data_get(ptr);
/* Get disabled hint from asset metadata polling. */
rna_AssetMetaData_editable(&asset_data_ptr, r_info);
diff --git a/source/blender/modifiers/intern/MOD_explode.c b/source/blender/modifiers/intern/MOD_explode.c
index 96bf836fa4a..b0806fed91c 100644
--- a/source/blender/modifiers/intern/MOD_explode.c
+++ b/source/blender/modifiers/intern/MOD_explode.c
@@ -987,7 +987,7 @@ static Mesh *explodeMesh(ExplodeModifierData *emd,
/* getting back to object space */
invert_m4_m4(imat, ctx->object->object_to_world);
- psmd->psys->lattice_deform_data = psys_create_lattice_deform_data(&sim);
+ psys_sim_data_init(&sim);
const MVert *mesh_verts = BKE_mesh_verts(mesh);
MVert *explode_verts = BKE_mesh_verts_for_write(explode);
@@ -1112,10 +1112,7 @@ static Mesh *explodeMesh(ExplodeModifierData *emd,
BKE_mesh_calc_edges_tessface(explode);
BKE_mesh_convert_mfaces_to_mpolys(explode);
- if (psmd->psys->lattice_deform_data) {
- BKE_lattice_deform_data_destroy(psmd->psys->lattice_deform_data);
- psmd->psys->lattice_deform_data = NULL;
- }
+ psys_sim_data_free(&sim);
return explode;
}
diff --git a/source/blender/modifiers/intern/MOD_particleinstance.c b/source/blender/modifiers/intern/MOD_particleinstance.c
index f65f8bc4fb3..46e14dd6bfb 100644
--- a/source/blender/modifiers/intern/MOD_particleinstance.c
+++ b/source/blender/modifiers/intern/MOD_particleinstance.c
@@ -303,7 +303,7 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *
maxedge += totedge;
}
- psys->lattice_deform_data = psys_create_lattice_deform_data(&sim);
+ psys_sim_data_init(&sim);
if (psys->flag & (PSYS_HAIR_DONE | PSYS_KEYED) || psys->pointcache->flag & PTCACHE_BAKED) {
float min[3], max[3];
@@ -514,10 +514,7 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *
p_skip++;
}
- if (psys->lattice_deform_data) {
- BKE_lattice_deform_data_destroy(psys->lattice_deform_data);
- psys->lattice_deform_data = NULL;
- }
+ psys_sim_data_free(&sim);
if (size) {
MEM_freeN(size);
diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_topology_curve_of_point.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_topology_curve_of_point.cc
index d442a8823cb..459f45ef8fb 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_topology_curve_of_point.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_topology_curve_of_point.cc
@@ -49,7 +49,7 @@ class CurveOfPointInput final : public bke::CurvesFieldInput {
return false;
}
- std::optional<eAttrDomain> preferred_domain(const bke::CurvesGeometry & /*curves*/)const final
+ std::optional<eAttrDomain> preferred_domain(const bke::CurvesGeometry & /*curves*/) const final
{
return ATTR_DOMAIN_POINT;
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_topology_points_of_curve.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_topology_points_of_curve.cc
index 02457043281..7f69503831f 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_topology_points_of_curve.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_topology_points_of_curve.cc
@@ -114,7 +114,7 @@ class PointsOfCurveInput final : public bke::CurvesFieldInput {
return false;
}
- std::optional<eAttrDomain> preferred_domain(const bke::CurvesGeometry & /*curves*/)const final
+ std::optional<eAttrDomain> preferred_domain(const bke::CurvesGeometry & /*curves*/) const final
{
return ATTR_DOMAIN_CURVE;
}
@@ -152,7 +152,7 @@ class CurvePointCountInput final : public bke::CurvesFieldInput {
return false;
}
- std::optional<eAttrDomain> preferred_domain(const bke::CurvesGeometry & /*curves*/)const final
+ std::optional<eAttrDomain> preferred_domain(const bke::CurvesGeometry & /*curves*/) const final
{
return ATTR_DOMAIN_CURVE;
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_trim.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_trim.cc
index 3ec71877b7c..b0c2f3117fa 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_trim.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_trim.cc
@@ -19,6 +19,7 @@ NODE_STORAGE_FUNCS(NodeGeometryCurveTrim)
static void node_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Geometry>(N_("Curve")).supported_type(GEO_COMPONENT_TYPE_CURVE);
+ b.add_input<decl::Bool>(N_("Selection")).default_value(true).hide_value().supports_field();
b.add_input<decl::Float>(N_("Start"))
.min(0.0f)
.max(1.0f)
@@ -64,7 +65,7 @@ static void node_update(bNodeTree *ntree, bNode *node)
const NodeGeometryCurveTrim &storage = node_storage(*node);
const GeometryNodeCurveSampleMode mode = (GeometryNodeCurveSampleMode)storage.mode;
- bNodeSocket *start_fac = static_cast<bNodeSocket *>(node->inputs.first)->next;
+ bNodeSocket *start_fac = static_cast<bNodeSocket *>(node->inputs.first)->next->next;
bNodeSocket *end_fac = start_fac->next;
bNodeSocket *start_len = end_fac->next;
bNodeSocket *end_len = start_len->next;
@@ -109,6 +110,7 @@ static void node_gather_link_searches(GatherLinkSearchOpParams &params)
static void geometry_set_curve_trim(GeometrySet &geometry_set,
const GeometryNodeCurveSampleMode mode,
+ Field<bool> &selection_field,
Field<float> &start_field,
Field<float> &end_field)
{
@@ -123,41 +125,21 @@ static void geometry_set_curve_trim(GeometrySet &geometry_set,
bke::CurvesFieldContext field_context{src_curves, ATTR_DOMAIN_CURVE};
fn::FieldEvaluator evaluator{field_context, src_curves.curves_num()};
+ evaluator.add(selection_field);
evaluator.add(start_field);
evaluator.add(end_field);
evaluator.evaluate();
- const VArray<float> starts = evaluator.get_evaluated<float>(0);
- const VArray<float> ends = evaluator.get_evaluated<float>(1);
-
- const VArray<bool> cyclic = src_curves.cyclic();
-
- /* If node length input is on form [0, 1] instead of [0, length]*/
- const bool normalized_length_lookup = mode == GEO_NODE_CURVE_SAMPLE_FACTOR;
-
- /* Stack start + end field. */
- Vector<float> length_factors(src_curves.curves_num() * 2);
- Vector<int64_t> lookup_indices(src_curves.curves_num() * 2);
- threading::parallel_for(src_curves.curves_range(), 512, [&](IndexRange curve_range) {
- for (const int64_t curve_i : curve_range) {
- const bool negative_trim = !cyclic[curve_i] && starts[curve_i] > ends[curve_i];
- length_factors[curve_i] = starts[curve_i];
- length_factors[curve_i + src_curves.curves_num()] = negative_trim ? starts[curve_i] :
- ends[curve_i];
- lookup_indices[curve_i] = curve_i;
- lookup_indices[curve_i + src_curves.curves_num()] = curve_i;
- }
- });
- /* Create curve trim lookup table. */
- Array<bke::curves::CurvePoint, 12> point_lookups = geometry::lookup_curve_points(
- src_curves, length_factors, lookup_indices, normalized_length_lookup);
+ const IndexMask selection = evaluator.get_evaluated_as_mask(0);
+ const VArray<float> starts = evaluator.get_evaluated<float>(1);
+ const VArray<float> ends = evaluator.get_evaluated<float>(2);
- bke::CurvesGeometry dst_curves = geometry::trim_curves(
- src_curves,
- src_curves.curves_range().as_span(),
- point_lookups.as_span().slice(0, src_curves.curves_num()),
- point_lookups.as_span().slice(src_curves.curves_num(), src_curves.curves_num()));
+ if (selection.is_empty()) {
+ return;
+ }
+ bke::CurvesGeometry dst_curves = geometry::trim_curves(
+ src_curves, selection, starts, ends, mode);
Curves *dst_curves_id = bke::curves_new_nomain(std::move(dst_curves));
bke::curves_copy_parameters(src_curves_id, *dst_curves_id);
geometry_set.replace_curves(dst_curves_id);
@@ -171,18 +153,19 @@ static void node_geo_exec(GeoNodeExecParams params)
GeometrySet geometry_set = params.extract_input<GeometrySet>("Curve");
GeometryComponentEditData::remember_deformed_curve_positions_if_necessary(geometry_set);
+ Field<bool> selection_field = params.extract_input<Field<bool>>("Selection");
if (mode == GEO_NODE_CURVE_SAMPLE_FACTOR) {
Field<float> start_field = params.extract_input<Field<float>>("Start");
Field<float> end_field = params.extract_input<Field<float>>("End");
geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) {
- geometry_set_curve_trim(geometry_set, mode, start_field, end_field);
+ geometry_set_curve_trim(geometry_set, mode, selection_field, start_field, end_field);
});
}
else if (mode == GEO_NODE_CURVE_SAMPLE_LENGTH) {
Field<float> start_field = params.extract_input<Field<float>>("Start_001");
Field<float> end_field = params.extract_input<Field<float>>("End_001");
geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) {
- geometry_set_curve_trim(geometry_set, mode, start_field, end_field);
+ geometry_set_curve_trim(geometry_set, mode, selection_field, start_field, end_field);
});
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_mesh_topology_corners_of_face.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_topology_corners_of_face.cc
index 95ae169a6e4..b464832409c 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_mesh_topology_corners_of_face.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_mesh_topology_corners_of_face.cc
@@ -118,7 +118,7 @@ class CornersOfFaceInput final : public bke::MeshFieldInput {
return false;
}
- std::optional<eAttrDomain> preferred_domain(const Mesh & /*mesh*/)const final
+ std::optional<eAttrDomain> preferred_domain(const Mesh & /*mesh*/) const final
{
return ATTR_DOMAIN_FACE;
}
@@ -159,7 +159,7 @@ class CornersOfFaceCountInput final : public bke::MeshFieldInput {
return false;
}
- std::optional<eAttrDomain> preferred_domain(const Mesh & /*mesh*/)const final
+ std::optional<eAttrDomain> preferred_domain(const Mesh & /*mesh*/) const final
{
return ATTR_DOMAIN_FACE;
}
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 cf579e498a5..c01c4149864 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
@@ -139,7 +139,7 @@ class CornersOfVertInput final : public bke::MeshFieldInput {
return false;
}
- std::optional<eAttrDomain> preferred_domain(const Mesh & /*mesh*/)const final
+ std::optional<eAttrDomain> preferred_domain(const Mesh & /*mesh*/) const final
{
return ATTR_DOMAIN_POINT;
}
@@ -180,7 +180,7 @@ class CornersOfVertCountInput final : public bke::MeshFieldInput {
return false;
}
- std::optional<eAttrDomain> preferred_domain(const Mesh & /*mesh*/)const final
+ std::optional<eAttrDomain> preferred_domain(const Mesh & /*mesh*/) const final
{
return ATTR_DOMAIN_POINT;
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_mesh_topology_edges_of_corner.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_topology_edges_of_corner.cc
index af41ae03588..e46061e0d65 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_mesh_topology_edges_of_corner.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_mesh_topology_edges_of_corner.cc
@@ -60,7 +60,7 @@ class CornerNextEdgeFieldInput final : public bke::MeshFieldInput {
return false;
}
- std::optional<eAttrDomain> preferred_domain(const Mesh & /*mesh*/)const final
+ std::optional<eAttrDomain> preferred_domain(const Mesh & /*mesh*/) const final
{
return ATTR_DOMAIN_CORNER;
}
@@ -106,7 +106,7 @@ class CornerPreviousEdgeFieldInput final : public bke::MeshFieldInput {
return false;
}
- std::optional<eAttrDomain> preferred_domain(const Mesh & /*mesh*/)const final
+ std::optional<eAttrDomain> preferred_domain(const Mesh & /*mesh*/) const final
{
return ATTR_DOMAIN_CORNER;
}
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 873f04df9a8..7aadc15f7f8 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
@@ -139,7 +139,7 @@ class EdgesOfVertInput final : public bke::MeshFieldInput {
return false;
}
- std::optional<eAttrDomain> preferred_domain(const Mesh & /*mesh*/)const final
+ std::optional<eAttrDomain> preferred_domain(const Mesh & /*mesh*/) const final
{
return ATTR_DOMAIN_POINT;
}
@@ -181,7 +181,7 @@ class EdgesOfVertCountInput final : public bke::MeshFieldInput {
return false;
}
- std::optional<eAttrDomain> preferred_domain(const Mesh & /*mesh*/)const final
+ std::optional<eAttrDomain> preferred_domain(const Mesh & /*mesh*/) const final
{
return ATTR_DOMAIN_POINT;
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_mesh_topology_offset_corner_in_face.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_topology_offset_corner_in_face.cc
index bd952b9d704..ef5c9a445f2 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_mesh_topology_offset_corner_in_face.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_mesh_topology_offset_corner_in_face.cc
@@ -87,7 +87,7 @@ class OffsetCornerInFaceFieldInput final : public bke::MeshFieldInput {
return false;
}
- std::optional<eAttrDomain> preferred_domain(const Mesh & /*mesh*/)const final
+ std::optional<eAttrDomain> preferred_domain(const Mesh & /*mesh*/) const final
{
return ATTR_DOMAIN_CORNER;
}
diff --git a/source/blender/render/intern/bake.c b/source/blender/render/intern/bake.c
index 67489440bef..b72b99a425f 100644
--- a/source/blender/render/intern/bake.c
+++ b/source/blender/render/intern/bake.c
@@ -747,6 +747,7 @@ void RE_bake_pixels_populate(Mesh *me,
BKE_mesh_recalc_looptri(loops, polys, verts, me->totloop, me->totpoly, looptri);
const int *material_indices = BKE_mesh_material_indices(me);
+ const int materials_num = targets->materials_num;
for (int i = 0; i < tottri; i++) {
const MLoopTri *lt = &looptri[i];
@@ -754,7 +755,10 @@ void RE_bake_pixels_populate(Mesh *me,
bd.primitive_id = i;
/* Find images matching this material. */
- Image *image = targets->material_to_image[material_indices ? material_indices[lt->poly] : 0];
+ const int material_index = (material_indices && materials_num) ?
+ clamp_i(material_indices[lt->poly], 0, materials_num - 1) :
+ 0;
+ Image *image = targets->material_to_image[material_index];
for (int image_id = 0; image_id < targets->images_num; image_id++) {
BakeImage *bk_image = &targets->images[image_id];
if (bk_image->image != image) {
diff --git a/source/blender/render/intern/texture_pointdensity.c b/source/blender/render/intern/texture_pointdensity.c
index 5c31192f62a..09173aaa0e3 100644
--- a/source/blender/render/intern/texture_pointdensity.c
+++ b/source/blender/render/intern/texture_pointdensity.c
@@ -178,7 +178,7 @@ static void pointdensity_cache_psys(
invert_m4_m4(ob->world_to_object, ob->object_to_world);
total_particles = psys->totpart + psys->totchild;
- psys->lattice_deform_data = psys_create_lattice_deform_data(&sim);
+ psys_sim_data_init(&sim);
pd->point_tree = BLI_bvhtree_new(total_particles, 0.0, 4, 6);
pd->totpoints = total_particles;
@@ -258,10 +258,7 @@ static void pointdensity_cache_psys(
BLI_bvhtree_balance(pd->point_tree);
- if (psys->lattice_deform_data) {
- BKE_lattice_deform_data_destroy(psys->lattice_deform_data);
- psys->lattice_deform_data = NULL;
- }
+ psys_sim_data_free(&sim);
}
static void pointdensity_cache_vertex_color(PointDensity *pd,
@@ -780,7 +777,7 @@ static void particle_system_minmax(Depsgraph *depsgraph,
invert_m4_m4(imat, object->object_to_world);
total_particles = psys->totpart + psys->totchild;
- psys->lattice_deform_data = psys_create_lattice_deform_data(&sim);
+ psys_sim_data_init(&sim);
for (i = 0, pa = psys->particles; i < total_particles; i++, pa++) {
float co_object[3], co_min[3], co_max[3];
@@ -796,10 +793,7 @@ static void particle_system_minmax(Depsgraph *depsgraph,
minmax_v3v3_v3(min, max, co_max);
}
- if (psys->lattice_deform_data) {
- BKE_lattice_deform_data_destroy(psys->lattice_deform_data);
- psys->lattice_deform_data = NULL;
- }
+ psys_sim_data_free(&sim);
}
void RE_point_density_cache(struct Depsgraph *depsgraph, PointDensity *pd)
diff --git a/source/blender/sequencer/intern/effects.c b/source/blender/sequencer/intern/effects.c
index 8469876ba25..3e3fe85ed39 100644
--- a/source/blender/sequencer/intern/effects.c
+++ b/source/blender/sequencer/intern/effects.c
@@ -704,10 +704,13 @@ static void do_gammacross_effect_float(
for (int i = 0; i < y; i++) {
for (int j = 0; j < x; j++) {
- *rt = gammaCorrect(mfac * invGammaCorrect(*rt1) + fac * invGammaCorrect(*rt2));
- rt1++;
- rt2++;
- rt++;
+ rt[0] = gammaCorrect(mfac * invGammaCorrect(rt1[0]) + fac * invGammaCorrect(rt2[0]));
+ rt[1] = gammaCorrect(mfac * invGammaCorrect(rt1[1]) + fac * invGammaCorrect(rt2[1]));
+ rt[2] = gammaCorrect(mfac * invGammaCorrect(rt1[2]) + fac * invGammaCorrect(rt2[2]));
+ rt[3] = gammaCorrect(mfac * invGammaCorrect(rt1[3]) + fac * invGammaCorrect(rt2[3]));
+ rt1 += 4;
+ rt2 += 4;
+ rt += 4;
}
}
}
diff --git a/source/blender/windowmanager/WM_api.h b/source/blender/windowmanager/WM_api.h
index 329e22c156a..3526a4349b5 100644
--- a/source/blender/windowmanager/WM_api.h
+++ b/source/blender/windowmanager/WM_api.h
@@ -1302,7 +1302,6 @@ bool WM_drag_is_ID_type(const struct wmDrag *drag, int idcode);
* \note Does not store \a asset in any way, so it's fine to pass a temporary.
*/
wmDragAsset *WM_drag_create_asset_data(const struct AssetHandle *asset,
- struct AssetMetaData *metadata,
const char *path,
int import_type);
struct wmDragAsset *WM_drag_get_asset_data(const struct wmDrag *drag, int idcode);
diff --git a/source/blender/windowmanager/intern/wm_dragdrop.cc b/source/blender/windowmanager/intern/wm_dragdrop.cc
index fb63abed9e9..393149f20f5 100644
--- a/source/blender/windowmanager/intern/wm_dragdrop.cc
+++ b/source/blender/windowmanager/intern/wm_dragdrop.cc
@@ -556,15 +556,12 @@ bool WM_drag_is_ID_type(const wmDrag *drag, int idcode)
return WM_drag_get_local_ID(drag, idcode) || WM_drag_get_asset_data(drag, idcode);
}
-wmDragAsset *WM_drag_create_asset_data(const AssetHandle *asset,
- AssetMetaData *metadata,
- const char *path,
- int import_type)
+wmDragAsset *WM_drag_create_asset_data(const AssetHandle *asset, const char *path, int import_type)
{
wmDragAsset *asset_drag = MEM_new<wmDragAsset>(__func__);
BLI_strncpy(asset_drag->name, ED_asset_handle_get_name(asset), sizeof(asset_drag->name));
- asset_drag->metadata = metadata;
+ asset_drag->metadata = ED_asset_handle_get_metadata(asset);
asset_drag->path = path;
asset_drag->id_type = ED_asset_handle_get_id_type(asset);
asset_drag->import_type = import_type;
@@ -733,12 +730,11 @@ void WM_drag_add_asset_list_item(
drag_asset->asset_data.local_id = local_id;
}
else {
- AssetMetaData *metadata = ED_asset_handle_get_metadata(asset);
char asset_blend_path[FILE_MAX_LIBEXTRA];
ED_asset_handle_get_full_library_path(C, asset_library_ref, asset, asset_blend_path);
drag_asset->is_external = true;
drag_asset->asset_data.external_info = WM_drag_create_asset_data(
- asset, metadata, BLI_strdup(asset_blend_path), FILE_ASSET_IMPORT_APPEND);
+ asset, BLI_strdup(asset_blend_path), FILE_ASSET_IMPORT_APPEND);
}
BLI_addtail(&drag->asset_items, drag_asset);
}