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
diff options
context:
space:
mode:
Diffstat (limited to 'source/blender/blenkernel/intern')
-rw-r--r--source/blender/blenkernel/intern/action.c2
-rw-r--r--source/blender/blenkernel/intern/appdir.c52
-rw-r--r--source/blender/blenkernel/intern/armature.c10
-rw-r--r--source/blender/blenkernel/intern/armature_deform.c4
-rw-r--r--source/blender/blenkernel/intern/armature_update.c4
-rw-r--r--source/blender/blenkernel/intern/asset_catalog.cc47
-rw-r--r--source/blender/blenkernel/intern/asset_catalog_path.cc2
-rw-r--r--source/blender/blenkernel/intern/asset_catalog_test.cc76
-rw-r--r--source/blender/blenkernel/intern/asset_library.cc30
-rw-r--r--source/blender/blenkernel/intern/asset_library_service.cc38
-rw-r--r--source/blender/blenkernel/intern/asset_library_service.hh3
-rw-r--r--source/blender/blenkernel/intern/asset_library_service_test.cc9
-rw-r--r--source/blender/blenkernel/intern/attribute_access.cc17
-rw-r--r--source/blender/blenkernel/intern/blender.c2
-rw-r--r--source/blender/blenkernel/intern/blender_undo.c2
-rw-r--r--source/blender/blenkernel/intern/blendfile.c6
-rw-r--r--source/blender/blenkernel/intern/blendfile_link_append.c6
-rw-r--r--source/blender/blenkernel/intern/boids.c2
-rw-r--r--source/blender/blenkernel/intern/bpath.c4
-rw-r--r--source/blender/blenkernel/intern/brush.cc22
-rw-r--r--source/blender/blenkernel/intern/camera.c20
-rw-r--r--source/blender/blenkernel/intern/cloth.c10
-rw-r--r--source/blender/blenkernel/intern/constraint.c89
-rw-r--r--source/blender/blenkernel/intern/context.c60
-rw-r--r--source/blender/blenkernel/intern/crazyspace.cc35
-rw-r--r--source/blender/blenkernel/intern/curve_deform.c4
-rw-r--r--source/blender/blenkernel/intern/curve_to_mesh_convert.cc10
-rw-r--r--source/blender/blenkernel/intern/curves.cc9
-rw-r--r--source/blender/blenkernel/intern/curves_geometry.cc22
-rw-r--r--source/blender/blenkernel/intern/customdata.cc8
-rw-r--r--source/blender/blenkernel/intern/dynamicpaint.c22
-rw-r--r--source/blender/blenkernel/intern/effect.c20
-rw-r--r--source/blender/blenkernel/intern/fcurve_driver.c14
-rw-r--r--source/blender/blenkernel/intern/fluid.c43
-rw-r--r--source/blender/blenkernel/intern/geometry_component_instances.cc385
-rw-r--r--source/blender/blenkernel/intern/geometry_fields.cc16
-rw-r--r--source/blender/blenkernel/intern/geometry_set.cc63
-rw-r--r--source/blender/blenkernel/intern/geometry_set_instances.cc47
-rw-r--r--source/blender/blenkernel/intern/gpencil.c18
-rw-r--r--source/blender/blenkernel/intern/gpencil_geom.cc17
-rw-r--r--source/blender/blenkernel/intern/gpencil_modifier.c2
-rw-r--r--source/blender/blenkernel/intern/icons.cc2
-rw-r--r--source/blender/blenkernel/intern/image.cc27
-rw-r--r--source/blender/blenkernel/intern/image_format.cc7
-rw-r--r--source/blender/blenkernel/intern/image_save.cc6
-rw-r--r--source/blender/blenkernel/intern/instances.cc337
-rw-r--r--source/blender/blenkernel/intern/ipo.c2
-rw-r--r--source/blender/blenkernel/intern/lattice.c6
-rw-r--r--source/blender/blenkernel/intern/lattice_deform.c6
-rw-r--r--source/blender/blenkernel/intern/layer.c4
-rw-r--r--source/blender/blenkernel/intern/lib_id.c2
-rw-r--r--source/blender/blenkernel/intern/lib_id_delete.c72
-rw-r--r--source/blender/blenkernel/intern/mask_rasterize.c4
-rw-r--r--source/blender/blenkernel/intern/material.c65
-rw-r--r--source/blender/blenkernel/intern/mball_tessellate.cc11
-rw-r--r--source/blender/blenkernel/intern/mesh_convert.cc10
-rw-r--r--source/blender/blenkernel/intern/mesh_mirror.c10
-rw-r--r--source/blender/blenkernel/intern/modifier.cc2
-rw-r--r--source/blender/blenkernel/intern/nla.c5
-rw-r--r--source/blender/blenkernel/intern/node.cc60
-rw-r--r--source/blender/blenkernel/intern/object.cc96
-rw-r--r--source/blender/blenkernel/intern/object_dupli.cc64
-rw-r--r--source/blender/blenkernel/intern/object_update.cc16
-rw-r--r--source/blender/blenkernel/intern/ocean.c2
-rw-r--r--source/blender/blenkernel/intern/packedFile.c2
-rw-r--r--source/blender/blenkernel/intern/paint.cc35
-rw-r--r--source/blender/blenkernel/intern/particle.c22
-rw-r--r--source/blender/blenkernel/intern/particle_child.c4
-rw-r--r--source/blender/blenkernel/intern/particle_system.c36
-rw-r--r--source/blender/blenkernel/intern/pbvh.c205
-rw-r--r--source/blender/blenkernel/intern/pointcache.c16
-rw-r--r--source/blender/blenkernel/intern/preferences.c3
-rw-r--r--source/blender/blenkernel/intern/rigidbody.c24
-rw-r--r--source/blender/blenkernel/intern/scene.cc11
-rw-r--r--source/blender/blenkernel/intern/screen.c2
-rw-r--r--source/blender/blenkernel/intern/softbody.c22
-rw-r--r--source/blender/blenkernel/intern/sound.c8
-rw-r--r--source/blender/blenkernel/intern/unit.c2
-rw-r--r--source/blender/blenkernel/intern/vfont.c4
-rw-r--r--source/blender/blenkernel/intern/volume.cc4
-rw-r--r--source/blender/blenkernel/intern/writeavi.c3
-rw-r--r--source/blender/blenkernel/intern/writeffmpeg.c238
82 files changed, 1762 insertions, 947 deletions
diff --git a/source/blender/blenkernel/intern/action.c b/source/blender/blenkernel/intern/action.c
index 10aa4ec7906..8f6bd812d8e 100644
--- a/source/blender/blenkernel/intern/action.c
+++ b/source/blender/blenkernel/intern/action.c
@@ -1738,7 +1738,7 @@ void what_does_obaction(Object *ob,
BKE_object_workob_clear(workob);
/* init workob */
- copy_m4_m4(workob->obmat, ob->obmat);
+ copy_m4_m4(workob->object_to_world, ob->object_to_world);
copy_m4_m4(workob->parentinv, ob->parentinv);
copy_m4_m4(workob->constinv, ob->constinv);
workob->parent = ob->parent;
diff --git a/source/blender/blenkernel/intern/appdir.c b/source/blender/blenkernel/intern/appdir.c
index b2f1e75cd1d..b3990b2b7fc 100644
--- a/source/blender/blenkernel/intern/appdir.c
+++ b/source/blender/blenkernel/intern/appdir.c
@@ -191,7 +191,7 @@ bool BKE_appdir_folder_documents(char *dir)
char try_documents_path[FILE_MAXDIR];
/* Own attempt at getting a valid Documents path. */
- BLI_path_join(try_documents_path, sizeof(try_documents_path), home_path, N_("Documents"), NULL);
+ BLI_path_join(try_documents_path, sizeof(try_documents_path), home_path, N_("Documents"));
if (!BLI_is_dir(try_documents_path)) {
return false;
}
@@ -214,11 +214,11 @@ bool BKE_appdir_folder_caches(char *r_path, const size_t path_len)
#ifdef WIN32
BLI_path_join(
- r_path, path_len, caches_root_path, "Blender Foundation", "Blender", "Cache", SEP_STR, NULL);
+ r_path, path_len, caches_root_path, "Blender Foundation", "Blender", "Cache", SEP_STR);
#elif defined(__APPLE__)
- BLI_path_join(r_path, path_len, caches_root_path, "Blender", SEP_STR, NULL);
+ BLI_path_join(r_path, path_len, caches_root_path, "Blender", SEP_STR);
#else /* __linux__ */
- BLI_path_join(r_path, path_len, caches_root_path, "blender", SEP_STR, NULL);
+ BLI_path_join(r_path, path_len, caches_root_path, "blender", SEP_STR);
#endif
return true;
@@ -237,7 +237,7 @@ bool BKE_appdir_font_folder_default(char *dir)
}
#elif defined(__APPLE__)
STRNCPY(test_dir, BLI_expand_tilde("~/Library/Fonts/"));
- BLI_path_slash_ensure(test_dir);
+ BLI_path_slash_ensure(test_dir, sizeof(test_dir));
#else
STRNCPY(test_dir, "/usr/share/fonts");
#endif
@@ -281,7 +281,9 @@ static bool test_path(char *targetpath,
/* Only the last argument should be NULL. */
BLI_assert(!(folder_name == NULL && (subfolder_name != NULL)));
- BLI_path_join(targetpath, targetpath_len, path_base, folder_name, subfolder_name, NULL);
+ const char *path_array[] = {path_base, folder_name, subfolder_name};
+ const int path_array_num = (folder_name ? (subfolder_name ? 3 : 2) : 1);
+ BLI_path_join_array(targetpath, targetpath_len, path_array, path_array_num);
if (check_is_dir == false) {
CLOG_INFO(&LOG, 3, "using without test: '%s'", targetpath);
return true;
@@ -365,7 +367,9 @@ static bool get_path_local_ex(char *targetpath,
STR_OR_FALLBACK(subfolder_name));
if (folder_name) { /* `subfolder_name` may be NULL. */
- BLI_path_join(relfolder, sizeof(relfolder), folder_name, subfolder_name, NULL);
+ const char *path_array[] = {folder_name, subfolder_name};
+ const int path_array_num = subfolder_name ? 2 : 1;
+ BLI_path_join_array(relfolder, sizeof(relfolder), path_array, path_array_num);
}
else {
relfolder[0] = '\0';
@@ -379,8 +383,7 @@ static bool get_path_local_ex(char *targetpath,
* we must move the blender_version dir with contents to Resources.
* Add 4 + 9 for the temporary `/../` path & `Resources`. */
char osx_resourses[FILE_MAX + 4 + 9];
- BLI_path_join(
- osx_resourses, sizeof(osx_resourses), g_app.program_dirname, "..", "Resources", NULL);
+ BLI_path_join(osx_resourses, sizeof(osx_resourses), g_app.program_dirname, "..", "Resources");
/* Remove the '/../' added above. */
BLI_path_normalize(NULL, osx_resourses);
path_base = osx_resourses;
@@ -525,7 +528,9 @@ static bool get_path_system_ex(char *targetpath,
char relfolder[FILE_MAX];
if (folder_name) { /* `subfolder_name` may be NULL. */
- BLI_path_join(relfolder, sizeof(relfolder), folder_name, subfolder_name, NULL);
+ const char *path_array[] = {folder_name, subfolder_name};
+ const int path_array_num = subfolder_name ? 2 : 1;
+ BLI_path_join_array(relfolder, sizeof(relfolder), path_array, path_array_num);
}
else {
relfolder[0] = '\0';
@@ -949,7 +954,7 @@ bool BKE_appdir_program_python_search(char *fullpath,
if (python_bin_dir) {
for (int i = 0; i < ARRAY_SIZE(python_names); i++) {
- BLI_join_dirfile(fullpath, fullpath_len, python_bin_dir, python_names[i]);
+ BLI_path_join(fullpath, fullpath_len, python_bin_dir, python_names[i]);
if (
#ifdef _WIN32
@@ -1018,7 +1023,7 @@ bool BKE_appdir_app_template_id_search(const char *app_template, char *path, siz
{
for (int i = 0; i < ARRAY_SIZE(app_template_directory_id); i++) {
char subdir[FILE_MAX];
- BLI_join_dirfile(subdir, sizeof(subdir), app_template_directory_search[i], app_template);
+ BLI_path_join(subdir, sizeof(subdir), app_template_directory_search[i], app_template);
if (BKE_appdir_folder_id_ex(app_template_directory_id[i], subdir, path, path_len)) {
return true;
}
@@ -1041,8 +1046,7 @@ bool BKE_appdir_app_template_has_userpref(const char *app_template)
}
char userpref_path[FILE_MAX];
- BLI_path_join(
- userpref_path, sizeof(userpref_path), app_template_path, BLENDER_USERPREF_FILE, NULL);
+ BLI_path_join(userpref_path, sizeof(userpref_path), app_template_path, BLENDER_USERPREF_FILE);
return BLI_exists(userpref_path);
}
@@ -1089,13 +1093,13 @@ void BKE_appdir_app_templates(ListBase *templates)
* \param userdir: Directory specified in user preferences (may be NULL).
* note that by default this is an empty string, only use when non-empty.
*/
-static void where_is_temp(char *tempdir, const size_t tempdir_len, const char *userdir)
+static void where_is_temp(char *tempdir, const size_t tempdir_maxlen, const char *userdir)
{
tempdir[0] = '\0';
if (userdir && BLI_is_dir(userdir)) {
- BLI_strncpy(tempdir, userdir, tempdir_len);
+ BLI_strncpy(tempdir, userdir, tempdir_maxlen);
}
if (tempdir[0] == '\0') {
@@ -1112,23 +1116,23 @@ static void where_is_temp(char *tempdir, const size_t tempdir_len, const char *u
for (int i = 0; i < ARRAY_SIZE(env_vars); i++) {
const char *tmp = BLI_getenv(env_vars[i]);
if (tmp && (tmp[0] != '\0') && BLI_is_dir(tmp)) {
- BLI_strncpy(tempdir, tmp, tempdir_len);
+ BLI_strncpy(tempdir, tmp, tempdir_maxlen);
break;
}
}
}
if (tempdir[0] == '\0') {
- BLI_strncpy(tempdir, "/tmp/", tempdir_len);
+ BLI_strncpy(tempdir, "/tmp/", tempdir_maxlen);
}
else {
/* add a trailing slash if needed */
- BLI_path_slash_ensure(tempdir);
+ BLI_path_slash_ensure(tempdir, tempdir_maxlen);
}
}
static void tempdir_session_create(char *tempdir_session,
- const size_t tempdir_session_len,
+ const size_t tempdir_session_maxlen,
const char *tempdir)
{
tempdir_session[0] = '\0';
@@ -1142,9 +1146,9 @@ static void tempdir_session_create(char *tempdir_session,
* #_mktemp_s also requires the last null character is included. */
const int tempdir_session_len_required = tempdir_len + session_name_len + 1;
- if (tempdir_session_len_required <= tempdir_session_len) {
+ if (tempdir_session_len_required <= tempdir_session_maxlen) {
/* No need to use path joining utility as we know the last character of #tempdir is a slash. */
- BLI_string_join(tempdir_session, tempdir_session_len, tempdir, session_name);
+ BLI_string_join(tempdir_session, tempdir_session_maxlen, tempdir, session_name);
#ifdef WIN32
const bool needs_create = (_mktemp_s(tempdir_session, tempdir_session_len_required) == 0);
#else
@@ -1154,7 +1158,7 @@ static void tempdir_session_create(char *tempdir_session,
BLI_dir_create_recursive(tempdir_session);
}
if (BLI_is_dir(tempdir_session)) {
- BLI_path_slash_ensure(tempdir_session);
+ BLI_path_slash_ensure(tempdir_session, tempdir_session_maxlen);
/* Success. */
return;
}
@@ -1164,7 +1168,7 @@ static void tempdir_session_create(char *tempdir_session,
"Could not generate a temp file name for '%s', falling back to '%s'",
tempdir_session,
tempdir);
- BLI_strncpy(tempdir_session, tempdir, tempdir_session_len);
+ BLI_strncpy(tempdir_session, tempdir, tempdir_session_maxlen);
}
void BKE_tempdir_init(const char *userdir)
diff --git a/source/blender/blenkernel/intern/armature.c b/source/blender/blenkernel/intern/armature.c
index 2e73cac99b5..0f8bf0e9928 100644
--- a/source/blender/blenkernel/intern/armature.c
+++ b/source/blender/blenkernel/intern/armature.c
@@ -1596,7 +1596,7 @@ void BKE_armature_mat_world_to_pose(Object *ob, const float inmat[4][4], float o
}
/* Get inverse of (armature) object's matrix. */
- invert_m4_m4(obmat, ob->obmat);
+ invert_m4_m4(obmat, ob->object_to_world);
/* multiply given matrix by object's-inverse to find pose-space matrix */
mul_m4_m4m4(outmat, inmat, obmat);
@@ -2569,7 +2569,7 @@ void BKE_pose_where_is(struct Depsgraph *depsgraph, Scene *scene, Object *ob)
}
}
else {
- invert_m4_m4(ob->imat, ob->obmat); /* imat is needed */
+ invert_m4_m4(ob->imat, ob->object_to_world); /* imat is needed */
/* 1. clear flags */
for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
@@ -2696,14 +2696,14 @@ void BKE_pchan_minmax(const Object *ob,
pchan->custom_translation[0],
pchan->custom_translation[1],
pchan->custom_translation[2]);
- mul_m4_series(mat, ob->obmat, tmp, rmat, smat);
+ mul_m4_series(mat, ob->object_to_world, tmp, rmat, smat);
BKE_boundbox_minmax(bb_custom, mat, r_min, r_max);
}
else {
float vec[3];
- mul_v3_m4v3(vec, ob->obmat, pchan_tx->pose_head);
+ mul_v3_m4v3(vec, ob->object_to_world, pchan_tx->pose_head);
minmax_v3v3_v3(r_min, r_max, vec);
- mul_v3_m4v3(vec, ob->obmat, pchan_tx->pose_tail);
+ mul_v3_m4v3(vec, ob->object_to_world, pchan_tx->pose_tail);
minmax_v3v3_v3(r_min, r_max, vec);
}
}
diff --git a/source/blender/blenkernel/intern/armature_deform.c b/source/blender/blenkernel/intern/armature_deform.c
index 89afb886fc2..64a3937c191 100644
--- a/source/blender/blenkernel/intern/armature_deform.c
+++ b/source/blender/blenkernel/intern/armature_deform.c
@@ -582,9 +582,9 @@ static void armature_deform_coords_impl(const Object *ob_arm,
};
float obinv[4][4];
- invert_m4_m4(obinv, ob_target->obmat);
+ invert_m4_m4(obinv, ob_target->object_to_world);
- mul_m4_m4m4(data.postmat, obinv, ob_arm->obmat);
+ mul_m4_m4m4(data.postmat, obinv, ob_arm->object_to_world);
invert_m4_m4(data.premat, data.postmat);
if (em_target != NULL) {
diff --git a/source/blender/blenkernel/intern/armature_update.c b/source/blender/blenkernel/intern/armature_update.c
index 6d7aed239e7..b9f46118c0d 100644
--- a/source/blender/blenkernel/intern/armature_update.c
+++ b/source/blender/blenkernel/intern/armature_update.c
@@ -249,7 +249,7 @@ static void apply_curve_transform(
* unless the option to allow curve to be positioned elsewhere is activated (i.e. no root).
*/
if ((ik_data->flag & CONSTRAINT_SPLINEIK_NO_ROOT) == 0) {
- mul_m4_v3(ik_data->tar->obmat, r_vec);
+ mul_m4_v3(ik_data->tar->object_to_world, r_vec);
}
/* Convert the position to pose-space. */
@@ -819,7 +819,7 @@ void BKE_pose_eval_init(struct Depsgraph *depsgraph, Scene *UNUSED(scene), Objec
BLI_assert((object->pose->flag & POSE_RECALC) == 0);
/* imat is needed for solvers. */
- invert_m4_m4(object->imat, object->obmat);
+ invert_m4_m4(object->imat, object->object_to_world);
/* clear flags */
for (bPoseChannel *pchan = pose->chanbase.first; pchan != NULL; pchan = pchan->next) {
diff --git a/source/blender/blenkernel/intern/asset_catalog.cc b/source/blender/blenkernel/intern/asset_catalog.cc
index f7b14cc3479..62d03b2d79b 100644
--- a/source/blender/blenkernel/intern/asset_catalog.cc
+++ b/source/blender/blenkernel/intern/asset_catalog.cc
@@ -9,6 +9,7 @@
#include "BKE_asset_catalog.hh"
#include "BKE_asset_library.h"
+#include "BKE_asset_library.hh"
#include "BLI_fileops.hh"
#include "BLI_path_util.h"
@@ -284,10 +285,10 @@ AssetCatalog *AssetCatalogService::create_catalog(const AssetCatalogPath &catalo
static std::string asset_definition_default_file_path_from_dir(StringRef asset_library_root)
{
char file_path[PATH_MAX];
- BLI_join_dirfile(file_path,
- sizeof(file_path),
- asset_library_root.data(),
- AssetCatalogService::DEFAULT_CATALOG_FILENAME.data());
+ BLI_path_join(file_path,
+ sizeof(file_path),
+ asset_library_root.data(),
+ AssetCatalogService::DEFAULT_CATALOG_FILENAME.data());
return file_path;
}
@@ -515,8 +516,7 @@ CatalogFilePath AssetCatalogService::find_suitable_cdf_path_for_writing(
BLI_path_join(asset_lib_cdf_path,
sizeof(asset_lib_cdf_path),
suitable_root_path,
- DEFAULT_CATALOG_FILENAME.c_str(),
- nullptr);
+ DEFAULT_CATALOG_FILENAME.c_str());
return asset_lib_cdf_path;
}
@@ -788,6 +788,41 @@ void AssetCatalogTree::foreach_root_item(const ItemIterFn callback)
}
}
+bool AssetCatalogTree::is_empty() const
+{
+ return root_items_.empty();
+}
+
+AssetCatalogTreeItem *AssetCatalogTree::find_item(const AssetCatalogPath &path)
+{
+ AssetCatalogTreeItem *result = nullptr;
+ this->foreach_item([&](AssetCatalogTreeItem &item) {
+ if (result) {
+ /* There is no way to stop iteration. */
+ return;
+ }
+ if (item.catalog_path() == path) {
+ result = &item;
+ }
+ });
+ return result;
+}
+
+AssetCatalogTreeItem *AssetCatalogTree::find_root_item(const AssetCatalogPath &path)
+{
+ AssetCatalogTreeItem *result = nullptr;
+ this->foreach_root_item([&](AssetCatalogTreeItem &item) {
+ if (result) {
+ /* There is no way to stop iteration. */
+ return;
+ }
+ if (item.catalog_path() == path) {
+ result = &item;
+ }
+ });
+ return result;
+}
+
/* ---------------------------------------------------------------------- */
/* ---------------------------------------------------------------------- */
diff --git a/source/blender/blenkernel/intern/asset_catalog_path.cc b/source/blender/blenkernel/intern/asset_catalog_path.cc
index 669adb7adf4..9c653c1a137 100644
--- a/source/blender/blenkernel/intern/asset_catalog_path.cc
+++ b/source/blender/blenkernel/intern/asset_catalog_path.cc
@@ -12,7 +12,7 @@ namespace blender::bke {
const char AssetCatalogPath::SEPARATOR = '/';
-AssetCatalogPath::AssetCatalogPath(const std::string &path) : path_(path)
+AssetCatalogPath::AssetCatalogPath(std::string path) : path_(std::move(path))
{
}
diff --git a/source/blender/blenkernel/intern/asset_catalog_test.cc b/source/blender/blenkernel/intern/asset_catalog_test.cc
index 81eb1786322..ee2dd652b61 100644
--- a/source/blender/blenkernel/intern/asset_catalog_test.cc
+++ b/source/blender/blenkernel/intern/asset_catalog_test.cc
@@ -98,7 +98,7 @@ class AssetCatalogTest : public testing::Test {
FAIL();
}
- asset_library_root_ = test_files_dir + "/" + "asset_library";
+ asset_library_root_ = test_files_dir + SEP_STR + "asset_library";
temp_library_path_ = "";
}
@@ -116,7 +116,7 @@ class AssetCatalogTest : public testing::Test {
{
BKE_tempdir_init("");
const CatalogFilePath tempdir = BKE_tempdir_session();
- temp_library_path_ = tempdir + "test-temporary-path/";
+ temp_library_path_ = tempdir + "test-temporary-path" + SEP_STR;
return temp_library_path_;
}
@@ -202,9 +202,10 @@ class AssetCatalogTest : public testing::Test {
void save_from_memory_into_existing_asset_lib(const bool should_top_level_cdf_exist)
{
const CatalogFilePath target_dir = create_temp_path(); /* Has trailing slash. */
- const CatalogFilePath original_cdf_file = asset_library_root_ + "/blender_assets.cats.txt";
- const CatalogFilePath registered_asset_lib = target_dir + "my_asset_library/";
- const CatalogFilePath asset_lib_subdir = registered_asset_lib + "subdir/";
+ const CatalogFilePath original_cdf_file = asset_library_root_ + SEP_STR +
+ "blender_assets.cats.txt";
+ const CatalogFilePath registered_asset_lib = target_dir + "my_asset_library" + SEP_STR;
+ const CatalogFilePath asset_lib_subdir = registered_asset_lib + "subdir" + SEP_STR;
CatalogFilePath cdf_toplevel = registered_asset_lib +
AssetCatalogService::DEFAULT_CATALOG_FILENAME;
CatalogFilePath cdf_in_subdir = asset_lib_subdir +
@@ -272,7 +273,7 @@ class AssetCatalogTest : public testing::Test {
TEST_F(AssetCatalogTest, load_single_file)
{
AssetCatalogService service(asset_library_root_);
- service.load_from_disk(asset_library_root_ + "/" + "blender_assets.cats.txt");
+ service.load_from_disk(asset_library_root_ + SEP_STR + "blender_assets.cats.txt");
/* Test getting a non-existent catalog ID. */
EXPECT_EQ(nullptr, service.find_catalog(BLI_uuid_generate_random()));
@@ -313,7 +314,7 @@ TEST_F(AssetCatalogTest, load_single_file)
TEST_F(AssetCatalogTest, load_catalog_path_backslashes)
{
AssetCatalogService service(asset_library_root_);
- service.load_from_disk(asset_library_root_ + "/" + "blender_assets.cats.txt");
+ service.load_from_disk(asset_library_root_ + SEP_STR + "blender_assets.cats.txt");
const AssetCatalog *found_by_id = service.find_catalog(UUID_POSES_ELLIE_BACKSLASHES);
ASSERT_NE(nullptr, found_by_id);
@@ -332,7 +333,7 @@ TEST_F(AssetCatalogTest, load_catalog_path_backslashes)
TEST_F(AssetCatalogTest, is_first_loaded_flag)
{
AssetCatalogService service(asset_library_root_);
- service.load_from_disk(asset_library_root_ + "/" + "blender_assets.cats.txt");
+ service.load_from_disk(asset_library_root_ + SEP_STR + "blender_assets.cats.txt");
AssetCatalog *new_cat = service.create_catalog("never/before/seen/path");
EXPECT_FALSE(new_cat->flags.is_first_loaded)
@@ -435,7 +436,7 @@ TEST_F(AssetCatalogTest, insert_item_into_tree)
TEST_F(AssetCatalogTest, load_single_file_into_tree)
{
AssetCatalogService service(asset_library_root_);
- service.load_from_disk(asset_library_root_ + "/" + "blender_assets.cats.txt");
+ service.load_from_disk(asset_library_root_ + SEP_STR + "blender_assets.cats.txt");
/* Contains not only paths from the CDF but also the missing parents (implicitly defined
* catalogs). */
@@ -476,7 +477,7 @@ TEST_F(AssetCatalogTest, foreach_in_tree)
}
AssetCatalogService service(asset_library_root_);
- service.load_from_disk(asset_library_root_ + "/" + "blender_assets.cats.txt");
+ service.load_from_disk(asset_library_root_ + SEP_STR + "blender_assets.cats.txt");
std::vector<AssetCatalogPath> expected_root_items{{"character", "path"}};
AssetCatalogTree *tree = service.get_catalog_tree();
@@ -499,7 +500,7 @@ TEST_F(AssetCatalogTest, foreach_in_tree)
TEST_F(AssetCatalogTest, find_catalog_by_path)
{
TestableAssetCatalogService service(asset_library_root_);
- service.load_from_disk(asset_library_root_ + "/" +
+ service.load_from_disk(asset_library_root_ + SEP_STR +
AssetCatalogService::DEFAULT_CATALOG_FILENAME);
AssetCatalog *catalog;
@@ -522,7 +523,7 @@ TEST_F(AssetCatalogTest, find_catalog_by_path)
TEST_F(AssetCatalogTest, write_single_file)
{
TestableAssetCatalogService service(asset_library_root_);
- service.load_from_disk(asset_library_root_ + "/" +
+ service.load_from_disk(asset_library_root_ + SEP_STR +
AssetCatalogService::DEFAULT_CATALOG_FILENAME);
const CatalogFilePath save_to_path = use_temp_path() +
@@ -550,7 +551,7 @@ TEST_F(AssetCatalogTest, write_single_file)
TEST_F(AssetCatalogTest, read_write_unicode_filepath)
{
TestableAssetCatalogService service(asset_library_root_);
- const CatalogFilePath load_from_path = asset_library_root_ + "/новый/" +
+ const CatalogFilePath load_from_path = asset_library_root_ + SEP_STR + "новый" + SEP_STR +
AssetCatalogService::DEFAULT_CATALOG_FILENAME;
service.load_from_disk(load_from_path);
@@ -588,8 +589,9 @@ TEST_F(AssetCatalogTest, on_blendfile_save__with_existing_cdf)
const CatalogFilePath top_level_dir = create_temp_path(); /* Has trailing slash. */
/* Create a copy of the CDF in SVN, so we can safely write to it. */
- const CatalogFilePath original_cdf_file = asset_library_root_ + "/blender_assets.cats.txt";
- const CatalogFilePath cdf_dirname = top_level_dir + "other_dir/";
+ const CatalogFilePath original_cdf_file = asset_library_root_ + SEP_STR +
+ "blender_assets.cats.txt";
+ const CatalogFilePath cdf_dirname = top_level_dir + "other_dir" + SEP_STR;
const CatalogFilePath cdf_filename = cdf_dirname + AssetCatalogService::DEFAULT_CATALOG_FILENAME;
ASSERT_TRUE(BLI_dir_create_recursive(cdf_dirname.c_str()));
ASSERT_EQ(0, BLI_copy(original_cdf_file.c_str(), cdf_filename.c_str()))
@@ -600,7 +602,7 @@ TEST_F(AssetCatalogTest, on_blendfile_save__with_existing_cdf)
service.load_from_disk();
const AssetCatalog *cat = service.create_catalog("some/catalog/path");
- const CatalogFilePath blendfilename = top_level_dir + "subdir/some_file.blend";
+ const CatalogFilePath blendfilename = top_level_dir + "subdir" + SEP_STR + "some_file.blend";
ASSERT_TRUE(service.write_to_disk(blendfilename));
EXPECT_EQ(cdf_filename, service.get_catalog_definition_file()->file_path);
@@ -650,7 +652,8 @@ TEST_F(AssetCatalogTest, on_blendfile_save__from_memory_into_empty_directory)
TEST_F(AssetCatalogTest, on_blendfile_save__from_memory_into_existing_cdf_and_merge)
{
const CatalogFilePath target_dir = create_temp_path(); /* Has trailing slash. */
- const CatalogFilePath original_cdf_file = asset_library_root_ + "/blender_assets.cats.txt";
+ const CatalogFilePath original_cdf_file = asset_library_root_ + SEP_STR +
+ "blender_assets.cats.txt";
CatalogFilePath writable_cdf_file = target_dir + AssetCatalogService::DEFAULT_CATALOG_FILENAME;
BLI_path_slash_native(writable_cdf_file.data());
ASSERT_EQ(0, BLI_copy(original_cdf_file.c_str(), writable_cdf_file.c_str()));
@@ -719,7 +722,7 @@ TEST_F(AssetCatalogTest, create_first_catalog_from_scratch)
service.write_to_disk(temp_lib_root + "phony.blend");
EXPECT_TRUE(BLI_is_dir(temp_lib_root.c_str()));
- const CatalogFilePath definition_file_path = temp_lib_root + "/" +
+ const CatalogFilePath definition_file_path = temp_lib_root + SEP_STR +
AssetCatalogService::DEFAULT_CATALOG_FILENAME;
EXPECT_TRUE(BLI_is_file(definition_file_path.c_str()));
@@ -739,7 +742,7 @@ TEST_F(AssetCatalogTest, create_catalog_after_loading_file)
/* Copy the asset catalog definition files to a separate location, so that we can test without
* overwriting the test file in SVN. */
- const CatalogFilePath default_catalog_path = asset_library_root_ + "/" +
+ const CatalogFilePath default_catalog_path = asset_library_root_ + SEP_STR +
AssetCatalogService::DEFAULT_CATALOG_FILENAME;
const CatalogFilePath writable_catalog_path = temp_lib_root +
AssetCatalogService::DEFAULT_CATALOG_FILENAME;
@@ -801,7 +804,7 @@ TEST_F(AssetCatalogTest, create_catalog_simple_name)
TEST_F(AssetCatalogTest, delete_catalog_leaf)
{
AssetCatalogService service(asset_library_root_);
- service.load_from_disk(asset_library_root_ + "/" + "blender_assets.cats.txt");
+ service.load_from_disk(asset_library_root_ + SEP_STR + "blender_assets.cats.txt");
/* Delete a leaf catalog, i.e. one that is not a parent of another catalog.
* This keeps this particular test easy. */
@@ -833,7 +836,7 @@ TEST_F(AssetCatalogTest, delete_catalog_leaf)
TEST_F(AssetCatalogTest, delete_catalog_parent_by_id)
{
TestableAssetCatalogService service(asset_library_root_);
- service.load_from_disk(asset_library_root_ + "/" + "blender_assets.cats.txt");
+ service.load_from_disk(asset_library_root_ + SEP_STR + "blender_assets.cats.txt");
/* Delete a parent catalog. */
service.delete_catalog_by_id_soft(UUID_POSES_RUZENA);
@@ -847,7 +850,7 @@ TEST_F(AssetCatalogTest, delete_catalog_parent_by_id)
TEST_F(AssetCatalogTest, delete_catalog_parent_by_path)
{
AssetCatalogService service(asset_library_root_);
- service.load_from_disk(asset_library_root_ + "/" + "blender_assets.cats.txt");
+ service.load_from_disk(asset_library_root_ + SEP_STR + "blender_assets.cats.txt");
/* Create an extra catalog with the to-be-deleted path, and one with a child of that.
* This creates some duplicates that are bound to occur in production asset libraries as well.
@@ -887,14 +890,14 @@ TEST_F(AssetCatalogTest, delete_catalog_parent_by_path)
TEST_F(AssetCatalogTest, delete_catalog_write_to_disk)
{
TestableAssetCatalogService service(asset_library_root_);
- service.load_from_disk(asset_library_root_ + "/" +
+ service.load_from_disk(asset_library_root_ + SEP_STR +
AssetCatalogService::DEFAULT_CATALOG_FILENAME);
service.delete_catalog_by_id_soft(UUID_POSES_ELLIE);
const CatalogFilePath save_to_path = use_temp_path();
AssetCatalogDefinitionFile *cdf = service.get_catalog_definition_file();
- cdf->write_to_disk(save_to_path + "/" + AssetCatalogService::DEFAULT_CATALOG_FILENAME);
+ cdf->write_to_disk(save_to_path + SEP_STR + AssetCatalogService::DEFAULT_CATALOG_FILENAME);
AssetCatalogService loaded_service(save_to_path);
loaded_service.load_from_disk();
@@ -911,7 +914,7 @@ TEST_F(AssetCatalogTest, delete_catalog_write_to_disk)
TEST_F(AssetCatalogTest, update_catalog_path)
{
AssetCatalogService service(asset_library_root_);
- service.load_from_disk(asset_library_root_ + "/" +
+ service.load_from_disk(asset_library_root_ + SEP_STR +
AssetCatalogService::DEFAULT_CATALOG_FILENAME);
const AssetCatalog *orig_cat = service.find_catalog(UUID_POSES_RUZENA);
@@ -940,7 +943,7 @@ TEST_F(AssetCatalogTest, update_catalog_path)
TEST_F(AssetCatalogTest, update_catalog_path_simple_name)
{
AssetCatalogService service(asset_library_root_);
- service.load_from_disk(asset_library_root_ + "/" +
+ service.load_from_disk(asset_library_root_ + SEP_STR +
AssetCatalogService::DEFAULT_CATALOG_FILENAME);
service.update_catalog_path(UUID_POSES_RUZENA, "charlib/Ružena");
@@ -956,7 +959,7 @@ TEST_F(AssetCatalogTest, update_catalog_path_simple_name)
TEST_F(AssetCatalogTest, update_catalog_path_longer_than_simplename)
{
AssetCatalogService service(asset_library_root_);
- service.load_from_disk(asset_library_root_ + "/" +
+ service.load_from_disk(asset_library_root_ + SEP_STR +
AssetCatalogService::DEFAULT_CATALOG_FILENAME);
const std::string new_path =
"this/is/a/very/long/path/that/exceeds/the/simple-name/length/of/assets";
@@ -978,7 +981,7 @@ TEST_F(AssetCatalogTest, update_catalog_path_longer_than_simplename)
TEST_F(AssetCatalogTest, update_catalog_path_add_slashes)
{
AssetCatalogService service(asset_library_root_);
- service.load_from_disk(asset_library_root_ + "/" +
+ service.load_from_disk(asset_library_root_ + SEP_STR +
AssetCatalogService::DEFAULT_CATALOG_FILENAME);
const AssetCatalog *orig_cat = service.find_catalog(UUID_POSES_RUZENA);
@@ -1019,8 +1022,10 @@ TEST_F(AssetCatalogTest, update_catalog_path_add_slashes)
TEST_F(AssetCatalogTest, merge_catalog_files)
{
const CatalogFilePath cdf_dir = create_temp_path();
- const CatalogFilePath original_cdf_file = asset_library_root_ + "/blender_assets.cats.txt";
- const CatalogFilePath modified_cdf_file = asset_library_root_ + "/modified_assets.cats.txt";
+ const CatalogFilePath original_cdf_file = asset_library_root_ + SEP_STR +
+ "blender_assets.cats.txt";
+ const CatalogFilePath modified_cdf_file = asset_library_root_ + SEP_STR +
+ "modified_assets.cats.txt";
const CatalogFilePath temp_cdf_file = cdf_dir + "blender_assets.cats.txt";
ASSERT_EQ(0, BLI_copy(original_cdf_file.c_str(), temp_cdf_file.c_str()));
@@ -1059,8 +1064,10 @@ TEST_F(AssetCatalogTest, merge_catalog_files)
TEST_F(AssetCatalogTest, refresh_catalogs_with_modification)
{
const CatalogFilePath cdf_dir = create_temp_path();
- const CatalogFilePath original_cdf_file = asset_library_root_ + "/blender_assets.cats.txt";
- const CatalogFilePath modified_cdf_file = asset_library_root_ + "/catalog_reload_test.cats.txt";
+ const CatalogFilePath original_cdf_file = asset_library_root_ + SEP_STR +
+ "blender_assets.cats.txt";
+ const CatalogFilePath modified_cdf_file = asset_library_root_ + SEP_STR +
+ "catalog_reload_test.cats.txt";
const CatalogFilePath temp_cdf_file = cdf_dir + "blender_assets.cats.txt";
ASSERT_EQ(0, BLI_copy(original_cdf_file.c_str(), temp_cdf_file.c_str()));
@@ -1131,8 +1138,9 @@ TEST_F(AssetCatalogTest, refresh_catalogs_with_modification)
TEST_F(AssetCatalogTest, backups)
{
const CatalogFilePath cdf_dir = create_temp_path();
- const CatalogFilePath original_cdf_file = asset_library_root_ + "/blender_assets.cats.txt";
- const CatalogFilePath writable_cdf_file = cdf_dir + "/blender_assets.cats.txt";
+ const CatalogFilePath original_cdf_file = asset_library_root_ + SEP_STR +
+ "blender_assets.cats.txt";
+ const CatalogFilePath writable_cdf_file = cdf_dir + SEP_STR + "blender_assets.cats.txt";
ASSERT_EQ(0, BLI_copy(original_cdf_file.c_str(), writable_cdf_file.c_str()));
/* Read a CDF, modify, and write it. */
diff --git a/source/blender/blenkernel/intern/asset_library.cc b/source/blender/blenkernel/intern/asset_library.cc
index 968873cbcbe..b8420af1168 100644
--- a/source/blender/blenkernel/intern/asset_library.cc
+++ b/source/blender/blenkernel/intern/asset_library.cc
@@ -10,6 +10,7 @@
#include "BKE_main.h"
#include "BKE_preferences.h"
+#include "BLI_fileops.h"
#include "BLI_path_util.h"
#include "DNA_asset_types.h"
@@ -19,6 +20,13 @@
bool blender::bke::AssetLibrary::save_catalogs_when_file_is_saved = true;
+blender::bke::AssetLibrary *BKE_asset_library_load(const Main *bmain,
+ const AssetLibraryReference &library_reference)
+{
+ blender::bke::AssetLibraryService *service = blender::bke::AssetLibraryService::get();
+ return service->get_asset_library(bmain, library_reference);
+}
+
/**
* Loading an asset library at this point only means loading the catalogs. Later on this should
* invoke reading of asset representations too.
@@ -172,4 +180,26 @@ void AssetLibrary::refresh_catalog_simplename(struct AssetMetaData *asset_data)
}
STRNCPY(asset_data->catalog_simple_name, catalog->simple_name.c_str());
}
+
+Vector<AssetLibraryReference> all_valid_asset_library_refs()
+{
+ Vector<AssetLibraryReference> result;
+ int i;
+ LISTBASE_FOREACH_INDEX (const bUserAssetLibrary *, asset_library, &U.asset_libraries, i) {
+ if (!BLI_is_dir(asset_library->path)) {
+ continue;
+ }
+ AssetLibraryReference library_ref{};
+ library_ref.custom_library_index = i;
+ library_ref.type = ASSET_LIBRARY_CUSTOM;
+ result.append(library_ref);
+ }
+
+ AssetLibraryReference library_ref{};
+ library_ref.custom_library_index = -1;
+ library_ref.type = ASSET_LIBRARY_LOCAL;
+ result.append(library_ref);
+ return result;
+}
+
} // namespace blender::bke
diff --git a/source/blender/blenkernel/intern/asset_library_service.cc b/source/blender/blenkernel/intern/asset_library_service.cc
index a6b2b7548a2..cd8de7908bf 100644
--- a/source/blender/blenkernel/intern/asset_library_service.cc
+++ b/source/blender/blenkernel/intern/asset_library_service.cc
@@ -7,11 +7,15 @@
#include "asset_library_service.hh"
#include "BKE_blender.h"
+#include "BKE_preferences.h"
#include "BLI_fileops.h" /* For PATH_MAX (at least on Windows). */
#include "BLI_path_util.h"
#include "BLI_string_ref.hh"
+#include "DNA_asset_types.h"
+#include "DNA_userdef_types.h"
+
#include "CLG_log.h"
static CLG_LogRef LOG = {"bke.asset_service"};
@@ -38,13 +42,45 @@ void AssetLibraryService::destroy()
instance_.reset();
}
+AssetLibrary *AssetLibraryService::get_asset_library(
+ const Main *bmain, const AssetLibraryReference &library_reference)
+{
+ if (library_reference.type == ASSET_LIBRARY_LOCAL) {
+ /* For the "Current File" library we get the asset library root path based on main. */
+ char root_path[FILE_MAX];
+ if (bmain) {
+ BKE_asset_library_find_suitable_root_path_from_main(bmain, root_path);
+ }
+ else {
+ root_path[0] = '\0';
+ }
+
+ if (root_path[0] == '\0') {
+ /* File wasn't saved yet. */
+ return get_asset_library_current_file();
+ }
+
+ return get_asset_library_on_disk(root_path);
+ }
+ if (library_reference.type == ASSET_LIBRARY_CUSTOM) {
+ bUserAssetLibrary *user_library = BKE_preferences_asset_library_find_from_index(
+ &U, library_reference.custom_library_index);
+
+ if (user_library) {
+ return get_asset_library_on_disk(user_library->path);
+ }
+ }
+
+ return nullptr;
+}
+
namespace {
std::string normalize_directory_path(StringRefNull directory)
{
char dir_normalized[PATH_MAX];
STRNCPY(dir_normalized, directory.c_str());
- BLI_path_normalize_dir(nullptr, dir_normalized);
+ BLI_path_normalize_dir(nullptr, dir_normalized, sizeof(dir_normalized));
return std::string(dir_normalized);
}
} // namespace
diff --git a/source/blender/blenkernel/intern/asset_library_service.hh b/source/blender/blenkernel/intern/asset_library_service.hh
index 277fb9db6cc..c22c6b182ce 100644
--- a/source/blender/blenkernel/intern/asset_library_service.hh
+++ b/source/blender/blenkernel/intern/asset_library_service.hh
@@ -44,6 +44,9 @@ class AssetLibraryService {
/** Destroy the AssetLibraryService singleton. It will be reallocated by #get() if necessary. */
static void destroy();
+ AssetLibrary *get_asset_library(const Main *bmain,
+ const AssetLibraryReference &library_reference);
+
/**
* Get the given asset library. Opens it (i.e. creates a new AssetLibrary instance) if necessary.
*/
diff --git a/source/blender/blenkernel/intern/asset_library_service_test.cc b/source/blender/blenkernel/intern/asset_library_service_test.cc
index de6180cb684..7952e7ea3b0 100644
--- a/source/blender/blenkernel/intern/asset_library_service_test.cc
+++ b/source/blender/blenkernel/intern/asset_library_service_test.cc
@@ -39,7 +39,7 @@ class AssetLibraryServiceTest : public testing::Test {
if (test_files_dir.empty()) {
FAIL();
}
- asset_library_root_ = test_files_dir + "/" + "asset_library";
+ asset_library_root_ = test_files_dir + SEP_STR + "asset_library";
temp_library_path_ = "";
}
@@ -59,7 +59,7 @@ class AssetLibraryServiceTest : public testing::Test {
{
BKE_tempdir_init("");
const CatalogFilePath tempdir = BKE_tempdir_session();
- temp_library_path_ = tempdir + "test-temporary-path/";
+ temp_library_path_ = tempdir + "test-temporary-path" + SEP_STR;
return temp_library_path_;
}
@@ -118,7 +118,7 @@ TEST_F(AssetLibraryServiceTest, library_path_trailing_slashes)
asset_lib_no_slash[strlen(asset_lib_no_slash) - 1] = '\0';
}
- BLI_path_slash_ensure(asset_lib_with_slash);
+ BLI_path_slash_ensure(asset_lib_with_slash, PATH_MAX);
AssetLibrary *const lib_no_slash = service->get_asset_library_on_disk(asset_lib_no_slash);
@@ -168,7 +168,8 @@ TEST_F(AssetLibraryServiceTest, has_any_unsaved_catalogs)
TEST_F(AssetLibraryServiceTest, has_any_unsaved_catalogs_after_write)
{
const CatalogFilePath writable_dir = create_temp_path(); /* Has trailing slash. */
- const CatalogFilePath original_cdf_file = asset_library_root_ + "/blender_assets.cats.txt";
+ const CatalogFilePath original_cdf_file = asset_library_root_ + SEP_STR +
+ "blender_assets.cats.txt";
CatalogFilePath writable_cdf_file = writable_dir + AssetCatalogService::DEFAULT_CATALOG_FILENAME;
BLI_path_slash_native(writable_cdf_file.data());
ASSERT_EQ(0, BLI_copy(original_cdf_file.c_str(), writable_cdf_file.c_str()));
diff --git a/source/blender/blenkernel/intern/attribute_access.cc b/source/blender/blenkernel/intern/attribute_access.cc
index b86353bdb74..544427cfdd3 100644
--- a/source/blender/blenkernel/intern/attribute_access.cc
+++ b/source/blender/blenkernel/intern/attribute_access.cc
@@ -642,15 +642,26 @@ CustomDataAttributes::CustomDataAttributes(CustomDataAttributes &&other)
size_ = other.size_;
data = other.data;
CustomData_reset(&other.data);
+ other.size_ = 0;
}
CustomDataAttributes &CustomDataAttributes::operator=(const CustomDataAttributes &other)
{
- if (this != &other) {
- CustomData_copy(&other.data, &data, CD_MASK_ALL, CD_DUPLICATE, other.size_);
- size_ = other.size_;
+ if (this == &other) {
+ return *this;
}
+ this->~CustomDataAttributes();
+ new (this) CustomDataAttributes(other);
+ return *this;
+}
+CustomDataAttributes &CustomDataAttributes::operator=(CustomDataAttributes &&other)
+{
+ if (this == &other) {
+ return *this;
+ }
+ this->~CustomDataAttributes();
+ new (this) CustomDataAttributes(std::move(other));
return *this;
}
diff --git a/source/blender/blenkernel/intern/blender.c b/source/blender/blenkernel/intern/blender.c
index 23cf368af01..3598201d906 100644
--- a/source/blender/blenkernel/intern/blender.c
+++ b/source/blender/blenkernel/intern/blender.c
@@ -59,7 +59,7 @@ void BKE_blender_free(void)
{
/* samples are in a global list..., also sets G_MAIN->sound->sample NULL */
- /* Needs to run before main free as wm is still referenced for icons preview jobs. */
+ /* Needs to run before main free as window-manager is still referenced for icons preview jobs. */
BKE_studiolight_free();
BKE_blender_globals_clear();
diff --git a/source/blender/blenkernel/intern/blender_undo.c b/source/blender/blenkernel/intern/blender_undo.c
index a5096b4f9eb..f22dfc6054a 100644
--- a/source/blender/blenkernel/intern/blender_undo.c
+++ b/source/blender/blenkernel/intern/blender_undo.c
@@ -116,7 +116,7 @@ MemFileUndoData *BKE_memfile_undo_encode(Main *bmain, MemFileUndoData *mfu_prev)
counter = counter % U.undosteps;
BLI_snprintf(numstr, sizeof(numstr), "%d.blend", counter);
- BLI_join_dirfile(filepath, sizeof(filepath), BKE_tempdir_session(), numstr);
+ BLI_path_join(filepath, sizeof(filepath), BKE_tempdir_session(), numstr);
/* success = */ /* UNUSED */ BLO_write_file(
bmain, filepath, fileflags, &(const struct BlendFileWriteParams){0}, NULL);
diff --git a/source/blender/blenkernel/intern/blendfile.c b/source/blender/blenkernel/intern/blendfile.c
index 6546659f6cd..8b0d3f2e92e 100644
--- a/source/blender/blenkernel/intern/blendfile.c
+++ b/source/blender/blenkernel/intern/blendfile.c
@@ -186,7 +186,7 @@ static void setup_app_data(bContext *C,
clean_paths(bfd->main);
}
- /* XXX here the complex windowmanager matching */
+ /* The following code blocks performs complex window-manager matching. */
/* no load screens? */
if (mode != LOAD_UI) {
@@ -737,7 +737,7 @@ bool BKE_blendfile_userdef_write_all(ReportList *reports)
if ((cfgdir = BKE_appdir_folder_id_create(BLENDER_USER_CONFIG, NULL))) {
bool ok_write;
- BLI_path_join(filepath, sizeof(filepath), cfgdir, BLENDER_USERPREF_FILE, NULL);
+ BLI_path_join(filepath, sizeof(filepath), cfgdir, BLENDER_USERPREF_FILE);
printf("Writing userprefs: '%s' ", filepath);
if (use_template_userpref) {
@@ -764,7 +764,7 @@ bool BKE_blendfile_userdef_write_all(ReportList *reports)
if (use_template_userpref) {
if ((cfgdir = BKE_appdir_folder_id_create(BLENDER_USER_CONFIG, U.app_template))) {
/* Also save app-template prefs */
- BLI_path_join(filepath, sizeof(filepath), cfgdir, BLENDER_USERPREF_FILE, NULL);
+ BLI_path_join(filepath, sizeof(filepath), cfgdir, BLENDER_USERPREF_FILE);
printf("Writing userprefs app-template: '%s' ", filepath);
if (BKE_blendfile_userdef_write(filepath, reports) != 0) {
diff --git a/source/blender/blenkernel/intern/blendfile_link_append.c b/source/blender/blenkernel/intern/blendfile_link_append.c
index 394469e19a4..4dd225c09ec 100644
--- a/source/blender/blenkernel/intern/blendfile_link_append.c
+++ b/source/blender/blenkernel/intern/blendfile_link_append.c
@@ -1494,6 +1494,7 @@ void BKE_blendfile_library_relocate(BlendfileLinkAppendContext *lapp_context,
* code is wrong, we need to redo it here after adding them back to main. */
BKE_main_id_refcount_recompute(bmain, false);
+ BKE_layer_collection_resync_forbid();
/* Note that in reload case, we also want to replace indirect usages. */
const short remap_flags = ID_REMAP_SKIP_NEVER_NULL_USAGE |
(do_reload ? 0 : ID_REMAP_SKIP_INDIRECT_USAGE);
@@ -1523,6 +1524,8 @@ void BKE_blendfile_library_relocate(BlendfileLinkAppendContext *lapp_context,
id_us_plus_no_lib(&old_key->id);
}
}
+ BKE_layer_collection_resync_allow();
+ BKE_main_collection_sync_remap(bmain);
BKE_main_unlock(bmain);
@@ -1614,6 +1617,9 @@ void BKE_blendfile_library_relocate(BlendfileLinkAppendContext *lapp_context,
(id->tag & LIB_TAG_PRE_EXISTING) == 0) {
continue;
}
+ if ((id->override_library->reference->tag & LIB_TAG_MISSING) == 0) {
+ id->tag &= ~LIB_TAG_MISSING;
+ }
if ((id->override_library->reference->tag & LIB_TAG_PRE_EXISTING) == 0) {
BKE_lib_override_library_update(bmain, id);
}
diff --git a/source/blender/blenkernel/intern/boids.c b/source/blender/blenkernel/intern/boids.c
index 2e07b52c7bf..a0458f0f8d8 100644
--- a/source/blender/blenkernel/intern/boids.c
+++ b/source/blender/blenkernel/intern/boids.c
@@ -959,7 +959,7 @@ void boids_precalc_rules(ParticleSettings *part, float cfra)
if (flbr->ob && flbr->cfra != cfra) {
/* save object locations for velocity calculations */
copy_v3_v3(flbr->oloc, flbr->loc);
- copy_v3_v3(flbr->loc, flbr->ob->obmat[3]);
+ copy_v3_v3(flbr->loc, flbr->ob->object_to_world[3]);
flbr->cfra = cfra;
}
}
diff --git a/source/blender/blenkernel/intern/bpath.c b/source/blender/blenkernel/intern/bpath.c
index f639d03ae0f..6bf121675bc 100644
--- a/source/blender/blenkernel/intern/bpath.c
+++ b/source/blender/blenkernel/intern/bpath.c
@@ -155,7 +155,7 @@ bool BKE_bpath_foreach_path_dirfile_fixed_process(BPathForeachPathData *bpath_da
char path_src[FILE_MAX];
char path_dst[FILE_MAX];
- BLI_join_dirfile(path_src, sizeof(path_src), path_dir, path_file);
+ BLI_path_join(path_src, sizeof(path_src), path_dir, path_file);
/* So that functions can access the old value. */
BLI_strncpy(path_dst, path_src, FILE_MAX);
@@ -279,7 +279,7 @@ static bool missing_files_find__recursive(const char *search_directory,
continue;
}
- BLI_join_dirfile(path, sizeof(path), search_directory, de->d_name);
+ BLI_path_join(path, sizeof(path), search_directory, de->d_name);
if (BLI_stat(path, &status) == -1) {
CLOG_WARN(&LOG, "Cannot get file status (`stat()`) of '%s'", path);
diff --git a/source/blender/blenkernel/intern/brush.cc b/source/blender/blenkernel/intern/brush.cc
index 20d86ea5a2d..6f1435e90b8 100644
--- a/source/blender/blenkernel/intern/brush.cc
+++ b/source/blender/blenkernel/intern/brush.cc
@@ -1974,19 +1974,37 @@ void BKE_brush_curve_preset(Brush *b, eCurveMappingPreset preset)
BKE_curvemapping_changed(cumap, false);
}
+const struct MTex *BKE_brush_mask_texture_get(const struct Brush *brush,
+ const eObjectMode object_mode)
+{
+ if (object_mode == OB_MODE_SCULPT) {
+ return &brush->mtex;
+ }
+ return &brush->mask_mtex;
+}
+
+const struct MTex *BKE_brush_color_texture_get(const struct Brush *brush,
+ const eObjectMode object_mode)
+{
+ if (object_mode == OB_MODE_SCULPT) {
+ return &brush->mask_mtex;
+ }
+ return &brush->mtex;
+}
+
float BKE_brush_sample_tex_3d(const Scene *scene,
const Brush *br,
+ const MTex *mtex,
const float point[3],
float rgba[4],
const int thread,
struct ImagePool *pool)
{
UnifiedPaintSettings *ups = &scene->toolsettings->unified_paint_settings;
- const MTex *mtex = &br->mtex;
float intensity = 1.0;
bool hasrgb = false;
- if (!mtex->tex) {
+ if (mtex == nullptr || mtex->tex == nullptr) {
intensity = 1;
}
else if (mtex->brush_map_mode == MTEX_MAP_MODE_3D) {
diff --git a/source/blender/blenkernel/intern/camera.c b/source/blender/blenkernel/intern/camera.c
index 8608ce97397..7c1193d80ab 100644
--- a/source/blender/blenkernel/intern/camera.c
+++ b/source/blender/blenkernel/intern/camera.c
@@ -221,16 +221,16 @@ float BKE_camera_object_dof_distance(const Object *ob)
}
if (cam->dof.focus_object) {
float view_dir[3], dof_dir[3];
- normalize_v3_v3(view_dir, ob->obmat[2]);
+ normalize_v3_v3(view_dir, ob->object_to_world[2]);
bPoseChannel *pchan = BKE_pose_channel_find_name(cam->dof.focus_object->pose,
cam->dof.focus_subtarget);
if (pchan) {
float posemat[4][4];
- mul_m4_m4m4(posemat, cam->dof.focus_object->obmat, pchan->pose_mat);
- sub_v3_v3v3(dof_dir, ob->obmat[3], posemat[3]);
+ mul_m4_m4m4(posemat, cam->dof.focus_object->object_to_world, pchan->pose_mat);
+ sub_v3_v3v3(dof_dir, ob->object_to_world[3], posemat[3]);
}
else {
- sub_v3_v3v3(dof_dir, ob->obmat[3], cam->dof.focus_object->obmat[3]);
+ sub_v3_v3v3(dof_dir, ob->object_to_world[3], cam->dof.focus_object->object_to_world[3]);
}
return fabsf(dot_v3v3(view_dir, dof_dir));
}
@@ -628,7 +628,7 @@ static void camera_frame_fit_data_init(const Scene *scene,
BKE_camera_params_compute_matrix(params);
/* initialize callback data */
- copy_m3_m4(data->camera_rotmat, (float(*)[4])ob->obmat);
+ copy_m3_m4(data->camera_rotmat, (float(*)[4])ob->object_to_world);
normalize_m3(data->camera_rotmat);
/* To transform a plane which is in its homogeneous representation (4d vector),
* we need the inverse of the transpose of the transform matrix... */
@@ -828,7 +828,7 @@ bool BKE_camera_view_frame_fit_to_coords(const Depsgraph *depsgraph,
static void camera_model_matrix(const Object *camera, float r_modelmat[4][4])
{
- copy_m4_m4(r_modelmat, camera->obmat);
+ copy_m4_m4(r_modelmat, camera->object_to_world);
}
static void camera_stereo3d_model_matrix(const Object *camera,
@@ -854,7 +854,7 @@ static void camera_stereo3d_model_matrix(const Object *camera,
}
float size[3];
- mat4_to_size(size, camera->obmat);
+ mat4_to_size(size, camera->object_to_world);
size_to_mat4(sizemat, size);
if (pivot == CAM_S3D_PIVOT_CENTER) {
@@ -894,7 +894,7 @@ static void camera_stereo3d_model_matrix(const Object *camera,
toeinmat[3][0] = interocular_distance * fac_signed;
/* transform */
- normalize_m4_m4(r_modelmat, camera->obmat);
+ normalize_m4_m4(r_modelmat, camera->object_to_world);
mul_m4_m4m4(r_modelmat, r_modelmat, toeinmat);
/* scale back to the original size */
@@ -902,7 +902,7 @@ static void camera_stereo3d_model_matrix(const Object *camera,
}
else { /* CAM_S3D_PIVOT_LEFT, CAM_S3D_PIVOT_RIGHT */
/* rotate perpendicular to the interocular line */
- normalize_m4_m4(r_modelmat, camera->obmat);
+ normalize_m4_m4(r_modelmat, camera->object_to_world);
mul_m4_m4m4(r_modelmat, r_modelmat, rotmat);
/* translate along the interocular line */
@@ -918,7 +918,7 @@ static void camera_stereo3d_model_matrix(const Object *camera,
}
}
else {
- normalize_m4_m4(r_modelmat, camera->obmat);
+ normalize_m4_m4(r_modelmat, camera->object_to_world);
/* translate - no rotation in CAM_S3D_OFFAXIS, CAM_S3D_PARALLEL */
translate_m4(r_modelmat, -interocular_distance * fac_signed, 0.0f, 0.0f);
diff --git a/source/blender/blenkernel/intern/cloth.c b/source/blender/blenkernel/intern/cloth.c
index 89983eb8f62..910869bbc72 100644
--- a/source/blender/blenkernel/intern/cloth.c
+++ b/source/blender/blenkernel/intern/cloth.c
@@ -269,7 +269,7 @@ static int do_step_cloth(
/* Get the current position. */
copy_v3_v3(verts->xconst, mvert[i].co);
- mul_m4_v3(ob->obmat, verts->xconst);
+ mul_m4_v3(ob->object_to_world, verts->xconst);
if (vert_mass_changed) {
verts->mass = clmd->sim_parms->mass;
@@ -581,7 +581,7 @@ static void cloth_to_object(Object *ob, ClothModifierData *clmd, float (*vertexC
if (clmd->clothObject) {
/* Inverse matrix is not up to date. */
- invert_m4_m4(ob->imat, ob->obmat);
+ invert_m4_m4(ob->imat, ob->object_to_world);
for (i = 0; i < cloth->mvert_num; i++) {
copy_v3_v3(vertexCos[i], cloth->verts[i].x);
@@ -763,11 +763,11 @@ static bool cloth_from_object(
if (first) {
copy_v3_v3(verts->x, mvert[i].co);
- mul_m4_v3(ob->obmat, verts->x);
+ mul_m4_v3(ob->object_to_world, verts->x);
if (shapekey_rest) {
copy_v3_v3(verts->xrest, shapekey_rest[i]);
- mul_m4_v3(ob->obmat, verts->xrest);
+ mul_m4_v3(ob->object_to_world, verts->xrest);
}
else {
copy_v3_v3(verts->xrest, verts->x);
@@ -1155,7 +1155,7 @@ static void cloth_update_verts(Object *ob, ClothModifierData *clmd, Mesh *mesh)
/* vertex count is already ensured to match */
for (i = 0; i < mesh->totvert; i++, verts++) {
copy_v3_v3(verts->xrest, mvert[i].co);
- mul_m4_v3(ob->obmat, verts->xrest);
+ mul_m4_v3(ob->object_to_world, verts->xrest);
}
}
diff --git a/source/blender/blenkernel/intern/constraint.c b/source/blender/blenkernel/intern/constraint.c
index a6a6a1ca28f..1f288aef5ad 100644
--- a/source/blender/blenkernel/intern/constraint.c
+++ b/source/blender/blenkernel/intern/constraint.c
@@ -149,7 +149,7 @@ bConstraintOb *BKE_constraints_make_evalob(
/* Quats/Axis-Angle, so Eulers should just use default order */
cob->rotOrder = EULER_ORDER_DEFAULT;
}
- copy_m4_m4(cob->matrix, ob->obmat);
+ copy_m4_m4(cob->matrix, ob->object_to_world);
}
else {
unit_m4(cob->matrix);
@@ -175,7 +175,7 @@ bConstraintOb *BKE_constraints_make_evalob(
}
/* matrix in world-space */
- mul_m4_m4m4(cob->matrix, ob->obmat, cob->pchan->pose_mat);
+ mul_m4_m4m4(cob->matrix, ob->object_to_world, cob->pchan->pose_mat);
}
else {
unit_m4(cob->matrix);
@@ -216,7 +216,7 @@ void BKE_constraints_clear_evalob(bConstraintOb *cob)
/* cob->ob might not exist! */
if (cob->ob) {
/* copy new ob-matrix back to owner */
- copy_m4_m4(cob->ob->obmat, cob->matrix);
+ copy_m4_m4(cob->ob->object_to_world, cob->matrix);
/* copy inverse of delta back to owner */
invert_m4_m4(cob->ob->constinv, delta);
@@ -276,7 +276,7 @@ void BKE_constraint_mat_convertspace(Object *ob,
}
else {
/* World to pose. */
- invert_m4_m4(imat, ob->obmat);
+ invert_m4_m4(imat, ob->object_to_world);
mul_m4_m4m4(mat, imat, mat);
/* Use pose-space as stepping stone for other spaces. */
@@ -319,7 +319,7 @@ void BKE_constraint_mat_convertspace(Object *ob,
}
else {
/* Pose to world. */
- mul_m4_m4m4(mat, ob->obmat, mat);
+ mul_m4_m4m4(mat, ob->object_to_world, mat);
/* Use world-space as stepping stone for other spaces. */
if (to != CONSTRAINT_SPACE_WORLD) {
/* Call self with slightly different values. */
@@ -429,7 +429,7 @@ void BKE_constraint_mat_convertspace(Object *ob,
/* Check if object has a parent. */
if (ob->parent) {
/* 'subtract' parent's effects from owner. */
- mul_m4_m4m4(diff_mat, ob->parent->obmat, ob->parentinv);
+ mul_m4_m4m4(diff_mat, ob->parent->object_to_world, ob->parentinv);
invert_m4_m4_safe(imat, diff_mat);
mul_m4_m4m4(mat, imat, mat);
}
@@ -465,7 +465,7 @@ void BKE_constraint_mat_convertspace(Object *ob,
/* check that object has a parent - otherwise this won't work */
if (ob->parent) {
/* 'add' parent's effect back to owner */
- mul_m4_m4m4(diff_mat, ob->parent->obmat, ob->parentinv);
+ mul_m4_m4m4(diff_mat, ob->parent->object_to_world, ob->parentinv);
mul_m4_m4m4(mat, diff_mat, mat);
}
else {
@@ -518,7 +518,7 @@ static void contarget_get_mesh_mat(Object *ob, const char *substring, float mat[
const int defgroup = BKE_object_defgroup_name_index(ob, substring);
/* initialize target matrix using target matrix */
- copy_m4_m4(mat, ob->obmat);
+ copy_m4_m4(mat, ob->object_to_world);
/* get index of vertex group */
if (defgroup == -1) {
@@ -584,7 +584,7 @@ static void contarget_get_mesh_mat(Object *ob, const char *substring, float mat[
* calc_gizmo_stats, V3D_ORIENT_NORMAL case */
/* We need the transpose of the inverse for a normal. */
- copy_m3_m4(imat, ob->obmat);
+ copy_m3_m4(imat, ob->object_to_world);
invert_m3_m3(tmat, imat);
transpose_m3(tmat);
@@ -605,7 +605,7 @@ static void contarget_get_mesh_mat(Object *ob, const char *substring, float mat[
normalize_m4(mat);
/* apply the average coordinate as the new location */
- mul_v3_m4v3(mat[3], ob->obmat, vec);
+ mul_v3_m4v3(mat[3], ob->object_to_world, vec);
}
/* function that sets the given matrix based on given vertex group in lattice */
@@ -627,7 +627,7 @@ static void contarget_get_lattice_mat(Object *ob, const char *substring, float m
const int defgroup = BKE_object_defgroup_name_index(ob, substring);
/* initialize target matrix using target matrix */
- copy_m4_m4(mat, ob->obmat);
+ copy_m4_m4(mat, ob->object_to_world);
/* get index of vertex group */
if (defgroup == -1) {
@@ -661,11 +661,11 @@ static void contarget_get_lattice_mat(Object *ob, const char *substring, float m
}
}
- /* find average location, then multiply by ob->obmat to find world-space location */
+ /* find average location, then multiply by ob->object_to_world to find world-space location */
if (grouped) {
mul_v3_fl(vec, 1.0f / grouped);
}
- mul_v3_m4v3(tvec, ob->obmat, vec);
+ mul_v3_m4v3(tvec, ob->object_to_world, vec);
/* copy new location to matrix */
copy_v3_v3(mat[3], tvec);
@@ -684,7 +684,7 @@ static void constraint_target_to_mat4(Object *ob,
{
/* Case OBJECT */
if (substring[0] == '\0') {
- copy_m4_m4(mat, ob->obmat);
+ copy_m4_m4(mat, ob->object_to_world);
BKE_constraint_mat_convertspace(ob, NULL, cob, mat, from, to, false);
}
/* Case VERTEXGROUP */
@@ -719,7 +719,7 @@ static void constraint_target_to_mat4(Object *ob,
if (headtail < 0.000001f && !(is_bbone && full_bbone)) {
/* skip length interpolation if set to head */
- mul_m4_m4m4(mat, ob->obmat, pchan->pose_mat);
+ mul_m4_m4m4(mat, ob->object_to_world, pchan->pose_mat);
}
else if (is_bbone && pchan->bone->segments == pchan->runtime.bbone_segments) {
/* use point along bbone */
@@ -745,7 +745,7 @@ static void constraint_target_to_mat4(Object *ob,
mul_v3_m4v3(tempmat[3], pchan->pose_mat, loc);
}
- mul_m4_m4m4(mat, ob->obmat, tempmat);
+ mul_m4_m4m4(mat, ob->object_to_world, tempmat);
}
else {
float tempmat[4][4], loc[3];
@@ -757,11 +757,11 @@ static void constraint_target_to_mat4(Object *ob,
copy_m4_m4(tempmat, pchan->pose_mat);
copy_v3_v3(tempmat[3], loc);
- mul_m4_m4m4(mat, ob->obmat, tempmat);
+ mul_m4_m4m4(mat, ob->object_to_world, tempmat);
}
}
else {
- copy_m4_m4(mat, ob->obmat);
+ copy_m4_m4(mat, ob->object_to_world);
}
/* convert matrix space as required */
@@ -1069,7 +1069,7 @@ static void childof_evaluate(bConstraint *con, bConstraintOb *cob, ListBase *tar
if (data->flag & CHILDOF_SET_INVERSE) {
invert_m4_m4(data->invmat, parmat);
if (cob->pchan != NULL) {
- mul_m4_series(data->invmat, data->invmat, cob->ob->obmat);
+ mul_m4_series(data->invmat, data->invmat, cob->ob->object_to_world);
}
copy_m4_m4(inverse_matrix, data->invmat);
@@ -1388,8 +1388,8 @@ static void kinematic_get_tarmat(struct Depsgraph *UNUSED(depsgraph),
else {
float vec[3];
/* move grabtarget into world space */
- mul_v3_m4v3(vec, ob->obmat, data->grabtarget);
- copy_m4_m4(ct->matrix, ob->obmat);
+ mul_v3_m4v3(vec, ob->object_to_world, data->grabtarget);
+ copy_m4_m4(ct->matrix, ob->object_to_world);
copy_v3_v3(ct->matrix[3], vec);
}
}
@@ -1528,7 +1528,7 @@ static void followpath_get_tarmat(struct Depsgraph *UNUSED(depsgraph),
copy_v3_v3(totmat[3], vec);
- mul_m4_m4m4(ct->matrix, ct->tar->obmat, totmat);
+ mul_m4_m4m4(ct->matrix, ct->tar->object_to_world, totmat);
}
}
}
@@ -2557,7 +2557,7 @@ static void armdef_get_tarmat(struct Depsgraph *UNUSED(depsgraph),
bPoseChannel *pchan = BKE_pose_channel_find_name(ct->tar->pose, ct->subtarget);
if (pchan != NULL) {
- mul_m4_m4m4(ct->matrix, ct->tar->obmat, pchan->pose_mat);
+ mul_m4_m4m4(ct->matrix, ct->tar->object_to_world, pchan->pose_mat);
return;
}
}
@@ -2613,7 +2613,7 @@ static void armdef_accumulate_bone(bConstraintTarget *ct,
float weight = ct->weight;
/* Our object's location in target pose space. */
- invert_m4_m4(iobmat, ct->tar->obmat);
+ invert_m4_m4(iobmat, ct->tar->object_to_world);
mul_v3_m4v3(co, iobmat, wco);
/* Multiply by the envelope weight when appropriate. */
@@ -2644,7 +2644,7 @@ static void armdef_accumulate_bone(bConstraintTarget *ct,
mul_m4_m4m4(basemat, bone->arm_mat, b_bone_rest_mats[index].mat);
}
- armdef_accumulate_matrix(ct->tar->obmat,
+ armdef_accumulate_matrix(ct->tar->object_to_world,
iobmat,
basemat,
b_bone_mats[index + 1].mat,
@@ -2657,7 +2657,7 @@ static void armdef_accumulate_bone(bConstraintTarget *ct,
mul_m4_m4m4(basemat, bone->arm_mat, b_bone_rest_mats[index + 1].mat);
}
- armdef_accumulate_matrix(ct->tar->obmat,
+ armdef_accumulate_matrix(ct->tar->object_to_world,
iobmat,
basemat,
b_bone_mats[index + 2].mat,
@@ -2667,8 +2667,13 @@ static void armdef_accumulate_bone(bConstraintTarget *ct,
}
else {
/* Simple bone. This requires DEG_OPCODE_BONE_DONE dependency due to chan_mat. */
- armdef_accumulate_matrix(
- ct->tar->obmat, iobmat, bone->arm_mat, pchan->chan_mat, weight, r_sum_mat, r_sum_dq);
+ armdef_accumulate_matrix(ct->tar->object_to_world,
+ iobmat,
+ bone->arm_mat,
+ pchan->chan_mat,
+ weight,
+ r_sum_mat,
+ r_sum_dq);
}
/* Accumulate the weight. */
@@ -2694,7 +2699,7 @@ static void armdef_evaluate(bConstraint *con, bConstraintOb *cob, ListBase *targ
/* For constraints on bones, use the rest position to bind b-bone segments
* and envelopes, to allow safely changing the bone location as if parented. */
copy_v3_v3(input_co, cob->pchan->bone->arm_head);
- mul_m4_v3(cob->ob->obmat, input_co);
+ mul_m4_v3(cob->ob->object_to_world, input_co);
}
else {
copy_v3_v3(input_co, cob->matrix[3]);
@@ -3927,7 +3932,7 @@ static void clampto_evaluate(bConstraint *con, bConstraintOb *cob, ListBase *tar
unit_m4(totmat);
copy_v3_v3(totmat[3], vec);
- mul_m4_m4m4(targetMatrix, ct->tar->obmat, totmat);
+ mul_m4_m4m4(targetMatrix, ct->tar->object_to_world, totmat);
}
}
@@ -4227,7 +4232,7 @@ static void shrinkwrap_get_tarmat(struct Depsgraph *UNUSED(depsgraph),
if (BKE_shrinkwrap_init_tree(
&tree, target_eval, scon->shrinkType, scon->shrinkMode, do_track_normal)) {
- BLI_space_transform_from_matrices(&transform, cob->matrix, ct->tar->obmat);
+ BLI_space_transform_from_matrices(&transform, cob->matrix, ct->tar->object_to_world);
switch (scon->shrinkType) {
case MOD_SHRINKWRAP_NEAREST_SURFACE:
@@ -4902,7 +4907,7 @@ static void followtrack_evaluate_using_3d_position_object(FollowTrackContext *co
/* Object matrix of the camera. */
float camera_obmat[4][4];
- copy_m4_m4(camera_obmat, camera_object->obmat);
+ copy_m4_m4(camera_obmat, camera_object->object_to_world);
/* Calculate inverted matrix of the solved camera at the current time. */
float reconstructed_camera_mat[4][4];
@@ -5054,10 +5059,10 @@ static void followtrack_project_to_depth_object_if_needed(FollowTrackContext *co
}
float depth_object_mat_inv[4][4];
- invert_m4_m4(depth_object_mat_inv, depth_object->obmat);
+ invert_m4_m4(depth_object_mat_inv, depth_object->object_to_world);
float ray_start[3], ray_end[3];
- mul_v3_m4v3(ray_start, depth_object_mat_inv, context->camera_object->obmat[3]);
+ mul_v3_m4v3(ray_start, depth_object_mat_inv, context->camera_object->object_to_world[3]);
mul_v3_m4v3(ray_end, depth_object_mat_inv, cob->matrix[3]);
float ray_direction[3];
@@ -5080,7 +5085,7 @@ static void followtrack_project_to_depth_object_if_needed(FollowTrackContext *co
&tree_data);
if (result != -1) {
- mul_v3_m4v3(cob->matrix[3], depth_object->obmat, hit.co);
+ mul_v3_m4v3(cob->matrix[3], depth_object->object_to_world, hit.co);
}
free_bvhtree_from_mesh(&tree_data);
@@ -5128,9 +5133,9 @@ static void followtrack_evaluate_using_2d_position(FollowTrackContext *context,
}
float disp[3];
- mul_v3_m4v3(disp, camera_object->obmat, vec);
+ mul_v3_m4v3(disp, camera_object->object_to_world, vec);
- copy_m4_m4(rmat, camera_object->obmat);
+ copy_m4_m4(rmat, camera_object->object_to_world);
zero_v3(rmat[3]);
mul_m4_m4m4(cob->matrix, cob->matrix, rmat);
@@ -5152,10 +5157,10 @@ static void followtrack_evaluate_using_2d_position(FollowTrackContext *context,
}
float disp[3];
- mul_v3_m4v3(disp, camera_object->obmat, vec);
+ mul_v3_m4v3(disp, camera_object->object_to_world, vec);
/* apply camera rotation so Z-axis would be co-linear */
- copy_m4_m4(rmat, camera_object->obmat);
+ copy_m4_m4(rmat, camera_object->object_to_world);
zero_v3(rmat[3]);
mul_m4_m4m4(cob->matrix, cob->matrix, rmat);
@@ -5303,7 +5308,7 @@ static void objectsolver_evaluate(bConstraint *con, bConstraintOb *cob, ListBase
BKE_tracking_camera_get_reconstructed_interpolate(tracking, object, framenr, mat);
invert_m4_m4(imat, mat);
- mul_m4_m4m4(parmat, camob->obmat, imat);
+ mul_m4_m4m4(parmat, camob->object_to_world, imat);
copy_m4_m4(obmat, cob->matrix);
@@ -5650,7 +5655,7 @@ bool BKE_constraint_apply_for_object(Depsgraph *depsgraph,
BLI_freelinkN(&single_con, new_con);
/* Apply transform from matrix. */
- BKE_object_apply_mat4(ob, ob_eval->obmat, true, true);
+ BKE_object_apply_mat4(ob, ob_eval->object_to_world, true, true);
return true;
}
@@ -6237,7 +6242,7 @@ void BKE_constraint_target_matrix_get(struct Depsgraph *depsgraph,
cob->ob = (Object *)ownerdata;
cob->pchan = NULL;
if (cob->ob) {
- copy_m4_m4(cob->matrix, cob->ob->obmat);
+ copy_m4_m4(cob->matrix, cob->ob->object_to_world);
copy_m4_m4(cob->startmat, cob->matrix);
}
else {
diff --git a/source/blender/blenkernel/intern/context.c b/source/blender/blenkernel/intern/context.c
index d7bd0038d3c..1d6092849cc 100644
--- a/source/blender/blenkernel/intern/context.c
+++ b/source/blender/blenkernel/intern/context.c
@@ -393,37 +393,37 @@ static void *ctx_data_pointer_get(const bContext *C, const char *member)
return NULL;
}
-static int ctx_data_pointer_verify(const bContext *C, const char *member, void **pointer)
+static bool ctx_data_pointer_verify(const bContext *C, const char *member, void **pointer)
{
/* if context is NULL, pointer must be NULL too and that is a valid return */
if (C == NULL) {
*pointer = NULL;
- return 1;
+ return true;
}
bContextDataResult result;
if (ctx_data_get((bContext *)C, member, &result) == CTX_RESULT_OK) {
BLI_assert(result.type == CTX_DATA_TYPE_POINTER);
*pointer = result.ptr.data;
- return 1;
+ return true;
}
*pointer = NULL;
- return 0;
+ return false;
}
-static int ctx_data_collection_get(const bContext *C, const char *member, ListBase *list)
+static bool ctx_data_collection_get(const bContext *C, const char *member, ListBase *list)
{
bContextDataResult result;
if (ctx_data_get((bContext *)C, member, &result) == CTX_RESULT_OK) {
BLI_assert(result.type == CTX_DATA_TYPE_COLLECTION);
*list = result.list;
- return 1;
+ return true;
}
BLI_listbase_clear(list);
- return 0;
+ return false;
}
static int ctx_data_base_collection_get(const bContext *C, const char *member, ListBase *list)
@@ -681,7 +681,7 @@ void CTX_data_list_add_ptr(bContextDataResult *result, const PointerRNA *ptr)
BLI_addtail(&result->list, link);
}
-int ctx_data_list_count(const bContext *C, int (*func)(const bContext *, ListBase *))
+int ctx_data_list_count(const bContext *C, bool (*func)(const bContext *, ListBase *))
{
ListBase list;
@@ -1291,62 +1291,62 @@ ToolSettings *CTX_data_tool_settings(const bContext *C)
return NULL;
}
-int CTX_data_selected_ids(const bContext *C, ListBase *list)
+bool CTX_data_selected_ids(const bContext *C, ListBase *list)
{
return ctx_data_collection_get(C, "selected_ids", list);
}
-int CTX_data_selected_nodes(const bContext *C, ListBase *list)
+bool CTX_data_selected_nodes(const bContext *C, ListBase *list)
{
return ctx_data_collection_get(C, "selected_nodes", list);
}
-int CTX_data_selected_editable_objects(const bContext *C, ListBase *list)
+bool CTX_data_selected_editable_objects(const bContext *C, ListBase *list)
{
return ctx_data_collection_get(C, "selected_editable_objects", list);
}
-int CTX_data_selected_editable_bases(const bContext *C, ListBase *list)
+bool CTX_data_selected_editable_bases(const bContext *C, ListBase *list)
{
return ctx_data_base_collection_get(C, "selected_editable_objects", list);
}
-int CTX_data_editable_objects(const bContext *C, ListBase *list)
+bool CTX_data_editable_objects(const bContext *C, ListBase *list)
{
return ctx_data_collection_get(C, "editable_objects", list);
}
-int CTX_data_editable_bases(const bContext *C, ListBase *list)
+bool CTX_data_editable_bases(const bContext *C, ListBase *list)
{
return ctx_data_base_collection_get(C, "editable_objects", list);
}
-int CTX_data_selected_objects(const bContext *C, ListBase *list)
+bool CTX_data_selected_objects(const bContext *C, ListBase *list)
{
return ctx_data_collection_get(C, "selected_objects", list);
}
-int CTX_data_selected_bases(const bContext *C, ListBase *list)
+bool CTX_data_selected_bases(const bContext *C, ListBase *list)
{
return ctx_data_base_collection_get(C, "selected_objects", list);
}
-int CTX_data_visible_objects(const bContext *C, ListBase *list)
+bool CTX_data_visible_objects(const bContext *C, ListBase *list)
{
return ctx_data_collection_get(C, "visible_objects", list);
}
-int CTX_data_visible_bases(const bContext *C, ListBase *list)
+bool CTX_data_visible_bases(const bContext *C, ListBase *list)
{
return ctx_data_base_collection_get(C, "visible_objects", list);
}
-int CTX_data_selectable_objects(const bContext *C, ListBase *list)
+bool CTX_data_selectable_objects(const bContext *C, ListBase *list)
{
return ctx_data_collection_get(C, "selectable_objects", list);
}
-int CTX_data_selectable_bases(const bContext *C, ListBase *list)
+bool CTX_data_selectable_bases(const bContext *C, ListBase *list)
{
return ctx_data_base_collection_get(C, "selectable_objects", list);
}
@@ -1404,22 +1404,22 @@ struct CacheFile *CTX_data_edit_cachefile(const bContext *C)
return ctx_data_pointer_get(C, "edit_cachefile");
}
-int CTX_data_selected_bones(const bContext *C, ListBase *list)
+bool CTX_data_selected_bones(const bContext *C, ListBase *list)
{
return ctx_data_collection_get(C, "selected_bones", list);
}
-int CTX_data_selected_editable_bones(const bContext *C, ListBase *list)
+bool CTX_data_selected_editable_bones(const bContext *C, ListBase *list)
{
return ctx_data_collection_get(C, "selected_editable_bones", list);
}
-int CTX_data_visible_bones(const bContext *C, ListBase *list)
+bool CTX_data_visible_bones(const bContext *C, ListBase *list)
{
return ctx_data_collection_get(C, "visible_bones", list);
}
-int CTX_data_editable_bones(const bContext *C, ListBase *list)
+bool CTX_data_editable_bones(const bContext *C, ListBase *list)
{
return ctx_data_collection_get(C, "editable_bones", list);
}
@@ -1429,17 +1429,17 @@ struct bPoseChannel *CTX_data_active_pose_bone(const bContext *C)
return ctx_data_pointer_get(C, "active_pose_bone");
}
-int CTX_data_selected_pose_bones(const bContext *C, ListBase *list)
+bool CTX_data_selected_pose_bones(const bContext *C, ListBase *list)
{
return ctx_data_collection_get(C, "selected_pose_bones", list);
}
-int CTX_data_selected_pose_bones_from_active_object(const bContext *C, ListBase *list)
+bool CTX_data_selected_pose_bones_from_active_object(const bContext *C, ListBase *list)
{
return ctx_data_collection_get(C, "selected_pose_bones_from_active_object", list);
}
-int CTX_data_visible_pose_bones(const bContext *C, ListBase *list)
+bool CTX_data_visible_pose_bones(const bContext *C, ListBase *list)
{
return ctx_data_collection_get(C, "visible_pose_bones", list);
}
@@ -1459,17 +1459,17 @@ bGPDframe *CTX_data_active_gpencil_frame(const bContext *C)
return ctx_data_pointer_get(C, "active_gpencil_frame");
}
-int CTX_data_visible_gpencil_layers(const bContext *C, ListBase *list)
+bool CTX_data_visible_gpencil_layers(const bContext *C, ListBase *list)
{
return ctx_data_collection_get(C, "visible_gpencil_layers", list);
}
-int CTX_data_editable_gpencil_layers(const bContext *C, ListBase *list)
+bool CTX_data_editable_gpencil_layers(const bContext *C, ListBase *list)
{
return ctx_data_collection_get(C, "editable_gpencil_layers", list);
}
-int CTX_data_editable_gpencil_strokes(const bContext *C, ListBase *list)
+bool CTX_data_editable_gpencil_strokes(const bContext *C, ListBase *list)
{
return ctx_data_collection_get(C, "editable_gpencil_strokes", list);
}
diff --git a/source/blender/blenkernel/intern/crazyspace.cc b/source/blender/blenkernel/intern/crazyspace.cc
index 190e2d3bb7e..f83c321c4ae 100644
--- a/source/blender/blenkernel/intern/crazyspace.cc
+++ b/source/blender/blenkernel/intern/crazyspace.cc
@@ -70,47 +70,48 @@ static void set_crazy_vertex_quat(float r_quat[4],
sub_qt_qtqt(r_quat, q2, q1);
}
-static bool modifiers_disable_subsurf_temporary(struct Scene *scene, Object *ob)
+static bool modifiers_disable_subsurf_temporary(Object *ob, const int cageIndex)
{
- bool disabled = false;
- int cageIndex = BKE_modifiers_get_cage_index(scene, ob, nullptr, true);
+ bool changed = false;
ModifierData *md = static_cast<ModifierData *>(ob->modifiers.first);
for (int i = 0; md && i <= cageIndex; i++, md = md->next) {
if (md->type == eModifierType_Subsurf) {
md->mode ^= eModifierMode_DisableTemporary;
- disabled = true;
+ changed = true;
}
}
- return disabled;
+ return changed;
}
float (*BKE_crazyspace_get_mapped_editverts(struct Depsgraph *depsgraph, Object *obedit))[3]
{
- Scene *scene = DEG_get_input_scene(depsgraph);
Scene *scene_eval = DEG_get_evaluated_scene(depsgraph);
Object *obedit_eval = DEG_get_evaluated_object(depsgraph, obedit);
- Mesh *mesh_eval = static_cast<Mesh *>(obedit_eval->data);
- BMEditMesh *editmesh_eval = mesh_eval->edit_mesh;
+ const int cageIndex = BKE_modifiers_get_cage_index(scene_eval, obedit_eval, nullptr, true);
- /* disable subsurf temporal, get mapped cos, and enable it */
- if (modifiers_disable_subsurf_temporary(scene_eval, obedit_eval)) {
- /* Need to make new derived-mesh. */
+ /* Disable subsurf temporal, get mapped cos, and enable it. */
+ if (modifiers_disable_subsurf_temporary(obedit_eval, cageIndex)) {
+ /* Need to make new cage.
+ * TODO: Avoid losing original evaluated geometry. */
makeDerivedMesh(depsgraph, scene_eval, obedit_eval, &CD_MASK_BAREMESH);
}
- /* now get the cage */
- Mesh *mesh_eval_cage = editbmesh_get_eval_cage_from_orig(
- depsgraph, scene, obedit, &CD_MASK_BAREMESH);
+ /* Now get the cage. */
+ BMEditMesh *em_eval = BKE_editmesh_from_object(obedit_eval);
+ Mesh *mesh_eval_cage = editbmesh_get_eval_cage(
+ depsgraph, scene_eval, obedit_eval, em_eval, &CD_MASK_BAREMESH);
- const int nverts = editmesh_eval->bm->totvert;
+ const int nverts = em_eval->bm->totvert;
float(*vertexcos)[3] = static_cast<float(*)[3]>(
MEM_mallocN(sizeof(*vertexcos) * nverts, "vertexcos map"));
mesh_get_mapped_verts_coords(mesh_eval_cage, vertexcos, nverts);
- /* set back the flag, no new cage needs to be built, transform does it */
- modifiers_disable_subsurf_temporary(scene_eval, obedit_eval);
+ /* Set back the flag, and ensure new cage needs to be built. */
+ if (modifiers_disable_subsurf_temporary(obedit_eval, cageIndex)) {
+ DEG_id_tag_update(&obedit->id, ID_RECALC_GEOMETRY);
+ }
return vertexcos;
}
diff --git a/source/blender/blenkernel/intern/curve_deform.c b/source/blender/blenkernel/intern/curve_deform.c
index 9a27ba91c2f..066d8494451 100644
--- a/source/blender/blenkernel/intern/curve_deform.c
+++ b/source/blender/blenkernel/intern/curve_deform.c
@@ -44,8 +44,8 @@ typedef struct {
static void init_curve_deform(const Object *ob_curve, const Object *ob_target, CurveDeform *cd)
{
float imat[4][4];
- invert_m4_m4(imat, ob_target->obmat);
- mul_m4_m4m4(cd->objectspace, imat, ob_curve->obmat);
+ invert_m4_m4(imat, ob_target->object_to_world);
+ mul_m4_m4m4(cd->objectspace, imat, ob_curve->object_to_world);
invert_m4_m4(cd->curvespace, cd->objectspace);
copy_m3_m4(cd->objectspace3, cd->objectspace);
cd->no_rot_axis = 0;
diff --git a/source/blender/blenkernel/intern/curve_to_mesh_convert.cc b/source/blender/blenkernel/intern/curve_to_mesh_convert.cc
index b9fea2a27b8..ecf3be9bd81 100644
--- a/source/blender/blenkernel/intern/curve_to_mesh_convert.cc
+++ b/source/blender/blenkernel/intern/curve_to_mesh_convert.cc
@@ -332,7 +332,8 @@ static eAttrDomain get_attribute_domain_for_mesh(const AttributeAccessor &mesh_a
static bool should_add_attribute_to_mesh(const AttributeAccessor &curve_attributes,
const AttributeAccessor &mesh_attributes,
- const AttributeIDRef &id)
+ const AttributeIDRef &id,
+ const AttributeMetaData &meta_data)
{
/* The position attribute has special non-generic evaluation. */
@@ -346,6 +347,9 @@ static bool should_add_attribute_to_mesh(const AttributeAccessor &curve_attribut
if (!id.should_be_kept()) {
return false;
}
+ if (meta_data.data_type == CD_PROP_STRING) {
+ return false;
+ }
return true;
}
@@ -714,7 +718,7 @@ Mesh *curve_to_mesh_sweep(const CurvesGeometry &main,
MutableAttributeAccessor mesh_attributes = mesh->attributes_for_write();
main_attributes.for_all([&](const AttributeIDRef &id, const AttributeMetaData meta_data) {
- if (!should_add_attribute_to_mesh(main_attributes, mesh_attributes, id)) {
+ if (!should_add_attribute_to_mesh(main_attributes, mesh_attributes, id, meta_data)) {
return true;
}
main_attributes_set.add_new(id);
@@ -751,7 +755,7 @@ Mesh *curve_to_mesh_sweep(const CurvesGeometry &main,
if (main_attributes.contains(id)) {
return true;
}
- if (!should_add_attribute_to_mesh(profile_attributes, mesh_attributes, id)) {
+ if (!should_add_attribute_to_mesh(profile_attributes, mesh_attributes, id, meta_data)) {
return true;
}
const eAttrDomain src_domain = meta_data.domain;
diff --git a/source/blender/blenkernel/intern/curves.cc b/source/blender/blenkernel/intern/curves.cc
index 01be22a57b0..61755a5be9b 100644
--- a/source/blender/blenkernel/intern/curves.cc
+++ b/source/blender/blenkernel/intern/curves.cc
@@ -287,7 +287,10 @@ static void curves_evaluate_modifiers(struct Depsgraph *depsgraph,
{
/* Modifier evaluation modes. */
const bool use_render = (DEG_get_mode(depsgraph) == DAG_EVAL_RENDER);
- const int required_mode = use_render ? eModifierMode_Render : eModifierMode_Realtime;
+ int required_mode = use_render ? eModifierMode_Render : eModifierMode_Realtime;
+ if (BKE_object_is_in_editmode(object)) {
+ required_mode = (ModifierMode)(int(required_mode) | eModifierMode_Editmode);
+ }
ModifierApplyFlag apply_flag = use_render ? MOD_APPLY_RENDER : MOD_APPLY_USECACHE;
const ModifierEvalContext mectx = {depsgraph, object, apply_flag};
@@ -409,11 +412,11 @@ void curves_copy_parameters(const Curves &src, Curves &dst)
CurvesSurfaceTransforms::CurvesSurfaceTransforms(const Object &curves_ob, const Object *surface_ob)
{
- this->curves_to_world = curves_ob.obmat;
+ this->curves_to_world = curves_ob.object_to_world;
this->world_to_curves = this->curves_to_world.inverted();
if (surface_ob != nullptr) {
- this->surface_to_world = surface_ob->obmat;
+ this->surface_to_world = surface_ob->object_to_world;
this->world_to_surface = this->surface_to_world.inverted();
this->surface_to_curves = this->world_to_curves * this->surface_to_world;
this->curves_to_surface = this->world_to_surface * this->curves_to_world;
diff --git a/source/blender/blenkernel/intern/curves_geometry.cc b/source/blender/blenkernel/intern/curves_geometry.cc
index f5c845443f1..7c338480c71 100644
--- a/source/blender/blenkernel/intern/curves_geometry.cc
+++ b/source/blender/blenkernel/intern/curves_geometry.cc
@@ -9,6 +9,7 @@
#include "MEM_guardedalloc.h"
+#include "BLI_array_utils.hh"
#include "BLI_bounds.hh"
#include "BLI_index_mask_ops.hh"
#include "BLI_length_parameterize.hh"
@@ -1111,21 +1112,11 @@ static void copy_between_buffers(const CPPType &type,
src_range.size());
}
-template<typename T>
-static void copy_with_map(const Span<T> src, const Span<int> map, MutableSpan<T> dst)
-{
- threading::parallel_for(map.index_range(), 1024, [&](const IndexRange range) {
- for (const int i : range) {
- dst[i] = src[map[i]];
- }
- });
-}
-
static void copy_with_map(const GSpan src, const Span<int> map, GMutableSpan dst)
{
attribute_math::convert_to_static_type(src.type(), [&](auto dummy) {
using T = decltype(dummy);
- copy_with_map(src.typed<T>(), map, dst.typed<T>());
+ array_utils::gather(src.typed<T>(), map, dst.typed<T>());
});
}
@@ -1233,6 +1224,10 @@ static CurvesGeometry copy_with_removed_points(const CurvesGeometry &curves,
attribute.dst.finish();
}
+ if (new_curves.curves_num() != curves.curves_num()) {
+ new_curves.remove_attributes_based_on_types();
+ }
+
return new_curves;
}
@@ -1338,6 +1333,8 @@ static CurvesGeometry copy_with_removed_curves(const CurvesGeometry &curves,
attribute.dst.finish();
}
+ new_curves.remove_attributes_based_on_types();
+
return new_curves;
}
@@ -1402,6 +1399,9 @@ void CurvesGeometry::reverse_curves(const IndexMask curves_to_reverse)
if (meta_data.domain != ATTR_DOMAIN_POINT) {
return true;
}
+ if (meta_data.data_type == CD_PROP_STRING) {
+ return true;
+ }
if (id.is_named() && bezier_handle_names.contains(id.name())) {
return true;
}
diff --git a/source/blender/blenkernel/intern/customdata.cc b/source/blender/blenkernel/intern/customdata.cc
index 6f2390fc28f..03a0f17a4bb 100644
--- a/source/blender/blenkernel/intern/customdata.cc
+++ b/source/blender/blenkernel/intern/customdata.cc
@@ -19,6 +19,7 @@
#include "BLI_bitmap.h"
#include "BLI_color.hh"
+#include "BLI_cpp_type_make.hh"
#include "BLI_endian_switch.h"
#include "BLI_index_range.hh"
#include "BLI_math.h"
@@ -5387,6 +5388,8 @@ const blender::CPPType *custom_data_type_to_cpp_type(const eCustomDataType type)
return &CPPType::get<int8_t>();
case CD_PROP_BYTE_COLOR:
return &CPPType::get<ColorGeometry4b>();
+ case CD_PROP_STRING:
+ return &CPPType::get<MStringProperty>();
default:
return nullptr;
}
@@ -5419,6 +5422,9 @@ eCustomDataType cpp_type_to_custom_data_type(const blender::CPPType &type)
if (type.is<ColorGeometry4b>()) {
return CD_PROP_BYTE_COLOR;
}
+ if (type.is<MStringProperty>()) {
+ return CD_PROP_STRING;
+ }
return static_cast<eCustomDataType>(-1);
}
@@ -5430,3 +5436,5 @@ size_t CustomData_get_elem_size(CustomDataLayer *layer)
{
return LAYERTYPEINFO[layer->type].size;
}
+
+BLI_CPP_TYPE_MAKE(MStringProperty, MStringProperty, CPPTypeFlags::None);
diff --git a/source/blender/blenkernel/intern/dynamicpaint.c b/source/blender/blenkernel/intern/dynamicpaint.c
index e177250ae5a..b9cec17b6e0 100644
--- a/source/blender/blenkernel/intern/dynamicpaint.c
+++ b/source/blender/blenkernel/intern/dynamicpaint.c
@@ -3783,7 +3783,7 @@ static void dynamicPaint_brushMeshCalculateVelocity(Depsgraph *depsgraph,
numOfVerts_p = mesh_p->totvert;
mvert_p = BKE_mesh_verts_for_write(mesh_p);
- copy_m4_m4(prev_obmat, ob->obmat);
+ copy_m4_m4(prev_obmat, ob->object_to_world);
/* current frame mesh */
scene->r.cfra = cur_fra;
@@ -3816,7 +3816,7 @@ static void dynamicPaint_brushMeshCalculateVelocity(Depsgraph *depsgraph,
.brush_vel = *brushVel,
.mvert_p = mvert_p,
.mvert_c = mvert_c,
- .obmat = ob->obmat,
+ .obmat = ob->object_to_world,
.prev_obmat = prev_obmat,
.timescale = timescale,
};
@@ -3856,7 +3856,7 @@ static void dynamicPaint_brushObjectCalculateVelocity(
SUBFRAME_RECURSION,
BKE_scene_ctime_get(scene),
eModifierType_DynamicPaint);
- copy_m4_m4(prev_obmat, ob->obmat);
+ copy_m4_m4(prev_obmat, ob->object_to_world);
/* current frame mesh */
scene->r.cfra = cur_fra;
@@ -3871,7 +3871,7 @@ static void dynamicPaint_brushObjectCalculateVelocity(
/* calculate speed */
mul_m4_v3(prev_obmat, prev_loc);
- mul_m4_v3(ob->obmat, cur_loc);
+ mul_m4_v3(ob->object_to_world, cur_loc);
sub_v3_v3v3(brushVel->v, cur_loc, prev_loc);
mul_v3_fl(brushVel->v, 1.0f / timescale);
@@ -4279,14 +4279,14 @@ static bool dynamicPaint_paintMesh(Depsgraph *depsgraph,
* (Faster than transforming per surface point
* coordinates and normals to object space) */
for (ii = 0; ii < numOfVerts; ii++) {
- mul_m4_v3(brushOb->obmat, mvert[ii].co);
+ mul_m4_v3(brushOb->object_to_world, mvert[ii].co);
boundInsert(&mesh_bb, mvert[ii].co);
/* for proximity project calculate average normal */
if (brush->flags & MOD_DPAINT_PROX_PROJECT && brush->collision != MOD_DPAINT_COL_VOLUME) {
float nor[3];
copy_v3_v3(nor, vert_normals[ii]);
- mul_mat3_m4_v3(brushOb->obmat, nor);
+ mul_mat3_m4_v3(brushOb->object_to_world, nor);
normalize_v3(nor);
add_v3_v3(avg_brushNor, nor);
@@ -5870,7 +5870,7 @@ static bool dynamicPaint_surfaceHasMoved(DynamicPaintSurface *surface, Object *o
}
/* matrix comparison */
- if (!equals_m4m4(bData->prev_obmat, ob->obmat)) {
+ if (!equals_m4m4(bData->prev_obmat, ob->object_to_world)) {
return true;
}
@@ -5957,7 +5957,7 @@ static void dynamic_paint_generate_bake_data_cb(void *__restrict userdata,
mul_v3_v3v3(scaled_nor, temp_nor, ob->scale);
bData->bNormal[index].normal_scale = len_v3(scaled_nor);
}
- mul_mat3_m4_v3(ob->obmat, temp_nor);
+ mul_mat3_m4_v3(ob->object_to_world, temp_nor);
normalize_v3(temp_nor);
negate_v3_v3(bData->bNormal[index].invNorm, temp_nor);
}
@@ -5995,7 +5995,7 @@ static void dynamic_paint_generate_bake_data_cb(void *__restrict userdata,
mul_v3_v3v3(scaled_nor, temp_nor, ob->scale);
bData->bNormal[index].normal_scale = len_v3(scaled_nor);
}
- mul_mat3_m4_v3(ob->obmat, temp_nor);
+ mul_mat3_m4_v3(ob->object_to_world, temp_nor);
normalize_v3(temp_nor);
negate_v3_v3(bData->bNormal[index].invNorm, temp_nor);
}
@@ -6113,7 +6113,7 @@ static bool dynamicPaint_generateBakeData(DynamicPaintSurface *surface,
bData->mesh_bounds.valid = false;
for (index = 0; index < canvasNumOfVerts; index++) {
copy_v3_v3(canvas_verts[index].v, mvert[index].co);
- mul_m4_v3(ob->obmat, canvas_verts[index].v);
+ mul_m4_v3(ob->object_to_world, canvas_verts[index].v);
boundInsert(&bData->mesh_bounds, canvas_verts[index].v);
}
@@ -6143,7 +6143,7 @@ static bool dynamicPaint_generateBakeData(DynamicPaintSurface *surface,
dynamicPaint_prepareAdjacencyData(surface, false);
/* Copy current frame vertices to check against in next frame */
- copy_m4_m4(bData->prev_obmat, ob->obmat);
+ copy_m4_m4(bData->prev_obmat, ob->object_to_world);
memcpy(bData->prev_verts, mvert, canvasNumOfVerts * sizeof(MVert));
bData->clear = 0;
diff --git a/source/blender/blenkernel/intern/effect.c b/source/blender/blenkernel/intern/effect.c
index 42b38854248..983e4b3c6e6 100644
--- a/source/blender/blenkernel/intern/effect.c
+++ b/source/blender/blenkernel/intern/effect.c
@@ -154,8 +154,8 @@ static void precalculate_effector(struct Depsgraph *depsgraph, EffectorCache *ef
if (eff->ob->runtime.curve_cache->anim_path_accum_length) {
BKE_where_on_path(
eff->ob, 0.0, eff->guide_loc, eff->guide_dir, NULL, &eff->guide_radius, NULL);
- mul_m4_v3(eff->ob->obmat, eff->guide_loc);
- mul_mat3_m4_v3(eff->ob->obmat, eff->guide_dir);
+ mul_m4_v3(eff->ob->object_to_world, eff->guide_loc);
+ mul_mat3_m4_v3(eff->ob->object_to_world, eff->guide_dir);
}
}
}
@@ -707,8 +707,8 @@ bool get_effector_data(EffectorCache *eff,
copy_v3_v3(efd->loc, verts[*efd->index].co);
copy_v3_v3(efd->nor, vert_normals[*efd->index]);
- mul_m4_v3(eff->ob->obmat, efd->loc);
- mul_mat3_m4_v3(eff->ob->obmat, efd->nor);
+ mul_m4_v3(eff->ob->object_to_world, efd->loc);
+ mul_mat3_m4_v3(eff->ob->object_to_world, efd->nor);
normalize_v3(efd->nor);
@@ -760,23 +760,23 @@ bool get_effector_data(EffectorCache *eff,
const Object *ob = eff->ob;
/* Use z-axis as normal. */
- normalize_v3_v3(efd->nor, ob->obmat[2]);
+ normalize_v3_v3(efd->nor, ob->object_to_world[2]);
if (eff->pd && ELEM(eff->pd->shape, PFIELD_SHAPE_PLANE, PFIELD_SHAPE_LINE)) {
float temp[3], translate[3];
- sub_v3_v3v3(temp, point->loc, ob->obmat[3]);
+ sub_v3_v3v3(temp, point->loc, ob->object_to_world[3]);
project_v3_v3v3(translate, temp, efd->nor);
/* for vortex the shape chooses between old / new force */
if (eff->pd->forcefield == PFIELD_VORTEX || eff->pd->shape == PFIELD_SHAPE_LINE) {
- add_v3_v3v3(efd->loc, ob->obmat[3], translate);
+ add_v3_v3v3(efd->loc, ob->object_to_world[3], translate);
}
else { /* normally efd->loc is closest point on effector xy-plane */
sub_v3_v3v3(efd->loc, point->loc, translate);
}
}
else {
- copy_v3_v3(efd->loc, ob->obmat[3]);
+ copy_v3_v3(efd->loc, ob->object_to_world[3]);
}
zero_v3(efd->vel);
@@ -801,8 +801,8 @@ bool get_effector_data(EffectorCache *eff,
}
else {
/* for some effectors we need the object center every time */
- sub_v3_v3v3(efd->vec_to_point2, point->loc, eff->ob->obmat[3]);
- normalize_v3_v3(efd->nor2, eff->ob->obmat[2]);
+ sub_v3_v3v3(efd->vec_to_point2, point->loc, eff->ob->object_to_world[3]);
+ normalize_v3_v3(efd->nor2, eff->ob->object_to_world[2]);
}
}
diff --git a/source/blender/blenkernel/intern/fcurve_driver.c b/source/blender/blenkernel/intern/fcurve_driver.c
index 9f63e2d3743..3d1439b5530 100644
--- a/source/blender/blenkernel/intern/fcurve_driver.c
+++ b/source/blender/blenkernel/intern/fcurve_driver.c
@@ -321,7 +321,7 @@ static float dvar_eval_rotDiff(ChannelDriver *driver, DriverVar *dvar)
}
else {
/* Object. */
- mat[i] = ob->obmat;
+ mat[i] = ob->object_to_world;
}
}
@@ -399,7 +399,7 @@ static float dvar_eval_locDiff(ChannelDriver *driver, DriverVar *dvar)
else {
/* Convert to world-space. */
copy_v3_v3(tmp_loc, pchan->pose_head);
- mul_m4_v3(ob->obmat, tmp_loc);
+ mul_m4_v3(ob->object_to_world, tmp_loc);
}
}
else {
@@ -410,7 +410,7 @@ static float dvar_eval_locDiff(ChannelDriver *driver, DriverVar *dvar)
float mat[4][4];
/* Extract transform just like how the constraints do it! */
- copy_m4_m4(mat, ob->obmat);
+ copy_m4_m4(mat, ob->object_to_world);
BKE_constraint_mat_convertspace(
ob, NULL, NULL, mat, CONSTRAINT_SPACE_WORLD, CONSTRAINT_SPACE_LOCAL, false);
@@ -424,7 +424,7 @@ static float dvar_eval_locDiff(ChannelDriver *driver, DriverVar *dvar)
}
else {
/* World-space. */
- copy_v3_v3(tmp_loc, ob->obmat[3]);
+ copy_v3_v3(tmp_loc, ob->object_to_world[3]);
}
}
@@ -500,7 +500,7 @@ static float dvar_eval_transChan(ChannelDriver *driver, DriverVar *dvar)
}
else {
/* World-space matrix. */
- mul_m4_m4m4(mat, ob->obmat, pchan->pose_mat);
+ mul_m4_m4m4(mat, ob->object_to_world, pchan->pose_mat);
}
}
else {
@@ -514,7 +514,7 @@ static float dvar_eval_transChan(ChannelDriver *driver, DriverVar *dvar)
if (dtar->flag & DTAR_FLAG_LOCALSPACE) {
if (dtar->flag & DTAR_FLAG_LOCAL_CONSTS) {
/* Just like how the constraints do it! */
- copy_m4_m4(mat, ob->obmat);
+ copy_m4_m4(mat, ob->object_to_world);
BKE_constraint_mat_convertspace(
ob, NULL, NULL, mat, CONSTRAINT_SPACE_WORLD, CONSTRAINT_SPACE_LOCAL, false);
}
@@ -525,7 +525,7 @@ static float dvar_eval_transChan(ChannelDriver *driver, DriverVar *dvar)
}
else {
/* World-space matrix - just the good-old one. */
- copy_m4_m4(mat, ob->obmat);
+ copy_m4_m4(mat, ob->object_to_world);
}
}
diff --git a/source/blender/blenkernel/intern/fluid.c b/source/blender/blenkernel/intern/fluid.c
index 0a39207184a..b0e99e10acc 100644
--- a/source/blender/blenkernel/intern/fluid.c
+++ b/source/blender/blenkernel/intern/fluid.c
@@ -327,17 +327,17 @@ void BKE_fluid_cache_free(FluidDomainSettings *fds, Object *ob, int cache_map)
if (cache_map & FLUID_DOMAIN_OUTDATED_DATA) {
flags &= ~(FLUID_DOMAIN_BAKING_DATA | FLUID_DOMAIN_BAKED_DATA | FLUID_DOMAIN_OUTDATED_DATA);
- BLI_path_join(temp_dir, sizeof(temp_dir), fds->cache_directory, FLUID_DOMAIN_DIR_CONFIG, NULL);
+ BLI_path_join(temp_dir, sizeof(temp_dir), fds->cache_directory, FLUID_DOMAIN_DIR_CONFIG);
BLI_path_abs(temp_dir, relbase);
if (BLI_exists(temp_dir)) {
BLI_delete(temp_dir, true, true);
}
- BLI_path_join(temp_dir, sizeof(temp_dir), fds->cache_directory, FLUID_DOMAIN_DIR_DATA, NULL);
+ BLI_path_join(temp_dir, sizeof(temp_dir), fds->cache_directory, FLUID_DOMAIN_DIR_DATA);
BLI_path_abs(temp_dir, relbase);
if (BLI_exists(temp_dir)) {
BLI_delete(temp_dir, true, true);
}
- BLI_path_join(temp_dir, sizeof(temp_dir), fds->cache_directory, FLUID_DOMAIN_DIR_SCRIPT, NULL);
+ BLI_path_join(temp_dir, sizeof(temp_dir), fds->cache_directory, FLUID_DOMAIN_DIR_SCRIPT);
BLI_path_abs(temp_dir, relbase);
if (BLI_exists(temp_dir)) {
BLI_delete(temp_dir, true, true);
@@ -346,7 +346,7 @@ void BKE_fluid_cache_free(FluidDomainSettings *fds, Object *ob, int cache_map)
}
if (cache_map & FLUID_DOMAIN_OUTDATED_NOISE) {
flags &= ~(FLUID_DOMAIN_BAKING_NOISE | FLUID_DOMAIN_BAKED_NOISE | FLUID_DOMAIN_OUTDATED_NOISE);
- BLI_path_join(temp_dir, sizeof(temp_dir), fds->cache_directory, FLUID_DOMAIN_DIR_NOISE, NULL);
+ BLI_path_join(temp_dir, sizeof(temp_dir), fds->cache_directory, FLUID_DOMAIN_DIR_NOISE);
BLI_path_abs(temp_dir, relbase);
if (BLI_exists(temp_dir)) {
BLI_delete(temp_dir, true, true);
@@ -355,7 +355,7 @@ void BKE_fluid_cache_free(FluidDomainSettings *fds, Object *ob, int cache_map)
}
if (cache_map & FLUID_DOMAIN_OUTDATED_MESH) {
flags &= ~(FLUID_DOMAIN_BAKING_MESH | FLUID_DOMAIN_BAKED_MESH | FLUID_DOMAIN_OUTDATED_MESH);
- BLI_path_join(temp_dir, sizeof(temp_dir), fds->cache_directory, FLUID_DOMAIN_DIR_MESH, NULL);
+ BLI_path_join(temp_dir, sizeof(temp_dir), fds->cache_directory, FLUID_DOMAIN_DIR_MESH);
BLI_path_abs(temp_dir, relbase);
if (BLI_exists(temp_dir)) {
BLI_delete(temp_dir, true, true);
@@ -365,8 +365,7 @@ void BKE_fluid_cache_free(FluidDomainSettings *fds, Object *ob, int cache_map)
if (cache_map & FLUID_DOMAIN_OUTDATED_PARTICLES) {
flags &= ~(FLUID_DOMAIN_BAKING_PARTICLES | FLUID_DOMAIN_BAKED_PARTICLES |
FLUID_DOMAIN_OUTDATED_PARTICLES);
- BLI_path_join(
- temp_dir, sizeof(temp_dir), fds->cache_directory, FLUID_DOMAIN_DIR_PARTICLES, NULL);
+ BLI_path_join(temp_dir, sizeof(temp_dir), fds->cache_directory, FLUID_DOMAIN_DIR_PARTICLES);
BLI_path_abs(temp_dir, relbase);
if (BLI_exists(temp_dir)) {
BLI_delete(temp_dir, true, true);
@@ -375,7 +374,7 @@ void BKE_fluid_cache_free(FluidDomainSettings *fds, Object *ob, int cache_map)
}
if (cache_map & FLUID_DOMAIN_OUTDATED_GUIDE) {
flags &= ~(FLUID_DOMAIN_BAKING_GUIDE | FLUID_DOMAIN_BAKED_GUIDE | FLUID_DOMAIN_OUTDATED_GUIDE);
- BLI_path_join(temp_dir, sizeof(temp_dir), fds->cache_directory, FLUID_DOMAIN_DIR_GUIDE, NULL);
+ BLI_path_join(temp_dir, sizeof(temp_dir), fds->cache_directory, FLUID_DOMAIN_DIR_GUIDE);
BLI_path_abs(temp_dir, relbase);
if (BLI_exists(temp_dir)) {
BLI_delete(temp_dir, true, true);
@@ -434,7 +433,7 @@ static void manta_set_domain_from_mesh(FluidDomainSettings *fds,
copy_v3_v3(fds->global_size, size);
copy_v3_v3(fds->dp0, min);
- invert_m4_m4(fds->imat, ob->obmat);
+ invert_m4_m4(fds->imat, ob->object_to_world);
/* Prevent crash when initializing a plane as domain. */
if (!init_resolution || (size[0] < FLT_EPSILON) || (size[1] < FLT_EPSILON) ||
@@ -499,8 +498,8 @@ static bool fluid_modifier_init(
zero_v3(fds->shift_f);
add_v3_fl(fds->shift_f, 0.5f);
zero_v3(fds->prev_loc);
- mul_m4_v3(ob->obmat, fds->prev_loc);
- copy_m4_m4(fds->obmat, ob->obmat);
+ mul_m4_v3(ob->object_to_world, fds->prev_loc);
+ copy_m4_m4(fds->obmat, ob->object_to_world);
/* Set resolutions. */
if (fmd->domain->type == FLUID_DOMAIN_TYPE_GAS &&
@@ -567,11 +566,11 @@ static int get_light(Scene *scene, ViewLayer *view_layer, float *light)
Light *la = base_tmp->object->data;
if (la->type == LA_LOCAL) {
- copy_v3_v3(light, base_tmp->object->obmat[3]);
+ copy_v3_v3(light, base_tmp->object->object_to_world[3]);
return 1;
}
if (!found_light) {
- copy_v3_v3(light, base_tmp->object->obmat[3]);
+ copy_v3_v3(light, base_tmp->object->object_to_world[3]);
found_light = 1;
}
}
@@ -1037,7 +1036,7 @@ static void obstacles_from_mesh(Object *coll_ob,
float co[3];
/* Vertex position. */
- mul_m4_v3(coll_ob->obmat, verts[i].co);
+ mul_m4_v3(coll_ob->object_to_world, verts[i].co);
manta_pos_to_cell(fds, verts[i].co);
/* Vertex velocity. */
@@ -2100,11 +2099,11 @@ static void emit_from_mesh(
float(*vert_normals)[3] = BKE_mesh_vertex_normals_for_write(me);
for (i = 0; i < numverts; i++) {
/* Vertex position. */
- mul_m4_v3(flow_ob->obmat, verts[i].co);
+ mul_m4_v3(flow_ob->object_to_world, verts[i].co);
manta_pos_to_cell(fds, verts[i].co);
/* Vertex normal. */
- mul_mat3_m4_v3(flow_ob->obmat, vert_normals[i]);
+ mul_mat3_m4_v3(flow_ob->object_to_world, vert_normals[i]);
mul_mat3_m4_v3(fds->imat, vert_normals[i]);
normalize_v3(vert_normals[i]);
@@ -2122,7 +2121,7 @@ static void emit_from_mesh(
/* Calculate emission map bounds. */
bb_boundInsert(bb, verts[i].co);
}
- mul_m4_v3(flow_ob->obmat, flow_center);
+ mul_m4_v3(flow_ob->object_to_world, flow_center);
manta_pos_to_cell(fds, flow_center);
/* Set emission map.
@@ -2192,7 +2191,7 @@ static void adaptive_domain_adjust(
float frame_shift_f[3];
float ob_loc[3] = {0};
- mul_m4_v3(ob->obmat, ob_loc);
+ mul_m4_v3(ob->object_to_world, ob_loc);
sub_v3_v3v3(frame_shift_f, ob_loc, fds->prev_loc);
copy_v3_v3(fds->prev_loc, ob_loc);
@@ -3496,8 +3495,8 @@ static Mesh *create_smoke_geometry(FluidDomainSettings *fds, Mesh *orgmesh, Obje
/* Calculate required shift to match domain's global position
* it was originally simulated at (if object moves without manta step). */
- invert_m4_m4(ob->imat, ob->obmat);
- mul_m4_v3(ob->obmat, ob_loc);
+ invert_m4_m4(ob->imat, ob->object_to_world);
+ mul_m4_v3(ob->object_to_world, ob_loc);
mul_m4_v3(fds->obmat, ob_cache_loc);
sub_v3_v3v3(fds->obj_shift_f, ob_cache_loc, ob_loc);
/* Convert shift to local space and apply to vertices. */
@@ -3526,8 +3525,8 @@ static int manta_step(
bool mode_replay = (mode == FLUID_DOMAIN_CACHE_REPLAY);
/* Update object state. */
- invert_m4_m4(fds->imat, ob->obmat);
- copy_m4_m4(fds->obmat, ob->obmat);
+ invert_m4_m4(fds->imat, ob->object_to_world);
+ copy_m4_m4(fds->obmat, ob->object_to_world);
/* Gas domain might use adaptive domain. */
if (fds->type == FLUID_DOMAIN_TYPE_GAS) {
diff --git a/source/blender/blenkernel/intern/geometry_component_instances.cc b/source/blender/blenkernel/intern/geometry_component_instances.cc
index 0b5f7cbf902..be1d9524509 100644
--- a/source/blender/blenkernel/intern/geometry_component_instances.cc
+++ b/source/blender/blenkernel/intern/geometry_component_instances.cc
@@ -16,6 +16,7 @@
#include "BKE_attribute_math.hh"
#include "BKE_geometry_set.hh"
#include "BKE_geometry_set_instances.hh"
+#include "BKE_instances.hh"
#include "attribute_access_intern.hh"
@@ -29,8 +30,8 @@ using blender::MutableSpan;
using blender::Set;
using blender::Span;
using blender::VectorSet;
-
-BLI_CPP_TYPE_MAKE(InstanceReference, InstanceReference, CPPTypeFlags::None)
+using blender::bke::InstanceReference;
+using blender::bke::Instances;
/* -------------------------------------------------------------------- */
/** \name Geometry Component Implementation
@@ -40,339 +41,76 @@ InstancesComponent::InstancesComponent() : GeometryComponent(GEO_COMPONENT_TYPE_
{
}
-GeometryComponent *InstancesComponent::copy() const
-{
- InstancesComponent *new_component = new InstancesComponent();
- new_component->instance_reference_handles_ = instance_reference_handles_;
- new_component->instance_transforms_ = instance_transforms_;
- new_component->references_ = references_;
- new_component->attributes_ = attributes_;
- return new_component;
-}
-
-void InstancesComponent::reserve(int min_capacity)
+InstancesComponent::~InstancesComponent()
{
- instance_reference_handles_.reserve(min_capacity);
- instance_transforms_.reserve(min_capacity);
- attributes_.reallocate(min_capacity);
+ this->clear();
}
-void InstancesComponent::resize(int capacity)
+GeometryComponent *InstancesComponent::copy() const
{
- instance_reference_handles_.resize(capacity);
- instance_transforms_.resize(capacity);
- attributes_.reallocate(capacity);
+ InstancesComponent *new_component = new InstancesComponent();
+ if (instances_ != nullptr) {
+ new_component->instances_ = new Instances(*instances_);
+ new_component->ownership_ = GeometryOwnershipType::Owned;
+ }
+ return new_component;
}
void InstancesComponent::clear()
{
- instance_reference_handles_.clear();
- instance_transforms_.clear();
- attributes_.clear();
- references_.clear();
-}
-
-void InstancesComponent::add_instance(const int instance_handle, const float4x4 &transform)
-{
- BLI_assert(instance_handle >= 0);
- BLI_assert(instance_handle < references_.size());
- instance_reference_handles_.append(instance_handle);
- instance_transforms_.append(transform);
- attributes_.reallocate(this->instances_num());
-}
-
-blender::Span<int> InstancesComponent::instance_reference_handles() const
-{
- return instance_reference_handles_;
-}
-
-blender::MutableSpan<int> InstancesComponent::instance_reference_handles()
-{
- return instance_reference_handles_;
-}
-
-blender::MutableSpan<blender::float4x4> InstancesComponent::instance_transforms()
-{
- return instance_transforms_;
-}
-blender::Span<blender::float4x4> InstancesComponent::instance_transforms() const
-{
- return instance_transforms_;
-}
-
-GeometrySet &InstancesComponent::geometry_set_from_reference(const int reference_index)
-{
- /* If this assert fails, it means #ensure_geometry_instances must be called first or that the
- * reference can't be converted to a geometry set. */
- BLI_assert(references_[reference_index].type() == InstanceReference::Type::GeometrySet);
-
- /* The const cast is okay because the instance's hash in the set
- * is not changed by adjusting the data inside the geometry set. */
- return const_cast<GeometrySet &>(references_[reference_index].geometry_set());
-}
-
-int InstancesComponent::add_reference(const InstanceReference &reference)
-{
- return references_.index_of_or_add_as(reference);
-}
-
-blender::Span<InstanceReference> InstancesComponent::references() const
-{
- return references_;
-}
-
-template<typename T>
-static void copy_data_based_on_mask(Span<T> src, MutableSpan<T> dst, IndexMask mask)
-{
- BLI_assert(src.data() != dst.data());
- using namespace blender;
- threading::parallel_for(mask.index_range(), 1024, [&](IndexRange range) {
- for (const int i : range) {
- dst[i] = src[mask[i]];
- }
- });
-}
-
-void InstancesComponent::remove_instances(const IndexMask mask)
-{
- using namespace blender;
- if (mask.is_range() && mask.as_range().start() == 0) {
- /* Deleting from the end of the array can be much faster since no data has to be shifted. */
- this->resize(mask.size());
- this->remove_unused_references();
- return;
+ BLI_assert(this->is_mutable());
+ if (ownership_ == GeometryOwnershipType::Owned) {
+ delete instances_;
}
-
- Vector<int> new_handles(mask.size());
- copy_data_based_on_mask<int>(this->instance_reference_handles(), new_handles, mask);
- instance_reference_handles_ = std::move(new_handles);
- Vector<float4x4> new_transforms(mask.size());
- copy_data_based_on_mask<float4x4>(this->instance_transforms(), new_transforms, mask);
- instance_transforms_ = std::move(new_transforms);
-
- const bke::CustomDataAttributes &src_attributes = attributes_;
-
- bke::CustomDataAttributes dst_attributes;
- dst_attributes.reallocate(mask.size());
-
- src_attributes.foreach_attribute(
- [&](const bke::AttributeIDRef &id, const bke::AttributeMetaData &meta_data) {
- if (!id.should_be_kept()) {
- return true;
- }
-
- GSpan src = *src_attributes.get_for_read(id);
- dst_attributes.create(id, meta_data.data_type);
- GMutableSpan dst = *dst_attributes.get_for_write(id);
-
- attribute_math::convert_to_static_type(src.type(), [&](auto dummy) {
- using T = decltype(dummy);
- copy_data_based_on_mask<T>(src.typed<T>(), dst.typed<T>(), mask);
- });
- return true;
- },
- ATTR_DOMAIN_INSTANCE);
-
- attributes_ = std::move(dst_attributes);
- this->remove_unused_references();
+ instances_ = nullptr;
}
-void InstancesComponent::remove_unused_references()
+bool InstancesComponent::is_empty() const
{
- using namespace blender;
- using namespace blender::bke;
-
- const int tot_instances = this->instances_num();
- const int tot_references_before = references_.size();
-
- if (tot_instances == 0) {
- /* If there are no instances, no reference is needed. */
- references_.clear();
- return;
- }
- if (tot_references_before == 1) {
- /* There is only one reference and at least one instance. So the only existing reference is
- * used. Nothing to do here. */
- return;
- }
-
- Array<bool> usage_by_handle(tot_references_before, false);
- std::mutex mutex;
-
- /* Loop over all instances to see which references are used. */
- threading::parallel_for(IndexRange(tot_instances), 1000, [&](IndexRange range) {
- /* Use local counter to avoid lock contention. */
- Array<bool> local_usage_by_handle(tot_references_before, false);
-
- for (const int i : range) {
- const int handle = instance_reference_handles_[i];
- BLI_assert(handle >= 0 && handle < tot_references_before);
- local_usage_by_handle[handle] = true;
- }
-
- std::lock_guard lock{mutex};
- for (const int i : IndexRange(tot_references_before)) {
- usage_by_handle[i] |= local_usage_by_handle[i];
- }
- });
-
- if (!usage_by_handle.as_span().contains(false)) {
- /* All references are used. */
- return;
- }
-
- /* Create new references and a mapping for the handles. */
- Vector<int> handle_mapping;
- VectorSet<InstanceReference> new_references;
- int next_new_handle = 0;
- bool handles_have_to_be_updated = false;
- for (const int old_handle : IndexRange(tot_references_before)) {
- if (!usage_by_handle[old_handle]) {
- /* Add some dummy value. It won't be read again. */
- handle_mapping.append(-1);
- }
- else {
- const InstanceReference &reference = references_[old_handle];
- handle_mapping.append(next_new_handle);
- new_references.add_new(reference);
- if (old_handle != next_new_handle) {
- handles_have_to_be_updated = true;
- }
- next_new_handle++;
+ if (instances_ != nullptr) {
+ if (instances_->instances_num() > 0) {
+ return false;
}
}
- references_ = new_references;
-
- if (!handles_have_to_be_updated) {
- /* All remaining handles are the same as before, so they don't have to be updated. This happens
- * when unused handles are only at the end. */
- return;
- }
-
- /* Update handles of instances. */
- threading::parallel_for(IndexRange(tot_instances), 1000, [&](IndexRange range) {
- for (const int i : range) {
- instance_reference_handles_[i] = handle_mapping[instance_reference_handles_[i]];
- }
- });
-}
-
-int InstancesComponent::instances_num() const
-{
- return instance_transforms_.size();
-}
-
-int InstancesComponent::references_num() const
-{
- return references_.size();
-}
-
-bool InstancesComponent::is_empty() const
-{
- return this->instance_reference_handles_.size() == 0;
+ return true;
}
bool InstancesComponent::owns_direct_data() const
{
- for (const InstanceReference &reference : references_) {
- if (!reference.owns_direct_data()) {
- return false;
- }
+ if (instances_ != nullptr) {
+ return instances_->owns_direct_data();
}
return true;
}
void InstancesComponent::ensure_owns_direct_data()
{
- BLI_assert(this->is_mutable());
- for (const InstanceReference &const_reference : references_) {
- /* Const cast is fine because we are not changing anything that would change the hash of the
- * reference. */
- InstanceReference &reference = const_cast<InstanceReference &>(const_reference);
- reference.ensure_owns_direct_data();
+ if (instances_ != nullptr) {
+ instances_->ensure_owns_direct_data();
}
}
-static blender::Array<int> generate_unique_instance_ids(Span<int> original_ids)
+const blender::bke::Instances *InstancesComponent::get_for_read() const
{
- using namespace blender;
- Array<int> unique_ids(original_ids.size());
-
- Set<int> used_unique_ids;
- used_unique_ids.reserve(original_ids.size());
- Vector<int> instances_with_id_collision;
- for (const int instance_index : original_ids.index_range()) {
- const int original_id = original_ids[instance_index];
- if (used_unique_ids.add(original_id)) {
- /* The original id has not been used by another instance yet. */
- unique_ids[instance_index] = original_id;
- }
- else {
- /* The original id of this instance collided with a previous instance, it needs to be looked
- * at again in a second pass. Don't generate a new random id here, because this might collide
- * with other existing ids. */
- instances_with_id_collision.append(instance_index);
- }
- }
-
- Map<int, RandomNumberGenerator> generator_by_original_id;
- for (const int instance_index : instances_with_id_collision) {
- const int original_id = original_ids[instance_index];
- RandomNumberGenerator &rng = generator_by_original_id.lookup_or_add_cb(original_id, [&]() {
- RandomNumberGenerator rng;
- rng.seed_random(original_id);
- return rng;
- });
-
- const int max_iteration = 100;
- for (int iteration = 0;; iteration++) {
- /* Try generating random numbers until an unused one has been found. */
- const int random_id = rng.get_int32();
- if (used_unique_ids.add(random_id)) {
- /* This random id is not used by another instance. */
- unique_ids[instance_index] = random_id;
- break;
- }
- if (iteration == max_iteration) {
- /* It seems to be very unlikely that we ever run into this case (assuming there are less
- * than 2^30 instances). However, if that happens, it's better to use an id that is not
- * unique than to be stuck in an infinite loop. */
- unique_ids[instance_index] = original_id;
- break;
- }
- }
- }
-
- return unique_ids;
+ return instances_;
}
-blender::Span<int> InstancesComponent::almost_unique_ids() const
+blender::bke::Instances *InstancesComponent::get_for_write()
{
- std::lock_guard lock(almost_unique_ids_mutex_);
- std::optional<GSpan> instance_ids_gspan = attributes_.get_for_read("id");
- if (instance_ids_gspan) {
- Span<int> instance_ids = instance_ids_gspan->typed<int>();
- if (almost_unique_ids_.size() != instance_ids.size()) {
- almost_unique_ids_ = generate_unique_instance_ids(instance_ids);
- }
- }
- else {
- almost_unique_ids_.reinitialize(this->instances_num());
- for (const int i : almost_unique_ids_.index_range()) {
- almost_unique_ids_[i] = i;
- }
+ BLI_assert(this->is_mutable());
+ if (ownership_ == GeometryOwnershipType::ReadOnly) {
+ instances_ = new Instances(*instances_);
+ ownership_ = GeometryOwnershipType::Owned;
}
- return almost_unique_ids_;
+ return instances_;
}
-blender::bke::CustomDataAttributes &InstancesComponent::instance_attributes()
+void InstancesComponent::replace(Instances *instances, GeometryOwnershipType ownership)
{
- return this->attributes_;
-}
-
-const blender::bke::CustomDataAttributes &InstancesComponent::instance_attributes() const
-{
- return this->attributes_;
+ BLI_assert(this->is_mutable());
+ this->clear();
+ instances_ = instances;
+ ownership_ = ownership;
}
namespace blender::bke {
@@ -397,16 +135,21 @@ class InstancePositionAttributeProvider final : public BuiltinAttributeProvider
GVArray try_get_for_read(const void *owner) const final
{
- const InstancesComponent &instances_component = *static_cast<const InstancesComponent *>(
- owner);
- Span<float4x4> transforms = instances_component.instance_transforms();
+ const Instances *instances = static_cast<const Instances *>(owner);
+ if (instances == nullptr) {
+ return {};
+ }
+ Span<float4x4> transforms = instances->transforms();
return VArray<float3>::ForDerivedSpan<float4x4, get_transform_position>(transforms);
}
GAttributeWriter try_get_for_write(void *owner) const final
{
- InstancesComponent &instances_component = *static_cast<InstancesComponent *>(owner);
- MutableSpan<float4x4> transforms = instances_component.instance_transforms();
+ Instances *instances = static_cast<Instances *>(owner);
+ if (instances == nullptr) {
+ return {};
+ }
+ MutableSpan<float4x4> transforms = instances->transforms();
return {VMutableArray<float3>::ForDerivedSpan<float4x4,
get_transform_position,
set_transform_position>(transforms),
@@ -434,16 +177,16 @@ static ComponentAttributeProviders create_attribute_providers_for_instances()
static InstancePositionAttributeProvider position;
static CustomDataAccessInfo instance_custom_data_access = {
[](void *owner) -> CustomData * {
- InstancesComponent &inst = *static_cast<InstancesComponent *>(owner);
- return &inst.instance_attributes().data;
+ Instances *instances = static_cast<Instances *>(owner);
+ return &instances->custom_data_attributes().data;
},
[](const void *owner) -> const CustomData * {
- const InstancesComponent &inst = *static_cast<const InstancesComponent *>(owner);
- return &inst.instance_attributes().data;
+ const Instances *instances = static_cast<const Instances *>(owner);
+ return &instances->custom_data_attributes().data;
},
[](const void *owner) -> int {
- const InstancesComponent &inst = *static_cast<const InstancesComponent *>(owner);
- return inst.instances_num();
+ const Instances *instances = static_cast<const Instances *>(owner);
+ return instances->instances_num();
}};
/**
@@ -479,10 +222,10 @@ static AttributeAccessorFunctions get_instances_accessor_functions()
if (owner == nullptr) {
return 0;
}
- const InstancesComponent &instances = *static_cast<const InstancesComponent *>(owner);
+ const Instances *instances = static_cast<const Instances *>(owner);
switch (domain) {
case ATTR_DOMAIN_INSTANCE:
- return instances.instances_num();
+ return instances->instances_num();
default:
return 0;
}
@@ -508,18 +251,30 @@ static const AttributeAccessorFunctions &get_instances_accessor_functions_ref()
return fn;
}
+blender::bke::AttributeAccessor Instances::attributes() const
+{
+ return blender::bke::AttributeAccessor(this,
+ blender::bke::get_instances_accessor_functions_ref());
+}
+
+blender::bke::MutableAttributeAccessor Instances::attributes_for_write()
+{
+ return blender::bke::MutableAttributeAccessor(
+ this, blender::bke::get_instances_accessor_functions_ref());
+}
+
} // namespace blender::bke
std::optional<blender::bke::AttributeAccessor> InstancesComponent::attributes() const
{
- return blender::bke::AttributeAccessor(this,
+ return blender::bke::AttributeAccessor(instances_,
blender::bke::get_instances_accessor_functions_ref());
}
std::optional<blender::bke::MutableAttributeAccessor> InstancesComponent::attributes_for_write()
{
return blender::bke::MutableAttributeAccessor(
- this, blender::bke::get_instances_accessor_functions_ref());
+ instances_, blender::bke::get_instances_accessor_functions_ref());
}
/** \} */
diff --git a/source/blender/blenkernel/intern/geometry_fields.cc b/source/blender/blenkernel/intern/geometry_fields.cc
index b492af4af77..82ffda57398 100644
--- a/source/blender/blenkernel/intern/geometry_fields.cc
+++ b/source/blender/blenkernel/intern/geometry_fields.cc
@@ -4,6 +4,7 @@
#include "BKE_curves.hh"
#include "BKE_geometry_fields.hh"
#include "BKE_geometry_set.hh"
+#include "BKE_instances.hh"
#include "BKE_mesh.h"
#include "BKE_pointcloud.h"
#include "BKE_type_conversions.hh"
@@ -64,7 +65,7 @@ GeometryFieldContext::GeometryFieldContext(const GeometryComponent &component,
case GEO_COMPONENT_TYPE_INSTANCES: {
const InstancesComponent &instances_component = static_cast<const InstancesComponent &>(
component);
- geometry_ = &instances_component;
+ geometry_ = instances_component.get_for_read();
break;
}
case GEO_COMPONENT_TYPE_VOLUME:
@@ -86,7 +87,7 @@ GeometryFieldContext::GeometryFieldContext(const PointCloud &points)
: geometry_(&points), type_(GEO_COMPONENT_TYPE_POINT_CLOUD), domain_(ATTR_DOMAIN_POINT)
{
}
-GeometryFieldContext::GeometryFieldContext(const InstancesComponent &instances)
+GeometryFieldContext::GeometryFieldContext(const Instances &instances)
: geometry_(&instances), type_(GEO_COMPONENT_TYPE_INSTANCES), domain_(ATTR_DOMAIN_INSTANCE)
{
}
@@ -102,7 +103,7 @@ std::optional<AttributeAccessor> GeometryFieldContext::attributes() const
if (const PointCloud *pointcloud = this->pointcloud()) {
return pointcloud->attributes();
}
- if (const InstancesComponent *instances = this->instances()) {
+ if (const Instances *instances = this->instances()) {
return instances->attributes();
}
return {};
@@ -124,11 +125,10 @@ const PointCloud *GeometryFieldContext::pointcloud() const
static_cast<const PointCloud *>(geometry_) :
nullptr;
}
-const InstancesComponent *GeometryFieldContext::instances() const
+const Instances *GeometryFieldContext::instances() const
{
- return this->type() == GEO_COMPONENT_TYPE_INSTANCES ?
- static_cast<const InstancesComponent *>(geometry_) :
- nullptr;
+ return this->type() == GEO_COMPONENT_TYPE_INSTANCES ? static_cast<const Instances *>(geometry_) :
+ nullptr;
}
GVArray GeometryFieldInput::get_varray_for_context(const fn::FieldContext &context,
@@ -230,7 +230,7 @@ GVArray InstancesFieldInput::get_varray_for_context(const fn::FieldContext &cont
{
if (const GeometryFieldContext *geometry_context = dynamic_cast<const GeometryFieldContext *>(
&context)) {
- if (const InstancesComponent *instances = geometry_context->instances()) {
+ if (const Instances *instances = geometry_context->instances()) {
return this->get_varray_for_context(*instances, mask);
}
}
diff --git a/source/blender/blenkernel/intern/geometry_set.cc b/source/blender/blenkernel/intern/geometry_set.cc
index 46ff8141504..ee4c398c3d6 100644
--- a/source/blender/blenkernel/intern/geometry_set.cc
+++ b/source/blender/blenkernel/intern/geometry_set.cc
@@ -9,6 +9,7 @@
#include "BKE_attribute.h"
#include "BKE_curves.hh"
#include "BKE_geometry_set.hh"
+#include "BKE_instances.hh"
#include "BKE_lib_id.h"
#include "BKE_mesh.h"
#include "BKE_mesh_wrapper.h"
@@ -31,6 +32,8 @@ using blender::MutableSpan;
using blender::Span;
using blender::StringRef;
using blender::Vector;
+using blender::bke::InstanceReference;
+using blender::bke::Instances;
/* -------------------------------------------------------------------- */
/** \name Geometry Component
@@ -256,8 +259,7 @@ std::ostream &operator<<(std::ostream &stream, const GeometrySet &geometry_set)
parts.append(std::to_string(BKE_volume_num_grids(volume)) + " volume grids");
}
if (geometry_set.has_instances()) {
- parts.append(std::to_string(
- geometry_set.get_component_for_read<InstancesComponent>()->instances_num()) +
+ parts.append(std::to_string(geometry_set.get_instances_for_read()->instances_num()) +
" instances");
}
if (geometry_set.get_curve_edit_hints_for_read()) {
@@ -338,6 +340,12 @@ const Curves *GeometrySet::get_curves_for_read() const
return (component == nullptr) ? nullptr : component->get_for_read();
}
+const Instances *GeometrySet::get_instances_for_read() const
+{
+ const InstancesComponent *component = this->get_component_for_read<InstancesComponent>();
+ return (component == nullptr) ? nullptr : component->get_for_read();
+}
+
const blender::bke::CurvesEditHints *GeometrySet::get_curve_edit_hints_for_read() const
{
const GeometryComponentEditData *component =
@@ -354,7 +362,8 @@ bool GeometrySet::has_pointcloud() const
bool GeometrySet::has_instances() const
{
const InstancesComponent *component = this->get_component_for_read<InstancesComponent>();
- return component != nullptr && component->instances_num() >= 1;
+ return component != nullptr && component->get_for_read() != nullptr &&
+ component->get_for_read()->instances_num() >= 1;
}
bool GeometrySet::has_volume() const
@@ -428,6 +437,14 @@ GeometrySet GeometrySet::create_with_curves(Curves *curves, GeometryOwnershipTyp
return geometry_set;
}
+GeometrySet GeometrySet::create_with_instances(Instances *instances,
+ GeometryOwnershipType ownership)
+{
+ GeometrySet geometry_set;
+ geometry_set.replace_instances(instances, ownership);
+ return geometry_set;
+}
+
void GeometrySet::replace_mesh(Mesh *mesh, GeometryOwnershipType ownership)
{
if (mesh == nullptr) {
@@ -456,6 +473,20 @@ void GeometrySet::replace_curves(Curves *curves, GeometryOwnershipType ownership
component.replace(curves, ownership);
}
+void GeometrySet::replace_instances(Instances *instances, GeometryOwnershipType ownership)
+{
+ if (instances == nullptr) {
+ this->remove<InstancesComponent>();
+ return;
+ }
+ if (instances == this->get_instances_for_read()) {
+ return;
+ }
+ this->remove<InstancesComponent>();
+ InstancesComponent &component = this->get_component_for_write<InstancesComponent>();
+ component.replace(instances, ownership);
+}
+
void GeometrySet::replace_pointcloud(PointCloud *pointcloud, GeometryOwnershipType ownership)
{
if (pointcloud == nullptr) {
@@ -508,6 +539,12 @@ Curves *GeometrySet::get_curves_for_write()
return component == nullptr ? nullptr : component->get_for_write();
}
+Instances *GeometrySet::get_instances_for_write()
+{
+ InstancesComponent *component = this->get_component_ptr<InstancesComponent>();
+ return component == nullptr ? nullptr : component->get_for_write();
+}
+
blender::bke::CurvesEditHints *GeometrySet::get_curve_edit_hints_for_write()
{
if (!this->has<GeometryComponentEditData>()) {
@@ -539,7 +576,7 @@ void GeometrySet::attribute_foreach(const Span<GeometryComponentType> component_
}
}
if (include_instances && this->has_instances()) {
- const InstancesComponent &instances = *this->get_component_for_read<InstancesComponent>();
+ const Instances &instances = *this->get_instances_for_read();
instances.foreach_referenced_geometry([&](const GeometrySet &instance_geometry_set) {
instance_geometry_set.attribute_foreach(component_types, include_instances, callback);
});
@@ -570,7 +607,10 @@ void GeometrySet::gather_attributes_for_propagation(
return;
}
}
-
+ if (meta_data.data_type == CD_PROP_STRING) {
+ /* Propagating string attributes is not supported yet. */
+ return;
+ }
if (!attribute_id.should_be_kept()) {
return;
}
@@ -611,7 +651,7 @@ static void gather_component_types_recursive(const GeometrySet &geometry_set,
if (!include_instances) {
return;
}
- const InstancesComponent *instances = geometry_set.get_component_for_read<InstancesComponent>();
+ const blender::bke::Instances *instances = geometry_set.get_instances_for_read();
if (instances == nullptr) {
return;
}
@@ -638,12 +678,11 @@ static void gather_mutable_geometry_sets(GeometrySet &geometry_set,
}
/* In the future this can be improved by deduplicating instance references across different
* instances. */
- InstancesComponent &instances_component =
- geometry_set.get_component_for_write<InstancesComponent>();
- instances_component.ensure_geometry_instances();
- for (const int handle : instances_component.references().index_range()) {
- if (instances_component.references()[handle].type() == InstanceReference::Type::GeometrySet) {
- GeometrySet &instance_geometry = instances_component.geometry_set_from_reference(handle);
+ Instances &instances = *geometry_set.get_instances_for_write();
+ instances.ensure_geometry_instances();
+ for (const int handle : instances.references().index_range()) {
+ if (instances.references()[handle].type() == InstanceReference::Type::GeometrySet) {
+ GeometrySet &instance_geometry = instances.geometry_set_from_reference(handle);
gather_mutable_geometry_sets(instance_geometry, r_geometry_sets);
}
}
diff --git a/source/blender/blenkernel/intern/geometry_set_instances.cc b/source/blender/blenkernel/intern/geometry_set_instances.cc
index 0ae49a586f1..2b36020b4e7 100644
--- a/source/blender/blenkernel/intern/geometry_set_instances.cc
+++ b/source/blender/blenkernel/intern/geometry_set_instances.cc
@@ -2,6 +2,7 @@
#include "BKE_collection.h"
#include "BKE_geometry_set_instances.hh"
+#include "BKE_instances.hh"
#include "BKE_material.h"
#include "BKE_mesh.h"
#include "BKE_mesh_wrapper.h"
@@ -62,12 +63,11 @@ GeometrySet object_get_evaluated_geometry_set(const Object &object)
return geometry_set;
}
if (object.type == OB_EMPTY && object.instance_collection != nullptr) {
- GeometrySet geometry_set;
Collection &collection = *object.instance_collection;
- InstancesComponent &instances = geometry_set.get_component_for_write<InstancesComponent>();
- const int handle = instances.add_reference(collection);
- instances.add_instance(handle, float4x4::identity());
- return geometry_set;
+ std::unique_ptr<Instances> instances = std::make_unique<Instances>();
+ const int handle = instances->add_reference(collection);
+ instances->add_instance(handle, float4x4::identity());
+ return GeometrySet::create_with_instances(instances.release());
}
/* Return by value since there is not always an existing geometry set owned elsewhere to use. */
@@ -98,7 +98,7 @@ static void geometry_set_collect_recursive_collection(const Collection &collecti
LISTBASE_FOREACH (const CollectionObject *, collection_object, &collection.gobject) {
BLI_assert(collection_object->ob != nullptr);
const Object &object = *collection_object->ob;
- const float4x4 object_transform = transform * object.obmat;
+ const float4x4 object_transform = transform * object.object_to_world;
geometry_set_collect_recursive_object(object, object_transform, r_sets);
}
LISTBASE_FOREACH (const CollectionChild *, collection_child, &collection.children) {
@@ -115,12 +115,11 @@ static void geometry_set_collect_recursive(const GeometrySet &geometry_set,
r_sets.append({geometry_set, {transform}});
if (geometry_set.has_instances()) {
- const InstancesComponent &instances_component =
- *geometry_set.get_component_for_read<InstancesComponent>();
+ const Instances &instances = *geometry_set.get_instances_for_read();
- Span<float4x4> transforms = instances_component.instance_transforms();
- Span<int> handles = instances_component.instance_reference_handles();
- Span<InstanceReference> references = instances_component.references();
+ Span<float4x4> transforms = instances.transforms();
+ Span<int> handles = instances.reference_handles();
+ Span<InstanceReference> references = instances.references();
for (const int i : transforms.index_range()) {
const InstanceReference &reference = references[handles[i]];
const float4x4 instance_transform = transform * transforms[i];
@@ -156,9 +155,7 @@ void geometry_set_gather_instances(const GeometrySet &geometry_set,
geometry_set_collect_recursive(geometry_set, float4x4::identity(), r_instance_groups);
}
-} // namespace blender::bke
-
-void InstancesComponent::foreach_referenced_geometry(
+void Instances::foreach_referenced_geometry(
blender::FunctionRef<void(const GeometrySet &geometry_set)> callback) const
{
using namespace blender::bke;
@@ -191,7 +188,7 @@ void InstancesComponent::foreach_referenced_geometry(
}
}
-void InstancesComponent::ensure_geometry_instances()
+void Instances::ensure_geometry_instances()
{
using namespace blender;
using namespace blender::bke;
@@ -211,9 +208,7 @@ void InstancesComponent::ensure_geometry_instances()
const Object &object = reference.object();
GeometrySet object_geometry_set = object_get_evaluated_geometry_set(object);
if (object_geometry_set.has_instances()) {
- InstancesComponent &component =
- object_geometry_set.get_component_for_write<InstancesComponent>();
- component.ensure_geometry_instances();
+ object_geometry_set.get_instances_for_write()->ensure_geometry_instances();
}
new_references.add_new(std::move(object_geometry_set));
break;
@@ -221,22 +216,22 @@ void InstancesComponent::ensure_geometry_instances()
case InstanceReference::Type::Collection: {
/* Create a new reference that contains a geometry set that contains all objects from the
* collection as instances. */
- GeometrySet collection_geometry_set;
- InstancesComponent &component =
- collection_geometry_set.get_component_for_write<InstancesComponent>();
+ std::unique_ptr<Instances> instances = std::make_unique<Instances>();
Collection &collection = reference.collection();
FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN (&collection, object) {
- const int handle = component.add_reference(*object);
- component.add_instance(handle, object->obmat);
- float4x4 &transform = component.instance_transforms().last();
+ const int handle = instances->add_reference(*object);
+ instances->add_instance(handle, object->object_to_world);
+ float4x4 &transform = instances->transforms().last();
sub_v3_v3(transform.values[3], collection.instance_offset);
}
FOREACH_COLLECTION_OBJECT_RECURSIVE_END;
- component.ensure_geometry_instances();
- new_references.add_new(std::move(collection_geometry_set));
+ instances->ensure_geometry_instances();
+ new_references.add_new(GeometrySet::create_with_instances(instances.release()));
break;
}
}
}
references_ = std::move(new_references);
}
+
+} // namespace blender::bke
diff --git a/source/blender/blenkernel/intern/gpencil.c b/source/blender/blenkernel/intern/gpencil.c
index 45e56717d6a..666142e3a54 100644
--- a/source/blender/blenkernel/intern/gpencil.c
+++ b/source/blender/blenkernel/intern/gpencil.c
@@ -2691,7 +2691,7 @@ void BKE_gpencil_layer_transform_matrix_get(const Depsgraph *depsgraph,
/* if not layer parented, try with object parented */
if (obparent_eval == NULL) {
if ((ob_eval != NULL) && (ob_eval->type == OB_GPENCIL)) {
- copy_m4_m4(diff_mat, ob_eval->obmat);
+ copy_m4_m4(diff_mat, ob_eval->object_to_world);
mul_m4_m4m4(diff_mat, diff_mat, gpl->layer_mat);
return;
}
@@ -2701,8 +2701,8 @@ void BKE_gpencil_layer_transform_matrix_get(const Depsgraph *depsgraph,
}
if (ELEM(gpl->partype, PAROBJECT, PARSKEL)) {
- mul_m4_m4m4(diff_mat, obparent_eval->obmat, gpl->inverse);
- add_v3_v3(diff_mat[3], ob_eval->obmat[3]);
+ mul_m4_m4m4(diff_mat, obparent_eval->object_to_world, gpl->inverse);
+ add_v3_v3(diff_mat[3], ob_eval->object_to_world[3]);
mul_m4_m4m4(diff_mat, diff_mat, gpl->layer_mat);
return;
}
@@ -2710,14 +2710,14 @@ void BKE_gpencil_layer_transform_matrix_get(const Depsgraph *depsgraph,
bPoseChannel *pchan = BKE_pose_channel_find_name(obparent_eval->pose, gpl->parsubstr);
if (pchan) {
float tmp_mat[4][4];
- mul_m4_m4m4(tmp_mat, obparent_eval->obmat, pchan->pose_mat);
+ mul_m4_m4m4(tmp_mat, obparent_eval->object_to_world, pchan->pose_mat);
mul_m4_m4m4(diff_mat, tmp_mat, gpl->inverse);
- add_v3_v3(diff_mat[3], ob_eval->obmat[3]);
+ add_v3_v3(diff_mat[3], ob_eval->object_to_world[3]);
}
else {
/* if bone not found use object (armature) */
- mul_m4_m4m4(diff_mat, obparent_eval->obmat, gpl->inverse);
- add_v3_v3(diff_mat[3], ob_eval->obmat[3]);
+ mul_m4_m4m4(diff_mat, obparent_eval->object_to_world, gpl->inverse);
+ add_v3_v3(diff_mat[3], ob_eval->object_to_world[3]);
}
mul_m4_m4m4(diff_mat, diff_mat, gpl->layer_mat);
return;
@@ -2771,12 +2771,12 @@ void BKE_gpencil_update_layer_transforms(const Depsgraph *depsgraph, Object *ob)
Object *ob_parent = DEG_get_evaluated_object(depsgraph, gpl->parent);
/* calculate new matrix */
if (ELEM(gpl->partype, PAROBJECT, PARSKEL)) {
- mul_m4_m4m4(cur_mat, ob->imat, ob_parent->obmat);
+ mul_m4_m4m4(cur_mat, ob->imat, ob_parent->object_to_world);
}
else if (gpl->partype == PARBONE) {
bPoseChannel *pchan = BKE_pose_channel_find_name(ob_parent->pose, gpl->parsubstr);
if (pchan != NULL) {
- mul_m4_series(cur_mat, ob->imat, ob_parent->obmat, pchan->pose_mat);
+ mul_m4_series(cur_mat, ob->imat, ob_parent->object_to_world, pchan->pose_mat);
}
else {
unit_m4(cur_mat);
diff --git a/source/blender/blenkernel/intern/gpencil_geom.cc b/source/blender/blenkernel/intern/gpencil_geom.cc
index 52fcdef8a43..9297663b157 100644
--- a/source/blender/blenkernel/intern/gpencil_geom.cc
+++ b/source/blender/blenkernel/intern/gpencil_geom.cc
@@ -789,7 +789,10 @@ bool BKE_gpencil_stroke_stretch(bGPDstroke *gps,
/** \name Stroke Trim
* \{ */
-bool BKE_gpencil_stroke_trim_points(bGPDstroke *gps, const int index_from, const int index_to)
+bool BKE_gpencil_stroke_trim_points(bGPDstroke *gps,
+ const int index_from,
+ const int index_to,
+ const bool keep_point)
{
bGPDspoint *pt = gps->points, *new_pt;
MDeformVert *dv, *new_dv;
@@ -800,7 +803,7 @@ bool BKE_gpencil_stroke_trim_points(bGPDstroke *gps, const int index_from, const
return false;
}
- if (new_count == 1) {
+ if ((!keep_point) && (new_count == 1)) {
if (gps->dvert) {
BKE_gpencil_free_stroke_weights(gps);
MEM_freeN(gps->dvert);
@@ -894,7 +897,7 @@ bool BKE_gpencil_stroke_split(bGPdata *gpd,
/* Trim the original stroke into a shorter one.
* Keep the end point. */
- BKE_gpencil_stroke_trim_points(gps, 0, old_count);
+ BKE_gpencil_stroke_trim_points(gps, 0, old_count, false);
BKE_gpencil_stroke_geometry_update(gpd, gps);
return true;
}
@@ -917,7 +920,7 @@ bool BKE_gpencil_stroke_shrink(bGPDstroke *gps, const float dist, const short mo
if (gps->totpoints == 1) {
second_last = &pt[1];
if (len_v3v3(&second_last->x, &pt->x) < dist) {
- BKE_gpencil_stroke_trim_points(gps, 0, 0);
+ BKE_gpencil_stroke_trim_points(gps, 0, 0, false);
return true;
}
}
@@ -969,7 +972,7 @@ bool BKE_gpencil_stroke_shrink(bGPDstroke *gps, const float dist, const short mo
index_start = index_end = 0; /* no length left to cut */
}
- BKE_gpencil_stroke_trim_points(gps, index_start, index_end);
+ BKE_gpencil_stroke_trim_points(gps, index_start, index_end, false);
if (gps->totpoints == 0) {
return false;
@@ -3562,8 +3565,8 @@ void BKE_gpencil_stroke_start_set(bGPDstroke *gps, int start_idx)
}
bGPDstroke *gps_b = BKE_gpencil_stroke_duplicate(gps, true, false);
- BKE_gpencil_stroke_trim_points(gps_b, 0, start_idx - 1);
- BKE_gpencil_stroke_trim_points(gps, start_idx, gps->totpoints - 1);
+ BKE_gpencil_stroke_trim_points(gps_b, 0, start_idx - 1, true);
+ BKE_gpencil_stroke_trim_points(gps, start_idx, gps->totpoints - 1, true);
/* Join both strokes. */
BKE_gpencil_stroke_join(gps, gps_b, false, false, false, false);
diff --git a/source/blender/blenkernel/intern/gpencil_modifier.c b/source/blender/blenkernel/intern/gpencil_modifier.c
index c84ee2e4a56..1ad7aeed41c 100644
--- a/source/blender/blenkernel/intern/gpencil_modifier.c
+++ b/source/blender/blenkernel/intern/gpencil_modifier.c
@@ -942,7 +942,7 @@ void BKE_gpencil_modifier_blend_read_data(BlendDataReader *reader, ListBase *lb)
BLO_read_data_address(reader, &gpmd->curve_intensity);
if (gpmd->curve_intensity) {
BKE_curvemapping_blend_read(reader, gpmd->curve_intensity);
- /* initialize the curve. Maybe this could be moved to modififer logic */
+ /* Initialize the curve. Maybe this could be moved to modifier logic. */
BKE_curvemapping_init(gpmd->curve_intensity);
}
}
diff --git a/source/blender/blenkernel/intern/icons.cc b/source/blender/blenkernel/intern/icons.cc
index dc1d23de7e0..7fd0515b52c 100644
--- a/source/blender/blenkernel/intern/icons.cc
+++ b/source/blender/blenkernel/intern/icons.cc
@@ -530,7 +530,7 @@ void BKE_previewimg_ensure(PreviewImage *prv, const int size)
thumb = IMB_thumb_manage(filepath, THB_LARGE, (ThumbSource)source);
if (thumb) {
- /* PreviewImage assumes premultiplied alhpa... */
+ /* #PreviewImage assumes pre-multiplied alpha. */
IMB_premultiply_alpha(thumb);
if (do_preview) {
diff --git a/source/blender/blenkernel/intern/image.cc b/source/blender/blenkernel/intern/image.cc
index 409eb0067b5..eae8b454189 100644
--- a/source/blender/blenkernel/intern/image.cc
+++ b/source/blender/blenkernel/intern/image.cc
@@ -297,7 +297,7 @@ static void image_foreach_path(ID *id, BPathForeachPathData *bpath_data)
/* Put the filepath back together using the new directory and the original file name. */
char new_dir[FILE_MAXDIR];
BLI_split_dir_part(temp_path, new_dir, sizeof(new_dir));
- BLI_join_dirfile(ima->filepath, sizeof(ima->filepath), new_dir, orig_file);
+ BLI_path_join(ima->filepath, sizeof(ima->filepath), new_dir, orig_file);
}
}
else {
@@ -3082,16 +3082,10 @@ void BKE_image_signal(Main *bmain, Image *ima, ImageUser *iuser, int signal)
/* Free all but the first tile. */
image_remove_all_tiles(ima);
- /* If the remaining tile is generated, we need to again ensure that we
- * wouldn't continue to use the old filepath.
- *
- * Otherwise, if this used to be a UDIM image, get the concrete filepath associated
+ /* If this used to be a UDIM image, get the concrete filepath associated
* with the remaining tile and use that as the new filepath. */
ImageTile *base_tile = BKE_image_get_tile(ima, 0);
- if ((base_tile->gen_flag & IMA_GEN_TILE) != 0) {
- ima->filepath[0] = '\0';
- }
- else if (BKE_image_is_filename_tokenized(ima->filepath)) {
+ if (BKE_image_is_filename_tokenized(ima->filepath)) {
const bool was_relative = BLI_path_is_rel(ima->filepath);
eUDIM_TILE_FORMAT tile_format;
@@ -3183,10 +3177,14 @@ void BKE_image_signal(Main *bmain, Image *ima, ImageUser *iuser, int signal)
* left. */
image_remove_all_tiles(ima);
- int remaining_tile_number = ((ImageTile *)ima->tiles.first)->tile_number;
+ ImageTile *base_tile = BKE_image_get_tile(ima, 0);
+ int remaining_tile_number = base_tile->tile_number;
bool needs_final_cleanup = true;
- /* Add in all the new tiles. */
+ /* Add in all the new tiles. As the image is proven to be on disk at this point, remove
+ * the generation flag from the remaining tile in case this was previously a generated
+ * image. */
+ base_tile->gen_flag &= ~IMA_GEN_TILE;
LISTBASE_FOREACH (LinkData *, new_tile, &new_tiles) {
int new_tile_number = POINTER_AS_INT(new_tile->data);
BKE_image_add_tile(ima, new_tile_number, nullptr);
@@ -3202,6 +3200,11 @@ void BKE_image_signal(Main *bmain, Image *ima, ImageUser *iuser, int signal)
}
BLI_freelistN(&new_tiles);
}
+ else if (ima->filepath[0] != '\0') {
+ /* If the filepath is set at this point remove the generation flag. */
+ ImageTile *base_tile = BKE_image_get_tile(ima, 0);
+ base_tile->gen_flag &= ~IMA_GEN_TILE;
+ }
if (iuser) {
image_tag_reload(ima, nullptr, iuser, ima);
@@ -3331,7 +3334,7 @@ bool BKE_image_get_tile_info(char *filepath, ListBase *tiles, int *r_tile_start,
MEM_SAFE_FREE(udim_pattern);
if (all_valid_udim && min_udim <= IMA_UDIM_MAX) {
- BLI_join_dirfile(filepath, FILE_MAX, dirname, filename);
+ BLI_path_join(filepath, FILE_MAX, dirname, filename);
*r_tile_start = min_udim;
*r_tile_range = max_udim - min_udim + 1;
diff --git a/source/blender/blenkernel/intern/image_format.cc b/source/blender/blenkernel/intern/image_format.cc
index 8d1aeac76fb..5b861eff166 100644
--- a/source/blender/blenkernel/intern/image_format.cc
+++ b/source/blender/blenkernel/intern/image_format.cc
@@ -201,6 +201,7 @@ bool BKE_imtype_is_movie(const char imtype)
case R_IMF_IMTYPE_H264:
case R_IMF_IMTYPE_THEORA:
case R_IMF_IMTYPE_XVID:
+ case R_IMF_IMTYPE_AV1:
return true;
}
return false;
@@ -433,7 +434,8 @@ static bool do_add_image_extension(char *string,
R_IMF_IMTYPE_FFMPEG,
R_IMF_IMTYPE_H264,
R_IMF_IMTYPE_THEORA,
- R_IMF_IMTYPE_XVID)) {
+ R_IMF_IMTYPE_XVID,
+ R_IMF_IMTYPE_AV1)) {
if (!BLI_path_extension_check(string, extension_test = ".png")) {
extension = extension_test;
}
@@ -627,7 +629,8 @@ void BKE_image_format_to_imbuf(ImBuf *ibuf, const ImageFormatData *imf)
R_IMF_IMTYPE_FFMPEG,
R_IMF_IMTYPE_H264,
R_IMF_IMTYPE_THEORA,
- R_IMF_IMTYPE_XVID)) {
+ R_IMF_IMTYPE_XVID,
+ R_IMF_IMTYPE_AV1)) {
ibuf->ftype = IMB_FTYPE_PNG;
if (imtype == R_IMF_IMTYPE_PNG) {
diff --git a/source/blender/blenkernel/intern/image_save.cc b/source/blender/blenkernel/intern/image_save.cc
index e227f9cba5e..003211e6288 100644
--- a/source/blender/blenkernel/intern/image_save.cc
+++ b/source/blender/blenkernel/intern/image_save.cc
@@ -175,12 +175,12 @@ bool BKE_image_save_options_init(ImageSaveOptions *opts,
BLI_strncpy(opts->filepath, G.ima, sizeof(opts->filepath));
}
else {
- BLI_path_join(opts->filepath, sizeof(opts->filepath), "//", DATA_("untitled"), nullptr);
+ BLI_path_join(opts->filepath, sizeof(opts->filepath), "//", DATA_("untitled"));
BLI_path_abs(opts->filepath, BKE_main_blendfile_path(bmain));
}
}
else {
- BLI_path_join(opts->filepath, sizeof(opts->filepath), "//", ima->id.name + 2, nullptr);
+ BLI_path_join(opts->filepath, sizeof(opts->filepath), "//", ima->id.name + 2);
BLI_path_make_safe(opts->filepath);
BLI_path_abs(opts->filepath, is_prev_save ? G.ima : BKE_main_blendfile_path(bmain));
}
@@ -968,6 +968,7 @@ bool BKE_image_render_write(ReportList *reports,
/* optional preview images for exr */
if (ok && (image_format.flag & R_IMF_FLAG_PREVIEW_JPG)) {
image_format.imtype = R_IMF_IMTYPE_JPEG90;
+ image_format.depth = R_IMF_CHAN_DEPTH_8;
if (BLI_path_extension_check(filepath, ".exr")) {
filepath[strlen(filepath) - 4] = 0;
@@ -1025,6 +1026,7 @@ bool BKE_image_render_write(ReportList *reports,
/* optional preview images for exr */
if (ok && is_exr_rr && (image_format.flag & R_IMF_FLAG_PREVIEW_JPG)) {
image_format.imtype = R_IMF_IMTYPE_JPEG90;
+ image_format.depth = R_IMF_CHAN_DEPTH_8;
if (BLI_path_extension_check(filepath, ".exr")) {
filepath[strlen(filepath) - 4] = 0;
diff --git a/source/blender/blenkernel/intern/instances.cc b/source/blender/blenkernel/intern/instances.cc
new file mode 100644
index 00000000000..4675562e927
--- /dev/null
+++ b/source/blender/blenkernel/intern/instances.cc
@@ -0,0 +1,337 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#include "BLI_array_utils.hh"
+#include "BLI_cpp_type_make.hh"
+#include "BLI_rand.hh"
+#include "BLI_task.hh"
+
+#include "BKE_attribute_math.hh"
+#include "BKE_geometry_set.hh"
+#include "BKE_instances.hh"
+
+BLI_CPP_TYPE_MAKE(InstanceReference, blender::bke::InstanceReference, CPPTypeFlags::None)
+
+namespace blender::bke {
+
+InstanceReference::InstanceReference(GeometrySet geometry_set)
+ : type_(Type::GeometrySet),
+ geometry_set_(std::make_unique<GeometrySet>(std::move(geometry_set)))
+{
+}
+
+void InstanceReference::ensure_owns_direct_data()
+{
+ if (type_ != Type::GeometrySet) {
+ return;
+ }
+ geometry_set_->ensure_owns_direct_data();
+}
+
+bool InstanceReference::owns_direct_data() const
+{
+ if (type_ != Type::GeometrySet) {
+ /* The object and collection instances are not direct data. */
+ return true;
+ }
+ return geometry_set_->owns_direct_data();
+}
+
+Instances::Instances(const Instances &other)
+ : references_(other.references_),
+ reference_handles_(other.reference_handles_),
+ transforms_(other.transforms_),
+ almost_unique_ids_(other.almost_unique_ids_),
+ attributes_(other.attributes_)
+{
+}
+
+void Instances::reserve(int min_capacity)
+{
+ reference_handles_.reserve(min_capacity);
+ transforms_.reserve(min_capacity);
+ attributes_.reallocate(min_capacity);
+}
+
+void Instances::resize(int capacity)
+{
+ reference_handles_.resize(capacity);
+ transforms_.resize(capacity);
+ attributes_.reallocate(capacity);
+}
+
+void Instances::add_instance(const int instance_handle, const float4x4 &transform)
+{
+ BLI_assert(instance_handle >= 0);
+ BLI_assert(instance_handle < references_.size());
+ reference_handles_.append(instance_handle);
+ transforms_.append(transform);
+ attributes_.reallocate(this->instances_num());
+}
+
+blender::Span<int> Instances::reference_handles() const
+{
+ return reference_handles_;
+}
+
+blender::MutableSpan<int> Instances::reference_handles()
+{
+ return reference_handles_;
+}
+
+blender::MutableSpan<blender::float4x4> Instances::transforms()
+{
+ return transforms_;
+}
+blender::Span<blender::float4x4> Instances::transforms() const
+{
+ return transforms_;
+}
+
+GeometrySet &Instances::geometry_set_from_reference(const int reference_index)
+{
+ /* If this assert fails, it means #ensure_geometry_instances must be called first or that the
+ * reference can't be converted to a geometry set. */
+ BLI_assert(references_[reference_index].type() == InstanceReference::Type::GeometrySet);
+
+ /* The const cast is okay because the instance's hash in the set
+ * is not changed by adjusting the data inside the geometry set. */
+ return const_cast<GeometrySet &>(references_[reference_index].geometry_set());
+}
+
+int Instances::add_reference(const InstanceReference &reference)
+{
+ return references_.index_of_or_add_as(reference);
+}
+
+blender::Span<InstanceReference> Instances::references() const
+{
+ return references_;
+}
+
+void Instances::remove(const IndexMask mask)
+{
+ using namespace blender;
+ if (mask.is_range() && mask.as_range().start() == 0) {
+ /* Deleting from the end of the array can be much faster since no data has to be shifted. */
+ this->resize(mask.size());
+ this->remove_unused_references();
+ return;
+ }
+
+ const Span<int> old_handles = this->reference_handles();
+ Vector<int> new_handles(mask.size());
+ array_utils::gather(old_handles, mask.indices(), new_handles.as_mutable_span());
+ reference_handles_ = std::move(new_handles);
+
+ const Span<float4x4> old_tansforms = this->transforms();
+ Vector<float4x4> new_transforms(mask.size());
+ array_utils::gather(old_tansforms, mask.indices(), new_transforms.as_mutable_span());
+ transforms_ = std::move(new_transforms);
+
+ const bke::CustomDataAttributes &src_attributes = attributes_;
+
+ bke::CustomDataAttributes dst_attributes;
+ dst_attributes.reallocate(mask.size());
+
+ src_attributes.foreach_attribute(
+ [&](const bke::AttributeIDRef &id, const bke::AttributeMetaData &meta_data) {
+ if (!id.should_be_kept()) {
+ return true;
+ }
+
+ GSpan src = *src_attributes.get_for_read(id);
+ dst_attributes.create(id, meta_data.data_type);
+ GMutableSpan dst = *dst_attributes.get_for_write(id);
+ array_utils::gather(src, mask.indices(), dst);
+
+ return true;
+ },
+ ATTR_DOMAIN_INSTANCE);
+
+ attributes_ = std::move(dst_attributes);
+ this->remove_unused_references();
+}
+
+void Instances::remove_unused_references()
+{
+ using namespace blender;
+ using namespace blender::bke;
+
+ const int tot_instances = this->instances_num();
+ const int tot_references_before = references_.size();
+
+ if (tot_instances == 0) {
+ /* If there are no instances, no reference is needed. */
+ references_.clear();
+ return;
+ }
+ if (tot_references_before == 1) {
+ /* There is only one reference and at least one instance. So the only existing reference is
+ * used. Nothing to do here. */
+ return;
+ }
+
+ Array<bool> usage_by_handle(tot_references_before, false);
+ std::mutex mutex;
+
+ /* Loop over all instances to see which references are used. */
+ threading::parallel_for(IndexRange(tot_instances), 1000, [&](IndexRange range) {
+ /* Use local counter to avoid lock contention. */
+ Array<bool> local_usage_by_handle(tot_references_before, false);
+
+ for (const int i : range) {
+ const int handle = reference_handles_[i];
+ BLI_assert(handle >= 0 && handle < tot_references_before);
+ local_usage_by_handle[handle] = true;
+ }
+
+ std::lock_guard lock{mutex};
+ for (const int i : IndexRange(tot_references_before)) {
+ usage_by_handle[i] |= local_usage_by_handle[i];
+ }
+ });
+
+ if (!usage_by_handle.as_span().contains(false)) {
+ /* All references are used. */
+ return;
+ }
+
+ /* Create new references and a mapping for the handles. */
+ Vector<int> handle_mapping;
+ VectorSet<InstanceReference> new_references;
+ int next_new_handle = 0;
+ bool handles_have_to_be_updated = false;
+ for (const int old_handle : IndexRange(tot_references_before)) {
+ if (!usage_by_handle[old_handle]) {
+ /* Add some dummy value. It won't be read again. */
+ handle_mapping.append(-1);
+ }
+ else {
+ const InstanceReference &reference = references_[old_handle];
+ handle_mapping.append(next_new_handle);
+ new_references.add_new(reference);
+ if (old_handle != next_new_handle) {
+ handles_have_to_be_updated = true;
+ }
+ next_new_handle++;
+ }
+ }
+ references_ = new_references;
+
+ if (!handles_have_to_be_updated) {
+ /* All remaining handles are the same as before, so they don't have to be updated. This happens
+ * when unused handles are only at the end. */
+ return;
+ }
+
+ /* Update handles of instances. */
+ threading::parallel_for(IndexRange(tot_instances), 1000, [&](IndexRange range) {
+ for (const int i : range) {
+ reference_handles_[i] = handle_mapping[reference_handles_[i]];
+ }
+ });
+}
+
+int Instances::instances_num() const
+{
+ return transforms_.size();
+}
+
+int Instances::references_num() const
+{
+ return references_.size();
+}
+
+bool Instances::owns_direct_data() const
+{
+ for (const InstanceReference &reference : references_) {
+ if (!reference.owns_direct_data()) {
+ return false;
+ }
+ }
+ return true;
+}
+
+void Instances::ensure_owns_direct_data()
+{
+ for (const InstanceReference &const_reference : references_) {
+ /* `const` cast is fine because we are not changing anything that would change the hash of the
+ * reference. */
+ InstanceReference &reference = const_cast<InstanceReference &>(const_reference);
+ reference.ensure_owns_direct_data();
+ }
+}
+
+static blender::Array<int> generate_unique_instance_ids(Span<int> original_ids)
+{
+ using namespace blender;
+ Array<int> unique_ids(original_ids.size());
+
+ Set<int> used_unique_ids;
+ used_unique_ids.reserve(original_ids.size());
+ Vector<int> instances_with_id_collision;
+ for (const int instance_index : original_ids.index_range()) {
+ const int original_id = original_ids[instance_index];
+ if (used_unique_ids.add(original_id)) {
+ /* The original id has not been used by another instance yet. */
+ unique_ids[instance_index] = original_id;
+ }
+ else {
+ /* The original id of this instance collided with a previous instance, it needs to be looked
+ * at again in a second pass. Don't generate a new random id here, because this might collide
+ * with other existing ids. */
+ instances_with_id_collision.append(instance_index);
+ }
+ }
+
+ Map<int, RandomNumberGenerator> generator_by_original_id;
+ for (const int instance_index : instances_with_id_collision) {
+ const int original_id = original_ids[instance_index];
+ RandomNumberGenerator &rng = generator_by_original_id.lookup_or_add_cb(original_id, [&]() {
+ RandomNumberGenerator rng;
+ rng.seed_random(original_id);
+ return rng;
+ });
+
+ const int max_iteration = 100;
+ for (int iteration = 0;; iteration++) {
+ /* Try generating random numbers until an unused one has been found. */
+ const int random_id = rng.get_int32();
+ if (used_unique_ids.add(random_id)) {
+ /* This random id is not used by another instance. */
+ unique_ids[instance_index] = random_id;
+ break;
+ }
+ if (iteration == max_iteration) {
+ /* It seems to be very unlikely that we ever run into this case (assuming there are less
+ * than 2^30 instances). However, if that happens, it's better to use an id that is not
+ * unique than to be stuck in an infinite loop. */
+ unique_ids[instance_index] = original_id;
+ break;
+ }
+ }
+ }
+
+ return unique_ids;
+}
+
+blender::Span<int> Instances::almost_unique_ids() const
+{
+ std::lock_guard lock(almost_unique_ids_mutex_);
+ std::optional<GSpan> instance_ids_gspan = attributes_.get_for_read("id");
+ if (instance_ids_gspan) {
+ Span<int> instance_ids = instance_ids_gspan->typed<int>();
+ if (almost_unique_ids_.size() != instance_ids.size()) {
+ almost_unique_ids_ = generate_unique_instance_ids(instance_ids);
+ }
+ }
+ else {
+ almost_unique_ids_.reinitialize(this->instances_num());
+ for (const int i : almost_unique_ids_.index_range()) {
+ almost_unique_ids_[i] = i;
+ }
+ }
+ return almost_unique_ids_;
+}
+
+} // namespace blender::bke
diff --git a/source/blender/blenkernel/intern/ipo.c b/source/blender/blenkernel/intern/ipo.c
index bd655caae2b..a21033a8b91 100644
--- a/source/blender/blenkernel/intern/ipo.c
+++ b/source/blender/blenkernel/intern/ipo.c
@@ -1147,7 +1147,7 @@ static char *get_rna_access(ID *id,
/* 'buf' _must_ be initialized in this block */
/* append preceding bits to path */
- /* NOTE: strings are not escapted and they should be! */
+ /* NOTE: strings are not escaped and they should be! */
if ((actname && actname[0]) && (constname && constname[0])) {
/* Constraint in Pose-Channel */
char actname_esc[sizeof(((bActionChannel *)NULL)->name) * 2];
diff --git a/source/blender/blenkernel/intern/lattice.c b/source/blender/blenkernel/intern/lattice.c
index f6a409ee3f0..0adf162b4eb 100644
--- a/source/blender/blenkernel/intern/lattice.c
+++ b/source/blender/blenkernel/intern/lattice.c
@@ -355,10 +355,10 @@ void BKE_lattice_resize(Lattice *lt, int uNew, int vNew, int wNew, Object *ltOb)
BKE_displist_free(&ltOb->runtime.curve_cache->disp);
}
- copy_m4_m4(mat, ltOb->obmat);
- unit_m4(ltOb->obmat);
+ copy_m4_m4(mat, ltOb->object_to_world);
+ unit_m4(ltOb->object_to_world);
BKE_lattice_deform_coords(ltOb, NULL, vert_coords, uNew * vNew * wNew, 0, NULL, 1.0f);
- copy_m4_m4(ltOb->obmat, mat);
+ copy_m4_m4(ltOb->object_to_world, mat);
lt->typeu = typeu;
lt->typev = typev;
diff --git a/source/blender/blenkernel/intern/lattice_deform.c b/source/blender/blenkernel/intern/lattice_deform.c
index 3a1c42b9178..892889aa426 100644
--- a/source/blender/blenkernel/intern/lattice_deform.c
+++ b/source/blender/blenkernel/intern/lattice_deform.c
@@ -79,15 +79,15 @@ LatticeDeformData *BKE_lattice_deform_data_create(const Object *oblatt, const Ob
/* for example with a particle system: (ob == NULL) */
if (ob == NULL) {
/* In deform-space, calc matrix. */
- invert_m4_m4(latmat, oblatt->obmat);
+ invert_m4_m4(latmat, oblatt->object_to_world);
/* back: put in deform array */
invert_m4_m4(imat, latmat);
}
else {
/* In deform-space, calc matrix. */
- invert_m4_m4(imat, oblatt->obmat);
- mul_m4_m4m4(latmat, imat, ob->obmat);
+ invert_m4_m4(imat, oblatt->object_to_world);
+ mul_m4_m4m4(latmat, imat, ob->object_to_world);
/* back: put in deform array. */
invert_m4_m4(imat, latmat);
diff --git a/source/blender/blenkernel/intern/layer.c b/source/blender/blenkernel/intern/layer.c
index fcb0adfde34..5b54f16661c 100644
--- a/source/blender/blenkernel/intern/layer.c
+++ b/source/blender/blenkernel/intern/layer.c
@@ -614,7 +614,7 @@ static bool layer_collection_hidden(ViewLayer *view_layer, LayerCollection *lc)
return true;
}
- /* Check visiblilty restriction flags */
+ /* Check visibility restriction flags */
if (lc->flag & LAYER_COLLECTION_HIDE || lc->collection->flag & COLLECTION_HIDE_VIEWPORT) {
return true;
}
@@ -1049,7 +1049,7 @@ static void layer_collection_objects_sync(ViewLayer *view_layer,
}
/* Holdout and indirect only */
- if ((layer->flag & LAYER_COLLECTION_HOLDOUT) || (base->object->visibility_flag & OB_HOLDOUT)) {
+ if ((layer->flag & LAYER_COLLECTION_HOLDOUT)) {
base->flag_from_collection |= BASE_HOLDOUT;
}
if (layer->flag & LAYER_COLLECTION_INDIRECT_ONLY) {
diff --git a/source/blender/blenkernel/intern/lib_id.c b/source/blender/blenkernel/intern/lib_id.c
index 158aaa961ce..f60234a684d 100644
--- a/source/blender/blenkernel/intern/lib_id.c
+++ b/source/blender/blenkernel/intern/lib_id.c
@@ -1612,7 +1612,7 @@ static void library_make_local_copying_check(ID *id,
if (!BLI_gset_haskey(done_ids, from_id)) {
if (BLI_gset_haskey(loop_tags, from_id)) {
/* We are in a 'dependency loop' of IDs, this does not say us anything, skip it.
- * Note that this is the situation that can lead to archipelagoes of linked data-blocks
+ * Note that this is the situation that can lead to archipelagos of linked data-blocks
* (since all of them have non-local users, they would all be duplicated,
* leading to a loop of unused linked data-blocks that cannot be freed since they all use
* each other...). */
diff --git a/source/blender/blenkernel/intern/lib_id_delete.c b/source/blender/blenkernel/intern/lib_id_delete.c
index f4f5ca7a1d7..c7643c56212 100644
--- a/source/blender/blenkernel/intern/lib_id_delete.c
+++ b/source/blender/blenkernel/intern/lib_id_delete.c
@@ -16,6 +16,7 @@
#include "BLI_utildefines.h"
+#include "BLI_linklist.h"
#include "BLI_listbase.h"
#include "BKE_anim_data.h"
@@ -23,10 +24,10 @@
#include "BKE_idprop.h"
#include "BKE_idtype.h"
#include "BKE_key.h"
+#include "BKE_layer.h"
#include "BKE_lib_id.h"
#include "BKE_lib_override.h"
#include "BKE_lib_remap.h"
-#include "BKE_library.h"
#include "BKE_main.h"
#include "BKE_main_namemap.h"
@@ -202,7 +203,6 @@ static size_t id_delete(Main *bmain, const bool do_tagged_deletion)
{
const int tag = LIB_TAG_DOIT;
ListBase *lbarray[INDEX_ID_MAX];
- Link dummy_link = {0};
int base_count, i;
/* Used by batch tagged deletion, when we call BKE_id_free then, id is no more in Main database,
@@ -217,6 +217,9 @@ static size_t id_delete(Main *bmain, const bool do_tagged_deletion)
BKE_main_lock(bmain);
if (do_tagged_deletion) {
+ struct IDRemapper *id_remapper = BKE_id_remapper_create();
+ BKE_layer_collection_resync_forbid();
+
/* Main idea of batch deletion is to remove all IDs to be deleted from Main database.
* This means that we won't have to loop over all deleted IDs to remove usages
* of other deleted IDs.
@@ -227,7 +230,6 @@ static size_t id_delete(Main *bmain, const bool do_tagged_deletion)
bool keep_looping = true;
while (keep_looping) {
ID *id, *id_next;
- ID *last_remapped_id = tagged_deleted_ids.last;
keep_looping = false;
/* First tag and remove from Main all datablocks directly from target lib.
@@ -243,6 +245,7 @@ static size_t id_delete(Main *bmain, const bool do_tagged_deletion)
BLI_remlink(lb, id);
BKE_main_namemap_remove_name(bmain, id, id->name + 2);
BLI_addtail(&tagged_deleted_ids, id);
+ BKE_id_remapper_add(id_remapper, id, NULL);
/* Do not tag as no_main now, we want to unlink it first (lower-level ID management
* code has some specific handling of 'no main' IDs that would be a problem in that
* case). */
@@ -251,33 +254,38 @@ static size_t id_delete(Main *bmain, const bool do_tagged_deletion)
}
}
}
- if (last_remapped_id == NULL) {
- dummy_link.next = tagged_deleted_ids.first;
- last_remapped_id = (ID *)(&dummy_link);
- }
- for (id = last_remapped_id->next; id; id = id->next) {
- /* Will tag 'never NULL' users of this ID too.
- *
- * NOTE: #BKE_libblock_unlink() cannot be used here, since it would ignore indirect
- * links, this can lead to nasty crashing here in second, actual deleting loop.
- * Also, this will also flag users of deleted data that cannot be unlinked
- * (object using deleted obdata, etc.), so that they also get deleted. */
- BKE_libblock_remap_locked(bmain,
- id,
- NULL,
- (ID_REMAP_FLAG_NEVER_NULL_USAGE |
- ID_REMAP_FORCE_NEVER_NULL_USAGE |
- ID_REMAP_FORCE_INTERNAL_RUNTIME_POINTERS));
- /* Since we removed ID from Main,
- * we also need to unlink its own other IDs usages ourself. */
- BKE_libblock_relink_ex(
- bmain,
- id,
- NULL,
- NULL,
- (ID_REMAP_FORCE_INTERNAL_RUNTIME_POINTERS | ID_REMAP_SKIP_USER_CLEAR));
- }
+
+ /* Will tag 'never NULL' users of this ID too.
+ *
+ * NOTE: #BKE_libblock_unlink() cannot be used here, since it would ignore indirect
+ * links, this can lead to nasty crashing here in second, actual deleting loop.
+ * Also, this will also flag users of deleted data that cannot be unlinked
+ * (object using deleted obdata, etc.), so that they also get deleted. */
+ BKE_libblock_remap_multiple_locked(bmain,
+ id_remapper,
+ ID_REMAP_FLAG_NEVER_NULL_USAGE |
+ ID_REMAP_FORCE_NEVER_NULL_USAGE |
+ ID_REMAP_FORCE_INTERNAL_RUNTIME_POINTERS);
+ BKE_id_remapper_clear(id_remapper);
+ }
+
+ /* Since we removed IDs from Main, their own other IDs usages need to be removed 'manually'. */
+ LinkNode *cleanup_ids = NULL;
+ for (ID *id = tagged_deleted_ids.first; id; id = id->next) {
+ BLI_linklist_prepend(&cleanup_ids, id);
}
+ BKE_libblock_relink_multiple(bmain,
+ cleanup_ids,
+ ID_REMAP_TYPE_CLEANUP,
+ id_remapper,
+ ID_REMAP_FORCE_INTERNAL_RUNTIME_POINTERS |
+ ID_REMAP_SKIP_USER_CLEAR);
+
+ BKE_id_remapper_free(id_remapper);
+ BLI_linklist_free(cleanup_ids, NULL);
+
+ BKE_layer_collection_resync_allow();
+ BKE_main_collection_sync_remap(bmain);
/* Now we can safely mark that ID as not being in Main database anymore. */
/* NOTE: This needs to be done in a separate loop than above, otherwise some user-counts of
@@ -285,10 +293,14 @@ static size_t id_delete(Main *bmain, const bool do_tagged_deletion)
* is never affected). */
for (ID *id = tagged_deleted_ids.first; id; id = id->next) {
id->tag |= LIB_TAG_NO_MAIN;
+ /* User-count needs to be reset artificially, since some usages may not be cleared in batch
+ * deletion (typically, if one deleted ID uses another deleted ID, this may not be cleared by
+ * remapping code, depending on order in which these are handled). */
+ id->us = ID_FAKE_USERS(id);
}
}
else {
- /* First tag all datablocks directly from target lib.
+ /* First tag all data-blocks directly from target lib.
* Note that we go forward here, since we want to check dependencies before users
* (e.g. meshes before objects).
* Avoids to have to loop twice. */
diff --git a/source/blender/blenkernel/intern/mask_rasterize.c b/source/blender/blenkernel/intern/mask_rasterize.c
index 55834d5cf4e..adc0eb5f78c 100644
--- a/source/blender/blenkernel/intern/mask_rasterize.c
+++ b/source/blender/blenkernel/intern/mask_rasterize.c
@@ -521,7 +521,7 @@ static void layer_bucket_init(MaskRasterLayer *layer, const float pixel_size)
}
if (1) {
- /* now convert linknodes into arrays for faster per pixel access */
+ /* Now convert link-nodes into arrays for faster per pixel access. */
uint **buckets_face = MEM_mallocN(bucket_tot * sizeof(*buckets_face), __func__);
uint bucket_index;
@@ -1186,7 +1186,7 @@ void BKE_maskrasterize_handle_init(MaskRasterHandle *mr_handle,
// printf("tris %d, feather tris %d\n", sf_tri_tot, tot_feather_quads);
}
- /* add trianges */
+ /* Add triangles. */
BLI_scanfill_end_arena(&sf_ctx, sf_arena);
}
diff --git a/source/blender/blenkernel/intern/material.c b/source/blender/blenkernel/intern/material.c
index 6c6d2298dbd..59530a6d6a6 100644
--- a/source/blender/blenkernel/intern/material.c
+++ b/source/blender/blenkernel/intern/material.c
@@ -1450,7 +1450,7 @@ static bool fill_texpaint_slots_cb(bNode *node, void *userdata)
NodeTexImage *storage = (NodeTexImage *)node->storage;
slot->interp = storage->interpolation;
slot->image_user = &storage->iuser;
- /* for new renderer, we need to traverse the treeback in search of a UV node */
+ /* For new renderer, we need to traverse the tree back in search of a UV node. */
bNode *uvnode = nodetree_uv_node_recursive(node);
if (uvnode) {
@@ -1512,58 +1512,65 @@ static ePaintSlotFilter material_paint_slot_filter(const struct Object *ob)
void BKE_texpaint_slot_refresh_cache(Scene *scene, Material *ma, const struct Object *ob)
{
- int count = 0;
-
if (!ma) {
return;
}
const ePaintSlotFilter slot_filter = material_paint_slot_filter(ob);
- /* COW needed when adding texture slot on an object with no materials. */
- DEG_id_tag_update(&ma->id, ID_RECALC_SHADING | ID_RECALC_COPY_ON_WRITE);
+ const TexPaintSlot *prev_texpaintslot = ma->texpaintslot;
+ const int prev_paint_active_slot = ma->paint_active_slot;
+ const int prev_paint_clone_slot = ma->paint_clone_slot;
+ const int prev_tot_slots = ma->tot_slots;
- if (ma->texpaintslot) {
- MEM_freeN(ma->texpaintslot);
- ma->tot_slots = 0;
- ma->texpaintslot = NULL;
- }
+ ma->texpaintslot = NULL;
+ ma->tot_slots = 0;
if (scene->toolsettings->imapaint.mode == IMAGEPAINT_MODE_IMAGE) {
ma->paint_active_slot = 0;
ma->paint_clone_slot = 0;
- return;
}
-
- if (!(ma->nodetree)) {
+ else if (!(ma->nodetree)) {
ma->paint_active_slot = 0;
ma->paint_clone_slot = 0;
- return;
}
+ else {
+ int count = count_texture_nodes_recursive(ma->nodetree, slot_filter);
- count = count_texture_nodes_recursive(ma->nodetree, slot_filter);
-
- if (count == 0) {
- ma->paint_active_slot = 0;
- ma->paint_clone_slot = 0;
- return;
- }
+ if (count == 0) {
+ ma->paint_active_slot = 0;
+ ma->paint_clone_slot = 0;
+ }
+ else {
+ ma->texpaintslot = MEM_callocN(sizeof(*ma->texpaintslot) * count, "texpaint_slots");
- ma->texpaintslot = MEM_callocN(sizeof(*ma->texpaintslot) * count, "texpaint_slots");
+ bNode *active_node = nodeGetActivePaintCanvas(ma->nodetree);
- bNode *active_node = nodeGetActivePaintCanvas(ma->nodetree);
+ fill_texpaint_slots_recursive(ma->nodetree, active_node, ob, ma, count, slot_filter);
- fill_texpaint_slots_recursive(ma->nodetree, active_node, ob, ma, count, slot_filter);
+ ma->tot_slots = count;
- ma->tot_slots = count;
+ if (ma->paint_active_slot >= count) {
+ ma->paint_active_slot = count - 1;
+ }
- if (ma->paint_active_slot >= count) {
- ma->paint_active_slot = count - 1;
+ if (ma->paint_clone_slot >= count) {
+ ma->paint_clone_slot = count - 1;
+ }
+ }
}
- if (ma->paint_clone_slot >= count) {
- ma->paint_clone_slot = count - 1;
+ /* COW needed when adding texture slot on an object with no materials.
+ * But do it only when slots actually change to avoid continuous depsgraph updates. */
+ if (ma->tot_slots != prev_tot_slots || ma->paint_active_slot != prev_paint_active_slot ||
+ ma->paint_clone_slot != prev_paint_clone_slot ||
+ (ma->texpaintslot && prev_texpaintslot &&
+ memcmp(ma->texpaintslot, prev_texpaintslot, sizeof(*ma->texpaintslot) * ma->tot_slots) !=
+ 0)) {
+ DEG_id_tag_update(&ma->id, ID_RECALC_SHADING | ID_RECALC_COPY_ON_WRITE);
}
+
+ MEM_SAFE_FREE(prev_texpaintslot);
}
void BKE_texpaint_slots_refresh_object(Scene *scene, struct Object *ob)
diff --git a/source/blender/blenkernel/intern/mball_tessellate.cc b/source/blender/blenkernel/intern/mball_tessellate.cc
index bb3713e770a..f8a64a7cd8b 100644
--- a/source/blender/blenkernel/intern/mball_tessellate.cc
+++ b/source/blender/blenkernel/intern/mball_tessellate.cc
@@ -1188,8 +1188,9 @@ static void init_meta(Depsgraph *depsgraph, PROCESS *process, Scene *scene, Obje
const eEvaluationMode deg_eval_mode = DEG_get_mode(depsgraph);
const short parenting_dupli_transflag = (OB_DUPLIFACES | OB_DUPLIVERTS);
- copy_m4_m4(obmat, ob->obmat); /* to cope with duplicators from BKE_scene_base_iter_next */
- invert_m4_m4(obinv, ob->obmat);
+ copy_m4_m4(obmat,
+ ob->object_to_world); /* to cope with duplicators from BKE_scene_base_iter_next */
+ invert_m4_m4(obinv, ob->object_to_world);
BLI_split_name_num(obname, &obnr, ob->id.name + 2, '.');
@@ -1237,13 +1238,13 @@ static void init_meta(Depsgraph *depsgraph, PROCESS *process, Scene *scene, Obje
/* when metaball object has zero scale, then MetaElem to this MetaBall
* will not be put to mainb array */
- if (has_zero_axis_m4(bob->obmat)) {
+ if (has_zero_axis_m4(bob->object_to_world)) {
zero_size = 1;
}
else if (bob->parent) {
struct Object *pob = bob->parent;
while (pob) {
- if (has_zero_axis_m4(pob->obmat)) {
+ if (has_zero_axis_m4(pob->object_to_world)) {
zero_size = 1;
break;
}
@@ -1307,7 +1308,7 @@ static void init_meta(Depsgraph *depsgraph, PROCESS *process, Scene *scene, Obje
* rotation ->
* ml local space
*/
- mul_m4_series((float(*)[4])new_ml->mat, obinv, bob->obmat, pos, rot);
+ mul_m4_series((float(*)[4])new_ml->mat, obinv, bob->object_to_world, pos, rot);
/* ml local space -> basis object space */
invert_m4_m4((float(*)[4])new_ml->imat, (float(*)[4])new_ml->mat);
diff --git a/source/blender/blenkernel/intern/mesh_convert.cc b/source/blender/blenkernel/intern/mesh_convert.cc
index 027423f5774..784d35a8d65 100644
--- a/source/blender/blenkernel/intern/mesh_convert.cc
+++ b/source/blender/blenkernel/intern/mesh_convert.cc
@@ -1313,6 +1313,7 @@ void BKE_mesh_nomain_to_mesh(Mesh *mesh_src, Mesh *mesh_dst, Object *ob)
CustomData_duplicate_referenced_layers(&mesh_src->pdata, mesh_src->totpoly);
CustomData_duplicate_referenced_layers(&mesh_src->ldata, mesh_src->totloop);
+ const bool verts_num_changed = mesh_dst->totvert != mesh_src->totvert;
mesh_dst->totvert = mesh_src->totvert;
mesh_dst->totedge = mesh_src->totedge;
mesh_dst->totpoly = mesh_src->totpoly;
@@ -1339,11 +1340,10 @@ void BKE_mesh_nomain_to_mesh(Mesh *mesh_src, Mesh *mesh_dst, Object *ob)
const int uid_active = ob ? find_object_active_key_uid(*key_dst, *ob) : -1;
move_shapekey_layers_to_keyblocks(*mesh_dst, mesh_src->vdata, *key_dst, uid_active);
}
- else if (mesh_src->totvert != mesh_dst->totvert) {
- CLOG_ERROR(&LOG, "Mesh in Main '%s' lost shape keys", mesh_src->id.name);
- if (mesh_src->key) {
- id_us_min(&mesh_src->key->id);
- }
+ else if (verts_num_changed) {
+ CLOG_WARN(&LOG, "Shape key data lost when replacing mesh '%s' in Main", mesh_src->id.name);
+ id_us_min(&mesh_dst->key->id);
+ mesh_dst->key = nullptr;
}
}
diff --git a/source/blender/blenkernel/intern/mesh_mirror.c b/source/blender/blenkernel/intern/mesh_mirror.c
index 261bc3d150b..ce3fc5d99c8 100644
--- a/source/blender/blenkernel/intern/mesh_mirror.c
+++ b/source/blender/blenkernel/intern/mesh_mirror.c
@@ -152,8 +152,8 @@ Mesh *BKE_mesh_mirror_apply_mirror_on_axis_for_modifier(MirrorModifierData *mmd,
/* tmp is a transform from coords relative to the object's own origin,
* to coords relative to the mirror object origin */
- invert_m4_m4(tmp, mirror_ob->obmat);
- mul_m4_m4m4(tmp, tmp, ob->obmat);
+ invert_m4_m4(tmp, mirror_ob->object_to_world);
+ mul_m4_m4m4(tmp, tmp, ob->object_to_world);
/* itmp is the reverse transform back to origin-relative coordinates */
invert_m4_m4(itmp, tmp);
@@ -169,9 +169,9 @@ Mesh *BKE_mesh_mirror_apply_mirror_on_axis_for_modifier(MirrorModifierData *mmd,
/* Account for non-uniform scale in `ob`, see: T87592. */
float ob_scale[3] = {
- len_squared_v3(ob->obmat[0]),
- len_squared_v3(ob->obmat[1]),
- len_squared_v3(ob->obmat[2]),
+ len_squared_v3(ob->object_to_world[0]),
+ len_squared_v3(ob->object_to_world[1]),
+ len_squared_v3(ob->object_to_world[2]),
};
/* Scale to avoid precision loss with extreme values. */
const float ob_scale_max = max_fff(UNPACK3(ob_scale));
diff --git a/source/blender/blenkernel/intern/modifier.cc b/source/blender/blenkernel/intern/modifier.cc
index fc1a0f47684..92a7c778b68 100644
--- a/source/blender/blenkernel/intern/modifier.cc
+++ b/source/blender/blenkernel/intern/modifier.cc
@@ -955,7 +955,7 @@ const char *BKE_modifier_path_relbase_from_global(Object *ob)
void BKE_modifier_path_init(char *path, int path_maxlen, const char *name)
{
const char *blendfile_path = BKE_main_blendfile_path_from_global();
- BLI_join_dirfile(path, path_maxlen, blendfile_path[0] ? "//" : BKE_tempdir_session(), name);
+ BLI_path_join(path, path_maxlen, blendfile_path[0] ? "//" : BKE_tempdir_session(), name);
}
/**
diff --git a/source/blender/blenkernel/intern/nla.c b/source/blender/blenkernel/intern/nla.c
index ba63cdff917..c0aff204069 100644
--- a/source/blender/blenkernel/intern/nla.c
+++ b/source/blender/blenkernel/intern/nla.c
@@ -464,6 +464,7 @@ NlaStrip *BKE_nlastack_add_strip(AnimData *adt, bAction *act, const bool is_libo
*/
nlt = BKE_nlatrack_add(adt, NULL, is_liboverride);
BKE_nlatrack_add_strip(nlt, strip, is_liboverride);
+ BLI_strncpy(nlt->name, act->id.name + 2, sizeof(nlt->name));
}
/* automatically name it too */
@@ -1918,7 +1919,7 @@ bool BKE_nla_action_stash(AnimData *adt, const bool is_liboverride)
* NOTE: this must be done *after* adding the strip to the track, or else
* the strip locking will prevent the strip from getting added
*/
- nlt->flag = (NLATRACK_MUTED | NLATRACK_PROTECTED);
+ nlt->flag |= (NLATRACK_MUTED | NLATRACK_PROTECTED);
strip->flag &= ~(NLASTRIP_FLAG_SELECT | NLASTRIP_FLAG_ACTIVE);
/* also mark the strip for auto syncing the length, so that the strips accurately
@@ -2054,7 +2055,7 @@ bool BKE_nla_tweakmode_enter(AnimData *adt)
}
/* If block is already in tweak-mode, just leave, but we should report
- * that this block is in tweak-mode (as our returncode). */
+ * that this block is in tweak-mode (as our return-code). */
if (adt->flag & ADT_NLA_EDIT_ON) {
return true;
}
diff --git a/source/blender/blenkernel/intern/node.cc b/source/blender/blenkernel/intern/node.cc
index 654eb06a781..8f8cd02e119 100644
--- a/source/blender/blenkernel/intern/node.cc
+++ b/source/blender/blenkernel/intern/node.cc
@@ -516,10 +516,6 @@ void ntreeBlendWrite(BlendWriter *writer, bNodeTree *ntree)
write_node_socket(writer, sock);
}
- LISTBASE_FOREACH (bNodeLink *, link, &node->internal_links) {
- BLO_write_struct(writer, bNodeLink, link);
- }
-
if (node->storage) {
if (ELEM(ntree->type, NTREE_SHADER, NTREE_GEOMETRY) &&
ELEM(node->type, SH_NODE_CURVE_VEC, SH_NODE_CURVE_RGB, SH_NODE_CURVE_FLOAT)) {
@@ -703,13 +699,7 @@ void ntreeBlendReadData(BlendDataReader *reader, ID *owner_id, bNodeTree *ntree)
BLO_read_data_address(reader, &node->prop);
IDP_BlendDataRead(reader, &node->prop);
- BLO_read_list(reader, &node->internal_links);
- LISTBASE_FOREACH (bNodeLink *, link, &node->internal_links) {
- BLO_read_data_address(reader, &link->fromnode);
- BLO_read_data_address(reader, &link->fromsock);
- BLO_read_data_address(reader, &link->tonode);
- BLO_read_data_address(reader, &link->tosock);
- }
+ BLI_listbase_clear(&node->internal_links);
if (node->type == CMP_NODE_MOVIEDISTORTION) {
/* Do nothing, this is runtime cache and hence handled by generic code using
@@ -2032,21 +2022,29 @@ bNode *nodeFindNodebyName(bNodeTree *ntree, const char *name)
bool nodeFindNode(bNodeTree *ntree, bNodeSocket *sock, bNode **r_node, int *r_sockindex)
{
*r_node = nullptr;
+ if (!ntree->runtime->topology_cache_is_dirty) {
+ bNode *node = &sock->owner_node();
+ *r_node = node;
+ if (r_sockindex) {
+ ListBase *sockets = (sock->in_out == SOCK_IN) ? &node->inputs : &node->outputs;
+ *r_sockindex = BLI_findindex(sockets, sock);
+ }
+ return true;
+ }
LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
ListBase *sockets = (sock->in_out == SOCK_IN) ? &node->inputs : &node->outputs;
- int index = 0;
- LISTBASE_FOREACH (bNodeSocket *, tsock, sockets) {
+ int i;
+ LISTBASE_FOREACH_INDEX (bNodeSocket *, tsock, sockets, i) {
if (sock == tsock) {
if (r_node != nullptr) {
*r_node = node;
}
if (r_sockindex != nullptr) {
- *r_sockindex = index;
+ *r_sockindex = i;
}
return true;
}
- index++;
}
}
return false;
@@ -2157,6 +2155,38 @@ void nodeParentsIter(bNode *node, bool (*callback)(bNode *, void *), void *userd
}
}
+bool nodeIsDanglingReroute(const bNodeTree *ntree, const bNode *node)
+{
+ ntree->ensure_topology_cache();
+ BLI_assert(blender::bke::node_tree_runtime::topology_cache_is_available(*ntree));
+ BLI_assert(!ntree->has_available_link_cycle());
+
+ const bNode *iter_node = node;
+ if (!iter_node->is_reroute()) {
+ return false;
+ }
+
+ while (true) {
+ const blender::Span<const bNodeLink *> links =
+ iter_node->input_socket(0).directly_linked_links();
+ BLI_assert(links.size() <= 1);
+ if (links.is_empty()) {
+ return true;
+ }
+ const bNodeLink &link = *links[0];
+ if (!link.is_available()) {
+ return false;
+ }
+ if (link.is_muted()) {
+ return false;
+ }
+ iter_node = link.fromnode;
+ if (!iter_node->is_reroute()) {
+ return false;
+ }
+ }
+}
+
/* ************** Add stuff ********** */
void nodeUniqueName(bNodeTree *ntree, bNode *node)
diff --git a/source/blender/blenkernel/intern/object.cc b/source/blender/blenkernel/intern/object.cc
index 2d949fb5c65..53e6d47860f 100644
--- a/source/blender/blenkernel/intern/object.cc
+++ b/source/blender/blenkernel/intern/object.cc
@@ -1330,14 +1330,14 @@ void BKE_object_modifier_hook_reset(Object *ob, HookModifierData *hmd)
/* Calculate the world-space matrix for the pose-channel target first,
* then carry on as usual. */
- mul_m4_m4m4(mat, hmd->object->obmat, pchan->pose_mat);
+ mul_m4_m4m4(mat, hmd->object->object_to_world, pchan->pose_mat);
invert_m4_m4(imat, mat);
- mul_m4_m4m4(hmd->parentinv, imat, ob->obmat);
+ mul_m4_m4m4(hmd->parentinv, imat, ob->object_to_world);
}
else {
- invert_m4_m4(hmd->object->imat, hmd->object->obmat);
- mul_m4_m4m4(hmd->parentinv, hmd->object->imat, ob->obmat);
+ invert_m4_m4(hmd->object->imat, hmd->object->object_to_world);
+ mul_m4_m4m4(hmd->parentinv, hmd->object->imat, ob->object_to_world);
}
}
}
@@ -1355,14 +1355,14 @@ void BKE_object_modifier_gpencil_hook_reset(Object *ob, HookGpencilModifierData
/* Calculate the world-space matrix for the pose-channel target first,
* then carry on as usual. */
- mul_m4_m4m4(mat, hmd->object->obmat, pchan->pose_mat);
+ mul_m4_m4m4(mat, hmd->object->object_to_world, pchan->pose_mat);
invert_m4_m4(imat, mat);
- mul_m4_m4m4(hmd->parentinv, imat, ob->obmat);
+ mul_m4_m4m4(hmd->parentinv, imat, ob->object_to_world);
}
else {
- invert_m4_m4(hmd->object->imat, hmd->object->obmat);
- mul_m4_m4m4(hmd->parentinv, hmd->object->imat, ob->obmat);
+ invert_m4_m4(hmd->object->imat, hmd->object->object_to_world);
+ mul_m4_m4m4(hmd->parentinv, hmd->object->imat, ob->object_to_world);
}
}
@@ -1902,6 +1902,7 @@ bool BKE_object_is_in_editmode(const Object *ob)
/* Grease Pencil object has no edit mode data. */
return GPENCIL_EDIT_MODE((bGPdata *)ob->data);
case OB_CURVES:
+ /* Curves object has no edit mode data. */
return ob->mode == OB_MODE_EDIT;
default:
return false;
@@ -3101,10 +3102,10 @@ void BKE_object_matrix_local_get(struct Object *ob, float r_mat[4][4])
BKE_object_get_parent_matrix(ob, ob->parent, par_imat);
invert_m4(par_imat);
- mul_m4_m4m4(r_mat, par_imat, ob->obmat);
+ mul_m4_m4m4(r_mat, par_imat, ob->object_to_world);
}
else {
- copy_m4_m4(r_mat, ob->obmat);
+ copy_m4_m4(r_mat, ob->object_to_world);
}
}
@@ -3358,32 +3359,32 @@ void BKE_object_get_parent_matrix(Object *ob, Object *par, float r_parentmat[4][
}
if (ok) {
- mul_m4_m4m4(r_parentmat, par->obmat, tmat);
+ mul_m4_m4m4(r_parentmat, par->object_to_world, tmat);
}
else {
- copy_m4_m4(r_parentmat, par->obmat);
+ copy_m4_m4(r_parentmat, par->object_to_world);
}
break;
}
case PARBONE:
ob_parbone(ob, par, tmat);
- mul_m4_m4m4(r_parentmat, par->obmat, tmat);
+ mul_m4_m4m4(r_parentmat, par->object_to_world, tmat);
break;
case PARVERT1:
unit_m4(r_parentmat);
give_parvert(par, ob->par1, vec);
- mul_v3_m4v3(r_parentmat[3], par->obmat, vec);
+ mul_v3_m4v3(r_parentmat[3], par->object_to_world, vec);
break;
case PARVERT3:
ob_parvert3(ob, par, tmat);
- mul_m4_m4m4(r_parentmat, par->obmat, tmat);
+ mul_m4_m4m4(r_parentmat, par->object_to_world, tmat);
break;
case PARSKEL:
- copy_m4_m4(r_parentmat, par->obmat);
+ copy_m4_m4(r_parentmat, par->object_to_world);
break;
}
}
@@ -3421,7 +3422,7 @@ static void solve_parenting(
/* origin, for help line */
if (set_origin) {
if ((ob->partype & PARTYPE) == PARSKEL) {
- copy_v3_v3(ob->runtime.parent_display_origin, par->obmat[3]);
+ copy_v3_v3(ob->runtime.parent_display_origin, par->object_to_world[3]);
}
else {
copy_v3_v3(ob->runtime.parent_display_origin, totmat[3]);
@@ -3440,10 +3441,10 @@ static void object_where_is_calc_ex(Depsgraph *depsgraph,
Object *par = ob->parent;
/* calculate parent matrix */
- solve_parenting(ob, par, true, ob->obmat, r_originmat);
+ solve_parenting(ob, par, true, ob->object_to_world, r_originmat);
}
else {
- BKE_object_to_mat4(ob, ob->obmat);
+ BKE_object_to_mat4(ob, ob->object_to_world);
}
/* try to fall back to the scene rigid body world if none given */
@@ -3460,7 +3461,7 @@ static void object_where_is_calc_ex(Depsgraph *depsgraph,
}
/* set negative scale flag in object */
- if (is_negative_m4(ob->obmat)) {
+ if (is_negative_m4(ob->object_to_world)) {
ob->transflag |= OB_NEG_SCALE;
}
else {
@@ -3506,7 +3507,7 @@ void BKE_object_workob_calc_parent(Depsgraph *depsgraph, Scene *scene, Object *o
{
BKE_object_workob_clear(workob);
- unit_m4(workob->obmat);
+ unit_m4(workob->object_to_world);
unit_m4(workob->parentinv);
unit_m4(workob->constinv);
@@ -3598,7 +3599,7 @@ void BKE_object_apply_parent_inverse(struct Object *ob)
* `inv(parent) @ world = parentinv`
* `parentinv = inv(parent) @ world`
*
- * NOTE: If `ob->obmat` has shear, then this `parentinv` is insufficient because
+ * NOTE: If `ob->object_to_world` has shear, then this `parentinv` is insufficient because
* `parent @ parentinv => shearless result`
*
* Thus, local will have shear which cannot be decomposed into TRS:
@@ -3627,7 +3628,7 @@ void BKE_object_apply_parent_inverse(struct Object *ob)
copy_m4_m4(ob_local, ob->parentinv);
invert_m4(ob_local);
mul_m4_m4_post(ob_local, par_imat);
- mul_m4_m4_post(ob_local, ob->obmat);
+ mul_m4_m4_post(ob_local, ob->object_to_world);
/* Send use_compat=False so the rotation is predictable. */
BKE_object_apply_mat4(ob, ob_local, false, false);
@@ -3792,7 +3793,7 @@ void BKE_object_dimensions_get(Object *ob, float r_vec[3])
const BoundBox *bb = BKE_object_boundbox_get(ob);
if (bb) {
float3 scale;
- mat4_to_size(scale, ob->obmat);
+ mat4_to_size(scale, ob->object_to_world);
r_vec[0] = fabsf(scale[0]) * (bb->vec[4][0] - bb->vec[0][0]);
r_vec[1] = fabsf(scale[1]) * (bb->vec[2][1] - bb->vec[0][1]);
@@ -3849,19 +3850,19 @@ void BKE_object_minmax(Object *ob, float r_min[3], float r_max[3], const bool us
case OB_FONT:
case OB_SURF: {
const BoundBox bb = *BKE_curve_boundbox_get(ob);
- BKE_boundbox_minmax(&bb, ob->obmat, r_min, r_max);
+ BKE_boundbox_minmax(&bb, ob->object_to_world, r_min, r_max);
changed = true;
break;
}
case OB_MESH: {
const BoundBox bb = *BKE_mesh_boundbox_get(ob);
- BKE_boundbox_minmax(&bb, ob->obmat, r_min, r_max);
+ BKE_boundbox_minmax(&bb, ob->object_to_world, r_min, r_max);
changed = true;
break;
}
case OB_GPENCIL: {
const BoundBox bb = *BKE_gpencil_boundbox_get(ob);
- BKE_boundbox_minmax(&bb, ob->obmat, r_min, r_max);
+ BKE_boundbox_minmax(&bb, ob->object_to_world, r_min, r_max);
changed = true;
break;
}
@@ -3874,7 +3875,7 @@ void BKE_object_minmax(Object *ob, float r_min[3], float r_max[3], const bool us
for (v = 0; v < lt->pntsv; v++) {
for (u = 0; u < lt->pntsu; u++, bp++) {
float3 vec;
- mul_v3_m4v3(vec, ob->obmat, bp->vec);
+ mul_v3_m4v3(vec, ob->object_to_world, bp->vec);
minmax_v3v3_v3(r_min, r_max, vec);
}
}
@@ -3889,7 +3890,8 @@ void BKE_object_minmax(Object *ob, float r_min[3], float r_max[3], const bool us
case OB_MBALL: {
float ob_min[3], ob_max[3];
- changed = BKE_mball_minmax_ex((const MetaBall *)ob->data, ob_min, ob_max, ob->obmat, 0);
+ changed = BKE_mball_minmax_ex(
+ (const MetaBall *)ob->data, ob_min, ob_max, ob->object_to_world, 0);
if (changed) {
minmax_v3v3_v3(r_min, r_max, ob_min);
minmax_v3v3_v3(r_min, r_max, ob_max);
@@ -3898,20 +3900,20 @@ void BKE_object_minmax(Object *ob, float r_min[3], float r_max[3], const bool us
}
case OB_CURVES: {
const BoundBox bb = *BKE_curves_boundbox_get(ob);
- BKE_boundbox_minmax(&bb, ob->obmat, r_min, r_max);
+ BKE_boundbox_minmax(&bb, ob->object_to_world, r_min, r_max);
changed = true;
break;
}
case OB_POINTCLOUD: {
const BoundBox bb = *BKE_pointcloud_boundbox_get(ob);
- BKE_boundbox_minmax(&bb, ob->obmat, r_min, r_max);
+ BKE_boundbox_minmax(&bb, ob->object_to_world, r_min, r_max);
changed = true;
break;
}
case OB_VOLUME: {
const BoundBox bb = *BKE_volume_boundbox_get(ob);
- BKE_boundbox_minmax(&bb, ob->obmat, r_min, r_max);
+ BKE_boundbox_minmax(&bb, ob->object_to_world, r_min, r_max);
changed = true;
break;
}
@@ -3925,14 +3927,14 @@ void BKE_object_minmax(Object *ob, float r_min[3], float r_max[3], const bool us
size *= ob->empty_drawsize;
}
- minmax_v3v3_v3(r_min, r_max, ob->obmat[3]);
+ minmax_v3v3_v3(r_min, r_max, ob->object_to_world[3]);
float3 vec;
- copy_v3_v3(vec, ob->obmat[3]);
+ copy_v3_v3(vec, ob->object_to_world[3]);
add_v3_v3(vec, size);
minmax_v3v3_v3(r_min, r_max, vec);
- copy_v3_v3(vec, ob->obmat[3]);
+ copy_v3_v3(vec, ob->object_to_world[3]);
sub_v3_v3(vec, size);
minmax_v3v3_v3(r_min, r_max, vec);
}
@@ -3979,12 +3981,12 @@ bool BKE_object_empty_image_data_is_visible_in_view3d(const Object *ob, const Re
* however the issue with empty objects being visible when viewed from the side
* is only noticeable in orthographic views. */
float3 view_dir;
- sub_v3_v3v3(view_dir, rv3d->viewinv[3], ob->obmat[3]);
- dot = dot_v3v3(ob->obmat[2], view_dir);
+ sub_v3_v3v3(view_dir, rv3d->viewinv[3], ob->object_to_world[3]);
+ dot = dot_v3v3(ob->object_to_world[2], view_dir);
eps = 0.0f;
}
else {
- dot = dot_v3v3(ob->obmat[2], rv3d->viewinv[2]);
+ dot = dot_v3v3(ob->object_to_world[2], rv3d->viewinv[2]);
eps = 1e-5f;
}
if (visibility_flag & OB_EMPTY_IMAGE_HIDE_BACK) {
@@ -4001,7 +4003,7 @@ bool BKE_object_empty_image_data_is_visible_in_view3d(const Object *ob, const Re
if (visibility_flag & OB_EMPTY_IMAGE_HIDE_NON_AXIS_ALIGNED) {
float3 proj, ob_z_axis;
- normalize_v3_v3(ob_z_axis, ob->obmat[2]);
+ normalize_v3_v3(ob_z_axis, ob->object_to_world[2]);
project_plane_v3_v3v3(proj, ob_z_axis, rv3d->viewinv[2]);
const float proj_length_sq = len_squared_v3(proj);
if (proj_length_sq > 1e-5f) {
@@ -4193,7 +4195,7 @@ void BKE_scene_foreach_display_point(Depsgraph *depsgraph,
DEG_ITER_OBJECT_FLAG_DUPLI;
DEG_OBJECT_ITER_BEGIN (&deg_iter_settings, ob) {
if ((ob->base_flag & BASE_SELECTED) != 0) {
- BKE_object_foreach_display_point(ob, ob->obmat, func_cb, user_data);
+ BKE_object_foreach_display_point(ob, ob->object_to_world, func_cb, user_data);
}
}
DEG_OBJECT_ITER_END;
@@ -4236,7 +4238,7 @@ void *BKE_object_tfm_backup(Object *ob)
copy_v3_v3(obtfm->drotAxis, ob->drotAxis);
obtfm->rotAngle = ob->rotAngle;
obtfm->drotAngle = ob->drotAngle;
- copy_m4_m4(obtfm->obmat, ob->obmat);
+ copy_m4_m4(obtfm->obmat, ob->object_to_world);
copy_m4_m4(obtfm->parentinv, ob->parentinv);
copy_m4_m4(obtfm->constinv, ob->constinv);
copy_m4_m4(obtfm->imat, ob->imat);
@@ -4259,7 +4261,7 @@ void BKE_object_tfm_restore(Object *ob, void *obtfm_pt)
copy_v3_v3(ob->drotAxis, obtfm->drotAxis);
ob->rotAngle = obtfm->rotAngle;
ob->drotAngle = obtfm->drotAngle;
- copy_m4_m4(ob->obmat, obtfm->obmat);
+ copy_m4_m4(ob->object_to_world, obtfm->obmat);
copy_m4_m4(ob->parentinv, obtfm->parentinv);
copy_m4_m4(ob->constinv, obtfm->constinv);
copy_m4_m4(ob->imat, obtfm->imat);
@@ -5290,7 +5292,7 @@ KDTree_3d *BKE_object_as_kdtree(Object *ob, int *r_tot)
for (i = 0; i < verts.size(); i++) {
if (index[i] != ORIGINDEX_NONE) {
float co[3];
- mul_v3_m4v3(co, ob->obmat, verts[i].co);
+ mul_v3_m4v3(co, ob->object_to_world, verts[i].co);
BLI_kdtree_3d_insert(tree, index[i], co);
tot++;
}
@@ -5304,7 +5306,7 @@ KDTree_3d *BKE_object_as_kdtree(Object *ob, int *r_tot)
for (i = 0; i < tot; i++) {
float co[3];
- mul_v3_m4v3(co, ob->obmat, verts[i].co);
+ mul_v3_m4v3(co, ob->object_to_world, verts[i].co);
BLI_kdtree_3d_insert(tree, i, co);
}
}
@@ -5333,7 +5335,7 @@ KDTree_3d *BKE_object_as_kdtree(Object *ob, int *r_tot)
a = nu->pntsu;
while (a--) {
float co[3];
- mul_v3_m4v3(co, ob->obmat, bezt->vec[1]);
+ mul_v3_m4v3(co, ob->object_to_world, bezt->vec[1]);
BLI_kdtree_3d_insert(tree, i++, co);
bezt++;
}
@@ -5345,7 +5347,7 @@ KDTree_3d *BKE_object_as_kdtree(Object *ob, int *r_tot)
a = nu->pntsu * nu->pntsv;
while (a--) {
float co[3];
- mul_v3_m4v3(co, ob->obmat, bp->vec);
+ mul_v3_m4v3(co, ob->object_to_world, bp->vec);
BLI_kdtree_3d_insert(tree, i++, co);
bp++;
}
@@ -5368,7 +5370,7 @@ KDTree_3d *BKE_object_as_kdtree(Object *ob, int *r_tot)
for (bp = lt->def; i < tot; bp++) {
float co[3];
- mul_v3_m4v3(co, ob->obmat, bp->vec);
+ mul_v3_m4v3(co, ob->object_to_world, bp->vec);
BLI_kdtree_3d_insert(tree, i++, co);
}
diff --git a/source/blender/blenkernel/intern/object_dupli.cc b/source/blender/blenkernel/intern/object_dupli.cc
index 96da99af97e..d029d307d6e 100644
--- a/source/blender/blenkernel/intern/object_dupli.cc
+++ b/source/blender/blenkernel/intern/object_dupli.cc
@@ -41,6 +41,7 @@
#include "BKE_geometry_set.hh"
#include "BKE_global.h"
#include "BKE_idprop.h"
+#include "BKE_instances.hh"
#include "BKE_lattice.h"
#include "BKE_main.h"
#include "BKE_mesh.h"
@@ -70,6 +71,8 @@ using blender::float3;
using blender::float4x4;
using blender::Span;
using blender::Vector;
+using blender::bke::InstanceReference;
+using blender::bke::Instances;
namespace geo_log = blender::nodes::geo_eval_log;
/* -------------------------------------------------------------------- */
@@ -194,7 +197,8 @@ static bool copy_dupli_context(DupliContext *r_ctx,
/**
* Generate a dupli instance.
*
- * \param mat: is transform of the object relative to current context (including #Object.obmat).
+ * \param mat: is transform of the object relative to current context (including
+ * #Object.object_to_world).
*/
static DupliObject *make_dupli(const DupliContext *ctx,
Object *ob,
@@ -293,7 +297,7 @@ static DupliObject *make_dupli(const DupliContext *ctx,
/**
* Recursive dupli-objects.
*
- * \param space_mat: is the local dupli-space (excluding dupli #Object.obmat).
+ * \param space_mat: is the local dupli-space (excluding dupli #Object.object_to_world).
*/
static void make_recursive_duplis(const DupliContext *ctx,
Object *ob,
@@ -465,8 +469,8 @@ static void make_duplis_collection(const DupliContext *ctx)
/* Combine collection offset and `obmat`. */
unit_m4(collection_mat);
sub_v3_v3(collection_mat[3], collection->instance_offset);
- mul_m4_m4m4(collection_mat, ob->obmat, collection_mat);
- /* Don't access 'ob->obmat' from now on. */
+ mul_m4_m4m4(collection_mat, ob->object_to_world, collection_mat);
+ /* Don't access 'ob->object_to_world' from now on. */
eEvaluationMode mode = DEG_get_mode(ctx->depsgraph);
FOREACH_COLLECTION_VISIBLE_OBJECT_RECURSIVE_BEGIN (collection, cob, mode) {
@@ -474,7 +478,7 @@ static void make_duplis_collection(const DupliContext *ctx)
float mat[4][4];
/* Collection dupli-offset, should apply after everything else. */
- mul_m4_m4m4(mat, collection_mat, cob->obmat);
+ mul_m4_m4m4(mat, collection_mat, cob->object_to_world);
make_dupli(ctx, cob, mat, _base_id);
@@ -581,7 +585,7 @@ static DupliObject *vertex_dupli(const DupliContext *ctx,
/* Make offset relative to inst_ob using relative child transform. */
mul_mat3_m4_v3(child_imat, obmat[3]);
/* Apply `obmat` _after_ the local vertex transform. */
- mul_m4_m4m4(obmat, inst_ob->obmat, obmat);
+ mul_m4_m4m4(obmat, inst_ob->object_to_world, obmat);
/* Space matrix is constructed by removing `obmat` transform,
* this yields the world-space transform for recursive duplis. */
@@ -605,10 +609,10 @@ static void make_child_duplis_verts_from_mesh(const DupliContext *ctx,
const MVert *mvert = vdd->mvert;
const int totvert = vdd->totvert;
- invert_m4_m4(inst_ob->imat, inst_ob->obmat);
+ invert_m4_m4(inst_ob->imat, inst_ob->object_to_world);
/* Relative transform from parent to child space. */
float child_imat[4][4];
- mul_m4_m4m4(child_imat, inst_ob->imat, ctx->object->obmat);
+ mul_m4_m4m4(child_imat, inst_ob->imat, ctx->object->object_to_world);
for (int i = 0; i < totvert; i++) {
DupliObject *dob = vertex_dupli(
@@ -627,10 +631,10 @@ static void make_child_duplis_verts_from_editmesh(const DupliContext *ctx,
BMEditMesh *em = vdd->em;
const bool use_rotation = vdd->params.use_rotation;
- invert_m4_m4(inst_ob->imat, inst_ob->obmat);
+ invert_m4_m4(inst_ob->imat, inst_ob->object_to_world);
/* Relative transform from parent to child space. */
float child_imat[4][4];
- mul_m4_m4m4(child_imat, inst_ob->imat, ctx->object->obmat);
+ mul_m4_m4m4(child_imat, inst_ob->imat, ctx->object->object_to_world);
BMVert *v;
BMIter iter;
@@ -755,7 +759,7 @@ static void make_duplis_font(const DupliContext *ctx)
return;
}
- copy_m4_m4(pmat, par->obmat);
+ copy_m4_m4(pmat, par->object_to_world);
/* In `par` the family name is stored, use this to find the other objects. */
@@ -800,7 +804,7 @@ static void make_duplis_font(const DupliContext *ctx)
mul_m4_v3(pmat, vec);
- copy_m4_m4(obmat, par->obmat);
+ copy_m4_m4(obmat, par->object_to_world);
if (UNLIKELY(ct->rot != 0.0f)) {
float rmat[4][4];
@@ -874,8 +878,8 @@ static void make_duplis_geometry_set_impl(const DupliContext *ctx,
}
const bool creates_duplis_for_components = component_index >= 1;
- const InstancesComponent *component = geometry_set.get_component_for_read<InstancesComponent>();
- if (component == nullptr) {
+ const Instances *instances = geometry_set.get_instances_for_read();
+ if (instances == nullptr) {
return;
}
@@ -890,13 +894,13 @@ static void make_duplis_geometry_set_impl(const DupliContext *ctx,
instances_ctx = &new_instances_ctx;
}
- Span<float4x4> instance_offset_matrices = component->instance_transforms();
- Span<int> instance_reference_handles = component->instance_reference_handles();
- Span<int> almost_unique_ids = component->almost_unique_ids();
- Span<InstanceReference> references = component->references();
+ Span<float4x4> instance_offset_matrices = instances->transforms();
+ Span<int> reference_handles = instances->reference_handles();
+ Span<int> almost_unique_ids = instances->almost_unique_ids();
+ Span<InstanceReference> references = instances->references();
for (int64_t i : instance_offset_matrices.index_range()) {
- const InstanceReference &reference = references[instance_reference_handles[i]];
+ const InstanceReference &reference = references[reference_handles[i]];
const int id = almost_unique_ids[i];
const DupliContext *ctx_for_instance = instances_ctx;
@@ -948,7 +952,7 @@ static void make_duplis_geometry_set_impl(const DupliContext *ctx,
}
float instance_matrix[4][4];
- mul_m4_m4m4(instance_matrix, collection_matrix, object->obmat);
+ mul_m4_m4m4(instance_matrix, collection_matrix, object->object_to_world);
make_dupli(&sub_ctx, object, instance_matrix, object_id++);
make_recursive_duplis(&sub_ctx, object, collection_matrix, object_id++);
@@ -983,7 +987,7 @@ static void make_duplis_geometry_set_impl(const DupliContext *ctx,
static void make_duplis_geometry_set(const DupliContext *ctx)
{
const GeometrySet *geometry_set = ctx->object->runtime.geometry_set_eval;
- make_duplis_geometry_set_impl(ctx, *geometry_set, ctx->object->obmat, false, false);
+ make_duplis_geometry_set_impl(ctx, *geometry_set, ctx->object->object_to_world, false, false);
}
static const DupliGenerator gen_dupli_geometry_set = {
@@ -1089,7 +1093,7 @@ static DupliObject *face_dupli(const DupliContext *ctx,
}
/* Apply `obmat` _after_ the local face transform. */
- mul_m4_m4m4(obmat, inst_ob->obmat, obmat);
+ mul_m4_m4m4(obmat, inst_ob->object_to_world, obmat);
/* Space matrix is constructed by removing `obmat` transform,
* this yields the world-space transform for recursive duplis. */
@@ -1173,9 +1177,9 @@ static void make_child_duplis_faces_from_mesh(const DupliContext *ctx,
float child_imat[4][4];
- invert_m4_m4(inst_ob->imat, inst_ob->obmat);
+ invert_m4_m4(inst_ob->imat, inst_ob->object_to_world);
/* Relative transform from parent to child space. */
- mul_m4_m4m4(child_imat, inst_ob->imat, ctx->object->obmat);
+ mul_m4_m4m4(child_imat, inst_ob->imat, ctx->object->object_to_world);
const float scale_fac = ctx->object->instance_faces_scale;
for (a = 0, mp = mpoly; a < totface; a++, mp++) {
@@ -1213,9 +1217,9 @@ static void make_child_duplis_faces_from_editmesh(const DupliContext *ctx,
BLI_assert((vert_coords == nullptr) || (em->bm->elem_index_dirty & BM_VERT) == 0);
- invert_m4_m4(inst_ob->imat, inst_ob->obmat);
+ invert_m4_m4(inst_ob->imat, inst_ob->object_to_world);
/* Relative transform from parent to child space. */
- mul_m4_m4m4(child_imat, inst_ob->imat, ctx->object->obmat);
+ mul_m4_m4m4(child_imat, inst_ob->imat, ctx->object->object_to_world);
const float scale_fac = ctx->object->instance_faces_scale;
BM_ITER_MESH_INDEX (f, &iter, em->bm, BM_FACES_OF_MESH, a) {
@@ -1345,7 +1349,7 @@ static void make_duplis_particle_system(const DupliContext *ctx, ParticleSystem
sim.psys = psys;
sim.psmd = psys_get_modifier(par, psys);
/* Make sure emitter `imat` is in global coordinates instead of render view coordinates. */
- invert_m4_m4(par->imat, par->obmat);
+ invert_m4_m4(par->imat, par->object_to_world);
/* First check for loops (particle system object used as dupli-object). */
if (part->ren_as == PART_DRAW_OB) {
@@ -1532,7 +1536,7 @@ static void make_duplis_particle_system(const DupliContext *ctx, ParticleSystem
b = 0;
FOREACH_COLLECTION_VISIBLE_OBJECT_RECURSIVE_BEGIN (
part->instance_collection, object, mode) {
- copy_m4_m4(tmat, oblist[b]->obmat);
+ copy_m4_m4(tmat, oblist[b]->object_to_world);
/* Apply collection instance offset. */
sub_v3_v3(tmat[3], part->instance_collection->instance_offset);
@@ -1555,7 +1559,7 @@ static void make_duplis_particle_system(const DupliContext *ctx, ParticleSystem
}
else {
float obmat[4][4];
- copy_m4_m4(obmat, ob->obmat);
+ copy_m4_m4(obmat, ob->object_to_world);
float vec[3];
copy_v3_v3(vec, obmat[3]);
@@ -1749,7 +1753,7 @@ ListBase *object_duplilist_preview(Depsgraph *depsgraph,
*viewer_path)) {
ctx.preview_base_geometry = &viewer_log->geometry;
make_duplis_geometry_set_impl(
- &ctx, viewer_log->geometry, ob_eval->obmat, true, ob_eval->type == OB_CURVES);
+ &ctx, viewer_log->geometry, ob_eval->object_to_world, true, ob_eval->type == OB_CURVES);
}
}
return duplilist;
diff --git a/source/blender/blenkernel/intern/object_update.cc b/source/blender/blenkernel/intern/object_update.cc
index ceef6404bf0..7ea13bfcc84 100644
--- a/source/blender/blenkernel/intern/object_update.cc
+++ b/source/blender/blenkernel/intern/object_update.cc
@@ -61,7 +61,7 @@ void BKE_object_eval_local_transform(Depsgraph *depsgraph, Object *ob)
DEG_debug_print_eval(depsgraph, __func__, ob->id.name, ob);
/* calculate local matrix */
- BKE_object_to_mat4(ob, ob->obmat);
+ BKE_object_to_mat4(ob, ob->object_to_world);
}
void BKE_object_eval_parent(Depsgraph *depsgraph, Object *ob)
@@ -78,18 +78,18 @@ void BKE_object_eval_parent(Depsgraph *depsgraph, Object *ob)
/* get local matrix (but don't calculate it, as that was done already!) */
/* XXX: redundant? */
- copy_m4_m4(locmat, ob->obmat);
+ copy_m4_m4(locmat, ob->object_to_world);
/* get parent effect matrix */
BKE_object_get_parent_matrix(ob, par, totmat);
/* total */
mul_m4_m4m4(tmat, totmat, ob->parentinv);
- mul_m4_m4m4(ob->obmat, tmat, locmat);
+ mul_m4_m4m4(ob->object_to_world, tmat, locmat);
/* origin, for help line */
if ((ob->partype & PARTYPE) == PARSKEL) {
- copy_v3_v3(ob->runtime.parent_display_origin, par->obmat[3]);
+ copy_v3_v3(ob->runtime.parent_display_origin, par->object_to_world[3]);
}
else {
copy_v3_v3(ob->runtime.parent_display_origin, totmat[3]);
@@ -121,9 +121,9 @@ void BKE_object_eval_transform_final(Depsgraph *depsgraph, Object *ob)
DEG_debug_print_eval(depsgraph, __func__, ob->id.name, ob);
/* Make sure inverse matrix is always up to date. This way users of it
* do not need to worry about recalculating it. */
- invert_m4_m4_safe(ob->imat, ob->obmat);
+ invert_m4_m4_safe(ob->imat, ob->object_to_world);
/* Set negative scale flag in object. */
- if (is_negative_m4(ob->obmat)) {
+ if (is_negative_m4(ob->object_to_world)) {
ob->transflag |= OB_NEG_SCALE;
}
else {
@@ -257,7 +257,7 @@ void BKE_object_sync_to_original(Depsgraph *depsgraph, Object *object)
/* Base flags. */
object_orig->base_flag = object->base_flag;
/* Transformation flags. */
- copy_m4_m4(object_orig->obmat, object->obmat);
+ copy_m4_m4(object_orig->object_to_world, object->object_to_world);
copy_m4_m4(object_orig->imat, object->imat);
copy_m4_m4(object_orig->constinv, object->constinv);
object_orig->transflag = object->transflag;
@@ -292,6 +292,8 @@ void BKE_object_batch_cache_dirty_tag(Object *ob)
BKE_lattice_batch_cache_dirty_tag((struct Lattice *)ob->data, BKE_LATTICE_BATCH_DIRTY_ALL);
break;
case OB_CURVES_LEGACY:
+ case OB_SURF:
+ case OB_FONT:
BKE_curve_batch_cache_dirty_tag((struct Curve *)ob->data, BKE_CURVE_BATCH_DIRTY_ALL);
break;
case OB_MBALL: {
diff --git a/source/blender/blenkernel/intern/ocean.c b/source/blender/blenkernel/intern/ocean.c
index 396c3443a73..bcf382b6022 100644
--- a/source/blender/blenkernel/intern/ocean.c
+++ b/source/blender/blenkernel/intern/ocean.c
@@ -1144,7 +1144,7 @@ static void cache_filename(
break;
}
- BLI_join_dirfile(cachepath, sizeof(cachepath), path, fname);
+ BLI_path_join(cachepath, sizeof(cachepath), path, fname);
BKE_image_path_from_imtype(
string, cachepath, relbase, frame, R_IMF_IMTYPE_OPENEXR, true, true, "");
diff --git a/source/blender/blenkernel/intern/packedFile.c b/source/blender/blenkernel/intern/packedFile.c
index 901b42ac0b2..0c9d9f5b048 100644
--- a/source/blender/blenkernel/intern/packedFile.c
+++ b/source/blender/blenkernel/intern/packedFile.c
@@ -545,7 +545,7 @@ static void unpack_generate_paths(const char *name,
break;
}
if (dir_name) {
- BLI_path_join(r_relpath, relpathlen, "//", dir_name, tempname, NULL);
+ BLI_path_join(r_relpath, relpathlen, "//", dir_name, tempname);
}
}
diff --git a/source/blender/blenkernel/intern/paint.cc b/source/blender/blenkernel/intern/paint.cc
index d45ce776b64..a39e53662aa 100644
--- a/source/blender/blenkernel/intern/paint.cc
+++ b/source/blender/blenkernel/intern/paint.cc
@@ -54,6 +54,7 @@
#include "BKE_object.h"
#include "BKE_paint.h"
#include "BKE_pbvh.h"
+#include "BKE_scene.h"
#include "BKE_subdiv_ccg.h"
#include "BKE_subsurf.h"
@@ -1042,6 +1043,8 @@ eObjectMode BKE_paint_object_mode_from_paintmode(ePaintMode mode)
return OB_MODE_TEXTURE_PAINT;
case PAINT_MODE_SCULPT_UV:
return OB_MODE_EDIT;
+ case PAINT_MODE_SCULPT_CURVES:
+ return OB_MODE_SCULPT_CURVES;
case PAINT_MODE_INVALID:
default:
return OB_MODE_OBJECT;
@@ -1198,7 +1201,7 @@ void BKE_paint_stroke_get_average(Scene *scene, Object *ob, float stroke[3])
mul_v3_v3fl(stroke, ups->average_stroke_accum, fac);
}
else {
- copy_v3_v3(stroke, ob->obmat[3]);
+ copy_v3_v3(stroke, ob->object_to_world[3]);
}
}
@@ -1785,8 +1788,8 @@ static void sculpt_update_object(
/* If the fully evaluated mesh has the same topology as the deform-only version, use it.
* This matters because crazyspace evaluation is very restrictive and excludes even modifiers
* that simply recompute vertex weights (which can even include Geometry Nodes). */
- if (me_eval_deform->polys().data() == me_eval->polys().data() &&
- me_eval_deform->loops().data() == me_eval->loops().data() &&
+ if (me_eval_deform->totpoly == me_eval->totpoly &&
+ me_eval_deform->totloop == me_eval->totloop &&
me_eval_deform->totvert == me_eval->totvert) {
BKE_sculptsession_free_deformMats(ss);
@@ -1986,7 +1989,10 @@ bool *BKE_sculpt_hide_poly_ensure(Mesh *mesh)
&mesh->pdata, CD_PROP_BOOL, CD_SET_DEFAULT, nullptr, mesh->totpoly, ".hide_poly"));
}
-int BKE_sculpt_mask_layers_ensure(Object *ob, MultiresModifierData *mmd)
+int BKE_sculpt_mask_layers_ensure(Depsgraph *depsgraph,
+ Main *bmain,
+ Object *ob,
+ MultiresModifierData *mmd)
{
Mesh *me = static_cast<Mesh *>(ob->data);
const Span<MPoly> polys = me->polys();
@@ -2045,6 +2051,9 @@ int BKE_sculpt_mask_layers_ensure(Object *ob, MultiresModifierData *mmd)
}
/* The evaluated multires CCG must be updated to contain the new data. */
DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
+ if (depsgraph) {
+ BKE_scene_graph_evaluated_ensure(depsgraph, bmain);
+ }
ret |= SCULPT_MASK_LAYER_CALC_LOOP;
}
@@ -2237,7 +2246,8 @@ static PBVH *build_pbvh_from_ccg(Object *ob, SubdivCCG *subdiv_ccg, bool respect
(void **)subdiv_ccg->grid_faces,
subdiv_ccg->grid_flag_mats,
subdiv_ccg->grid_hidden,
- base_mesh);
+ base_mesh,
+ subdiv_ccg);
pbvh_show_mask_set(pbvh, ob->sculpt->show_mask);
pbvh_show_face_sets_set(pbvh, ob->sculpt->show_face_sets);
return pbvh;
@@ -2295,14 +2305,18 @@ PBVH *BKE_sculpt_object_pbvh_ensure(Depsgraph *depsgraph, Object *ob)
void BKE_sculpt_bvh_update_from_ccg(PBVH *pbvh, SubdivCCG *subdiv_ccg)
{
+ CCGKey key;
+ BKE_subdiv_ccg_key_top_level(&key, subdiv_ccg);
+
BKE_pbvh_grids_update(pbvh,
subdiv_ccg->grids,
(void **)subdiv_ccg->grid_faces,
subdiv_ccg->grid_flag_mats,
- subdiv_ccg->grid_hidden);
+ subdiv_ccg->grid_hidden,
+ &key);
}
-bool BKE_sculptsession_use_pbvh_draw(const Object *ob, const View3D * /*v3d*/)
+bool BKE_sculptsession_use_pbvh_draw(const Object *ob, const RegionView3D *rv3d)
{
SculptSession *ss = ob->sculpt;
if (ss == nullptr || ss->pbvh == nullptr || ss->mode_type != OB_MODE_SCULPT) {
@@ -2310,9 +2324,10 @@ bool BKE_sculptsession_use_pbvh_draw(const Object *ob, const View3D * /*v3d*/)
}
if (BKE_pbvh_type(ss->pbvh) == PBVH_FACES) {
- /* Regular mesh only draws from PBVH without modifiers and shape keys. */
-
- return !(ss->shapekey_active || ss->deform_modifiers_active);
+ /* Regular mesh only draws from PBVH without modifiers and shape keys, or for
+ * external engines that do not have access to the PBVH like Eevee does. */
+ const bool external_engine = rv3d && rv3d->render_engine != nullptr;
+ return !(ss->shapekey_active || ss->deform_modifiers_active || external_engine);
}
/* Multires and dyntopo always draw directly from the PBVH. */
diff --git a/source/blender/blenkernel/intern/particle.c b/source/blender/blenkernel/intern/particle.c
index d6dd3cf0dbb..f111e2dde17 100644
--- a/source/blender/blenkernel/intern/particle.c
+++ b/source/blender/blenkernel/intern/particle.c
@@ -2370,8 +2370,8 @@ void precalc_guides(ParticleSimulationData *sim, ListBase *effectors)
0,
0);
- mul_m4_v3(sim->ob->obmat, state.co);
- mul_mat3_m4_v3(sim->ob->obmat, state.vel);
+ mul_m4_v3(sim->ob->object_to_world, state.co);
+ mul_mat3_m4_v3(sim->ob->object_to_world, state.vel);
pd_point_from_particle(sim, pa, &state, &point);
@@ -2454,8 +2454,8 @@ bool do_guides(Depsgraph *depsgraph,
}
}
- mul_m4_v3(eff->ob->obmat, guidevec);
- mul_mat3_m4_v3(eff->ob->obmat, guidedir);
+ mul_m4_v3(eff->ob->object_to_world, guidevec);
+ mul_mat3_m4_v3(eff->ob->object_to_world, guidedir);
normalize_v3(guidedir);
@@ -2956,7 +2956,7 @@ static void psys_thread_create_path(ParticleTask *task,
psys_particle_on_emitter(
ctx->sim.psmd, cpa_from, cpa_num, DMCACHE_ISCHILD, cpa->fuv, foffset, co, 0, 0, 0, orco);
- mul_m4_v3(ob->obmat, co);
+ mul_m4_v3(ob->object_to_world, co);
for (w = 0; w < 4; w++) {
sub_v3_v3v3(off1[w], co, key[w]->co);
@@ -3419,7 +3419,7 @@ void psys_cache_paths(ParticleSimulationData *sim, float cfra, const bool use_re
/* dynamic hair is in object space */
/* keyed and baked are already in global space */
if (hair_mesh) {
- mul_m4_v3(sim->ob->obmat, ca->co);
+ mul_m4_v3(sim->ob->object_to_world, ca->co);
}
else if (!keyed && !baked && !(psys->flag & PSYS_GLOBAL_HAIR)) {
mul_m4_v3(hairmat, ca->co);
@@ -3929,7 +3929,7 @@ void psys_mat_hair_to_global(
psys_mat_hair_to_object(ob, mesh, from, pa, facemat);
- mul_m4_m4m4(hairmat, ob->obmat, facemat);
+ mul_m4_m4m4(hairmat, ob->object_to_world, facemat);
}
/************************************************/
@@ -4661,8 +4661,8 @@ void psys_get_particle_on_path(ParticleSimulationData *sim,
do_particle_interpolation(psys, p, pa, t, &pind, state);
if (pind.mesh) {
- mul_m4_v3(sim->ob->obmat, state->co);
- mul_mat3_m4_v3(sim->ob->obmat, state->vel);
+ mul_m4_v3(sim->ob->object_to_world, state->co);
+ mul_mat3_m4_v3(sim->ob->object_to_world, state->vel);
}
else if (!keyed && !cached && !(psys->flag & PSYS_GLOBAL_HAIR)) {
if ((pa->flag & PARS_REKEY) == 0) {
@@ -4685,7 +4685,7 @@ void psys_get_particle_on_path(ParticleSimulationData *sim,
}
}
else if (totchild) {
- // invert_m4_m4(imat, ob->obmat);
+ // invert_m4_m4(imat, ob->object_to_world);
/* interpolate childcache directly if it exists */
if (psys->childcache) {
@@ -4733,7 +4733,7 @@ void psys_get_particle_on_path(ParticleSimulationData *sim,
* positioning it accurately to the surface of the emitter. */
// copy_v3_v3(cpa_1st, co);
- // mul_m4_v3(ob->obmat, cpa_1st);
+ // mul_m4_v3(ob->object_to_world, cpa_1st);
pa = psys->particles + cpa->parent;
diff --git a/source/blender/blenkernel/intern/particle_child.c b/source/blender/blenkernel/intern/particle_child.c
index a890812cfc4..6cc7dbc70d0 100644
--- a/source/blender/blenkernel/intern/particle_child.c
+++ b/source/blender/blenkernel/intern/particle_child.c
@@ -187,7 +187,7 @@ static void do_kink_spiral(ParticleThreadContext *ctx,
zero_v3(kink_base);
kink_base[part->kink_axis] = 1.0f;
- mul_mat3_m4_v3(ctx->sim.ob->obmat, kink_base);
+ mul_mat3_m4_v3(ctx->sim.ob->object_to_world, kink_base);
/* Fill in invariant part of modifier context. */
ParticleChildModifierContext modifier_ctx = {NULL};
@@ -873,7 +873,7 @@ void do_child_modifiers(const ParticleChildModifierContext *modifier_ctx,
part->kink_flat,
part->kink,
part->kink_axis,
- sim->ob->obmat,
+ sim->ob->object_to_world,
smooth_start);
}
}
diff --git a/source/blender/blenkernel/intern/particle_system.c b/source/blender/blenkernel/intern/particle_system.c
index c72bbe2fd08..7317318e828 100644
--- a/source/blender/blenkernel/intern/particle_system.c
+++ b/source/blender/blenkernel/intern/particle_system.c
@@ -750,10 +750,10 @@ void psys_get_birth_coords(
/* particles live in global space so */
/* let's convert: */
/* -location */
- mul_m4_v3(ob->obmat, loc);
+ mul_m4_v3(ob->object_to_world, loc);
/* -normal */
- mul_mat3_m4_v3(ob->obmat, nor);
+ mul_mat3_m4_v3(ob->object_to_world, nor);
normalize_v3(nor);
/* -tangent */
@@ -771,7 +771,7 @@ void psys_get_birth_coords(
fac = -sinf((float)M_PI * (part->tanphase + phase));
madd_v3_v3fl(vtan, utan, fac);
- mul_mat3_m4_v3(ob->obmat, vtan);
+ mul_mat3_m4_v3(ob->object_to_world, vtan);
copy_v3_v3(utan, nor);
mul_v3_fl(utan, dot_v3v3(vtan, nor));
@@ -786,7 +786,7 @@ void psys_get_birth_coords(
r_vel[1] = 2.0f * (psys_frand(psys, p + 11) - 0.5f);
r_vel[2] = 2.0f * (psys_frand(psys, p + 12) - 0.5f);
- mul_mat3_m4_v3(ob->obmat, r_vel);
+ mul_mat3_m4_v3(ob->object_to_world, r_vel);
normalize_v3(r_vel);
}
@@ -796,7 +796,7 @@ void psys_get_birth_coords(
r_ave[1] = 2.0f * (psys_frand(psys, p + 14) - 0.5f);
r_ave[2] = 2.0f * (psys_frand(psys, p + 15) - 0.5f);
- mul_mat3_m4_v3(ob->obmat, r_ave);
+ mul_mat3_m4_v3(ob->object_to_world, r_ave);
normalize_v3(r_ave);
}
@@ -808,7 +808,7 @@ void psys_get_birth_coords(
r_rot[3] = 2.0f * (psys_frand(psys, p + 19) - 0.5f);
normalize_qt(r_rot);
- mat4_to_quat(rot, ob->obmat);
+ mat4_to_quat(rot, ob->object_to_world);
mul_qt_qtqt(r_rot, r_rot, rot);
}
@@ -822,7 +822,7 @@ void psys_get_birth_coords(
/* boids store direction in ave */
if (fabsf(nor[2]) == 1.0f) {
- sub_v3_v3v3(state->ave, loc, ob->obmat[3]);
+ sub_v3_v3v3(state->ave, loc, ob->object_to_world[3]);
normalize_v3(state->ave);
}
else {
@@ -868,15 +868,15 @@ void psys_get_birth_coords(
/* *emitter object orientation */
if (part->ob_vel[0] != 0.0f) {
- normalize_v3_v3(vec, ob->obmat[0]);
+ normalize_v3_v3(vec, ob->object_to_world[0]);
madd_v3_v3fl(vel, vec, part->ob_vel[0]);
}
if (part->ob_vel[1] != 0.0f) {
- normalize_v3_v3(vec, ob->obmat[1]);
+ normalize_v3_v3(vec, ob->object_to_world[1]);
madd_v3_v3fl(vel, vec, part->ob_vel[1]);
}
if (part->ob_vel[2] != 0.0f) {
- normalize_v3_v3(vec, ob->obmat[2]);
+ normalize_v3_v3(vec, ob->object_to_world[2]);
madd_v3_v3fl(vel, vec, part->ob_vel[2]);
}
@@ -924,7 +924,7 @@ void psys_get_birth_coords(
case PART_ROT_OB_X:
case PART_ROT_OB_Y:
case PART_ROT_OB_Z:
- copy_v3_v3(rot_vec, ob->obmat[part->rotmode - PART_ROT_OB_X]);
+ copy_v3_v3(rot_vec, ob->object_to_world[part->rotmode - PART_ROT_OB_X]);
use_global_space = false;
break;
default:
@@ -951,7 +951,7 @@ void psys_get_birth_coords(
float q_obmat[4];
float q_imat[4];
- mat4_to_quat(q_obmat, ob->obmat);
+ mat4_to_quat(q_obmat, ob->object_to_world);
invert_qt_qt_normalized(q_imat, q_obmat);
if (part->rotmode != PART_ROT_NOR_TAN) {
@@ -1639,7 +1639,7 @@ static void sph_springs_modify(ParticleSystem *psys, float dtime)
}
}
- /* Loop through springs backwaqrds - for efficient delete function */
+ /* Loop through springs backwards - for efficient delete function. */
for (i = psys->tot_fluidsprings - 1; i >= 0; i--) {
if (psys->fluid_springs[i].delete_flag) {
sph_spring_delete(psys, i);
@@ -3364,7 +3364,7 @@ static void hair_create_input_mesh(ParticleSimulationData *sim,
use_hair = psys_hair_use_simulation(pa, max_length);
psys_mat_hair_to_object(sim->ob, sim->psmd->mesh_final, psys->part->from, pa, hairmat);
- mul_m4_m4m4(root_mat, sim->ob->obmat, hairmat);
+ mul_m4_m4m4(root_mat, sim->ob->object_to_world, hairmat);
normalize_m4(root_mat);
bending_stiffness = CLAMPIS(
@@ -3555,7 +3555,7 @@ static void save_hair(ParticleSimulationData *sim, float UNUSED(cfra))
HairKey *key, *root;
PARTICLE_P;
- invert_m4_m4(ob->imat, ob->obmat);
+ invert_m4_m4(ob->imat, ob->object_to_world);
psys->lattice_deform_data = psys_create_lattice_deform_data(sim);
@@ -4380,7 +4380,7 @@ static void particles_fluid_step(ParticleSimulationData *sim,
mul_v3_v3(pa->state.co, scaleAbs);
/* Match domain scale. */
- mul_m4_v3(ob->obmat, pa->state.co);
+ mul_m4_v3(ob->object_to_world, pa->state.co);
/* Add origin offset to particle position. */
zero_v3(tmp);
@@ -4764,7 +4764,7 @@ void particle_system_update(struct Depsgraph *depsgraph,
float cfra;
ParticleSystemModifierData *psmd = psys_get_modifier(ob, psys);
- /* drawdata is outdated after ANY change */
+ /* Draw data is outdated after ANY change. */
if (psys->pdd) {
psys->pdd->flag &= ~PARTICLE_DRAW_DATA_UPDATED;
}
@@ -4963,7 +4963,7 @@ void particle_system_update(struct Depsgraph *depsgraph,
/* Save matrix for duplicators,
* at render-time the actual dupli-object's matrix is used so don't update! */
- invert_m4_m4(psys->imat, ob->obmat);
+ invert_m4_m4(psys->imat, ob->object_to_world);
BKE_particle_batch_cache_dirty_tag(psys, BKE_PARTICLE_BATCH_DIRTY_ALL);
}
diff --git a/source/blender/blenkernel/intern/pbvh.c b/source/blender/blenkernel/intern/pbvh.c
index b23fe53e80c..98e89b09060 100644
--- a/source/blender/blenkernel/intern/pbvh.c
+++ b/source/blender/blenkernel/intern/pbvh.c
@@ -39,8 +39,10 @@
#define LEAF_LIMIT 10000
-//#define PERFCNTRS
+/* Uncomment to test that faces are only assigned to one PBVHNode */
+//#define VALIDATE_UNIQUE_NODE_FACES
+//#define PERFCNTRS
#define STACK_FIXED_DEPTH 100
typedef struct PBVHStack {
@@ -422,6 +424,56 @@ static bool leaf_needs_material_split(PBVH *pbvh, int offset, int count)
return false;
}
+static int adjust_partition_faces(PBVH *pbvh, int offset, int mid, int count)
+{
+ int poly = pbvh->looptri[pbvh->prim_indices[mid]].poly;
+
+ /* Scan backwards. */
+ while (mid > offset + 2) { /* First node should have at least 1 primitive */
+ if (pbvh->looptri[pbvh->prim_indices[mid - 1]].poly != poly) {
+ return mid;
+ }
+
+ mid--;
+ }
+
+ /* If that didn't work try scanning forward. */
+ while (mid < pbvh->totprim + count) {
+ if (pbvh->looptri[pbvh->prim_indices[mid]].poly != poly) {
+ break;
+ }
+
+ mid++;
+ }
+
+ return mid;
+}
+
+static int adjust_partition_grids(PBVH *pbvh, int offset, int mid, int count)
+{
+ int poly = BKE_subdiv_ccg_grid_to_face_index(pbvh->subdiv_ccg, pbvh->prim_indices[mid]);
+
+ /* Scan backwards. */
+ while (mid > offset + 2) { /* First node should have at least 1 primitive */
+ if (BKE_subdiv_ccg_grid_to_face_index(pbvh->subdiv_ccg, pbvh->prim_indices[mid - 1]) != poly) {
+ return mid;
+ }
+
+ mid--;
+ }
+
+ /* If that didn't work try scanning forward. */
+ while (mid < pbvh->totprim + count) {
+ if (BKE_subdiv_ccg_grid_to_face_index(pbvh->subdiv_ccg, pbvh->prim_indices[mid]) != poly) {
+ break;
+ }
+
+ mid++;
+ }
+
+ return mid;
+}
+
/* Recursively build a node in the tree
*
* vb is the voxel box around all of the primitives contained in
@@ -478,6 +530,13 @@ static void build_sub(PBVH *pbvh, int node_index, BB *cb, BBC *prim_bbc, int off
end = partition_indices_material(pbvh, offset, offset + count - 1);
}
+ if (pbvh->header.type == PBVH_FACES) {
+ end = adjust_partition_faces(pbvh, offset, end, count);
+ }
+ else {
+ end = adjust_partition_grids(pbvh, offset, end, count);
+ }
+
/* Build children */
build_sub(pbvh, pbvh->nodes[node_index].children_offset, NULL, prim_bbc, offset, end - offset);
build_sub(pbvh,
@@ -587,6 +646,73 @@ static void pbvh_draw_args_init(PBVH *pbvh, PBVH_GPU_Args *args, PBVHNode *node)
}
}
+#ifdef VALIDATE_UNIQUE_NODE_FACES
+static void pbvh_validate_node_prims(PBVH *pbvh)
+{
+ int totface = 0;
+
+ if (pbvh->header.type == PBVH_BMESH) {
+ return;
+ }
+
+ for (int i = 0; i < pbvh->totnode; i++) {
+ PBVHNode *node = pbvh->nodes + i;
+
+ if (!(node->flag & PBVH_Leaf)) {
+ continue;
+ }
+
+ for (int j = 0; j < node->totprim; j++) {
+ int poly;
+
+ if (pbvh->header.type == PBVH_FACES) {
+ poly = pbvh->looptri[node->prim_indices[j]].poly;
+ }
+ else {
+ poly = BKE_subdiv_ccg_grid_to_face_index(pbvh->subdiv_ccg, node->prim_indices[j]);
+ }
+
+ totface = max_ii(totface, poly + 1);
+ }
+ }
+
+ int *facemap = (int *)MEM_malloc_arrayN(totface, sizeof(*facemap), __func__);
+
+ for (int i = 0; i < totface; i++) {
+ facemap[i] = -1;
+ }
+
+ for (int i = 0; i < pbvh->totnode; i++) {
+ PBVHNode *node = pbvh->nodes + i;
+
+ if (!(node->flag & PBVH_Leaf)) {
+ continue;
+ }
+
+ for (int j = 0; j < node->totprim; j++) {
+ int poly;
+
+ if (pbvh->header.type == PBVH_FACES) {
+ poly = pbvh->looptri[node->prim_indices[j]].poly;
+ }
+ else {
+ poly = BKE_subdiv_ccg_grid_to_face_index(pbvh->subdiv_ccg, node->prim_indices[j]);
+ }
+
+ if (facemap[poly] != -1 && facemap[poly] != i) {
+ printf("%s: error: face spanned multiple nodes (old: %d new: %d)\n",
+ __func__,
+ facemap[poly],
+ i);
+ }
+
+ facemap[poly] = i;
+ }
+ }
+ MEM_SAFE_FREE(facemap);
+}
+#endif
+
void BKE_pbvh_build_mesh(PBVH *pbvh,
Mesh *mesh,
const MPoly *mpoly,
@@ -645,6 +771,32 @@ void BKE_pbvh_build_mesh(PBVH *pbvh,
BB_expand(&cb, bbc->bcentroid);
}
+ /* Ensure all primitives belonging to the same base face
+ * have the same bounds. This is needed to prevent them
+ * from being swapped away from each other inside the partition
+ * array.
+ */
+ for (int i = 0; i < looptri_num; i++) {
+ const MLoopTri *lt = &looptri[i];
+ int poly = lt->poly;
+ BBC *bbc = prim_bbc + i;
+ int j = i + 1;
+
+ while (j < looptri_num && looptri[j].poly == poly) {
+ BBC *bbc2 = prim_bbc + j;
+
+ BB_expand((BB *)bbc, bbc2->bmin);
+ BB_expand((BB *)bbc, bbc2->bmax);
+ j++;
+ }
+
+ j = i + 1;
+ while (j < looptri_num && looptri[j].poly == poly) {
+ prim_bbc[j] = prim_bbc[i];
+ j++;
+ }
+ }
+
if (looptri_num) {
pbvh_build(pbvh, &cb, prim_bbc, looptri_num);
}
@@ -655,6 +807,10 @@ void BKE_pbvh_build_mesh(PBVH *pbvh,
memset(pbvh->vert_bitmap, 0, sizeof(bool) * totvert);
BKE_pbvh_update_active_vcol(pbvh, mesh);
+
+#ifdef VALIDATE_UNIQUE_NODE_FACES
+ pbvh_validate_node_prims(pbvh);
+#endif
}
void BKE_pbvh_build_grids(PBVH *pbvh,
@@ -664,7 +820,8 @@ void BKE_pbvh_build_grids(PBVH *pbvh,
void **gridfaces,
DMFlagMat *flagmats,
BLI_bitmap **grid_hidden,
- Mesh *me)
+ Mesh *me,
+ SubdivCCG *subdiv_ccg)
{
const int gridsize = key->grid_size;
@@ -675,6 +832,7 @@ void BKE_pbvh_build_grids(PBVH *pbvh,
pbvh->totgrid = totgrid;
pbvh->gridkey = *key;
pbvh->grid_hidden = grid_hidden;
+ pbvh->subdiv_ccg = subdiv_ccg;
pbvh->leaf_limit = max_ii(LEAF_LIMIT / (gridsize * gridsize), 1);
/* We need the base mesh attribute layout for PBVH draw. */
@@ -706,11 +864,40 @@ void BKE_pbvh_build_grids(PBVH *pbvh,
BB_expand(&cb, bbc->bcentroid);
}
+ /* Ensure all primitives belonging to the same base face
+ * have the same bounds. This is needed to prevent them
+ * from being swapped away from each other inside the partition
+ * array.
+ */
+ for (int i = 0; i < totgrid; i++) {
+ int poly = BKE_subdiv_ccg_grid_to_face_index(pbvh->subdiv_ccg, i);
+
+ BBC *bbc = prim_bbc + i;
+ int j = i + 1;
+
+ while (j < totgrid && BKE_subdiv_ccg_grid_to_face_index(pbvh->subdiv_ccg, j) == poly) {
+ BBC *bbc2 = prim_bbc + j;
+
+ BB_expand((BB *)bbc, bbc2->bmin);
+ BB_expand((BB *)bbc, bbc2->bmax);
+ j++;
+ }
+
+ j = i + 1;
+ while (j < totgrid && BKE_subdiv_ccg_grid_to_face_index(pbvh->subdiv_ccg, j) == poly) {
+ prim_bbc[j] = prim_bbc[i];
+ j++;
+ }
+ }
+
if (totgrid) {
pbvh_build(pbvh, &cb, prim_bbc, totgrid);
}
MEM_freeN(prim_bbc);
+#ifdef VALIDATE_UNIQUE_NODE_FACES
+ pbvh_validate_node_prims(pbvh);
+#endif
}
PBVH *BKE_pbvh_new(PBVHType type)
@@ -719,6 +906,11 @@ PBVH *BKE_pbvh_new(PBVHType type)
pbvh->respect_hide = true;
pbvh->draw_cache_invalid = true;
pbvh->header.type = type;
+
+ /* Initialize this to true, instead of waiting for a draw engine
+ * to set it. Prevents a crash in draw manager instancing code.
+ */
+ pbvh->is_drawing = true;
return pbvh;
}
@@ -2872,9 +3064,14 @@ void BKE_pbvh_draw_debug_cb(PBVH *pbvh,
}
}
-void BKE_pbvh_grids_update(
- PBVH *pbvh, CCGElem **grids, void **gridfaces, DMFlagMat *flagmats, BLI_bitmap **grid_hidden)
+void BKE_pbvh_grids_update(PBVH *pbvh,
+ CCGElem **grids,
+ void **gridfaces,
+ DMFlagMat *flagmats,
+ BLI_bitmap **grid_hidden,
+ CCGKey *key)
{
+ pbvh->gridkey = *key;
pbvh->grids = grids;
pbvh->gridfaces = gridfaces;
diff --git a/source/blender/blenkernel/intern/pointcache.c b/source/blender/blenkernel/intern/pointcache.c
index 5ec69f9bc45..868cdde6d01 100644
--- a/source/blender/blenkernel/intern/pointcache.c
+++ b/source/blender/blenkernel/intern/pointcache.c
@@ -1317,7 +1317,7 @@ static int ptcache_path(PTCacheID *pid, char *dirname)
BLI_path_abs(dirname, blendfilename);
}
- return BLI_path_slash_ensure(dirname); /* new strlen() */
+ return BLI_path_slash_ensure(dirname, MAX_PTCACHE_FILE); /* new strlen() */
}
if ((blendfile_path[0] != '\0') || lib) {
char file[MAX_PTCACHE_PATH]; /* we don't want the dir, only the file */
@@ -1334,14 +1334,14 @@ static int ptcache_path(PTCacheID *pid, char *dirname)
BLI_snprintf(dirname, MAX_PTCACHE_PATH, "//" PTCACHE_PATH "%s", file);
BLI_path_abs(dirname, blendfilename);
- return BLI_path_slash_ensure(dirname); /* new strlen() */
+ return BLI_path_slash_ensure(dirname, MAX_PTCACHE_FILE); /* new strlen() */
}
/* use the temp path. this is weak but better than not using point cache at all */
/* temporary directory is assumed to exist and ALWAYS has a trailing slash */
BLI_snprintf(dirname, MAX_PTCACHE_PATH, "%s" PTCACHE_PATH, BKE_tempdir_session());
- return BLI_path_slash_ensure(dirname); /* new strlen() */
+ return BLI_path_slash_ensure(dirname, MAX_PTCACHE_FILE); /* new strlen() */
}
static size_t ptcache_filepath_ext_append(PTCacheID *pid,
@@ -2611,7 +2611,7 @@ void BKE_ptcache_id_clear(PTCacheID *pid, int mode, uint cfra)
}
#endif
- /* clear all files in the temp dir with the prefix of the ID and the ".bphys" suffix */
+ /* Clear all files in the temp dir with the prefix of the ID and the `.bphys` suffix. */
switch (mode) {
case PTCACHE_CLEAR_ALL:
case PTCACHE_CLEAR_BEFORE:
@@ -2640,7 +2640,7 @@ void BKE_ptcache_id_clear(PTCacheID *pid, int mode, uint cfra)
if (STREQLEN(filepath, de->d_name, len)) { /* Do we have the right prefix. */
if (mode == PTCACHE_CLEAR_ALL) {
pid->cache->last_exact = MIN2(pid->cache->startframe, 0);
- BLI_join_dirfile(path_full, sizeof(path_full), path, de->d_name);
+ BLI_path_join(path_full, sizeof(path_full), path, de->d_name);
BLI_delete(path_full, false, false);
}
else {
@@ -2650,7 +2650,7 @@ void BKE_ptcache_id_clear(PTCacheID *pid, int mode, uint cfra)
if (frame != -1) {
if ((mode == PTCACHE_CLEAR_BEFORE && frame < cfra) ||
(mode == PTCACHE_CLEAR_AFTER && frame > cfra)) {
- BLI_join_dirfile(path_full, sizeof(path_full), path, de->d_name);
+ BLI_path_join(path_full, sizeof(path_full), path, de->d_name);
BLI_delete(path_full, false, false);
if (pid->cache->cached_frames && frame >= sta && frame <= end) {
pid->cache->cached_frames[frame - sta] = 0;
@@ -2775,7 +2775,7 @@ void BKE_ptcache_id_time(
/* time handling for point cache:
* - simulation time is scaled by result of bsystem_time
* - for offsetting time only time offset is taken into account, since
- * that's always the same and can't be animated. a timeoffset which
+ * that's always the same and can't be animated. a time-offset which
* varies over time is not simple to support.
* - field and motion blur offsets are currently ignored, proper solution
* is probably to interpolate results from two frames for that ..
@@ -3524,7 +3524,7 @@ void BKE_ptcache_disk_cache_rename(PTCacheID *pid, const char *name_src, const c
const int frame = ptcache_frame_from_filename(de->d_name, ext);
if (frame != -1) {
- BLI_join_dirfile(old_path_full, sizeof(old_path_full), path, de->d_name);
+ BLI_path_join(old_path_full, sizeof(old_path_full), path, de->d_name);
ptcache_filepath(pid, new_path_full, frame, true, true);
BLI_rename(old_path_full, new_path_full);
}
diff --git a/source/blender/blenkernel/intern/preferences.c b/source/blender/blenkernel/intern/preferences.c
index b2e795901fb..dd76f9eddc1 100644
--- a/source/blender/blenkernel/intern/preferences.c
+++ b/source/blender/blenkernel/intern/preferences.c
@@ -115,8 +115,7 @@ void BKE_preferences_asset_library_default_add(UserDef *userdef)
userdef, DATA_(BKE_PREFS_ASSET_LIBRARY_DEFAULT_NAME), NULL);
/* Add new "Default" library under '[doc_path]/Blender/Assets'. */
- BLI_path_join(
- library->path, sizeof(library->path), documents_path, N_("Blender"), N_("Assets"), NULL);
+ BLI_path_join(library->path, sizeof(library->path), documents_path, N_("Blender"), N_("Assets"));
}
/** \} */
diff --git a/source/blender/blenkernel/intern/rigidbody.c b/source/blender/blenkernel/intern/rigidbody.c
index ffc6bc8d7a3..5e91b23bce3 100644
--- a/source/blender/blenkernel/intern/rigidbody.c
+++ b/source/blender/blenkernel/intern/rigidbody.c
@@ -264,13 +264,13 @@ static RigidBodyCon *rigidbody_copy_constraint(const Object *ob, const int UNUSE
RigidBodyCon *rbcN = NULL;
if (ob->rigidbody_constraint) {
- /* just duplicate the whole struct first (to catch all the settings) */
+ /* Just duplicate the whole struct first (to catch all the settings). */
rbcN = MEM_dupallocN(ob->rigidbody_constraint);
- /* tag object as needing to be verified */
+ /* Tag object as needing to be verified. */
rbcN->flag |= RBC_FLAG_NEEDS_VALIDATE;
- /* clear out all the fields which need to be revalidated later */
+ /* Clear out all the fields which need to be re-validated later. */
rbcN->physics_constraint = NULL;
}
@@ -684,7 +684,7 @@ void BKE_rigidbody_calc_volume(Object *ob, float *r_vol)
if (totvert > 0 && tottri > 0) {
BKE_mesh_calc_volume(mvert, totvert, lt, tottri, mloop, &volume, NULL);
- const float volume_scale = mat4_to_volume_scale(ob->obmat);
+ const float volume_scale = mat4_to_volume_scale(ob->object_to_world);
volume *= fabsf(volume_scale);
}
}
@@ -809,7 +809,7 @@ static void rigidbody_validate_sim_object(RigidBodyWorld *rbw, Object *ob, bool
return;
}
- mat4_to_loc_quat(loc, rot, ob->obmat);
+ mat4_to_loc_quat(loc, rot, ob->object_to_world);
rbo->shared->physics_object = RB_body_new(rbo->shared->physics_shape, loc, rot);
@@ -974,7 +974,7 @@ static void rigidbody_validate_sim_constraint(RigidBodyWorld *rbw, Object *ob, b
rbc->physics_constraint = NULL;
}
- mat4_to_loc_quat(loc, rot, ob->obmat);
+ mat4_to_loc_quat(loc, rot, ob->object_to_world);
if (rb1 && rb2) {
switch (rbc->type) {
@@ -1266,7 +1266,7 @@ RigidBodyOb *BKE_rigidbody_create_object(Scene *scene, Object *ob, short type)
rbo->mesh_source = RBO_MESH_DEFORM;
/* set initial transform */
- mat4_to_loc_quat(rbo->pos, rbo->orn, ob->obmat);
+ mat4_to_loc_quat(rbo->pos, rbo->orn, ob->object_to_world);
/* flag cache as outdated */
BKE_rigidbody_cache_reset(rbw);
@@ -1689,7 +1689,7 @@ static void rigidbody_update_sim_ob(Depsgraph *depsgraph, Object *ob, RigidBodyO
if (!(rbo->flag & RBO_FLAG_KINEMATIC)) {
/* update scale for all non kinematic objects */
float new_scale[3], old_scale[3];
- mat4_to_size(new_scale, ob->obmat);
+ mat4_to_size(new_scale, ob->object_to_world);
RB_body_get_scale(rbo->shared->physics_object, old_scale);
/* Avoid updating collision shape AABBs if scale didn't change. */
@@ -1886,7 +1886,7 @@ static ListBase rigidbody_create_substep_data(RigidBodyWorld *rbw)
copy_v4_v4(data->old_rot, rot);
copy_v3_v3(data->old_scale, scale);
- mat4_decompose(loc, rot, scale, ob->obmat);
+ mat4_decompose(loc, rot, scale, ob->object_to_world);
copy_v3_v3(data->new_pos, loc);
copy_v4_v4(data->new_rot, rot);
@@ -2055,15 +2055,15 @@ void BKE_rigidbody_sync_transforms(RigidBodyWorld *rbw, Object *ob, float ctime)
quat_to_mat4(mat, rbo->orn);
copy_v3_v3(mat[3], rbo->pos);
- mat4_to_size(size, ob->obmat);
+ mat4_to_size(size, ob->object_to_world);
size_to_mat4(size_mat, size);
mul_m4_m4m4(mat, mat, size_mat);
- copy_m4_m4(ob->obmat, mat);
+ copy_m4_m4(ob->object_to_world, mat);
}
/* otherwise set rigid body transform to current obmat */
else {
- mat4_to_loc_quat(rbo->pos, rbo->orn, ob->obmat);
+ mat4_to_loc_quat(rbo->pos, rbo->orn, ob->object_to_world);
}
}
diff --git a/source/blender/blenkernel/intern/scene.cc b/source/blender/blenkernel/intern/scene.cc
index fc47fb71bf3..c921cf603de 100644
--- a/source/blender/blenkernel/intern/scene.cc
+++ b/source/blender/blenkernel/intern/scene.cc
@@ -280,6 +280,9 @@ static void scene_copy_data(Main *bmain, ID *id_dst, const ID *id_src, const int
}
/* View Layers */
+ LISTBASE_FOREACH (ViewLayer *, view_layer, &scene_src->view_layers) {
+ BKE_view_layer_synced_ensure(scene_src, view_layer);
+ }
BLI_duplicatelist(&scene_dst->view_layers, &scene_src->view_layers);
for (ViewLayer *view_layer_src = static_cast<ViewLayer *>(scene_src->view_layers.first),
*view_layer_dst = static_cast<ViewLayer *>(scene_dst->view_layers.first);
@@ -2275,13 +2278,13 @@ int BKE_scene_base_iter_next(
if (iter->dupli_refob != *ob) {
if (iter->dupli_refob) {
/* Restore previous object's real matrix. */
- copy_m4_m4(iter->dupli_refob->obmat, iter->omat);
+ copy_m4_m4(iter->dupli_refob->object_to_world, iter->omat);
}
/* Backup new object's real matrix. */
iter->dupli_refob = *ob;
- copy_m4_m4(iter->omat, iter->dupli_refob->obmat);
+ copy_m4_m4(iter->omat, iter->dupli_refob->object_to_world);
}
- copy_m4_m4((*ob)->obmat, iter->dupob->mat);
+ copy_m4_m4((*ob)->object_to_world, iter->dupob->mat);
iter->dupob = iter->dupob->next;
}
@@ -2291,7 +2294,7 @@ int BKE_scene_base_iter_next(
if (iter->dupli_refob) {
/* Restore last object's real matrix. */
- copy_m4_m4(iter->dupli_refob->obmat, iter->omat);
+ copy_m4_m4(iter->dupli_refob->object_to_world, iter->omat);
iter->dupli_refob = nullptr;
}
diff --git a/source/blender/blenkernel/intern/screen.c b/source/blender/blenkernel/intern/screen.c
index 3e5dbc47c40..2c896788b20 100644
--- a/source/blender/blenkernel/intern/screen.c
+++ b/source/blender/blenkernel/intern/screen.c
@@ -304,7 +304,7 @@ IDTypeInfo IDType_ID_SCR = {
/* ************ Space-type/region-type handling ************** */
-/* keep global; this has to be accessible outside of windowmanager */
+/** Keep global; this has to be accessible outside of window-manager. */
static ListBase spacetypes = {NULL, NULL};
/* not SpaceType itself */
diff --git a/source/blender/blenkernel/intern/softbody.c b/source/blender/blenkernel/intern/softbody.c
index 14a7d26a354..4147999bef8 100644
--- a/source/blender/blenkernel/intern/softbody.c
+++ b/source/blender/blenkernel/intern/softbody.c
@@ -133,9 +133,9 @@ typedef struct SB_thread_context {
#define BSF_INTERSECT 1 /* edge intersects collider face */
-/* private definitions for bodypoint states */
-#define SBF_DOFUZZY 1 /* Bodypoint do fuzzy. */
-#define SBF_OUTOFCOLLISION 2 /* Bodypoint does not collide. */
+/* private definitions for body-point states */
+#define SBF_DOFUZZY 1 /* Body-point do fuzzy. */
+#define SBF_OUTOFCOLLISION 2 /* Body-point does not collide. */
#define BFF_INTERSECT 1 /* collider edge intrudes face. */
#define BFF_CLOSEVERT 2 /* collider vertex repulses face. */
@@ -318,7 +318,7 @@ static ccd_Mesh *ccd_mesh_make(Object *ob)
/* OBBs for idea1 */
pccd_M->mima = MEM_mallocN(sizeof(ccdf_minmax) * pccd_M->tri_num, "ccd_Mesh_Faces_mima");
- /* anyhoo we need to walk the list of faces and find OBB they live in */
+ /* Anyhow we need to walk the list of faces and find OBB they live in. */
for (i = 0, mima = pccd_M->mima, vt = pccd_M->tri; i < pccd_M->tri_num; i++, mima++, vt++) {
const float *v;
@@ -413,7 +413,7 @@ static void ccd_mesh_update(Object *ob, ccd_Mesh *pccd_M)
pccd_M->bbmax[2] = max_ff(pccd_M->bbmax[2], v[2] + hull);
}
- /* anyhoo we need to walk the list of faces and find OBB they live in */
+ /* Anyhow we need to walk the list of faces and find OBB they live in. */
for (i = 0, mima = pccd_M->mima, vt = pccd_M->tri; i < pccd_M->tri_num; i++, mima++, vt++) {
const float *v;
@@ -2644,7 +2644,7 @@ static void springs_from_mesh(Object *ob)
bp = ob->soft->bpoint;
for (a = 0; a < me->totvert; a++, bp++) {
copy_v3_v3(bp->origS, verts[a].co);
- mul_m4_v3(ob->obmat, bp->origS);
+ mul_m4_v3(ob->object_to_world, bp->origS);
}
}
/* recalculate spring length for meshes here */
@@ -2809,9 +2809,9 @@ static float globallen(float *v1, float *v2, Object *ob)
{
float p1[3], p2[3];
copy_v3_v3(p1, v1);
- mul_m4_v3(ob->obmat, p1);
+ mul_m4_v3(ob->object_to_world, p1);
copy_v3_v3(p2, v2);
- mul_m4_v3(ob->obmat, p2);
+ mul_m4_v3(ob->object_to_world, p2);
return len_v3v3(p1, p2);
}
@@ -3073,7 +3073,7 @@ static void softbody_to_object(Object *ob, float (*vertexCos)[3], int numVerts,
SB_estimate_transform(ob, sb->lcom, sb->lrot, sb->lscale);
}
/* Inverse matrix is not up to date. */
- invert_m4_m4(ob->imat, ob->obmat);
+ invert_m4_m4(ob->imat, ob->object_to_world);
for (a = 0; a < numVerts; a++, bp++) {
copy_v3_v3(vertexCos[a], bp->pos);
@@ -3223,7 +3223,7 @@ static void softbody_update_positions(Object *ob,
/* copy the position of the goals at desired end time */
copy_v3_v3(bp->origE, vertexCos[a]);
/* vertexCos came from local world, go global */
- mul_m4_v3(ob->obmat, bp->origE);
+ mul_m4_v3(ob->object_to_world, bp->origE);
/* just to be save give bp->origT a defined value
* will be calculated in interpolate_exciter() */
copy_v3_v3(bp->origT, bp->origE);
@@ -3279,7 +3279,7 @@ static void softbody_reset(Object *ob, SoftBody *sb, float (*vertexCos)[3], int
for (a = 0, bp = sb->bpoint; a < numVerts; a++, bp++) {
copy_v3_v3(bp->pos, vertexCos[a]);
- mul_m4_v3(ob->obmat, bp->pos); /* Yep, soft-body is global coords. */
+ mul_m4_v3(ob->object_to_world, bp->pos); /* Yep, soft-body is global coords. */
copy_v3_v3(bp->origS, bp->pos);
copy_v3_v3(bp->origE, bp->pos);
copy_v3_v3(bp->origT, bp->pos);
diff --git a/source/blender/blenkernel/intern/sound.c b/source/blender/blenkernel/intern/sound.c
index d08fba0e657..1aef42ef037 100644
--- a/source/blender/blenkernel/intern/sound.c
+++ b/source/blender/blenkernel/intern/sound.c
@@ -1129,9 +1129,9 @@ static void sound_update_base(Scene *scene, Object *object, void *new_set)
AUD_SequenceEntry_setConeAngleInner(strip->speaker_handle, speaker->cone_angle_inner);
AUD_SequenceEntry_setConeVolumeOuter(strip->speaker_handle, speaker->cone_volume_outer);
- mat4_to_quat(quat, object->obmat);
+ mat4_to_quat(quat, object->object_to_world);
AUD_SequenceEntry_setAnimationData(
- strip->speaker_handle, AUD_AP_LOCATION, scene->r.cfra, object->obmat[3], 1);
+ strip->speaker_handle, AUD_AP_LOCATION, scene->r.cfra, object->object_to_world[3], 1);
AUD_SequenceEntry_setAnimationData(
strip->speaker_handle, AUD_AP_ORIENTATION, scene->r.cfra, quat, 1);
AUD_SequenceEntry_setAnimationData(
@@ -1171,9 +1171,9 @@ void BKE_sound_update_scene(Depsgraph *depsgraph, Scene *scene)
}
if (scene->camera) {
- mat4_to_quat(quat, scene->camera->obmat);
+ mat4_to_quat(quat, scene->camera->object_to_world);
AUD_Sequence_setAnimationData(
- scene->sound_scene, AUD_AP_LOCATION, scene->r.cfra, scene->camera->obmat[3], 1);
+ scene->sound_scene, AUD_AP_LOCATION, scene->r.cfra, scene->camera->object_to_world[3], 1);
AUD_Sequence_setAnimationData(scene->sound_scene, AUD_AP_ORIENTATION, scene->r.cfra, quat, 1);
}
diff --git a/source/blender/blenkernel/intern/unit.c b/source/blender/blenkernel/intern/unit.c
index f7ea4c81fbf..f5badfc9e94 100644
--- a/source/blender/blenkernel/intern/unit.c
+++ b/source/blender/blenkernel/intern/unit.c
@@ -715,7 +715,7 @@ static const char *unit_find_str(const char *str, const char *substr, bool case_
/* Weak unicode support!, so "µm" won't match up be replaced by "m"
* since non ascii utf8 values will NEVER return true */
isalpha_or_utf8(*BLI_str_find_prev_char_utf8(str_found, str)) == 0) {
- /* Next char cannot be alphanum. */
+ /* Next char cannot be alpha-numeric. */
int len_name = strlen(substr);
if (!isalpha_or_utf8(*(str_found + len_name))) {
diff --git a/source/blender/blenkernel/intern/vfont.c b/source/blender/blenkernel/intern/vfont.c
index 7ace1a3aa3b..9f48b9b9c4a 100644
--- a/source/blender/blenkernel/intern/vfont.c
+++ b/source/blender/blenkernel/intern/vfont.c
@@ -1310,14 +1310,14 @@ static bool vfont_to_curve(Object *ob,
float timeofs, sizefac;
if (ob != NULL) {
- invert_m4_m4(imat, ob->obmat);
+ invert_m4_m4(imat, ob->object_to_world);
}
else {
unit_m4(imat);
}
copy_m3_m4(imat3, imat);
- copy_m3_m4(cmat, cu->textoncurve->obmat);
+ copy_m3_m4(cmat, cu->textoncurve->object_to_world);
mul_m3_m3m3(cmat, cmat, imat3);
sizefac = normalize_v3(cmat[0]) / font_size;
diff --git a/source/blender/blenkernel/intern/volume.cc b/source/blender/blenkernel/intern/volume.cc
index 7c54b4d3f2f..e81657f9ef0 100644
--- a/source/blender/blenkernel/intern/volume.cc
+++ b/source/blender/blenkernel/intern/volume.cc
@@ -445,7 +445,7 @@ struct VolumeGrid {
* may actually be loaded by another user while this is false. But only after
* calling load() and is_loaded changes to true is it safe to access.
*
- * Const write access to this must be protected by `entry->mutex`.
+ * `const` write access to this must be protected by `entry->mutex`.
*/
mutable bool is_loaded;
};
@@ -480,7 +480,7 @@ struct VolumeGridVector : public std::list<VolumeGrid> {
metadata.reset();
}
- /* Mutex for file loading of grids list. Const write access to the fields after this must be
+ /* Mutex for file loading of grids list. `const` write access to the fields after this must be
* protected by locking with this mutex. */
mutable std::mutex mutex;
/* Absolute file path that grids have been loaded from. */
diff --git a/source/blender/blenkernel/intern/writeavi.c b/source/blender/blenkernel/intern/writeavi.c
index dbdf8cc395d..de2e196c163 100644
--- a/source/blender/blenkernel/intern/writeavi.c
+++ b/source/blender/blenkernel/intern/writeavi.c
@@ -122,7 +122,8 @@ bMovieHandle *BKE_movie_handle_get(const char imtype)
R_IMF_IMTYPE_FFMPEG,
R_IMF_IMTYPE_H264,
R_IMF_IMTYPE_XVID,
- R_IMF_IMTYPE_THEORA)) {
+ R_IMF_IMTYPE_THEORA,
+ R_IMF_IMTYPE_AV1)) {
mh.start_movie = BKE_ffmpeg_start;
mh.append_movie = BKE_ffmpeg_append;
mh.end_movie = BKE_ffmpeg_end;
diff --git a/source/blender/blenkernel/intern/writeffmpeg.c b/source/blender/blenkernel/intern/writeffmpeg.c
index 99df07b6105..ee827cd8cd4 100644
--- a/source/blender/blenkernel/intern/writeffmpeg.c
+++ b/source/blender/blenkernel/intern/writeffmpeg.c
@@ -299,6 +299,10 @@ static const char **get_file_extensions(int format)
static const char *rv[] = {".webm", NULL};
return rv;
}
+ case FFMPEG_AV1: {
+ static const char *rv[] = {".mp4", ".mkv", NULL};
+ return rv;
+ }
default:
return NULL;
}
@@ -455,6 +459,204 @@ static AVRational calc_time_base(uint den, double num, int codec_id)
return time_base;
}
+static const AVCodec *get_av1_encoder(
+ FFMpegContext *context, RenderData *rd, AVDictionary **opts, int rectx, int recty)
+{
+ /* There are three possible encoders for AV1: libaom-av1, librav1e, and libsvtav1. librav1e tends
+ * to give the best compression quality while libsvtav1 tends to be the fastest encoder. One of
+ * each will be picked based on the preset setting, and if a particular encoder is not available,
+ * then use the default returned by FFMpeg. */
+ const AVCodec *codec = NULL;
+ switch (context->ffmpeg_preset) {
+ case FFM_PRESET_BEST:
+ /* Default to libaom-av1 for BEST preset due to it performing better than rav1e in terms of
+ * video quality (VMAF scores). Fallback to rav1e if libaom-av1 isn't available. */
+ codec = avcodec_find_encoder_by_name("libaom-av1");
+ if (!codec) {
+ codec = avcodec_find_encoder_by_name("librav1e");
+ }
+ break;
+ case FFM_PRESET_REALTIME:
+ codec = avcodec_find_encoder_by_name("libsvtav1");
+ break;
+ case FFM_PRESET_GOOD:
+ default:
+ codec = avcodec_find_encoder_by_name("libaom-av1");
+ break;
+ }
+
+ /* Use the default AV1 encoder if the specified encoder wasn't found. */
+ if (!codec) {
+ codec = avcodec_find_encoder(AV_CODEC_ID_AV1);
+ }
+
+ /* Apply AV1 encoder specific settings. */
+ if (codec) {
+ if (STREQ(codec->name, "librav1e")) {
+ /* Set "tiles" to 8 to enable multi-threaded encoding. */
+ if (rd->threads > 8) {
+ ffmpeg_dict_set_int(opts, "tiles", rd->threads);
+ }
+ else {
+ ffmpeg_dict_set_int(opts, "tiles", 8);
+ }
+
+ /* Use a reasonable speed setting based on preset. Speed ranges from 0-10.
+ * Must check context->ffmpeg_preset again in case this encoder was selected due to the
+ * absence of another. */
+ switch (context->ffmpeg_preset) {
+ case FFM_PRESET_BEST:
+ ffmpeg_dict_set_int(opts, "speed", 4);
+ break;
+ case FFM_PRESET_REALTIME:
+ ffmpeg_dict_set_int(opts, "speed", 10);
+ break;
+ case FFM_PRESET_GOOD:
+ default:
+ ffmpeg_dict_set_int(opts, "speed", 6);
+ break;
+ }
+ if (context->ffmpeg_crf >= 0) {
+ /* librav1e does not use -crf, but uses -qp in the range of 0-255. Calculates the roughly
+ * equivalent float, and truncates it to an integer. */
+ unsigned int qp_value = ((float)context->ffmpeg_crf) * 255.0F / 51.0F;
+ if (qp_value > 255) {
+ qp_value = 255;
+ }
+ ffmpeg_dict_set_int(opts, "qp", qp_value);
+ }
+ /* Set gop_size as rav1e's "--keyint". */
+ char buffer[64];
+ BLI_snprintf(buffer, sizeof(buffer), "keyint=%d", context->ffmpeg_gop_size);
+ av_dict_set(opts, "rav1e-params", buffer, 0);
+ }
+ else if (STREQ(codec->name, "libsvtav1")) {
+ /* Set preset value based on ffmpeg_preset.
+ * Must check context->ffmpeg_preset again in case this encoder was selected due to the
+ * absence of another. */
+ switch (context->ffmpeg_preset) {
+ case FFM_PRESET_REALTIME:
+ ffmpeg_dict_set_int(opts, "preset", 8);
+ break;
+ case FFM_PRESET_BEST:
+ ffmpeg_dict_set_int(opts, "preset", 3);
+ break;
+ case FFM_PRESET_GOOD:
+ default:
+ ffmpeg_dict_set_int(opts, "preset", 5);
+ break;
+ }
+ if (context->ffmpeg_crf >= 0) {
+ /* libsvtav1 does not support crf until FFmpeg builds since 2022-02-24, use qp as fallback.
+ */
+ ffmpeg_dict_set_int(opts, "qp", context->ffmpeg_crf);
+ }
+ }
+ else if (STREQ(codec->name, "libaom-av1")) {
+ /* Speed up libaom-av1 encoding by enabling multithreading and setting tiles. */
+ ffmpeg_dict_set_int(opts, "row-mt", 1);
+ const char *tiles_string = NULL;
+ bool tiles_string_is_dynamic = false;
+ if (rd->threads > 0) {
+ /* See if threads is a square. */
+ int threads_sqrt = sqrtf(rd->threads);
+ if (threads_sqrt < 4) {
+ /* Ensure a default minimum. */
+ threads_sqrt = 4;
+ }
+ if (is_power_of_2_i(threads_sqrt) && threads_sqrt * threads_sqrt == rd->threads) {
+ /* Is a square num, therefore just do "sqrt x sqrt" for tiles parameter. */
+ int digits = 0;
+ for (int t_sqrt_copy = threads_sqrt; t_sqrt_copy > 0; t_sqrt_copy /= 10) {
+ ++digits;
+ }
+ /* A char array need only an alignment of 1. */
+ char *tiles_string_mut = (char *)calloc(digits * 2 + 2, 1);
+ BLI_snprintf(tiles_string_mut, digits * 2 + 2, "%dx%d", threads_sqrt, threads_sqrt);
+ tiles_string_is_dynamic = true;
+ tiles_string = tiles_string_mut;
+ }
+ else {
+ /* Is not a square num, set greater side based on longer side, or use a square if both
+ sides are equal. */
+ int sqrt_p2 = power_of_2_min_i(threads_sqrt);
+ if (sqrt_p2 < 2) {
+ /* Ensure a default minimum. */
+ sqrt_p2 = 2;
+ }
+ int sqrt_p2_next = power_of_2_min_i((int)rd->threads / sqrt_p2);
+ if (sqrt_p2_next < 1) {
+ sqrt_p2_next = 1;
+ }
+ if (sqrt_p2 > sqrt_p2_next) {
+ /* Ensure sqrt_p2_next is greater or equal to sqrt_p2. */
+ int temp = sqrt_p2;
+ sqrt_p2 = sqrt_p2_next;
+ sqrt_p2_next = temp;
+ }
+ int combined_digits = 0;
+ for (int sqrt_p2_copy = sqrt_p2; sqrt_p2_copy > 0; sqrt_p2_copy /= 10) {
+ ++combined_digits;
+ }
+ for (int sqrt_p2_copy = sqrt_p2_next; sqrt_p2_copy > 0; sqrt_p2_copy /= 10) {
+ ++combined_digits;
+ }
+ /* A char array need only an alignment of 1. */
+ char *tiles_string_mut = (char *)calloc(combined_digits + 2, 1);
+ if (rectx > recty) {
+ BLI_snprintf(tiles_string_mut, combined_digits + 2, "%dx%d", sqrt_p2_next, sqrt_p2);
+ }
+ else if (rectx < recty) {
+ BLI_snprintf(tiles_string_mut, combined_digits + 2, "%dx%d", sqrt_p2, sqrt_p2_next);
+ }
+ else {
+ BLI_snprintf(tiles_string_mut, combined_digits + 2, "%dx%d", sqrt_p2, sqrt_p2);
+ }
+ tiles_string_is_dynamic = true;
+ tiles_string = tiles_string_mut;
+ }
+ }
+ else {
+ /* Thread count unknown, default to 8. */
+ if (rectx > recty) {
+ tiles_string = "4x2";
+ }
+ else if (rectx < recty) {
+ tiles_string = "2x4";
+ }
+ else {
+ tiles_string = "2x2";
+ }
+ }
+ av_dict_set(opts, "tiles", tiles_string, 0);
+ if (tiles_string_is_dynamic) {
+ free((void *)tiles_string);
+ }
+ /* libaom-av1 uses "cpu-used" instead of "preset" for defining compression quality.
+ * This value is in a range from 0-8. 0 and 8 are extremes, but we will allow 8.
+ * Must check context->ffmpeg_preset again in case this encoder was selected due to the
+ * absence of another. */
+ switch (context->ffmpeg_preset) {
+ case FFM_PRESET_REALTIME:
+ ffmpeg_dict_set_int(opts, "cpu-used", 8);
+ break;
+ case FFM_PRESET_BEST:
+ ffmpeg_dict_set_int(opts, "cpu-used", 4);
+ break;
+ case FFM_PRESET_GOOD:
+ default:
+ ffmpeg_dict_set_int(opts, "cpu-used", 6);
+ break;
+ }
+
+ /* CRF related settings is similar to H264 for libaom-av1, so we will rely on those settings
+ * applied later. */
+ }
+ }
+
+ return codec;
+}
+
/* prepare a video stream for the output file */
static AVStream *alloc_video_stream(FFMpegContext *context,
@@ -480,7 +682,14 @@ static AVStream *alloc_video_stream(FFMpegContext *context,
/* Set up the codec context */
- codec = avcodec_find_encoder(codec_id);
+ if (codec_id == AV_CODEC_ID_AV1) {
+ /* Use get_av1_encoder() to get the ideal (hopefully) encoder for AV1 based
+ * on given parameters, and also set up opts. */
+ codec = get_av1_encoder(context, rd, &opts, rectx, recty);
+ }
+ else {
+ codec = avcodec_find_encoder(codec_id);
+ }
if (!codec) {
fprintf(stderr, "Couldn't find valid video codec\n");
context->video_codec = NULL;
@@ -568,7 +777,9 @@ static AVStream *alloc_video_stream(FFMpegContext *context,
default:
printf("Unknown preset number %i, ignoring.\n", context->ffmpeg_preset);
}
- if (preset_name != NULL) {
+ /* "codec_id != AV_CODEC_ID_AV1" is required due to "preset" already being set by an AV1 codec.
+ */
+ if (preset_name != NULL && codec_id != AV_CODEC_ID_AV1) {
av_dict_set(&opts, "preset", preset_name, 0);
}
if (deadline_name != NULL) {
@@ -806,7 +1017,7 @@ static AVStream *alloc_audio_stream(FFMpegContext *context,
return NULL;
}
- /* need to prevent floating point exception when using vorbis audio codec,
+ /* Need to prevent floating point exception when using VORBIS audio codec,
* initialize this value in the same way as it's done in FFmpeg itself (sergey) */
c->time_base.num = 1;
c->time_base.den = c->sample_rate;
@@ -951,6 +1162,9 @@ static int start_ffmpeg_impl(FFMpegContext *context,
case FFMPEG_FLV:
video_codec = AV_CODEC_ID_FLV1;
break;
+ case FFMPEG_AV1:
+ video_codec = AV_CODEC_ID_AV1;
+ break;
default:
/* These containers are not restricted to any specific codec types.
* Currently we expect these to be .avi, .mov, .mkv, and .mp4.
@@ -1482,6 +1696,18 @@ void BKE_ffmpeg_preset_set(RenderData *rd, int preset)
rd->ffcodecdata.mux_packet_size = 2048;
rd->ffcodecdata.mux_rate = 10080000;
break;
+ case FFMPEG_PRESET_AV1:
+ rd->ffcodecdata.type = FFMPEG_AV1;
+ rd->ffcodecdata.codec = AV_CODEC_ID_AV1;
+ rd->ffcodecdata.video_bitrate = 6000;
+ rd->ffcodecdata.gop_size = is_ntsc ? 18 : 15;
+ rd->ffcodecdata.rc_max_rate = 9000;
+ rd->ffcodecdata.rc_min_rate = 0;
+ rd->ffcodecdata.rc_buffer_size = 224 * 8;
+ rd->ffcodecdata.mux_packet_size = 2048;
+ rd->ffcodecdata.mux_rate = 10080000;
+
+ break;
}
}
@@ -1521,6 +1747,12 @@ void BKE_ffmpeg_image_type_verify(RenderData *rd, const ImageFormatData *imf)
audio = 1;
}
}
+ else if (imf->imtype == R_IMF_IMTYPE_AV1) {
+ if (rd->ffcodecdata.codec != AV_CODEC_ID_AV1) {
+ BKE_ffmpeg_preset_set(rd, FFMPEG_PRESET_AV1);
+ audio = 1;
+ }
+ }
if (audio && rd->ffcodecdata.audio_codec < 0) {
rd->ffcodecdata.audio_codec = AV_CODEC_ID_NONE;