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/DerivedMesh.c13
-rw-r--r--source/blender/blenkernel/intern/appdir.c178
-rw-r--r--source/blender/blenkernel/intern/armature.c14
-rw-r--r--source/blender/blenkernel/intern/blender.c122
-rw-r--r--source/blender/blenkernel/intern/blender_undo.c6
-rw-r--r--source/blender/blenkernel/intern/blendfile.c90
-rw-r--r--source/blender/blenkernel/intern/bvhutils.c417
-rw-r--r--source/blender/blenkernel/intern/cdderivedmesh.c46
-rw-r--r--source/blender/blenkernel/intern/cloth.c37
-rw-r--r--source/blender/blenkernel/intern/colortools.c2
-rw-r--r--source/blender/blenkernel/intern/curve.c23
-rw-r--r--source/blender/blenkernel/intern/customdata.c57
-rw-r--r--source/blender/blenkernel/intern/depsgraph.c16
-rw-r--r--source/blender/blenkernel/intern/displist.c2
-rw-r--r--source/blender/blenkernel/intern/dynamicpaint.c6
-rw-r--r--source/blender/blenkernel/intern/editderivedmesh.c8
-rw-r--r--source/blender/blenkernel/intern/effect.c8
-rw-r--r--source/blender/blenkernel/intern/fcurve.c146
-rw-r--r--source/blender/blenkernel/intern/idprop.c14
-rw-r--r--source/blender/blenkernel/intern/image.c8
-rw-r--r--source/blender/blenkernel/intern/lattice.c2
-rw-r--r--source/blender/blenkernel/intern/library.c2
-rw-r--r--source/blender/blenkernel/intern/library_remap.c3
-rw-r--r--source/blender/blenkernel/intern/mesh.c405
-rw-r--r--source/blender/blenkernel/intern/mesh_evaluate.c380
-rw-r--r--source/blender/blenkernel/intern/object.c60
-rw-r--r--source/blender/blenkernel/intern/object_update.c7
-rw-r--r--source/blender/blenkernel/intern/particle.c5
-rw-r--r--source/blender/blenkernel/intern/scene.c21
-rw-r--r--source/blender/blenkernel/intern/sequencer.c89
-rw-r--r--source/blender/blenkernel/intern/text.c16
-rw-r--r--source/blender/blenkernel/intern/texture.c15
-rw-r--r--source/blender/blenkernel/intern/tracking_stabilize.c13
-rw-r--r--source/blender/blenkernel/intern/writeffmpeg.c7
34 files changed, 1367 insertions, 871 deletions
diff --git a/source/blender/blenkernel/intern/DerivedMesh.c b/source/blender/blenkernel/intern/DerivedMesh.c
index 160adcc3988..8b7329cf940 100644
--- a/source/blender/blenkernel/intern/DerivedMesh.c
+++ b/source/blender/blenkernel/intern/DerivedMesh.c
@@ -2912,9 +2912,6 @@ DerivedMesh *editbmesh_get_derived_base(Object *obedit, BMEditMesh *em, CustomDa
/* get derived mesh from an object, using editbmesh if available. */
DerivedMesh *object_get_derived_final(Object *ob, const bool for_render)
{
- Mesh *me = ob->data;
- BMEditMesh *em = me->edit_btmesh;
-
if (for_render) {
/* TODO(sergey): use proper derived render here in the future. */
return ob->derivedFinal;
@@ -2922,9 +2919,13 @@ DerivedMesh *object_get_derived_final(Object *ob, const bool for_render)
/* only return the editmesh if its from this object because
* we don't a mesh from another object's modifier stack: T43122 */
- if (em && (em->ob == ob)) {
- DerivedMesh *dm = em->derivedFinal;
- return dm;
+ if (ob->type == OB_MESH) {
+ Mesh *me = ob->data;
+ BMEditMesh *em = me->edit_btmesh;
+ if (em && (em->ob == ob)) {
+ DerivedMesh *dm = em->derivedFinal;
+ return dm;
+ }
}
return ob->derivedFinal;
diff --git a/source/blender/blenkernel/intern/appdir.c b/source/blender/blenkernel/intern/appdir.c
index b1dcc40279f..43fd47981b1 100644
--- a/source/blender/blenkernel/intern/appdir.c
+++ b/source/blender/blenkernel/intern/appdir.c
@@ -114,18 +114,26 @@ static char *blender_version_decimal(const int ver)
* Concatenates path_base, (optional) path_sep and (optional) folder_name into targetpath,
* returning true if result points to a directory.
*/
-static bool test_path(char *targetpath, const char *path_base, const char *path_sep, const char *folder_name)
+static bool test_path(
+ char *targetpath, size_t targetpath_len,
+ const char *path_base, const char *path_sep, const char *folder_name)
{
char tmppath[FILE_MAX];
- if (path_sep) BLI_join_dirfile(tmppath, sizeof(tmppath), path_base, path_sep);
- else BLI_strncpy(tmppath, path_base, sizeof(tmppath));
-
- /* rare cases folder_name is omitted (when looking for ~/.blender/2.xx dir only) */
- if (folder_name)
- BLI_make_file_string("/", targetpath, tmppath, folder_name);
- else
- BLI_strncpy(targetpath, tmppath, sizeof(tmppath));
+ if (path_sep) {
+ BLI_join_dirfile(tmppath, sizeof(tmppath), path_base, path_sep);
+ }
+ else {
+ BLI_strncpy(tmppath, path_base, sizeof(tmppath));
+ }
+
+ /* rare cases folder_name is omitted (when looking for ~/.config/blender/2.xx dir only) */
+ if (folder_name) {
+ BLI_join_dirfile(targetpath, targetpath_len, tmppath, folder_name);
+ }
+ else {
+ BLI_strncpy(targetpath, tmppath, targetpath_len);
+ }
/* FIXME: why is "//" on front of tmppath expanded to "/" (by BLI_join_dirfile)
* if folder_name is specified but not otherwise? */
@@ -179,7 +187,9 @@ static bool test_env_path(char *path, const char *envvar)
* \param ver To construct name of version-specific directory within bprogdir
* \return true if such a directory exists.
*/
-static bool get_path_local(char *targetpath, const char *folder_name, const char *subfolder_name, const int ver)
+static bool get_path_local(
+ char *targetpath, size_t targetpath_len,
+ const char *folder_name, const char *subfolder_name, const int ver)
{
char relfolder[FILE_MAX];
@@ -201,11 +211,12 @@ static bool get_path_local(char *targetpath, const char *folder_name, const char
/* try EXECUTABLE_DIR/2.5x/folder_name - new default directory for local blender installed files */
#ifdef __APPLE__
- static char osx_resourses[FILE_MAX]; /* due new codesign situation in OSX > 10.9.5 we must move the blender_version dir with contents to Resources */
+ /* due new codesign situation in OSX > 10.9.5 we must move the blender_version dir with contents to Resources */
+ static char osx_resourses[FILE_MAX];
sprintf(osx_resourses, "%s../Resources", bprogdir);
- return test_path(targetpath, osx_resourses, blender_version_decimal(ver), relfolder);
+ return test_path(targetpath, targetpath_len, osx_resourses, blender_version_decimal(ver), relfolder);
#else
- return test_path(targetpath, bprogdir, blender_version_decimal(ver), relfolder);
+ return test_path(targetpath, targetpath_len, bprogdir, blender_version_decimal(ver), relfolder);
#endif
}
@@ -219,7 +230,7 @@ static bool is_portable_install(void)
const int ver = BLENDER_VERSION;
char path[FILE_MAX];
- return get_path_local(path, "config", NULL, ver);
+ return get_path_local(path, sizeof(path), "config", NULL, ver);
}
/**
@@ -233,20 +244,22 @@ static bool is_portable_install(void)
* \param ver Blender version, used to construct a subdirectory name
* \return true if it was able to construct such a path.
*/
-static bool get_path_user(char *targetpath, const char *folder_name, const char *subfolder_name, const char *envvar, const int ver)
+static bool get_path_user(
+ char *targetpath, size_t targetpath_len, const char *folder_name, const char *subfolder_name,
+ const char *envvar, const int ver)
{
char user_path[FILE_MAX];
const char *user_base_path;
/* for portable install, user path is always local */
- if (is_portable_install())
- return get_path_local(targetpath, folder_name, subfolder_name, ver);
-
+ if (is_portable_install()) {
+ return get_path_local(targetpath, targetpath_len, folder_name, subfolder_name, ver);
+ }
user_path[0] = '\0';
if (test_env_path(user_path, envvar)) {
if (subfolder_name) {
- return test_path(targetpath, user_path, NULL, subfolder_name);
+ return test_path(targetpath, targetpath_len, user_path, NULL, subfolder_name);
}
else {
BLI_strncpy(targetpath, user_path, FILE_MAX);
@@ -266,10 +279,10 @@ static bool get_path_user(char *targetpath, const char *folder_name, const char
#endif
if (subfolder_name) {
- return test_path(targetpath, user_path, folder_name, subfolder_name);
+ return test_path(targetpath, targetpath_len, user_path, folder_name, subfolder_name);
}
else {
- return test_path(targetpath, user_path, NULL, folder_name);
+ return test_path(targetpath, targetpath_len, user_path, NULL, folder_name);
}
}
@@ -283,7 +296,9 @@ static bool get_path_user(char *targetpath, const char *folder_name, const char
* \param ver Blender version, used to construct a subdirectory name
* \return true if it was able to construct such a path.
*/
-static bool get_path_system(char *targetpath, const char *folder_name, const char *subfolder_name, const char *envvar, const int ver)
+static bool get_path_system(
+ char *targetpath, size_t targetpath_len, const char *folder_name, const char *subfolder_name,
+ const char *envvar, const int ver)
{
char system_path[FILE_MAX];
const char *system_base_path;
@@ -307,13 +322,13 @@ static bool get_path_system(char *targetpath, const char *folder_name, const cha
/* try CWD/release/folder_name */
if (BLI_current_working_dir(cwd, sizeof(cwd))) {
- if (test_path(targetpath, cwd, "release", relfolder)) {
+ if (test_path(targetpath, targetpath_len, cwd, "release", relfolder)) {
return true;
}
}
/* try EXECUTABLE_DIR/release/folder_name */
- if (test_path(targetpath, bprogdir, "release", relfolder))
+ if (test_path(targetpath, targetpath_len, bprogdir, "release", relfolder))
return true;
/* end developer overrides */
@@ -324,7 +339,7 @@ static bool get_path_system(char *targetpath, const char *folder_name, const cha
if (test_env_path(system_path, envvar)) {
if (subfolder_name) {
- return test_path(targetpath, system_path, NULL, subfolder_name);
+ return test_path(targetpath, targetpath_len, system_path, NULL, subfolder_name);
}
else {
BLI_strncpy(targetpath, system_path, FILE_MAX);
@@ -345,57 +360,63 @@ static bool get_path_system(char *targetpath, const char *folder_name, const cha
if (subfolder_name) {
/* try $BLENDERPATH/folder_name/subfolder_name */
- return test_path(targetpath, system_path, folder_name, subfolder_name);
+ return test_path(targetpath, targetpath_len, system_path, folder_name, subfolder_name);
}
else {
/* try $BLENDERPATH/folder_name */
- return test_path(targetpath, system_path, NULL, folder_name);
+ return test_path(targetpath, targetpath_len, system_path, NULL, folder_name);
}
}
-/* get a folder out of the 'folder_id' presets for paths */
-/* returns the path if found, NULL string if not */
-const char *BKE_appdir_folder_id(const int folder_id, const char *subfolder)
+/**
+ * Get a folder out of the 'folder_id' presets for paths.
+ * returns the path if found, NULL string if not
+ *
+ * \param subfolder: The name of a directory to check for,
+ * this may contain path separators but must resolve to a directory, checked with #BLI_is_dir.
+ */
+const char *BKE_appdir_folder_id_ex(
+ const int folder_id, const char *subfolder,
+ char *path, size_t path_len)
{
const int ver = BLENDER_VERSION;
- static char path[FILE_MAX] = "";
-
+
switch (folder_id) {
case BLENDER_DATAFILES: /* general case */
- if (get_path_user(path, "datafiles", subfolder, "BLENDER_USER_DATAFILES", ver)) break;
- if (get_path_local(path, "datafiles", subfolder, ver)) break;
- if (get_path_system(path, "datafiles", subfolder, "BLENDER_SYSTEM_DATAFILES", ver)) break;
+ if (get_path_user(path, path_len, "datafiles", subfolder, "BLENDER_USER_DATAFILES", ver)) break;
+ if (get_path_local(path, path_len, "datafiles", subfolder, ver)) break;
+ if (get_path_system(path, path_len, "datafiles", subfolder, "BLENDER_SYSTEM_DATAFILES", ver)) break;
return NULL;
case BLENDER_USER_DATAFILES:
- if (get_path_user(path, "datafiles", subfolder, "BLENDER_USER_DATAFILES", ver)) break;
+ if (get_path_user(path, path_len, "datafiles", subfolder, "BLENDER_USER_DATAFILES", ver)) break;
return NULL;
case BLENDER_SYSTEM_DATAFILES:
- if (get_path_local(path, "datafiles", subfolder, ver)) break;
- if (get_path_system(path, "datafiles", subfolder, "BLENDER_SYSTEM_DATAFILES", ver)) break;
+ if (get_path_local(path, path_len, "datafiles", subfolder, ver)) break;
+ if (get_path_system(path, path_len, "datafiles", subfolder, "BLENDER_SYSTEM_DATAFILES", ver)) break;
return NULL;
case BLENDER_USER_AUTOSAVE:
- if (get_path_user(path, "autosave", subfolder, "BLENDER_USER_DATAFILES", ver)) break;
+ if (get_path_user(path, path_len, "autosave", subfolder, "BLENDER_USER_DATAFILES", ver)) break;
return NULL;
case BLENDER_USER_CONFIG:
- if (get_path_user(path, "config", subfolder, "BLENDER_USER_CONFIG", ver)) break;
+ if (get_path_user(path, path_len, "config", subfolder, "BLENDER_USER_CONFIG", ver)) break;
return NULL;
case BLENDER_USER_SCRIPTS:
- if (get_path_user(path, "scripts", subfolder, "BLENDER_USER_SCRIPTS", ver)) break;
+ if (get_path_user(path, path_len, "scripts", subfolder, "BLENDER_USER_SCRIPTS", ver)) break;
return NULL;
case BLENDER_SYSTEM_SCRIPTS:
- if (get_path_local(path, "scripts", subfolder, ver)) break;
- if (get_path_system(path, "scripts", subfolder, "BLENDER_SYSTEM_SCRIPTS", ver)) break;
+ if (get_path_local(path, path_len, "scripts", subfolder, ver)) break;
+ if (get_path_system(path, path_len, "scripts", subfolder, "BLENDER_SYSTEM_SCRIPTS", ver)) break;
return NULL;
case BLENDER_SYSTEM_PYTHON:
- if (get_path_local(path, "python", subfolder, ver)) break;
- if (get_path_system(path, "python", subfolder, "BLENDER_SYSTEM_PYTHON", ver)) break;
+ if (get_path_local(path, path_len, "python", subfolder, ver)) break;
+ if (get_path_system(path, path_len, "python", subfolder, "BLENDER_SYSTEM_PYTHON", ver)) break;
return NULL;
default:
@@ -406,6 +427,13 @@ const char *BKE_appdir_folder_id(const int folder_id, const char *subfolder)
return path;
}
+const char *BKE_appdir_folder_id(
+ const int folder_id, const char *subfolder)
+{
+ static char path[FILE_MAX] = "";
+ return BKE_appdir_folder_id_ex(folder_id, subfolder, path, sizeof(path));
+}
+
/**
* Returns the path to a folder in the user area without checking that it actually exists first.
*/
@@ -416,16 +444,16 @@ const char *BKE_appdir_folder_id_user_notest(const int folder_id, const char *su
switch (folder_id) {
case BLENDER_USER_DATAFILES:
- get_path_user(path, "datafiles", subfolder, "BLENDER_USER_DATAFILES", ver);
+ get_path_user(path, sizeof(path), "datafiles", subfolder, "BLENDER_USER_DATAFILES", ver);
break;
case BLENDER_USER_CONFIG:
- get_path_user(path, "config", subfolder, "BLENDER_USER_CONFIG", ver);
+ get_path_user(path, sizeof(path), "config", subfolder, "BLENDER_USER_CONFIG", ver);
break;
case BLENDER_USER_AUTOSAVE:
- get_path_user(path, "autosave", subfolder, "BLENDER_USER_AUTOSAVE", ver);
+ get_path_user(path, sizeof(path), "autosave", subfolder, "BLENDER_USER_AUTOSAVE", ver);
break;
case BLENDER_USER_SCRIPTS:
- get_path_user(path, "scripts", subfolder, "BLENDER_USER_SCRIPTS", ver);
+ get_path_user(path, sizeof(path), "scripts", subfolder, "BLENDER_USER_SCRIPTS", ver);
break;
default:
BLI_assert(0);
@@ -469,13 +497,13 @@ const char *BKE_appdir_folder_id_version(const int folder_id, const int ver, con
bool ok;
switch (folder_id) {
case BLENDER_RESOURCE_PATH_USER:
- ok = get_path_user(path, NULL, NULL, NULL, ver);
+ ok = get_path_user(path, sizeof(path), NULL, NULL, NULL, ver);
break;
case BLENDER_RESOURCE_PATH_LOCAL:
- ok = get_path_local(path, NULL, NULL, ver);
+ ok = get_path_local(path, sizeof(path), NULL, NULL, ver);
break;
case BLENDER_RESOURCE_PATH_SYSTEM:
- ok = get_path_system(path, NULL, NULL, NULL, ver);
+ ok = get_path_system(path, sizeof(path), NULL, NULL, NULL, ver);
break;
default:
path[0] = '\0'; /* in case do_check is false */
@@ -655,6 +683,48 @@ bool BKE_appdir_program_python_search(
return is_found;
}
+static const char *app_template_directory_search[2] = {
+ "startup" SEP_STR "bl_app_templates_user",
+ "startup" SEP_STR "bl_app_templates_system",
+};
+
+static const int app_template_directory_id[2] = {
+ BLENDER_USER_SCRIPTS,
+ BLENDER_SYSTEM_SCRIPTS,
+};
+
+/**
+ * Return true if templates exist
+ */
+bool BKE_appdir_app_template_any(void)
+{
+ char temp_dir[FILE_MAX];
+ for (int i = 0; i < 2; i++) {
+ if (BKE_appdir_folder_id_ex(
+ app_template_directory_id[i], app_template_directory_search[i],
+ temp_dir, sizeof(temp_dir)))
+ {
+ return true;
+ }
+ }
+ return false;
+}
+
+bool BKE_appdir_app_template_id_search(const char *app_template, char *path, size_t path_len)
+{
+ for (int i = 0; i < 2; i++) {
+ char subdir[FILE_MAX];
+ BLI_join_dirfile(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;
+ }
+ }
+ return false;
+}
+
/**
* Gets the temp directory when blender first runs.
* If the default path is not found, use try $TEMP
@@ -713,7 +783,8 @@ static void where_is_temp(char *fullname, char *basename, const size_t maxlen, c
BLI_add_slash(fullname);
#ifdef WIN32
if (userdir && userdir != fullname) {
- BLI_strncpy(userdir, fullname, maxlen); /* also set user pref to show %TEMP%. /tmp/ is just plain confusing for Windows users. */
+ /* also set user pref to show %TEMP%. /tmp/ is just plain confusing for Windows users. */
+ BLI_strncpy(userdir, fullname, maxlen);
}
#endif
}
@@ -755,7 +826,6 @@ static void where_is_temp(char *fullname, char *basename, const size_t maxlen, c
void BKE_tempdir_init(char *userdir)
{
where_is_temp(btempdir_session, btempdir_base, FILE_MAX, userdir);
-;
}
/**
diff --git a/source/blender/blenkernel/intern/armature.c b/source/blender/blenkernel/intern/armature.c
index 0287d6ae9ca..02cc31e5977 100644
--- a/source/blender/blenkernel/intern/armature.c
+++ b/source/blender/blenkernel/intern/armature.c
@@ -1037,6 +1037,17 @@ void armature_deform_verts(Object *armOb, Object *target, DerivedMesh *dm, float
if (use_dverts) {
defnrToPC = MEM_callocN(sizeof(*defnrToPC) * defbase_tot, "defnrToBone");
defnrToPCIndex = MEM_callocN(sizeof(*defnrToPCIndex) * defbase_tot, "defnrToIndex");
+ /* TODO(sergey): Some considerations here:
+ *
+ * - Make it more generic function, maybe even keep together with chanhash.
+ * - Check whether keeping this consistent across frames gives speedup.
+ * - Don't use hash for small armatures.
+ */
+ GHash *idx_hash = BLI_ghash_ptr_new("pose channel index by name");
+ int pchan_index = 0;
+ for (pchan = armOb->pose->chanbase.first; pchan != NULL; pchan = pchan->next, ++pchan_index) {
+ BLI_ghash_insert(idx_hash, pchan, SET_INT_IN_POINTER(pchan_index));
+ }
for (i = 0, dg = target->defbase.first; dg; i++, dg = dg->next) {
defnrToPC[i] = BKE_pose_channel_find_name(armOb->pose, dg->name);
/* exclude non-deforming bones */
@@ -1045,10 +1056,11 @@ void armature_deform_verts(Object *armOb, Object *target, DerivedMesh *dm, float
defnrToPC[i] = NULL;
}
else {
- defnrToPCIndex[i] = BLI_findindex(&armOb->pose->chanbase, defnrToPC[i]);
+ defnrToPCIndex[i] = GET_INT_FROM_POINTER(BLI_ghash_lookup(idx_hash, defnrToPC[i]));
}
}
}
+ BLI_ghash_free(idx_hash, NULL, NULL);
}
}
}
diff --git a/source/blender/blenkernel/intern/blender.c b/source/blender/blenkernel/intern/blender.c
index a8670395fc4..ceb641073e0 100644
--- a/source/blender/blenkernel/intern/blender.c
+++ b/source/blender/blenkernel/intern/blender.c
@@ -100,6 +100,18 @@ void BKE_blender_free(void)
free_nodesystem();
}
+void BKE_blender_version_string(char *version_str, size_t maxncpy, short version, short subversion, bool v_prefix, bool include_subversion)
+{
+ const char *prefix = v_prefix ? "v" : "";
+
+ if (include_subversion && subversion > 0) {
+ BLI_snprintf(version_str, maxncpy, "%s%d.%02d.%d", prefix, version / 100, version % 100, subversion);
+ }
+ else {
+ BLI_snprintf(version_str, maxncpy, "%s%d.%02d", prefix, version / 100, version % 100);
+ }
+}
+
void BKE_blender_globals_init(void)
{
memset(&G, 0, sizeof(Global));
@@ -110,10 +122,7 @@ void BKE_blender_globals_init(void)
strcpy(G.ima, "//");
- if (BLENDER_SUBVERSION)
- BLI_snprintf(versionstr, sizeof(versionstr), "v%d.%02d.%d", BLENDER_VERSION / 100, BLENDER_VERSION % 100, BLENDER_SUBVERSION);
- else
- BLI_snprintf(versionstr, sizeof(versionstr), "v%d.%02d", BLENDER_VERSION / 100, BLENDER_VERSION % 100);
+ BKE_blender_version_string(versionstr, sizeof(versionstr), BLENDER_VERSION, BLENDER_SUBVERSION, true, true);
#ifndef WITH_PYTHON_SECURITY /* default */
G.f |= G_SCRIPT_AUTOEXEC;
@@ -141,20 +150,18 @@ static void keymap_item_free(wmKeyMapItem *kmi)
MEM_freeN(kmi->ptr);
}
-/**
- * When loading a new userdef from file,
- * or when exiting Blender.
- */
-void BKE_blender_userdef_free(void)
+void BKE_blender_userdef_set_data(UserDef *userdef)
{
- wmKeyMap *km;
- wmKeyMapItem *kmi;
- wmKeyMapDiffItem *kmdi;
- bAddon *addon, *addon_next;
- uiFont *font;
-
- for (km = U.user_keymaps.first; km; km = km->next) {
- for (kmdi = km->diff_items.first; kmdi; kmdi = kmdi->next) {
+ /* only here free userdef themes... */
+ BKE_blender_userdef_free_data(&U);
+ U = *userdef;
+}
+
+static void userdef_free_keymaps(UserDef *userdef)
+{
+ for (wmKeyMap *km = userdef->user_keymaps.first, *km_next; km; km = km_next) {
+ km_next = km->next;
+ for (wmKeyMapDiffItem *kmdi = km->diff_items.first; kmdi; kmdi = kmdi->next) {
if (kmdi->add_item) {
keymap_item_free(kmdi->add_item);
MEM_freeN(kmdi->add_item);
@@ -165,14 +172,21 @@ void BKE_blender_userdef_free(void)
}
}
- for (kmi = km->items.first; kmi; kmi = kmi->next)
+ for (wmKeyMapItem *kmi = km->items.first; kmi; kmi = kmi->next) {
keymap_item_free(kmi);
+ }
BLI_freelistN(&km->diff_items);
BLI_freelistN(&km->items);
+
+ MEM_freeN(km);
}
-
- for (addon = U.addons.first; addon; addon = addon_next) {
+ BLI_listbase_clear(&userdef->user_keymaps);
+}
+
+static void userdef_free_addons(UserDef *userdef)
+{
+ for (bAddon *addon = userdef->addons.first, *addon_next; addon; addon = addon_next) {
addon_next = addon->next;
if (addon->prop) {
IDP_FreeProperty(addon->prop);
@@ -180,19 +194,35 @@ void BKE_blender_userdef_free(void)
}
MEM_freeN(addon);
}
+ BLI_listbase_clear(&userdef->addons);
+}
- for (font = U.uifonts.first; font; font = font->next) {
+/**
+ * When loading a new userdef from file,
+ * or when exiting Blender.
+ */
+void BKE_blender_userdef_free_data(UserDef *userdef)
+{
+#define U _invalid_access_ /* ensure no accidental global access */
+#ifdef U /* quiet warning */
+#endif
+
+ userdef_free_keymaps(userdef);
+ userdef_free_addons(userdef);
+
+ for (uiFont *font = userdef->uifonts.first; font; font = font->next) {
BLF_unload_id(font->blf_id);
}
BLF_default_set(-1);
- BLI_freelistN(&U.autoexec_paths);
+ BLI_freelistN(&userdef->autoexec_paths);
+
+ BLI_freelistN(&userdef->uistyles);
+ BLI_freelistN(&userdef->uifonts);
+ BLI_freelistN(&userdef->themes);
- BLI_freelistN(&U.uistyles);
- BLI_freelistN(&U.uifonts);
- BLI_freelistN(&U.themes);
- BLI_freelistN(&U.user_keymaps);
+#undef U
}
/**
@@ -208,6 +238,44 @@ void BKE_blender_userdef_refresh(void)
}
+/**
+ * Write U from userdef.
+ * This function defines which settings a template will override for the user preferences.
+ */
+void BKE_blender_userdef_set_app_template(UserDef *userdef)
+{
+ /* TODO:
+ * - keymaps
+ * - various minor settings (add as needed).
+ */
+
+#define LIST_OVERRIDE(id) { \
+ BLI_freelistN(&U.id); \
+ BLI_movelisttolist(&U.id, &userdef->id); \
+} ((void)0)
+
+#define MEMCPY_OVERRIDE(id) \
+ memcpy(U.id, userdef->id, sizeof(U.id));
+
+ /* for some types we need custom free functions */
+ userdef_free_addons(&U);
+ userdef_free_keymaps(&U);
+
+ LIST_OVERRIDE(uistyles);
+ LIST_OVERRIDE(uifonts);
+ LIST_OVERRIDE(themes);
+ LIST_OVERRIDE(addons);
+ LIST_OVERRIDE(user_keymaps);
+
+ MEMCPY_OVERRIDE(light);
+
+ MEMCPY_OVERRIDE(font_path_ui);
+ MEMCPY_OVERRIDE(font_path_ui_mono);
+
+#undef LIST_OVERRIDE
+#undef MEMCPY_OVERRIDE
+}
+
/* ***************** testing for break ************* */
static void (*blender_test_break_cb)(void) = NULL;
@@ -234,7 +302,7 @@ int BKE_blender_test_break(void)
* \note Don't use MEM_mallocN so functions can be registered at any time.
* \{ */
-struct AtExitData {
+static struct AtExitData {
struct AtExitData *next;
void (*func)(void *user_data);
diff --git a/source/blender/blenkernel/intern/blender_undo.c b/source/blender/blenkernel/intern/blender_undo.c
index bc98d6f6805..e3a5edb2049 100644
--- a/source/blender/blenkernel/intern/blender_undo.c
+++ b/source/blender/blenkernel/intern/blender_undo.c
@@ -108,9 +108,9 @@ static int read_undosave(bContext *C, UndoElem *uel)
G.fileflags |= G_FILE_NO_UI;
if (UNDO_DISK)
- success = (BKE_blendfile_read(C, uel->str, NULL) != BKE_BLENDFILE_READ_FAIL);
+ success = (BKE_blendfile_read(C, uel->str, NULL, 0) != BKE_BLENDFILE_READ_FAIL);
else
- success = BKE_blendfile_read_from_memfile(C, &uel->memfile, NULL);
+ success = BKE_blendfile_read_from_memfile(C, &uel->memfile, NULL, 0);
/* restore */
BLI_strncpy(G.main->name, mainstr, sizeof(G.main->name)); /* restore */
@@ -389,7 +389,7 @@ bool BKE_undo_save_file(const char *filename)
Main *BKE_undo_get_main(Scene **r_scene)
{
Main *mainp = NULL;
- BlendFileData *bfd = BLO_read_from_memfile(G.main, G.main->name, &curundo->memfile, NULL);
+ BlendFileData *bfd = BLO_read_from_memfile(G.main, G.main->name, &curundo->memfile, NULL, BLO_READ_SKIP_NONE);
if (bfd) {
mainp = bfd->main;
diff --git a/source/blender/blenkernel/intern/blendfile.c b/source/blender/blenkernel/intern/blendfile.c
index 54f709a1e5b..a521d671ea4 100644
--- a/source/blender/blenkernel/intern/blendfile.c
+++ b/source/blender/blenkernel/intern/blendfile.c
@@ -227,7 +227,7 @@ static void setup_app_data(
if (bfd->user) {
/* only here free userdef themes... */
- BKE_blender_userdef_free();
+ BKE_blender_userdef_free_data(&U);
U = *bfd->user;
@@ -349,17 +349,23 @@ static int handle_subversion_warning(Main *main, ReportList *reports)
return 1;
}
-int BKE_blendfile_read(bContext *C, const char *filepath, ReportList *reports)
+int BKE_blendfile_read(
+ bContext *C, const char *filepath,
+ ReportList *reports, int skip_flags)
{
BlendFileData *bfd;
int retval = BKE_BLENDFILE_READ_OK;
- if (strstr(filepath, BLENDER_STARTUP_FILE) == NULL) /* don't print user-pref loading */
- printf("read blend: %s\n", filepath);
+ /* don't print user-pref loading */
+ if (strstr(filepath, BLENDER_STARTUP_FILE) == NULL) {
+ printf("Read blend: %s\n", filepath);
+ }
- bfd = BLO_read_from_file(filepath, reports);
+ bfd = BLO_read_from_file(filepath, reports, skip_flags);
if (bfd) {
- if (bfd->user) retval = BKE_BLENDFILE_READ_OK_USERPREFS;
+ if (bfd->user) {
+ retval = BKE_BLENDFILE_READ_OK_USERPREFS;
+ }
if (0 == handle_subversion_warning(bfd->main, reports)) {
BKE_main_free(bfd->main);
@@ -379,11 +385,11 @@ int BKE_blendfile_read(bContext *C, const char *filepath, ReportList *reports)
bool BKE_blendfile_read_from_memory(
bContext *C, const void *filebuf, int filelength,
- ReportList *reports, bool update_defaults)
+ ReportList *reports, int skip_flags, bool update_defaults)
{
BlendFileData *bfd;
- bfd = BLO_read_from_memory(filebuf, filelength, reports);
+ bfd = BLO_read_from_memory(filebuf, filelength, reports, skip_flags);
if (bfd) {
if (update_defaults)
BLO_update_defaults_startup_blend(bfd->main);
@@ -399,11 +405,11 @@ bool BKE_blendfile_read_from_memory(
/* memfile is the undo buffer */
bool BKE_blendfile_read_from_memfile(
bContext *C, struct MemFile *memfile,
- ReportList *reports)
+ ReportList *reports, int skip_flags)
{
BlendFileData *bfd;
- bfd = BLO_read_from_memfile(CTX_data_main(C), G.main->name, memfile, reports);
+ bfd = BLO_read_from_memfile(CTX_data_main(C), G.main->name, memfile, reports, skip_flags);
if (bfd) {
/* remove the unused screens and wm */
while (bfd->main->wm.first)
@@ -420,32 +426,76 @@ bool BKE_blendfile_read_from_memfile(
return (bfd != NULL);
}
+/**
+ * Utility to make a file 'empty' used for startup to optionally give an empty file.
+ * Handy for tests.
+ */
+void BKE_blendfile_read_make_empty(bContext *C)
+{
+ Main *bmain = CTX_data_main(C);
+
+ ListBase *lbarray[MAX_LIBARRAY];
+ ID *id;
+ int a;
+
+ a = set_listbasepointers(bmain, lbarray);
+ while (a--) {
+ id = lbarray[a]->first;
+ if (id != NULL) {
+ if (ELEM(GS(id->name), ID_SCE, ID_SCR, ID_WM)) {
+ continue;
+ }
+ while ((id = lbarray[a]->first)) {
+ BKE_libblock_delete(bmain, id);
+ }
+ }
+ }
+}
+
/* only read the userdef from a .blend */
-int BKE_blendfile_read_userdef(const char *filepath, ReportList *reports)
+UserDef *BKE_blendfile_userdef_read(const char *filepath, ReportList *reports)
{
BlendFileData *bfd;
- int retval = BKE_BLENDFILE_READ_FAIL;
+ UserDef *userdef = NULL;
- bfd = BLO_read_from_file(filepath, reports);
+ bfd = BLO_read_from_file(filepath, reports, BLO_READ_SKIP_ALL & ~BLO_READ_SKIP_USERDEF);
if (bfd) {
if (bfd->user) {
- retval = BKE_BLENDFILE_READ_OK_USERPREFS;
+ userdef = bfd->user;
+ }
+ BKE_main_free(bfd->main);
+ MEM_freeN(bfd);
+ }
- /* only here free userdef themes... */
- BKE_blender_userdef_free();
+ return userdef;
+}
- U = *bfd->user;
- MEM_freeN(bfd->user);
+
+UserDef *BKE_blendfile_userdef_read_from_memory(
+ const void *filebuf, int filelength,
+ ReportList *reports)
+{
+ BlendFileData *bfd;
+ UserDef *userdef = NULL;
+
+ bfd = BLO_read_from_memory(filebuf, filelength, reports, BLO_READ_SKIP_ALL & ~BLO_READ_SKIP_USERDEF);
+ if (bfd) {
+ if (bfd->user) {
+ userdef = bfd->user;
}
BKE_main_free(bfd->main);
MEM_freeN(bfd);
}
+ else {
+ BKE_reports_prepend(reports, "Loading failed: ");
+ }
- return retval;
+ return userdef;
}
+
/* only write the userdef in a .blend */
-int BKE_blendfile_write_userdef(const char *filepath, ReportList *reports)
+int BKE_blendfile_userdef_write(const char *filepath, ReportList *reports)
{
Main *mainb = MEM_callocN(sizeof(Main), "empty main");
int retval = 0;
diff --git a/source/blender/blenkernel/intern/bvhutils.c b/source/blender/blenkernel/intern/bvhutils.c
index c1dd3c0a5d8..c0e4ef37a93 100644
--- a/source/blender/blenkernel/intern/bvhutils.c
+++ b/source/blender/blenkernel/intern/bvhutils.c
@@ -393,7 +393,6 @@ static BVHTree *bvhtree_from_editmesh_verts_create_tree(
BMEditMesh *em, const int verts_num,
const BLI_bitmap *verts_mask, int verts_num_active)
{
- BVHTree *tree = NULL;
BM_mesh_elem_table_ensure(em->bm, BM_VERT);
if (verts_mask) {
BLI_assert(IN_RANGE_INCL(verts_num_active, 0, verts_num));
@@ -402,14 +401,15 @@ static BVHTree *bvhtree_from_editmesh_verts_create_tree(
verts_num_active = verts_num;
}
- tree = BLI_bvhtree_new(verts_num_active, epsilon, tree_type, axis);
+ BVHTree *tree = BLI_bvhtree_new(verts_num_active, epsilon, tree_type, axis);
if (tree) {
for (int i = 0; i < verts_num; i++) {
- if (!verts_mask || BLI_BITMAP_TEST_BOOL(verts_mask, i)) {
- BMVert *eve = BM_vert_at_index(em->bm, i);
- BLI_bvhtree_insert(tree, i, eve->co, 1);
+ if (verts_mask && !BLI_BITMAP_TEST_BOOL(verts_mask, i)) {
+ continue;
}
+ BMVert *eve = BM_vert_at_index(em->bm, i);
+ BLI_bvhtree_insert(tree, i, eve->co, 1);
}
BLI_assert(BLI_bvhtree_get_size(tree) == verts_num_active);
BLI_bvhtree_balance(tree);
@@ -420,31 +420,28 @@ static BVHTree *bvhtree_from_editmesh_verts_create_tree(
static BVHTree *bvhtree_from_mesh_verts_create_tree(
float epsilon, int tree_type, int axis,
- MVert *vert, const int verts_num,
+ const MVert *vert, const int verts_num,
const BLI_bitmap *verts_mask, int verts_num_active)
{
- BVHTree *tree = NULL;
- int i;
- if (vert) {
- if (verts_mask) {
- BLI_assert(IN_RANGE_INCL(verts_num_active, 0, verts_num));
- }
- else {
- verts_num_active = verts_num;
- }
+ BLI_assert(vert != NULL);
+ if (verts_mask) {
+ BLI_assert(IN_RANGE_INCL(verts_num_active, 0, verts_num));
+ }
+ else {
+ verts_num_active = verts_num;
+ }
- tree = BLI_bvhtree_new(verts_num_active, epsilon, tree_type, axis);
+ BVHTree *tree = BLI_bvhtree_new(verts_num_active, epsilon, tree_type, axis);
- if (tree) {
- for (i = 0; i < verts_num; i++) {
- if (verts_mask && !BLI_BITMAP_TEST_BOOL(verts_mask, i)) {
- continue;
- }
- BLI_bvhtree_insert(tree, i, vert[i].co, 1);
+ if (tree) {
+ for (int i = 0; i < verts_num; i++) {
+ if (verts_mask && !BLI_BITMAP_TEST_BOOL(verts_mask, i)) {
+ continue;
}
- BLI_assert(BLI_bvhtree_get_size(tree) == verts_num_active);
- BLI_bvhtree_balance(tree);
+ BLI_bvhtree_insert(tree, i, vert[i].co, 1);
}
+ BLI_assert(BLI_bvhtree_get_size(tree) == verts_num_active);
+ BLI_bvhtree_balance(tree);
}
return tree;
@@ -452,31 +449,23 @@ static BVHTree *bvhtree_from_mesh_verts_create_tree(
static void bvhtree_from_mesh_verts_setup_data(
BVHTreeFromMesh *data, BVHTree *tree, const bool is_cached, float epsilon,
- MVert *vert, const bool vert_allocated)
+ const MVert *vert, const bool vert_allocated)
{
memset(data, 0, sizeof(*data));
- if (tree) {
- data->tree = tree;
- data->cached = is_cached;
+ data->tree = tree;
+ data->cached = is_cached;
- /* a NULL nearest callback works fine
- * remember the min distance to point is the same as the min distance to BV of point */
- data->nearest_callback = NULL;
- data->raycast_callback = mesh_verts_spherecast;
- data->nearest_to_ray_callback = NULL;
+ /* a NULL nearest callback works fine
+ * remember the min distance to point is the same as the min distance to BV of point */
+ data->nearest_callback = NULL;
+ data->raycast_callback = mesh_verts_spherecast;
- data->vert = vert;
- data->vert_allocated = vert_allocated;
- //data->face = DM_get_tessface_array(dm, &data->face_allocated); /* XXX WHY???? */
+ data->vert = vert;
+ data->vert_allocated = vert_allocated;
+ //data->face = DM_get_tessface_array(dm, &data->face_allocated); /* XXX WHY???? */
- data->sphere_radius = epsilon;
- }
- else {
- if (vert_allocated) {
- MEM_freeN(vert);
- }
- }
+ data->sphere_radius = epsilon;
}
/* Builds a bvh tree where nodes are the vertices of the given em */
@@ -485,11 +474,9 @@ BVHTree *bvhtree_from_editmesh_verts_ex(
const BLI_bitmap *verts_mask, int verts_num_active,
float epsilon, int tree_type, int axis)
{
- int vert_num = em->bm->totvert;
-
BVHTree *tree = bvhtree_from_editmesh_verts_create_tree(
epsilon, tree_type, axis,
- em, vert_num, verts_mask, verts_num_active);
+ em, em->bm->totvert, verts_mask, verts_num_active);
if (tree) {
memset(data, 0, sizeof(*data));
@@ -497,11 +484,11 @@ BVHTree *bvhtree_from_editmesh_verts_ex(
data->em = em;
data->nearest_callback = NULL;
data->raycast_callback = editmesh_verts_spherecast;
- data->nearest_to_ray_callback = NULL;
}
return tree;
}
+
BVHTree *bvhtree_from_editmesh_verts(
BVHTreeFromEditMesh *data, BMEditMesh *em,
float epsilon, int tree_type, int axis)
@@ -512,8 +499,8 @@ BVHTree *bvhtree_from_editmesh_verts(
epsilon, tree_type, axis);
}
-
-/* Builds a bvh tree where nodes are the vertices of the given dm */
+/* Builds a bvh tree where nodes are the vertices of the given dm
+ * and stores the BVHTree in dm->bvhCache */
BVHTree *bvhtree_from_mesh_verts(
BVHTreeFromMesh *data, DerivedMesh *dm,
float epsilon, int tree_type, int axis)
@@ -553,10 +540,18 @@ BVHTree *bvhtree_from_mesh_verts(
/* printf("BVHTree is already build, using cached tree\n"); */
}
- /* Setup BVHTreeFromMesh */
- bvhtree_from_mesh_verts_setup_data(data, tree, true, epsilon, vert, vert_allocated);
-
- return data->tree;
+ if (tree) {
+ /* Setup BVHTreeFromMesh */
+ bvhtree_from_mesh_verts_setup_data(
+ data, tree, true, epsilon, vert, vert_allocated);
+ }
+ else {
+ if (vert_allocated) {
+ MEM_freeN(vert);
+ }
+ memset(data, 0, sizeof(*data));
+ }
+ return tree;
}
/**
@@ -566,7 +561,7 @@ BVHTree *bvhtree_from_mesh_verts(
* \param verts_num_active if >= 0, number of active verts to add to BVH tree (else will be computed from mask).
*/
BVHTree *bvhtree_from_mesh_verts_ex(
- BVHTreeFromMesh *data, MVert *vert, const int verts_num, const bool vert_allocated,
+ BVHTreeFromMesh *data, const MVert *vert, const int verts_num, const bool vert_allocated,
const BLI_bitmap *verts_mask, int verts_num_active,
float epsilon, int tree_type, int axis)
{
@@ -574,9 +569,10 @@ BVHTree *bvhtree_from_mesh_verts_ex(
epsilon, tree_type, axis, vert, verts_num, verts_mask, verts_num_active);
/* Setup BVHTreeFromMesh */
- bvhtree_from_mesh_verts_setup_data(data, tree, false, epsilon, vert, vert_allocated);
+ bvhtree_from_mesh_verts_setup_data(
+ data, tree, false, epsilon, vert, vert_allocated);
- return data->tree;
+ return tree;
}
/** \} */
@@ -592,8 +588,6 @@ static BVHTree *bvhtree_from_editmesh_edges_create_tree(
BMEditMesh *em, const int edges_num,
const BLI_bitmap *edges_mask, int edges_num_active)
{
- BVHTree *tree = NULL;
- int i;
BM_mesh_elem_table_ensure(em->bm, BM_EDGE);
if (edges_mask) {
BLI_assert(IN_RANGE_INCL(edges_num_active, 0, edges_num));
@@ -602,9 +596,10 @@ static BVHTree *bvhtree_from_editmesh_edges_create_tree(
edges_num_active = edges_num;
}
- tree = BLI_bvhtree_new(edges_num_active, epsilon, tree_type, axis);
+ BVHTree *tree = BLI_bvhtree_new(edges_num_active, epsilon, tree_type, axis);
if (tree) {
+ int i;
BMIter iter;
BMEdge *eed;
BM_ITER_MESH_INDEX (eed, &iter, em->bm, BM_EDGES_OF_MESH, i) {
@@ -624,6 +619,62 @@ static BVHTree *bvhtree_from_editmesh_edges_create_tree(
return tree;
}
+static BVHTree *bvhtree_from_mesh_edges_create_tree(
+ const MVert *vert, const MEdge *edge, const int edge_num,
+ const BLI_bitmap *edges_mask, int edges_num_active,
+ float epsilon, int tree_type, int axis)
+{
+ if (edges_mask) {
+ BLI_assert(IN_RANGE_INCL(edges_num_active, 0, edge_num));
+ }
+ else {
+ edges_num_active = edge_num;
+ }
+ BLI_assert(vert != NULL);
+ BLI_assert(edge != NULL);
+
+ /* Create a bvh-tree of the given target */
+ BVHTree *tree = BLI_bvhtree_new(edges_num_active, epsilon, tree_type, axis);
+ if (tree) {
+ for (int i = 0; i < edge_num; i++) {
+ if (edges_mask && !BLI_BITMAP_TEST_BOOL(edges_mask, i)) {
+ continue;
+ }
+ float co[2][3];
+ copy_v3_v3(co[0], vert[edge[i].v1].co);
+ copy_v3_v3(co[1], vert[edge[i].v2].co);
+
+ BLI_bvhtree_insert(tree, i, co[0], 2);
+ }
+ BLI_bvhtree_balance(tree);
+ }
+
+ return tree;
+}
+
+static void bvhtree_from_mesh_edges_setup_data(
+ BVHTreeFromMesh *data, BVHTree *tree,
+ const bool is_cached, float epsilon,
+ const MVert *vert, const bool vert_allocated,
+ const MEdge *edge, const bool edge_allocated)
+{
+ memset(data, 0, sizeof(*data));
+
+ data->tree = tree;
+
+ data->cached = is_cached;
+
+ data->nearest_callback = mesh_edges_nearest_point;
+ data->raycast_callback = mesh_edges_spherecast;
+
+ data->vert = vert;
+ data->vert_allocated = vert_allocated;
+ data->edge = edge;
+ data->edge_allocated = edge_allocated;
+
+ data->sphere_radius = epsilon;
+}
+
/* Builds a bvh tree where nodes are the edges of the given em */
BVHTree *bvhtree_from_editmesh_edges_ex(
BVHTreeFromEditMesh *data, BMEditMesh *em,
@@ -642,12 +693,11 @@ BVHTree *bvhtree_from_editmesh_edges_ex(
data->em = em;
data->nearest_callback = NULL; /* TODO */
data->raycast_callback = NULL; /* TODO */
- /* TODO: not urgent however since users currently define own callbacks */
- data->nearest_to_ray_callback = NULL;
}
return tree;
}
+
BVHTree *bvhtree_from_editmesh_edges(
BVHTreeFromEditMesh *data, BMEditMesh *em,
float epsilon, int tree_type, int axis)
@@ -680,27 +730,13 @@ BVHTree *bvhtree_from_mesh_edges(
BLI_rw_mutex_lock(&cache_rwlock, THREAD_LOCK_WRITE);
tree = bvhcache_find(dm->bvhCache, BVHTREE_FROM_EDGES);
if (tree == NULL) {
- int i;
- int numEdges = dm->getNumEdges(dm);
-
- if (vert != NULL && edge != NULL) {
- /* Create a bvh-tree of the given target */
- tree = BLI_bvhtree_new(numEdges, epsilon, tree_type, axis);
- if (tree != NULL) {
- for (i = 0; i < numEdges; i++) {
- float co[2][3];
- copy_v3_v3(co[0], vert[edge[i].v1].co);
- copy_v3_v3(co[1], vert[edge[i].v2].co);
-
- BLI_bvhtree_insert(tree, i, co[0], 2);
- }
- BLI_bvhtree_balance(tree);
+ tree = bvhtree_from_mesh_edges_create_tree(
+ vert, edge, dm->getNumEdges(dm),
+ NULL, -1, epsilon, tree_type, axis);
- /* Save on cache for later use */
- /* printf("BVHTree built and saved on cache\n"); */
- bvhcache_insert(&dm->bvhCache, tree, BVHTREE_FROM_EDGES);
- }
- }
+ /* Save on cache for later use */
+ /* printf("BVHTree built and saved on cache\n"); */
+ bvhcache_insert(&dm->bvhCache, tree, BVHTREE_FROM_EDGES);
}
BLI_rw_mutex_unlock(&cache_rwlock);
}
@@ -708,24 +744,10 @@ BVHTree *bvhtree_from_mesh_edges(
/* printf("BVHTree is already build, using cached tree\n"); */
}
-
- /* Setup BVHTreeFromMesh */
- memset(data, 0, sizeof(*data));
- data->tree = tree;
-
- if (data->tree) {
- data->cached = true;
-
- data->nearest_callback = mesh_edges_nearest_point;
- data->raycast_callback = mesh_edges_spherecast;
- data->nearest_to_ray_callback = NULL;
-
- data->vert = vert;
- data->vert_allocated = vert_allocated;
- data->edge = edge;
- data->edge_allocated = edge_allocated;
-
- data->sphere_radius = epsilon;
+ if (tree) {
+ /* Setup BVHTreeFromMesh */
+ bvhtree_from_mesh_edges_setup_data(
+ data, tree, true, epsilon, vert, vert_allocated, edge, edge_allocated);
}
else {
if (vert_allocated) {
@@ -734,8 +756,33 @@ BVHTree *bvhtree_from_mesh_edges(
if (edge_allocated) {
MEM_freeN(edge);
}
+ memset(data, 0, sizeof(*data));
}
- return data->tree;
+ return tree;
+}
+
+/**
+ * Builds a bvh tree where nodes are the given edges .
+ * \param vert/edge_allocated if true, elem freeing will be done when freeing data.
+ * \param edges_mask if not null, true elements give which vert to add to BVH tree.
+ * \param edges_num_active if >= 0, number of active edges to add to BVH tree (else will be computed from mask).
+ */
+BVHTree *bvhtree_from_mesh_edges_ex(
+ BVHTreeFromMesh *data,
+ const MVert *vert, const bool vert_allocated,
+ const MEdge *edge, const int edges_num, const bool edge_allocated,
+ const BLI_bitmap *edges_mask, int edges_num_active,
+ float epsilon, int tree_type, int axis)
+{
+ BVHTree *tree = bvhtree_from_mesh_edges_create_tree(
+ vert, edge, edges_num, edges_mask, edges_num_active,
+ epsilon, tree_type, axis);
+
+ /* Setup BVHTreeFromMesh */
+ bvhtree_from_mesh_edges_setup_data(
+ data, tree, false, epsilon, vert, vert_allocated, edge, edge_allocated);
+
+ return tree;
}
/** \} */
@@ -748,7 +795,7 @@ BVHTree *bvhtree_from_mesh_edges(
static BVHTree *bvhtree_from_mesh_faces_create_tree(
float epsilon, int tree_type, int axis,
- MVert *vert, MFace *face, const int faces_num,
+ const MVert *vert, const MFace *face, const int faces_num,
const BLI_bitmap *faces_mask, int faces_num_active)
{
BVHTree *tree = NULL;
@@ -792,34 +839,23 @@ static BVHTree *bvhtree_from_mesh_faces_create_tree(
static void bvhtree_from_mesh_faces_setup_data(
BVHTreeFromMesh *data, BVHTree *tree, const bool is_cached, float epsilon,
- MVert *vert, const bool vert_allocated,
- MFace *face, const bool face_allocated)
+ const MVert *vert, const bool vert_allocated,
+ const MFace *face, const bool face_allocated)
{
memset(data, 0, sizeof(*data));
- if (tree) {
- data->tree = tree;
- data->cached = is_cached;
+ data->tree = tree;
+ data->cached = is_cached;
- data->nearest_callback = mesh_faces_nearest_point;
- data->raycast_callback = mesh_faces_spherecast;
- data->nearest_to_ray_callback = NULL;
+ data->nearest_callback = mesh_faces_nearest_point;
+ data->raycast_callback = mesh_faces_spherecast;
- data->vert = vert;
- data->vert_allocated = vert_allocated;
- data->face = face;
- data->face_allocated = face_allocated;
+ data->vert = vert;
+ data->vert_allocated = vert_allocated;
+ data->face = face;
+ data->face_allocated = face_allocated;
- data->sphere_radius = epsilon;
- }
- else {
- if (vert_allocated) {
- MEM_freeN(vert);
- }
- if (face_allocated) {
- MEM_freeN(face);
- }
- }
+ data->sphere_radius = epsilon;
}
/* Builds a bvh tree where nodes are the tesselated faces of the given dm */
@@ -862,10 +898,21 @@ BVHTree *bvhtree_from_mesh_faces(
/* printf("BVHTree is already build, using cached tree\n"); */
}
- /* Setup BVHTreeFromMesh */
- bvhtree_from_mesh_faces_setup_data(data, tree, true, epsilon, vert, vert_allocated, face, face_allocated);
-
- return data->tree;
+ if (tree) {
+ /* Setup BVHTreeFromMesh */
+ bvhtree_from_mesh_faces_setup_data(
+ data, tree, true, epsilon, vert, vert_allocated, face, face_allocated);
+ }
+ else {
+ if (vert_allocated) {
+ MEM_freeN(vert);
+ }
+ if (face_allocated) {
+ MEM_freeN(face);
+ }
+ memset(data, 0, sizeof(*data));
+ }
+ return tree;
}
/**
@@ -876,8 +923,8 @@ BVHTree *bvhtree_from_mesh_faces(
* \param numFaces_active if >= 0, number of active faces to add to BVH tree (else will be computed from mask).
*/
BVHTree *bvhtree_from_mesh_faces_ex(
- BVHTreeFromMesh *data, MVert *vert, const bool vert_allocated,
- MFace *face, const int numFaces, const bool face_allocated,
+ BVHTreeFromMesh *data, const MVert *vert, const bool vert_allocated,
+ const MFace *face, const int numFaces, const bool face_allocated,
const BLI_bitmap *faces_mask, int faces_num_active,
float epsilon, int tree_type, int axis)
{
@@ -887,9 +934,10 @@ BVHTree *bvhtree_from_mesh_faces_ex(
faces_mask, faces_num_active);
/* Setup BVHTreeFromMesh */
- bvhtree_from_mesh_faces_setup_data(data, tree, false, epsilon, vert, vert_allocated, face, face_allocated);
+ bvhtree_from_mesh_faces_setup_data(
+ data, tree, false, epsilon, vert, vert_allocated, face, face_allocated);
- return data->tree;
+ return tree;
}
/** \} */
@@ -1000,34 +1048,20 @@ static void bvhtree_from_mesh_looptri_setup_data(
{
memset(data, 0, sizeof(*data));
- if (tree) {
- data->tree = tree;
- data->cached = is_cached;
+ data->tree = tree;
+ data->cached = is_cached;
- data->nearest_callback = mesh_looptri_nearest_point;
- data->raycast_callback = mesh_looptri_spherecast;
- data->nearest_to_ray_callback = NULL;
+ data->nearest_callback = mesh_looptri_nearest_point;
+ data->raycast_callback = mesh_looptri_spherecast;
- data->vert = vert;
- data->vert_allocated = vert_allocated;
- data->loop = mloop;
- data->loop_allocated = loop_allocated;
- data->looptri = looptri;
- data->looptri_allocated = looptri_allocated;
+ data->vert = vert;
+ data->vert_allocated = vert_allocated;
+ data->loop = mloop;
+ data->loop_allocated = loop_allocated;
+ data->looptri = looptri;
+ data->looptri_allocated = looptri_allocated;
- data->sphere_radius = epsilon;
- }
- else {
- if (vert_allocated) {
- MEM_freeN((void *)vert);
- }
- if (loop_allocated) {
- MEM_freeN((void *)mloop);
- }
- if (looptri_allocated) {
- MEM_freeN((void *)looptri);
- }
- }
+ data->sphere_radius = epsilon;
}
/**
@@ -1072,7 +1106,6 @@ BVHTree *bvhtree_from_editmesh_looptri_ex(
data->tree = tree;
data->nearest_callback = editmesh_looptri_nearest_point;
data->raycast_callback = editmesh_looptri_spherecast;
- data->nearest_to_ray_callback = NULL;
data->sphere_radius = 0.0f;
data->em = em;
data->cached = bvhCache != NULL;
@@ -1154,14 +1187,28 @@ BVHTree *bvhtree_from_mesh_looptri(
/* printf("BVHTree is already build, using cached tree\n"); */
}
- /* Setup BVHTreeFromMesh */
- bvhtree_from_mesh_looptri_setup_data(
- data, tree, true, epsilon,
- mvert, vert_allocated,
- mloop, loop_allocated,
- looptri, looptri_allocated);
+ if (tree) {
+ /* Setup BVHTreeFromMesh */
+ bvhtree_from_mesh_looptri_setup_data(
+ data, tree, true, epsilon,
+ mvert, vert_allocated,
+ mloop, loop_allocated,
+ looptri, looptri_allocated);
+ }
+ else {
+ if (vert_allocated) {
+ MEM_freeN(mvert);
+ }
+ if (loop_allocated) {
+ MEM_freeN(mloop);
+ }
+ if (looptri_allocated) {
+ MEM_freeN((void *)looptri);
+ }
+ memset(data, 0, sizeof(*data));
+ }
- return data->tree;
+ return tree;
}
BVHTree *bvhtree_from_mesh_looptri_ex(
@@ -1184,7 +1231,7 @@ BVHTree *bvhtree_from_mesh_looptri_ex(
mloop, loop_allocated,
looptri, looptri_allocated);
- return data->tree;
+ return tree;
}
/** \} */
@@ -1204,29 +1251,27 @@ void free_bvhtree_from_editmesh(struct BVHTreeFromEditMesh *data)
/* Frees data allocated by a call to bvhtree_from_mesh_*. */
void free_bvhtree_from_mesh(struct BVHTreeFromMesh *data)
{
- if (data->tree) {
- if (!data->cached) {
- BLI_bvhtree_free(data->tree);
- }
-
- if (data->vert_allocated) {
- MEM_freeN((void *)data->vert);
- }
- if (data->edge_allocated) {
- MEM_freeN((void *)data->edge);
- }
- if (data->face_allocated) {
- MEM_freeN((void *)data->face);
- }
- if (data->loop_allocated) {
- MEM_freeN((void *)data->loop);
- }
- if (data->looptri_allocated) {
- MEM_freeN((void *)data->looptri);
- }
+ if (data->tree && !data->cached) {
+ BLI_bvhtree_free(data->tree);
+ }
- memset(data, 0, sizeof(*data));
+ if (data->vert_allocated) {
+ MEM_freeN((void *)data->vert);
+ }
+ if (data->edge_allocated) {
+ MEM_freeN((void *)data->edge);
}
+ if (data->face_allocated) {
+ MEM_freeN((void *)data->face);
+ }
+ if (data->loop_allocated) {
+ MEM_freeN((void *)data->loop);
+ }
+ if (data->looptri_allocated) {
+ MEM_freeN((void *)data->looptri);
+ }
+
+ memset(data, 0, sizeof(*data));
}
diff --git a/source/blender/blenkernel/intern/cdderivedmesh.c b/source/blender/blenkernel/intern/cdderivedmesh.c
index fc3e358cb25..7042b46330b 100644
--- a/source/blender/blenkernel/intern/cdderivedmesh.c
+++ b/source/blender/blenkernel/intern/cdderivedmesh.c
@@ -2398,13 +2398,16 @@ DerivedMesh *CDDM_from_editbmesh(BMEditMesh *em, const bool use_mdisps, const bo
use_tessface, em->tottri, (const BMLoop *(*)[3])em->looptris);
}
-static DerivedMesh *cddm_copy_ex(DerivedMesh *source, int faces_from_tessfaces)
+static DerivedMesh *cddm_copy_ex(DerivedMesh *source,
+ const bool need_tessface_data,
+ const bool faces_from_tessfaces)
{
+ const bool copy_tessface_data = (faces_from_tessfaces || need_tessface_data);
CDDerivedMesh *cddm = cdDM_create("CDDM_copy cddm");
DerivedMesh *dm = &cddm->dm;
int numVerts = source->numVertData;
int numEdges = source->numEdgeData;
- int numTessFaces = source->numTessFaceData;
+ int numTessFaces = copy_tessface_data ? source->numTessFaceData : 0;
int numLoops = source->numLoopData;
int numPolys = source->numPolyData;
@@ -2414,20 +2417,29 @@ static DerivedMesh *cddm_copy_ex(DerivedMesh *source, int faces_from_tessfaces)
source->getVertDataArray(source, CD_ORIGINDEX);
source->getEdgeDataArray(source, CD_ORIGINDEX);
source->getPolyDataArray(source, CD_ORIGINDEX);
+ if (copy_tessface_data) {
+ source->getTessFaceDataArray(source, CD_ORIGINDEX);
+ }
/* this initializes dm, and copies all non mvert/medge/mface layers */
- DM_from_template(dm, source, DM_TYPE_CDDM, numVerts, numEdges,
- faces_from_tessfaces ? numTessFaces : 0,
+ DM_from_template(dm, source, DM_TYPE_CDDM, numVerts, numEdges, numTessFaces,
numLoops, numPolys);
dm->deformedOnly = source->deformedOnly;
dm->cd_flag = source->cd_flag;
dm->dirty = source->dirty;
- /* Tessellation data is never copied, so tag it here. */
- dm->dirty |= DM_DIRTY_TESS_CDLAYERS;
+ /* Tessellation data is never copied, so tag it here.
+ * Only tag dirty layers if we really ignored tessellation faces.
+ */
+ if (!copy_tessface_data) {
+ dm->dirty |= DM_DIRTY_TESS_CDLAYERS;
+ }
CustomData_copy_data(&source->vertData, &dm->vertData, 0, 0, numVerts);
CustomData_copy_data(&source->edgeData, &dm->edgeData, 0, 0, numEdges);
+ if (copy_tessface_data) {
+ CustomData_copy_data(&source->faceData, &dm->faceData, 0, 0, numTessFaces);
+ }
/* now add mvert/medge/mface layers */
cddm->mvert = source->dupVertArray(source);
@@ -2435,17 +2447,16 @@ static DerivedMesh *cddm_copy_ex(DerivedMesh *source, int faces_from_tessfaces)
CustomData_add_layer(&dm->vertData, CD_MVERT, CD_ASSIGN, cddm->mvert, numVerts);
CustomData_add_layer(&dm->edgeData, CD_MEDGE, CD_ASSIGN, cddm->medge, numEdges);
-
- if (!faces_from_tessfaces) {
- DM_DupPolys(source, dm);
- }
- else {
- source->getTessFaceDataArray(source, CD_ORIGINDEX);
- CustomData_copy_data(&source->faceData, &dm->faceData, 0, 0, numTessFaces);
+ if (faces_from_tessfaces || copy_tessface_data) {
cddm->mface = source->dupTessFaceArray(source);
CustomData_add_layer(&dm->faceData, CD_MFACE, CD_ASSIGN, cddm->mface, numTessFaces);
+ }
+ if (!faces_from_tessfaces) {
+ DM_DupPolys(source, dm);
+ }
+ else {
CDDM_tessfaces_to_faces(dm);
}
@@ -2457,12 +2468,17 @@ static DerivedMesh *cddm_copy_ex(DerivedMesh *source, int faces_from_tessfaces)
DerivedMesh *CDDM_copy(DerivedMesh *source)
{
- return cddm_copy_ex(source, 0);
+ return cddm_copy_ex(source, false, false);
}
DerivedMesh *CDDM_copy_from_tessface(DerivedMesh *source)
{
- return cddm_copy_ex(source, 1);
+ return cddm_copy_ex(source, false, true);
+}
+
+DerivedMesh *CDDM_copy_with_tessface(DerivedMesh *source)
+{
+ return cddm_copy_ex(source, true, false);
}
/* note, the CD_ORIGINDEX layers are all 0, so if there is a direct
diff --git a/source/blender/blenkernel/intern/cloth.c b/source/blender/blenkernel/intern/cloth.c
index 28ef3f6f248..ee0fde1ea61 100644
--- a/source/blender/blenkernel/intern/cloth.c
+++ b/source/blender/blenkernel/intern/cloth.c
@@ -869,12 +869,6 @@ static int cloth_from_object(Object *ob, ClothModifierData *clmd, DerivedMesh *d
return 0;
}
- for ( i = 0; i < dm->getNumVerts(dm); i++) {
- if ((!(cloth->verts[i].flags & CLOTH_VERT_FLAG_PINNED)) && (cloth->verts[i].goal > ALMOST_ZERO)) {
- cloth_add_spring (clmd, i, i, 0.0, CLOTH_SPRING_TYPE_GOAL);
- }
- }
-
// init our solver
BPH_cloth_solver_init(ob, clmd);
@@ -944,37 +938,6 @@ BLI_INLINE void spring_verts_ordered_set(ClothSpring *spring, int v0, int v1)
}
}
-// be careful: implicit solver has to be resettet when using this one!
-// --> only for implicit handling of this spring!
-int cloth_add_spring(ClothModifierData *clmd, unsigned int indexA, unsigned int indexB, float restlength, int spring_type)
-{
- Cloth *cloth = clmd->clothObject;
- ClothSpring *spring = NULL;
-
- if (cloth) {
- // TODO: look if this spring is already there
-
- spring = (ClothSpring *)MEM_callocN ( sizeof ( ClothSpring ), "cloth spring" );
-
- if (!spring)
- return 0;
-
- spring->ij = indexA;
- spring->kl = indexB;
- spring->restlen = restlength;
- spring->type = spring_type;
- spring->flags = 0;
- spring->stiffness = 0;
-
- cloth->numsprings++;
-
- BLI_linklist_prepend ( &cloth->springs, spring );
-
- return 1;
- }
- return 0;
-}
-
static void cloth_free_edgelist(LinkNodePair *edgelist, unsigned int mvert_num)
{
if (edgelist) {
diff --git a/source/blender/blenkernel/intern/colortools.c b/source/blender/blenkernel/intern/colortools.c
index 4f3ffed41bc..b3a0895d063 100644
--- a/source/blender/blenkernel/intern/colortools.c
+++ b/source/blender/blenkernel/intern/colortools.c
@@ -508,7 +508,7 @@ static void calchandle_curvemap(
if ((bezt->h2 == HD_AUTO_ANIM) && next && prev) { /* keep horizontal if extrema */
const float ydiff1 = prev->vec[1][1] - bezt->vec[1][1];
const float ydiff2 = next->vec[1][1] - bezt->vec[1][1];
- if ((ydiff1 <= 0.0f && ydiff2 <= 0.0f)||
+ if ((ydiff1 <= 0.0f && ydiff2 <= 0.0f) ||
(ydiff1 >= 0.0f && ydiff2 >= 0.0f))
{
bezt->vec[2][1] = bezt->vec[1][1];
diff --git a/source/blender/blenkernel/intern/curve.c b/source/blender/blenkernel/intern/curve.c
index 90a514781d7..439abb1d593 100644
--- a/source/blender/blenkernel/intern/curve.c
+++ b/source/blender/blenkernel/intern/curve.c
@@ -89,20 +89,33 @@ void BKE_curve_editfont_free(Curve *cu)
}
}
-void BKE_curve_editNurb_keyIndex_free(EditNurb *editnurb)
+static void curve_editNurb_keyIndex_cv_free_cb(void *val)
{
- if (!editnurb->keyindex) {
+ CVKeyIndex *index = val;
+ MEM_freeN(index->orig_cv);
+ MEM_freeN(val);
+}
+
+void BKE_curve_editNurb_keyIndex_delCV(GHash *keyindex, const void *cv)
+{
+ BLI_assert(keyindex != NULL);
+ BLI_ghash_remove(keyindex, cv, NULL, curve_editNurb_keyIndex_cv_free_cb);
+}
+
+void BKE_curve_editNurb_keyIndex_free(GHash **keyindex)
+{
+ if (!(*keyindex)) {
return;
}
- BLI_ghash_free(editnurb->keyindex, NULL, MEM_freeN);
- editnurb->keyindex = NULL;
+ BLI_ghash_free(*keyindex, NULL, curve_editNurb_keyIndex_cv_free_cb);
+ *keyindex = NULL;
}
void BKE_curve_editNurb_free(Curve *cu)
{
if (cu->editnurb) {
BKE_nurbList_free(&cu->editnurb->nurbs);
- BKE_curve_editNurb_keyIndex_free(cu->editnurb);
+ BKE_curve_editNurb_keyIndex_free(&cu->editnurb->keyindex);
MEM_freeN(cu->editnurb);
cu->editnurb = NULL;
}
diff --git a/source/blender/blenkernel/intern/customdata.c b/source/blender/blenkernel/intern/customdata.c
index 98d37fb07bf..7c3f0ac630d 100644
--- a/source/blender/blenkernel/intern/customdata.c
+++ b/source/blender/blenkernel/intern/customdata.c
@@ -33,14 +33,10 @@
/** \file blender/blenkernel/intern/customdata.c
* \ingroup bke
*/
-
-
-#include <math.h>
-#include <string.h>
-#include <assert.h>
#include "MEM_guardedalloc.h"
+#include "DNA_customdata_types.h"
#include "DNA_meshdata_types.h"
#include "DNA_ID.h"
@@ -62,20 +58,16 @@
#include "BKE_mesh_remap.h"
#include "BKE_multires.h"
-#include "data_transfer_intern.h"
-
#include "bmesh.h"
-#include <math.h>
-#include <string.h>
+/* only for customdata_data_transfer_interp_normal_normals */
+#include "data_transfer_intern.h"
/* number of layers to add when growing a CustomData object */
#define CUSTOMDATA_GROW 5
/* ensure typemap size is ok */
-BLI_STATIC_ASSERT(sizeof(((CustomData *)NULL)->typemap) /
- sizeof(((CustomData *)NULL)->typemap[0]) == CD_NUMTYPES,
- "size mismatch");
+BLI_STATIC_ASSERT(ARRAY_SIZE(((CustomData *)NULL)->typemap) == CD_NUMTYPES, "size mismatch");
/********************* Layer type information **********************/
@@ -805,18 +797,15 @@ static void layerInterp_mloopcol(
const float *sub_weights, int count, void *dest)
{
MLoopCol *mc = dest;
- int i;
- const float *sub_weight;
struct {
float a;
float r;
float g;
float b;
- } col;
- col.a = col.r = col.g = col.b = 0;
+ } col = {0};
- sub_weight = sub_weights;
- for (i = 0; i < count; ++i) {
+ const float *sub_weight = sub_weights;
+ for (int i = 0; i < count; ++i) {
float weight = weights ? weights[i] : 1;
const MLoopCol *src = sources[i];
if (sub_weights) {
@@ -833,19 +822,16 @@ static void layerInterp_mloopcol(
col.a += src->a * weight;
}
}
-
+
+
/* Subdivide smooth or fractal can cause problems without clamping
* although weights should also not cause this situation */
- CLAMP(col.a, 0.0f, 255.0f);
- CLAMP(col.r, 0.0f, 255.0f);
- CLAMP(col.g, 0.0f, 255.0f);
- CLAMP(col.b, 0.0f, 255.0f);
- /* delay writing to the destination incase dest is in sources */
- mc->r = (int)col.r;
- mc->g = (int)col.g;
- mc->b = (int)col.b;
- mc->a = (int)col.a;
+ /* also delay writing to the destination incase dest is in sources */
+ mc->r = CLAMPIS(iroundf(col.r), 0, 255);
+ mc->g = CLAMPIS(iroundf(col.g), 0, 255);
+ mc->b = CLAMPIS(iroundf(col.b), 0, 255);
+ mc->a = CLAMPIS(iroundf(col.a), 0, 255);
}
static int layerMaxNum_mloopcol(void)
@@ -1068,15 +1054,10 @@ static void layerInterp_mcol(
/* Subdivide smooth or fractal can cause problems without clamping
* although weights should also not cause this situation */
- CLAMP(col[j].a, 0.0f, 255.0f);
- CLAMP(col[j].r, 0.0f, 255.0f);
- CLAMP(col[j].g, 0.0f, 255.0f);
- CLAMP(col[j].b, 0.0f, 255.0f);
-
- mc[j].a = (int)col[j].a;
- mc[j].r = (int)col[j].r;
- mc[j].g = (int)col[j].g;
- mc[j].b = (int)col[j].b;
+ mc[j].a = CLAMPIS(iroundf(col[j].a), 0, 255);
+ mc[j].r = CLAMPIS(iroundf(col[j].r), 0, 255);
+ mc[j].g = CLAMPIS(iroundf(col[j].g), 0, 255);
+ mc[j].b = CLAMPIS(iroundf(col[j].b), 0, 255);
}
}
@@ -2595,7 +2576,7 @@ bool CustomData_from_bmeshpoly_test(CustomData *fdata, CustomData *pdata, Custom
if (!LAYER_CMP(ldata, CD_TANGENT, fdata, CD_TANGENT))
return false;
-#undef TEST_RET
+#undef LAYER_CMP
/* if no layers are on either CustomData's,
* then there was nothing to do... */
diff --git a/source/blender/blenkernel/intern/depsgraph.c b/source/blender/blenkernel/intern/depsgraph.c
index 294a4ce76b7..678dc92a5f2 100644
--- a/source/blender/blenkernel/intern/depsgraph.c
+++ b/source/blender/blenkernel/intern/depsgraph.c
@@ -544,10 +544,16 @@ static void build_dag_object(DagForest *dag, DagNode *scenenode, Main *bmain, Sc
if (ct->tar->type == OB_MESH)
node3->customdata_mask |= CD_MASK_MDEFORMVERT;
}
- else if (ELEM(con->type, CONSTRAINT_TYPE_FOLLOWPATH, CONSTRAINT_TYPE_CLAMPTO, CONSTRAINT_TYPE_SPLINEIK))
+ else if (ELEM(con->type, CONSTRAINT_TYPE_FOLLOWPATH,
+ CONSTRAINT_TYPE_CLAMPTO,
+ CONSTRAINT_TYPE_SPLINEIK,
+ CONSTRAINT_TYPE_SHRINKWRAP))
+ {
dag_add_relation(dag, node3, node, DAG_RL_DATA_DATA | DAG_RL_OB_DATA, cti->name);
- else
+ }
+ else {
dag_add_relation(dag, node3, node, DAG_RL_OB_DATA, cti->name);
+ }
}
}
@@ -881,8 +887,12 @@ static void build_dag_object(DagForest *dag, DagNode *scenenode, Main *bmain, Sc
if (obt->type == OB_MESH)
node2->customdata_mask |= CD_MASK_MDEFORMVERT;
}
- else
+ else if (cti->type == CONSTRAINT_TYPE_SHRINKWRAP) {
+ dag_add_relation(dag, node2, node, DAG_RL_DATA_DATA | DAG_RL_OB_DATA, cti->name);
+ }
+ else {
dag_add_relation(dag, node2, node, DAG_RL_OB_OB, cti->name);
+ }
}
addtoroot = 0;
}
diff --git a/source/blender/blenkernel/intern/displist.c b/source/blender/blenkernel/intern/displist.c
index 49db75a0474..f8a9d57f579 100644
--- a/source/blender/blenkernel/intern/displist.c
+++ b/source/blender/blenkernel/intern/displist.c
@@ -819,7 +819,7 @@ static void curve_calc_modifiers_pre(Scene *scene, Object *ob, ListBase *nurb,
if (editmode)
required_mode |= eModifierMode_Editmode;
- if (cu->editnurb == NULL) {
+ if (!editmode) {
keyVerts = BKE_key_evaluate_object(ob, &numVerts);
if (keyVerts) {
diff --git a/source/blender/blenkernel/intern/dynamicpaint.c b/source/blender/blenkernel/intern/dynamicpaint.c
index dc9f3b57f1f..c525e75b825 100644
--- a/source/blender/blenkernel/intern/dynamicpaint.c
+++ b/source/blender/blenkernel/intern/dynamicpaint.c
@@ -2460,8 +2460,7 @@ static void dynamic_paint_find_island_border(
const unsigned int *other_loop_idx = mlooptri[lt_index].tri;
/* Check edges for match, looping in the same order as the outer loop. */
- for (int j = 0; j < 3; j++)
- {
+ for (int j = 0; j < 3; j++) {
const int overt0 = mloop[other_loop_idx[(j + 0)]].v;
const int overt1 = mloop[other_loop_idx[(j + 1) % 3]].v;
@@ -2525,8 +2524,7 @@ static void dynamic_paint_find_island_border(
int final_pixel[2] = { (int)floorf(tgt_pixel[0] * w), (int)floorf(tgt_pixel[1] * h) };
/* If current pixel uv is outside of texture */
- if (final_pixel[0] < 0 || final_pixel[0] >= w || final_pixel[1] < 0 || final_pixel[1] >= h)
- {
+ if (final_pixel[0] < 0 || final_pixel[0] >= w || final_pixel[1] < 0 || final_pixel[1] >= h) {
if (bdata->best_index == NOT_FOUND)
bdata->best_index = OUT_OF_TEXTURE;
diff --git a/source/blender/blenkernel/intern/editderivedmesh.c b/source/blender/blenkernel/intern/editderivedmesh.c
index e7c0e69b1cb..2fffa0dea28 100644
--- a/source/blender/blenkernel/intern/editderivedmesh.c
+++ b/source/blender/blenkernel/intern/editderivedmesh.c
@@ -642,10 +642,10 @@ static void emDM_recalcLoopTri(DerivedMesh *dm)
MLoopTri *lt = &mlooptri[i];
ARRAY_SET_ITEMS(
- lt->tri,
- BM_elem_index_get(ltri[0]),
- BM_elem_index_get(ltri[1]),
- BM_elem_index_get(ltri[2]));
+ lt->tri,
+ BM_elem_index_get(ltri[0]),
+ BM_elem_index_get(ltri[1]),
+ BM_elem_index_get(ltri[2]));
lt->poly = BM_elem_index_get(ltri[0]->f);
}
}
diff --git a/source/blender/blenkernel/intern/effect.c b/source/blender/blenkernel/intern/effect.c
index fe8f5ebdca6..4eee24b378f 100644
--- a/source/blender/blenkernel/intern/effect.c
+++ b/source/blender/blenkernel/intern/effect.c
@@ -848,6 +848,14 @@ static void do_physical_effector(EffectorCache *eff, EffectorData *efd, Effected
break;
case PFIELD_FORCE:
normalize_v3(force);
+ if (pd->flag & PFIELD_GRAVITATION){ /* Option: Multiply by 1/distance^2 */
+ if (efd->distance < FLT_EPSILON){
+ strength = 0.0f;
+ }
+ else {
+ strength *= powf(efd->distance, -2.0f);
+ }
+ }
mul_v3_fl(force, strength * efd->falloff);
break;
case PFIELD_VORTEX:
diff --git a/source/blender/blenkernel/intern/fcurve.c b/source/blender/blenkernel/intern/fcurve.c
index c67a61a5aad..7dbc43e0a32 100644
--- a/source/blender/blenkernel/intern/fcurve.c
+++ b/source/blender/blenkernel/intern/fcurve.c
@@ -1217,6 +1217,7 @@ bool driver_get_variable_property(
return true;
}
+#if 0
/* Helper function to obtain a pointer to a Pose Channel (for evaluating drivers) */
static bPoseChannel *dtar_get_pchan_ptr(ChannelDriver *driver, DriverTarget *dtar)
{
@@ -1239,6 +1240,32 @@ static bPoseChannel *dtar_get_pchan_ptr(ChannelDriver *driver, DriverTarget *dta
return NULL;
}
}
+#endif
+
+static short driver_check_valid_targets(ChannelDriver *driver, DriverVar *dvar)
+{
+ short valid_targets = 0;
+
+ DRIVER_TARGETS_USED_LOOPER(dvar)
+ {
+ Object *ob = (Object *)dtar_id_ensure_proxy_from(dtar->id);
+
+ /* check if this target has valid data */
+ if ((ob == NULL) || (GS(ob->id.name) != ID_OB)) {
+ /* invalid target, so will not have enough targets */
+ driver->flag |= DRIVER_FLAG_INVALID;
+ dtar->flag |= DTAR_FLAG_INVALID;
+ }
+ else {
+ /* target seems to be OK now... */
+ dtar->flag &= ~DTAR_FLAG_INVALID;
+ valid_targets++;
+ }
+ }
+ DRIVER_TARGETS_LOOPER_END
+
+ return valid_targets;
+}
/* ......... */
@@ -1252,62 +1279,54 @@ static float dvar_eval_singleProp(ChannelDriver *driver, DriverVar *dvar)
/* evaluate 'rotation difference' driver variable */
static float dvar_eval_rotDiff(ChannelDriver *driver, DriverVar *dvar)
{
- DriverTarget *dtar1 = &dvar->targets[0];
- DriverTarget *dtar2 = &dvar->targets[1];
- bPoseChannel *pchan, *pchan2;
- float q1[4], q2[4], quat[4], angle;
-
- /* get pose channels, and check if we've got two */
- pchan = dtar_get_pchan_ptr(driver, dtar1);
- pchan2 = dtar_get_pchan_ptr(driver, dtar2);
-
- if (ELEM(NULL, pchan, pchan2)) {
- /* disable this driver, since it doesn't work correctly... */
- driver->flag |= DRIVER_FLAG_INVALID;
-
- /* check what the error was */
- if ((pchan == NULL) && (pchan2 == NULL)) {
- if (G.debug & G_DEBUG) {
- printf("Driver Evaluation Error: Rotational difference failed - first 2 targets invalid\n");
- }
-
- dtar1->flag |= DTAR_FLAG_INVALID;
- dtar2->flag |= DTAR_FLAG_INVALID;
- }
- else if (pchan == NULL) {
- if (G.debug & G_DEBUG) {
- printf("Driver Evaluation Error: Rotational difference failed - first target not valid PoseChannel\n");
- }
-
- dtar1->flag |= DTAR_FLAG_INVALID;
- dtar2->flag &= ~DTAR_FLAG_INVALID;
- }
- else if (pchan2 == NULL) {
- if (G.debug & G_DEBUG) {
- printf("Driver Evaluation Error: Rotational difference failed - second target not valid PoseChannel\n");
- }
-
- dtar1->flag &= ~DTAR_FLAG_INVALID;
- dtar2->flag |= DTAR_FLAG_INVALID;
+ short valid_targets = driver_check_valid_targets(driver, dvar);
+
+ /* make sure we have enough valid targets to use - all or nothing for now... */
+ if (driver_check_valid_targets(driver, dvar) != 2) {
+ if (G.debug & G_DEBUG) {
+ printf("RotDiff DVar: not enough valid targets (n = %d) (a = %p, b = %p)\n",
+ valid_targets, dvar->targets[0].id, dvar->targets[1].id);
}
-
- /* stop here... */
return 0.0f;
}
- else {
- dtar1->flag &= ~DTAR_FLAG_INVALID;
- dtar2->flag &= ~DTAR_FLAG_INVALID;
+
+ float (*mat[2])[4];
+
+ /* NOTE: for now, these are all just worldspace */
+ for (int i = 0; i < 2; i++) {
+ /* get pointer to loc values to store in */
+ DriverTarget *dtar = &dvar->targets[i];
+ Object *ob = (Object *)dtar_id_ensure_proxy_from(dtar->id);
+ bPoseChannel *pchan;
+
+ /* after the checks above, the targets should be valid here... */
+ BLI_assert((ob != NULL) && (GS(ob->id.name) == ID_OB));
+
+ /* try to get posechannel */
+ pchan = BKE_pose_channel_find_name(ob->pose, dtar->pchan_name);
+
+ /* check if object or bone */
+ if (pchan) {
+ /* bone */
+ mat[i] = pchan->pose_mat;
+ }
+ else {
+ /* object */
+ mat[i] = ob->obmat;
+ }
}
-
+
+ float q1[4], q2[4], quat[4], angle;
+
/* use the final posed locations */
- mat4_to_quat(q1, pchan->pose_mat);
- mat4_to_quat(q2, pchan2->pose_mat);
-
+ mat4_to_quat(q1, mat[0]);
+ mat4_to_quat(q2, mat[1]);
+
invert_qt_normalized(q1);
mul_qt_qtqt(quat, q1, q2);
angle = 2.0f * (saacos(quat[0]));
angle = ABS(angle);
-
+
return (angle > (float)M_PI) ? (float)((2.0f * (float)M_PI) - angle) : (float)(angle);
}
@@ -1317,32 +1336,8 @@ static float dvar_eval_locDiff(ChannelDriver *driver, DriverVar *dvar)
{
float loc1[3] = {0.0f, 0.0f, 0.0f};
float loc2[3] = {0.0f, 0.0f, 0.0f};
- short valid_targets = 0;
-
- /* Perform two passes
- *
- * FIRST PASS - to just check that everything works...
- * NOTE: we use loops here to reduce code duplication, though in practice,
- * there can only be 2 items or else we run into some problems later
- */
- DRIVER_TARGETS_USED_LOOPER(dvar)
- {
- Object *ob = (Object *)dtar_id_ensure_proxy_from(dtar->id);
-
- /* check if this target has valid data */
- if ((ob == NULL) || (GS(ob->id.name) != ID_OB)) {
- /* invalid target, so will not have enough targets */
- driver->flag |= DRIVER_FLAG_INVALID;
- dtar->flag |= DTAR_FLAG_INVALID;
- }
- else {
- /* target seems to be OK now... */
- dtar->flag &= ~DTAR_FLAG_INVALID;
- valid_targets++;
- }
- }
- DRIVER_TARGETS_LOOPER_END
-
+ short valid_targets = driver_check_valid_targets(driver, dvar);
+
/* make sure we have enough valid targets to use - all or nothing for now... */
if (valid_targets < dvar->num_targets) {
if (G.debug & G_DEBUG) {
@@ -1351,8 +1346,7 @@ static float dvar_eval_locDiff(ChannelDriver *driver, DriverVar *dvar)
}
return 0.0f;
}
-
-
+
/* SECOND PASS: get two location values */
/* NOTE: for now, these are all just worldspace */
DRIVER_TARGETS_USED_LOOPER(dvar)
@@ -1570,7 +1564,7 @@ static DriverVarTypeInfo dvar_types[MAX_DVAR_TYPES] = {
BEGIN_DVAR_TYPEDEF(DVAR_TYPE_ROT_DIFF)
dvar_eval_rotDiff, /* eval callback */
2, /* number of targets used */
- {"Bone 1", "Bone 2"}, /* UI names for targets */
+ {"Object/Bone 1", "Object/Bone 2"}, /* UI names for targets */
{DTAR_FLAG_STRUCT_REF | DTAR_FLAG_ID_OB_ONLY, DTAR_FLAG_STRUCT_REF | DTAR_FLAG_ID_OB_ONLY} /* flags */
END_DVAR_TYPEDEF,
diff --git a/source/blender/blenkernel/intern/idprop.c b/source/blender/blenkernel/intern/idprop.c
index b2641b110f8..a596869e5e8 100644
--- a/source/blender/blenkernel/intern/idprop.c
+++ b/source/blender/blenkernel/intern/idprop.c
@@ -130,18 +130,22 @@ void IDP_FreeIDPArray(IDProperty *prop)
MEM_freeN(prop->data.pointer);
}
-/*shallow copies item*/
+/* shallow copies item */
void IDP_SetIndexArray(IDProperty *prop, int index, IDProperty *item)
{
IDProperty *old;
BLI_assert(prop->type == IDP_IDPARRAY);
+ if (index >= prop->len || index < 0)
+ return;
+
old = GETPROP(prop, index);
- if (index >= prop->len || index < 0) return;
- if (item != old) IDP_FreeProperty(old);
-
- memcpy(GETPROP(prop, index), item, sizeof(IDProperty));
+ if (item != old) {
+ IDP_FreeProperty(old);
+
+ memcpy(old, item, sizeof(IDProperty));
+ }
}
IDProperty *IDP_GetIndexArray(IDProperty *prop, int index)
diff --git a/source/blender/blenkernel/intern/image.c b/source/blender/blenkernel/intern/image.c
index a2d94ccc478..318f6480aaf 100644
--- a/source/blender/blenkernel/intern/image.c
+++ b/source/blender/blenkernel/intern/image.c
@@ -3159,7 +3159,7 @@ static ImBuf *load_sequence_single(Image *ima, ImageUser *iuser, int frame, cons
struct ImBuf *ibuf;
char name[FILE_MAX];
int flag;
- ImageUser iuser_t;
+ ImageUser iuser_t = {0};
/* XXX temp stuff? */
if (ima->lastframe != frame)
@@ -3167,8 +3167,12 @@ static ImBuf *load_sequence_single(Image *ima, ImageUser *iuser, int frame, cons
ima->lastframe = frame;
- if (iuser)
+ if (iuser) {
iuser_t = *iuser;
+ }
+ else {
+ /* TODO(sergey): Do we need to initialize something here? */
+ }
iuser_t.view = view_id;
BKE_image_user_file_path(&iuser_t, ima, name);
diff --git a/source/blender/blenkernel/intern/lattice.c b/source/blender/blenkernel/intern/lattice.c
index b0671f33094..54cfae620a1 100644
--- a/source/blender/blenkernel/intern/lattice.c
+++ b/source/blender/blenkernel/intern/lattice.c
@@ -67,7 +67,7 @@
#include "BKE_deform.h"
-/* Workaround for cyclic depenndnecy with curves.
+/* Workaround for cyclic dependency with curves.
* In such case curve_cache might not be ready yet,
*/
#define CYCLIC_DEPENDENCY_WORKAROUND
diff --git a/source/blender/blenkernel/intern/library.c b/source/blender/blenkernel/intern/library.c
index 6b4b492b212..e380b5c17e0 100644
--- a/source/blender/blenkernel/intern/library.c
+++ b/source/blender/blenkernel/intern/library.c
@@ -1863,7 +1863,7 @@ void BKE_library_make_local(
/* Special case for objects because we don't want proxy pointers to be
* cleared yet. This will happen down the road in this function.
*/
- BKE_object_make_local_ex(bmain, (Object*)id, true, false);
+ BKE_object_make_local_ex(bmain, (Object *)id, true, false);
}
else {
id_make_local(bmain, id, false, true);
diff --git a/source/blender/blenkernel/intern/library_remap.c b/source/blender/blenkernel/intern/library_remap.c
index a408b498f18..b6f4621a0b3 100644
--- a/source/blender/blenkernel/intern/library_remap.c
+++ b/source/blender/blenkernel/intern/library_remap.c
@@ -179,6 +179,7 @@ static int foreach_libblock_remap_callback(void *user_data, ID *id_self, ID **id
* on the other hand since they get reset to lib data on file open/reload it is indirect too...
* Edit Mode is also a 'skip direct' case. */
const bool is_obj = (GS(id->name) == ID_OB);
+ const bool is_obj_proxy = (is_obj && (((Object *)id)->proxy || ((Object *)id)->proxy_group));
const bool is_obj_editmode = (is_obj && BKE_object_is_in_editmode((Object *)id));
const bool is_never_null = ((cb_flag & IDWALK_CB_NEVER_NULL) && (new_id == NULL) &&
(id_remap_data->flag & ID_REMAP_FORCE_NEVER_NULL_USAGE) == 0);
@@ -231,7 +232,7 @@ static int foreach_libblock_remap_callback(void *user_data, ID *id_self, ID **id
/* We cannot affect old_id->us directly, LIB_TAG_EXTRAUSER(_SET) are assumed to be set as needed,
* that extra user is processed in final handling... */
}
- if (!is_indirect) {
+ if (!is_indirect || is_obj_proxy) {
id_remap_data->status |= ID_REMAP_IS_LINKED_DIRECT;
}
}
diff --git a/source/blender/blenkernel/intern/mesh.c b/source/blender/blenkernel/intern/mesh.c
index af02e02b017..c12890a354e 100644
--- a/source/blender/blenkernel/intern/mesh.c
+++ b/source/blender/blenkernel/intern/mesh.c
@@ -39,7 +39,9 @@
#include "BLI_utildefines.h"
#include "BLI_math.h"
+#include "BLI_linklist.h"
#include "BLI_listbase.h"
+#include "BLI_memarena.h"
#include "BLI_edgehash.h"
#include "BLI_string.h"
@@ -66,6 +68,11 @@
#include "DEG_depsgraph.h"
+/* Define for cases when you want extra validation of mesh
+ * after certain modifications.
+ */
+// #undef VALIDATE_MESH
+
enum {
MESHCMP_DVERT_WEIGHTMISMATCH = 1,
MESHCMP_DVERT_GROUPMISMATCH,
@@ -2048,7 +2055,7 @@ void BKE_mesh_mselect_active_set(Mesh *me, int index, int type)
(me->mselect[me->totselect - 1].type == type));
}
-void BKE_mesh_calc_normals_split(Mesh *mesh)
+void BKE_mesh_calc_normals_split_ex(Mesh *mesh, MLoopNorSpaceArray *r_lnors_spacearr)
{
float (*r_loopnors)[3];
float (*polynors)[3];
@@ -2083,113 +2090,339 @@ void BKE_mesh_calc_normals_split(Mesh *mesh)
BKE_mesh_normals_loop_split(
mesh->mvert, mesh->totvert, mesh->medge, mesh->totedge,
mesh->mloop, r_loopnors, mesh->totloop, mesh->mpoly, (const float (*)[3])polynors, mesh->totpoly,
- (mesh->flag & ME_AUTOSMOOTH) != 0, mesh->smoothresh, NULL, clnors, NULL);
+ (mesh->flag & ME_AUTOSMOOTH) != 0, mesh->smoothresh, r_lnors_spacearr, clnors, NULL);
if (free_polynors) {
MEM_freeN(polynors);
}
}
-/* Spli faces based on the edge angle.
- * Matches behavior of face splitting in render engines.
- */
-void BKE_mesh_split_faces(Mesh *mesh)
+void BKE_mesh_calc_normals_split(Mesh *mesh)
{
- const int num_verts = mesh->totvert;
- const int num_edges = mesh->totedge;
- const int num_polys = mesh->totpoly;
+ BKE_mesh_calc_normals_split_ex(mesh, NULL);
+}
+
+/* Split faces helper functions. */
+
+typedef struct SplitFaceNewVert {
+ struct SplitFaceNewVert *next;
+ int new_index;
+ int orig_index;
+ float *vnor;
+} SplitFaceNewVert;
+
+typedef struct SplitFaceNewEdge {
+ struct SplitFaceNewEdge *next;
+ int new_index;
+ int orig_index;
+ int v1;
+ int v2;
+} SplitFaceNewEdge;
+
+/* Detect needed new vertices, and update accordingly loops' vertex indices.
+ * WARNING! Leaves mesh in invalid state. */
+static int split_faces_prepare_new_verts(
+ const Mesh *mesh, MLoopNorSpaceArray *lnors_spacearr, SplitFaceNewVert **new_verts, MemArena *memarena,
+ bool *r_need_vnors_recalc)
+{
+ /* Note: if lnors_spacearr is NULL, ther is no autosmooth handling, and we only split out flat polys. */
+ const int num_loops = mesh->totloop;
+ int num_verts = mesh->totvert;
MVert *mvert = mesh->mvert;
- MEdge *medge = mesh->medge;
MLoop *mloop = mesh->mloop;
- MPoly *mpoly = mesh->mpoly;
- float (*lnors)[3];
- int poly, num_new_verts = 0;
- if ((mesh->flag & ME_AUTOSMOOTH) == 0) {
- return;
- }
- BKE_mesh_tessface_clear(mesh);
- /* Compute loop normals if needed. */
- if (!CustomData_has_layer(&mesh->ldata, CD_NORMAL)) {
- BKE_mesh_calc_normals_split(mesh);
- }
- lnors = CustomData_get_layer(&mesh->ldata, CD_NORMAL);
- /* Count number of vertices to be split. */
- for (poly = 0; poly < num_polys; poly++) {
- MPoly *mp = &mpoly[poly];
- int loop;
- for (loop = 0; loop < mp->totloop; loop++) {
- MLoop *ml = &mloop[mp->loopstart + loop];
- MVert *mv = &mvert[ml->v];
- float vn[3];
- normal_short_to_float_v3(vn, mv->no);
- if (!equals_v3v3(vn, lnors[mp->loopstart + loop])) {
- num_new_verts++;
+
+ BLI_bitmap *verts_used = BLI_BITMAP_NEW(num_verts, __func__);
+
+ if (lnors_spacearr) {
+ BLI_bitmap *done_loops = BLI_BITMAP_NEW(num_loops, __func__);
+
+ MLoop *ml = mloop;
+ MLoopNorSpace **lnor_space = lnors_spacearr->lspacearr;
+ for (int loop_idx = 0; loop_idx < num_loops; loop_idx++, ml++, lnor_space++) {
+ if (!BLI_BITMAP_TEST(done_loops, loop_idx)) {
+ const int vert_idx = ml->v;
+ const bool vert_used = BLI_BITMAP_TEST_BOOL(verts_used, vert_idx);
+ /* If vert is already used by another smooth fan, we need a new vert for this one. */
+ const int new_vert_idx = vert_used ? num_verts++ : vert_idx;
+
+ BLI_assert(*lnor_space);
+
+ if ((*lnor_space)->loops) {
+ for (LinkNode *lnode = (*lnor_space)->loops; lnode; lnode = lnode->next) {
+ const int ml_fan_idx = GET_INT_FROM_POINTER(lnode->link);
+ BLI_BITMAP_ENABLE(done_loops, ml_fan_idx);
+ if (vert_used) {
+ mloop[ml_fan_idx].v = new_vert_idx;
+ }
+ }
+ }
+ else {
+ /* Single loop in this fan... */
+ BLI_BITMAP_ENABLE(done_loops, loop_idx);
+ if (vert_used) {
+ ml->v = new_vert_idx;
+ }
+ }
+
+ if (!vert_used) {
+ BLI_BITMAP_ENABLE(verts_used, vert_idx);
+ /* We need to update that vertex's normal here, we won't go over it again. */
+ /* This is important! *DO NOT* set vnor to final computed lnor, vnor should always be defined to
+ * 'automatic normal' value computed from its polys, not some custom normal.
+ * Fortunately, that's the loop normal space's 'lnor' reference vector. ;) */
+ normal_float_to_short_v3(mvert[vert_idx].no, (*lnor_space)->vec_lnor);
+ }
+ else {
+ /* Add new vert to list. */
+ SplitFaceNewVert *new_vert = BLI_memarena_alloc(memarena, sizeof(*new_vert));
+ new_vert->orig_index = vert_idx;
+ new_vert->new_index = new_vert_idx;
+ new_vert->vnor = (*lnor_space)->vec_lnor; /* See note above. */
+ new_vert->next = *new_verts;
+ *new_verts = new_vert;
+ }
}
}
+
+ MEM_freeN(done_loops);
}
- if (num_new_verts == 0) {
- /* No new vertices are to be added, can do early exit. */
- return;
- }
- /* Reallocate all vert and edge related data. */
- mesh->totvert += num_new_verts;
- mesh->totedge += 2 * num_new_verts;
- CustomData_realloc(&mesh->vdata, mesh->totvert);
- CustomData_realloc(&mesh->edata, mesh->totedge);
- /* Update pointers to a newly allocated memory. */
- BKE_mesh_update_customdata_pointers(mesh, false);
- mvert = mesh->mvert;
- medge = mesh->medge;
- /* Perform actual vertex split. */
- num_new_verts = 0;
- for (poly = 0; poly < num_polys; poly++) {
- MPoly *mp = &mpoly[poly];
- int loop;
- for (loop = 0; loop < mp->totloop; loop++) {
- int poly_loop = mp->loopstart + loop;
- MLoop *ml = &mloop[poly_loop];
- MVert *mv = &mvert[ml->v];
- float vn[3];
- normal_short_to_float_v3(vn, mv->no);
- if (!equals_v3v3(vn, lnors[mp->loopstart + loop])) {
- int poly_loop_prev = mp->loopstart + (loop + mp->totloop - 1) % mp->totloop;
- MLoop *ml_prev = &mloop[poly_loop_prev];
- int new_edge_prev, new_edge;
- /* Cretae new vertex. */
- int new_vert = num_verts + num_new_verts;
- CustomData_copy_data(&mesh->vdata, &mesh->vdata,
- ml->v, new_vert, 1);
- normal_float_to_short_v3(mvert[new_vert].no,
- lnors[poly_loop]);
- /* Create new edges. */
- new_edge_prev = num_edges + 2 * num_new_verts;
- new_edge = num_edges + 2 * num_new_verts + 1;
- CustomData_copy_data(&mesh->edata, &mesh->edata,
- ml_prev->e, new_edge_prev, 1);
- CustomData_copy_data(&mesh->edata, &mesh->edata,
- ml->e, new_edge, 1);
- if (medge[new_edge_prev].v1 == ml->v) {
- medge[new_edge_prev].v1 = new_vert;
+ else {
+ /* No loop normal spaces available, we only split out flat polys. */
+ const int num_polys = mesh->totpoly;
+ const MPoly *mpoly = mesh->mpoly;
+
+ /* We do that in two loops, to keep original edges/verts to smooth polys preferencially. */
+ const MPoly *mp = mpoly;
+ for (int i = 0; i < num_polys; i++, mp++) {
+ if (mp->flag & ME_SMOOTH) {
+ const MLoop *ml = &mloop[mp->loopstart];
+ for (int j = 0; j < mp->totloop; j++, ml++) {
+ /* Just mark the vertex as used/reserved, that way neighbor flat polys, if any,
+ * will have to create their own. */
+ BLI_BITMAP_ENABLE(verts_used, ml->v);
}
- else {
- medge[new_edge_prev].v2 = new_vert;
+ }
+ }
+
+ mp = mpoly;
+ for (int i = 0; i < num_polys; i++, mp++) {
+ if (!(mp->flag & ME_SMOOTH)) {
+ MLoop *ml = &mloop[mp->loopstart];
+ for (int j = 0; j < mp->totloop; j++, ml++) {
+ const int vert_idx = ml->v;
+
+ if (BLI_BITMAP_TEST(verts_used, vert_idx)) {
+ /* Add new vert to list. */
+ const int new_vert_idx = num_verts++;
+ ml->v = new_vert_idx;
+
+ SplitFaceNewVert *new_vert = BLI_memarena_alloc(memarena, sizeof(*new_vert));
+ new_vert->orig_index = vert_idx;
+ new_vert->new_index = new_vert_idx;
+ new_vert->vnor = NULL; /* See note below about normals. */
+ new_vert->next = *new_verts;
+ *new_verts = new_vert;
+ }
+ else {
+ BLI_BITMAP_ENABLE(verts_used, vert_idx);
+ }
}
- if (medge[new_edge].v1 == ml->v) {
- medge[new_edge].v1 = new_vert;
+ /* Note: there is no way to get new normals for smooth vertices here (and we don't have direct access
+ * to poly normals either for flat ones), so we'll have to recompute all vnors at the end... */
+ *r_need_vnors_recalc = true;
+ }
+ }
+ }
+
+ MEM_freeN(verts_used);
+
+ return num_verts - mesh->totvert;
+}
+
+/* Detect needed new edges, and update accordingly loops' edge indices.
+ * WARNING! Leaves mesh in invalid state. */
+static int split_faces_prepare_new_edges(
+ const Mesh *mesh, SplitFaceNewEdge **new_edges, MemArena *memarena)
+{
+ const int num_polys = mesh->totpoly;
+ int num_edges = mesh->totedge;
+ MEdge *medge = mesh->medge;
+ MLoop *mloop = mesh->mloop;
+ const MPoly *mpoly = mesh->mpoly;
+
+ BLI_bitmap *edges_used = BLI_BITMAP_NEW(num_edges, __func__);
+ EdgeHash *edges_hash = BLI_edgehash_new_ex(__func__, num_edges);
+
+ const MPoly *mp = mpoly;
+ for (int poly_idx = 0; poly_idx < num_polys; poly_idx++, mp++) {
+ MLoop *ml_prev = &mloop[mp->loopstart + mp->totloop - 1];
+ MLoop *ml = &mloop[mp->loopstart];
+ for (int loop_idx = 0; loop_idx < mp->totloop; loop_idx++, ml++) {
+ void **eval;
+ if (!BLI_edgehash_ensure_p(edges_hash, ml_prev->v, ml->v, &eval)) {
+ const int edge_idx = ml_prev->e;
+
+ /* That edge has not been encountered yet, define it. */
+ if (BLI_BITMAP_TEST(edges_used, edge_idx)) {
+ /* Original edge has already been used, we need to define a new one. */
+ const int new_edge_idx = num_edges++;
+ *eval = SET_INT_IN_POINTER(new_edge_idx);
+ ml_prev->e = new_edge_idx;
+
+ SplitFaceNewEdge *new_edge = BLI_memarena_alloc(memarena, sizeof(*new_edge));
+ new_edge->orig_index = edge_idx;
+ new_edge->new_index = new_edge_idx;
+ new_edge->v1 = ml_prev->v;
+ new_edge->v2 = ml->v;
+ new_edge->next = *new_edges;
+ *new_edges = new_edge;
}
else {
- medge[new_edge].v2 = new_vert;
+ /* We can re-use original edge. */
+ medge[edge_idx].v1 = ml_prev->v;
+ medge[edge_idx].v2 = ml->v;
+ *eval = SET_INT_IN_POINTER(edge_idx);
+ BLI_BITMAP_ENABLE(edges_used, edge_idx);
}
-
- ml->v = new_vert;
- ml_prev->e = new_edge_prev;
- ml->e = new_edge;
- num_new_verts++;
}
+ else {
+ /* Edge already known, just update loop's edge index. */
+ ml_prev->e = GET_INT_FROM_POINTER(*eval);
+ }
+
+ ml_prev = ml;
+ }
+ }
+
+ MEM_freeN(edges_used);
+ BLI_edgehash_free(edges_hash, NULL);
+
+ return num_edges - mesh->totedge;
+}
+
+/* Perform actual split of vertices. */
+static void split_faces_split_new_verts(
+ Mesh *mesh, SplitFaceNewVert *new_verts, const int num_new_verts)
+{
+ const int num_verts = mesh->totvert - num_new_verts;
+ MVert *mvert = mesh->mvert;
+
+ /* Remember new_verts is a single linklist, so its items are in reversed order... */
+ MVert *new_mv = &mvert[mesh->totvert - 1];
+ for (int i = mesh->totvert - 1; i >= num_verts ; i--, new_mv--, new_verts = new_verts->next) {
+ BLI_assert(new_verts->new_index == i);
+ BLI_assert(new_verts->new_index != new_verts->orig_index);
+ CustomData_copy_data(&mesh->vdata, &mesh->vdata, new_verts->orig_index, i, 1);
+ if (new_verts->vnor) {
+ normal_float_to_short_v3(new_mv->no, new_verts->vnor);
}
}
}
+/* Perform actual split of edges. */
+static void split_faces_split_new_edges(
+ Mesh *mesh, SplitFaceNewEdge *new_edges, const int num_new_edges)
+{
+ const int num_edges = mesh->totedge - num_new_edges;
+ MEdge *medge = mesh->medge;
+
+ /* Remember new_edges is a single linklist, so its items are in reversed order... */
+ MEdge *new_med = &medge[mesh->totedge - 1];
+ for (int i = mesh->totedge - 1; i >= num_edges ; i--, new_med--, new_edges = new_edges->next) {
+ BLI_assert(new_edges->new_index == i);
+ BLI_assert(new_edges->new_index != new_edges->orig_index);
+ CustomData_copy_data(&mesh->edata, &mesh->edata, new_edges->orig_index, i, 1);
+ new_med->v1 = new_edges->v1;
+ new_med->v2 = new_edges->v2;
+ }
+}
+
+/* Split faces based on the edge angle and loop normals.
+ * Matches behavior of face splitting in render engines.
+ *
+ * NOTE: Will leave CD_NORMAL loop data layer which is
+ * used by render engines to set shading up.
+ */
+void BKE_mesh_split_faces(Mesh *mesh, bool free_loop_normals)
+{
+ const int num_polys = mesh->totpoly;
+
+ if (num_polys == 0) {
+ return;
+ }
+ BKE_mesh_tessface_clear(mesh);
+
+ MLoopNorSpaceArray *lnors_spacearr = NULL;
+ MemArena *memarena;
+ bool need_vnors_recalc = false;
+
+ if (mesh->flag & ME_AUTOSMOOTH) {
+ lnors_spacearr = MEM_callocN(sizeof(*lnors_spacearr), __func__);
+ /* Compute loop normals and loop normal spaces (a.k.a. smooth fans of faces around vertices). */
+ BKE_mesh_calc_normals_split_ex(mesh, lnors_spacearr);
+ /* Stealing memarena from loop normals space array. */
+ memarena = lnors_spacearr->mem;
+ }
+ else {
+ /* We still have to split out flat faces... */
+ memarena = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, __func__);
+ }
+
+ SplitFaceNewVert *new_verts = NULL;
+ SplitFaceNewEdge *new_edges = NULL;
+
+ /* Detect loop normal spaces (a.k.a. smooth fans) that will need a new vert. */
+ const int num_new_verts = split_faces_prepare_new_verts(mesh, lnors_spacearr, &new_verts, memarena, &need_vnors_recalc);
+
+ if (num_new_verts > 0) {
+ /* Reminder: beyond this point, there is no way out, mesh is in invalid state (due to early-reassignment of
+ * loops' vertex and edge indices to new, to-be-created split ones). */
+
+ const int num_new_edges = split_faces_prepare_new_edges(mesh, &new_edges, memarena);
+ /* We can have to split a vertex without having to add a single new edge... */
+ const bool do_edges = (num_new_edges > 0);
+
+ /* Reallocate all vert and edge related data. */
+ mesh->totvert += num_new_verts;
+ mesh->totedge += num_new_edges;
+ CustomData_realloc(&mesh->vdata, mesh->totvert);
+ if (do_edges) {
+ CustomData_realloc(&mesh->edata, mesh->totedge);
+ }
+ /* Update pointers to a newly allocated memory. */
+ BKE_mesh_update_customdata_pointers(mesh, false);
+
+ /* Perform actual split of vertices and edges. */
+ split_faces_split_new_verts(mesh, new_verts, num_new_verts);
+ if (do_edges) {
+ split_faces_split_new_edges(mesh, new_edges, num_new_edges);
+ }
+ }
+
+ /* Note: after this point mesh is expected to be valid again. */
+
+ /* CD_NORMAL is expected to be temporary only. */
+ if (free_loop_normals) {
+ CustomData_free_layers(&mesh->ldata, CD_NORMAL, mesh->totloop);
+ }
+
+ if (lnors_spacearr) {
+ /* Also frees new_verts/edges temp data, since we used its memarena to allocate them. */
+ BKE_lnor_spacearr_free(lnors_spacearr);
+ MEM_freeN(lnors_spacearr);
+ }
+ else {
+ BLI_memarena_free(memarena);
+ }
+
+ if (need_vnors_recalc) {
+ BKE_mesh_calc_normals(mesh);
+ }
+#ifdef VALIDATE_MESH
+ BKE_mesh_validate(mesh, true, true);
+#endif
+}
+
/* settings: 1 - preview, 2 - render */
Mesh *BKE_mesh_new_from_object(
Main *bmain, Scene *sce, Object *ob,
diff --git a/source/blender/blenkernel/intern/mesh_evaluate.c b/source/blender/blenkernel/intern/mesh_evaluate.c
index f9eba118383..0d0055113b7 100644
--- a/source/blender/blenkernel/intern/mesh_evaluate.c
+++ b/source/blender/blenkernel/intern/mesh_evaluate.c
@@ -304,13 +304,13 @@ void BKE_mesh_calc_normals_poly(
void BKE_mesh_calc_normals(Mesh *mesh)
{
#ifdef DEBUG_TIME
- TIMEIT_START(BKE_mesh_calc_normals);
+ TIMEIT_START_AVERAGED(BKE_mesh_calc_normals);
#endif
BKE_mesh_calc_normals_poly(mesh->mvert, NULL, mesh->totvert,
mesh->mloop, mesh->mpoly, mesh->totloop, mesh->totpoly,
NULL, false);
#ifdef DEBUG_TIME
- TIMEIT_END(BKE_mesh_calc_normals);
+ TIMEIT_END_AVERAGED(BKE_mesh_calc_normals);
#endif
}
@@ -630,7 +630,6 @@ typedef struct LoopSplitTaskDataCommon {
* Note we do not need to protect it, though, since two different tasks will *always* affect different
* elements in the arrays. */
MLoopNorSpaceArray *lnors_spacearr;
- BLI_bitmap *sharp_verts;
float (*loopnors)[3];
short (*clnors_data)[2];
@@ -643,11 +642,8 @@ typedef struct LoopSplitTaskDataCommon {
const int *loop_to_poly;
const float (*polynors)[3];
+ int numLoops;
int numPolys;
-
- /* ***** Workers communication. ***** */
- ThreadQueue *task_queue;
-
} LoopSplitTaskDataCommon;
#define INDEX_UNSET INT_MIN
@@ -655,6 +651,50 @@ typedef struct LoopSplitTaskDataCommon {
/* See comment about edge_to_loops below. */
#define IS_EDGE_SHARP(_e2l) (ELEM((_e2l)[1], INDEX_UNSET, INDEX_INVALID))
+static void loop_manifold_fan_around_vert_next(
+ const MLoop *mloops, const MPoly *mpolys,
+ const int *loop_to_poly, const int *e2lfan_curr, const uint mv_pivot_index,
+ const MLoop **r_mlfan_curr, int *r_mlfan_curr_index, int *r_mlfan_vert_index, int *r_mpfan_curr_index)
+{
+ const MLoop *mlfan_next;
+ const MPoly *mpfan_next;
+
+ /* Warning! This is rather complex!
+ * We have to find our next edge around the vertex (fan mode).
+ * First we find the next loop, which is either previous or next to mlfan_curr_index, depending
+ * whether both loops using current edge are in the same direction or not, and whether
+ * mlfan_curr_index actually uses the vertex we are fanning around!
+ * mlfan_curr_index is the index of mlfan_next here, and mlfan_next is not the real next one
+ * (i.e. not the future mlfan_curr)...
+ */
+ *r_mlfan_curr_index = (e2lfan_curr[0] == *r_mlfan_curr_index) ? e2lfan_curr[1] : e2lfan_curr[0];
+ *r_mpfan_curr_index = loop_to_poly[*r_mlfan_curr_index];
+
+ BLI_assert(*r_mlfan_curr_index >= 0);
+ BLI_assert(*r_mpfan_curr_index >= 0);
+
+ mlfan_next = &mloops[*r_mlfan_curr_index];
+ mpfan_next = &mpolys[*r_mpfan_curr_index];
+ if (((*r_mlfan_curr)->v == mlfan_next->v && (*r_mlfan_curr)->v == mv_pivot_index) ||
+ ((*r_mlfan_curr)->v != mlfan_next->v && (*r_mlfan_curr)->v != mv_pivot_index))
+ {
+ /* We need the previous loop, but current one is our vertex's loop. */
+ *r_mlfan_vert_index = *r_mlfan_curr_index;
+ if (--(*r_mlfan_curr_index) < mpfan_next->loopstart) {
+ *r_mlfan_curr_index = mpfan_next->loopstart + mpfan_next->totloop - 1;
+ }
+ }
+ else {
+ /* We need the next loop, which is also our vertex's loop. */
+ if (++(*r_mlfan_curr_index) >= mpfan_next->loopstart + mpfan_next->totloop) {
+ *r_mlfan_curr_index = mpfan_next->loopstart;
+ }
+ *r_mlfan_vert_index = *r_mlfan_curr_index;
+ }
+ *r_mlfan_curr = &mloops[*r_mlfan_curr_index];
+ /* And now we are back in sync, mlfan_curr_index is the index of mlfan_curr! Pff! */
+}
+
static void split_loop_nor_single_do(LoopSplitTaskDataCommon *common_data, LoopSplitTaskData *data)
{
MLoopNorSpaceArray *lnors_spacearr = common_data->lnors_spacearr;
@@ -680,7 +720,7 @@ static void split_loop_nor_single_do(LoopSplitTaskDataCommon *common_data, LoopS
*/
copy_v3_v3(*lnor, polynors[mp_index]);
- /* printf("BASIC: handling loop %d / edge %d / vert %d / poly %d\n", ml_curr_index, ml_curr->e, ml_curr->v, mp_index); */
+// printf("BASIC: handling loop %d / edge %d / vert %d / poly %d\n", ml_curr_index, ml_curr->e, ml_curr->v, mp_index);
/* If needed, generate this (simple!) lnor space. */
if (lnors_spacearr) {
@@ -747,8 +787,7 @@ static void split_loop_nor_fan_do(LoopSplitTaskDataCommon *common_data, LoopSpli
const MEdge *me_org = &medges[ml_curr->e]; /* ml_curr would be mlfan_prev if we needed that one */
const int *e2lfan_curr;
float vec_curr[3], vec_prev[3], vec_org[3];
- const MLoop *mlfan_curr, *mlfan_next;
- const MPoly *mpfan_next;
+ const MLoop *mlfan_curr;
float lnor[3] = {0.0f, 0.0f, 0.0f};
/* mlfan_vert_index: the loop of our current edge might not be the loop of our current vertex! */
int mlfan_curr_index, mlfan_vert_index, mpfan_curr_index;
@@ -787,7 +826,7 @@ static void split_loop_nor_fan_do(LoopSplitTaskDataCommon *common_data, LoopSpli
}
}
- /* printf("FAN: vert %d, start edge %d\n", mv_pivot_index, ml_curr->e); */
+// printf("FAN: vert %d, start edge %d\n", mv_pivot_index, ml_curr->e);
while (true) {
const MEdge *me_curr = &medges[mlfan_curr->e];
@@ -803,7 +842,7 @@ static void split_loop_nor_fan_do(LoopSplitTaskDataCommon *common_data, LoopSpli
normalize_v3(vec_curr);
}
- /* printf("\thandling edge %d / loop %d\n", mlfan_curr->e, mlfan_curr_index); */
+// printf("\thandling edge %d / loop %d\n", mlfan_curr->e, mlfan_curr_index);
{
/* Code similar to accumulate_vertex_normals_poly. */
@@ -845,46 +884,16 @@ static void split_loop_nor_fan_do(LoopSplitTaskDataCommon *common_data, LoopSpli
/* Current edge is sharp and we have finished with this fan of faces around this vert,
* or this vert is smooth, and we have completed a full turn around it.
*/
- /* printf("FAN: Finished!\n"); */
+// printf("FAN: Finished!\n");
break;
}
copy_v3_v3(vec_prev, vec_curr);
- /* Warning! This is rather complex!
- * We have to find our next edge around the vertex (fan mode).
- * First we find the next loop, which is either previous or next to mlfan_curr_index, depending
- * whether both loops using current edge are in the same direction or not, and whether
- * mlfan_curr_index actually uses the vertex we are fanning around!
- * mlfan_curr_index is the index of mlfan_next here, and mlfan_next is not the real next one
- * (i.e. not the future mlfan_curr)...
- */
- mlfan_curr_index = (e2lfan_curr[0] == mlfan_curr_index) ? e2lfan_curr[1] : e2lfan_curr[0];
- mpfan_curr_index = loop_to_poly[mlfan_curr_index];
-
- BLI_assert(mlfan_curr_index >= 0);
- BLI_assert(mpfan_curr_index >= 0);
-
- mlfan_next = &mloops[mlfan_curr_index];
- mpfan_next = &mpolys[mpfan_curr_index];
- if ((mlfan_curr->v == mlfan_next->v && mlfan_curr->v == mv_pivot_index) ||
- (mlfan_curr->v != mlfan_next->v && mlfan_curr->v != mv_pivot_index))
- {
- /* We need the previous loop, but current one is our vertex's loop. */
- mlfan_vert_index = mlfan_curr_index;
- if (--mlfan_curr_index < mpfan_next->loopstart) {
- mlfan_curr_index = mpfan_next->loopstart + mpfan_next->totloop - 1;
- }
- }
- else {
- /* We need the next loop, which is also our vertex's loop. */
- if (++mlfan_curr_index >= mpfan_next->loopstart + mpfan_next->totloop) {
- mlfan_curr_index = mpfan_next->loopstart;
- }
- mlfan_vert_index = mlfan_curr_index;
- }
- mlfan_curr = &mloops[mlfan_curr_index];
- /* And now we are back in sync, mlfan_curr_index is the index of mlfan_curr! Pff! */
+ /* Find next loop of the smooth fan. */
+ loop_manifold_fan_around_vert_next(
+ mloops, mpolys, loop_to_poly, e2lfan_curr, mv_pivot_index,
+ &mlfan_curr, &mlfan_curr_index, &mlfan_vert_index, &mpfan_curr_index);
e2lfan_curr = edge_to_loops[mlfan_curr->e];
}
@@ -955,31 +964,25 @@ static void loop_split_worker_do(
}
}
-static void loop_split_worker(TaskPool * __restrict UNUSED(pool), void *taskdata, int UNUSED(threadid))
+static void loop_split_worker(TaskPool * __restrict pool, void *taskdata, int UNUSED(threadid))
{
- LoopSplitTaskDataCommon *common_data = taskdata;
- LoopSplitTaskData *data_buff;
+ LoopSplitTaskDataCommon *common_data = BLI_task_pool_userdata(pool);
+ LoopSplitTaskData *data = taskdata;
/* Temp edge vectors stack, only used when computing lnor spacearr. */
BLI_Stack *edge_vectors = common_data->lnors_spacearr ? BLI_stack_new(sizeof(float[3]), __func__) : NULL;
#ifdef DEBUG_TIME
- TIMEIT_START(loop_split_worker);
+ TIMEIT_START_AVERAGED(loop_split_worker);
#endif
- while ((data_buff = BLI_thread_queue_pop(common_data->task_queue))) {
- LoopSplitTaskData *data = data_buff;
- int i;
-
- for (i = 0; i < LOOP_SPLIT_TASK_BLOCK_SIZE; i++, data++) {
- /* A NULL ml_curr is used to tag ended data! */
- if (data->ml_curr == NULL) {
- break;
- }
- loop_split_worker_do(common_data, data, edge_vectors);
+ for (int i = 0; i < LOOP_SPLIT_TASK_BLOCK_SIZE; i++, data++) {
+ /* A NULL ml_curr is used to tag ended data! */
+ if (data->ml_curr == NULL) {
+ break;
}
- MEM_freeN(data_buff);
+ loop_split_worker_do(common_data, data, edge_vectors);
}
if (edge_vectors) {
@@ -987,49 +990,117 @@ static void loop_split_worker(TaskPool * __restrict UNUSED(pool), void *taskdata
}
#ifdef DEBUG_TIME
- TIMEIT_END(loop_split_worker);
+ TIMEIT_END_AVERAGED(loop_split_worker);
#endif
}
-/* Note we use data_buff to detect whether we are in threaded context or not, in later case it is NULL. */
-static void loop_split_generator_do(LoopSplitTaskDataCommon *common_data, const bool threaded)
+/* Check whether gievn loop is part of an unknown-so-far cyclic smooth fan, or not.
+ * Needed because cyclic smooth fans have no obvious 'entry point', and yet we need to walk them once, and only once. */
+static bool loop_split_generator_check_cyclic_smooth_fan(
+ const MLoop *mloops, const MPoly *mpolys,
+ const int (*edge_to_loops)[2], const int *loop_to_poly, const int *e2l_prev, BLI_bitmap *skip_loops,
+ const MLoop *ml_curr, const MLoop *ml_prev, const int ml_curr_index, const int ml_prev_index,
+ const int mp_curr_index)
+{
+ const unsigned int mv_pivot_index = ml_curr->v; /* The vertex we are "fanning" around! */
+ const int *e2lfan_curr;
+ const MLoop *mlfan_curr;
+ /* mlfan_vert_index: the loop of our current edge might not be the loop of our current vertex! */
+ int mlfan_curr_index, mlfan_vert_index, mpfan_curr_index;
+
+ e2lfan_curr = e2l_prev;
+ if (IS_EDGE_SHARP(e2lfan_curr)) {
+ /* Sharp loop, so not a cyclic smooth fan... */
+ return false;
+ }
+
+ mlfan_curr = ml_prev;
+ mlfan_curr_index = ml_prev_index;
+ mlfan_vert_index = ml_curr_index;
+ mpfan_curr_index = mp_curr_index;
+
+ BLI_assert(mlfan_curr_index >= 0);
+ BLI_assert(mlfan_vert_index >= 0);
+ BLI_assert(mpfan_curr_index >= 0);
+
+ BLI_assert(!BLI_BITMAP_TEST(skip_loops, mlfan_vert_index));
+ BLI_BITMAP_ENABLE(skip_loops, mlfan_vert_index);
+
+ while(true) {
+ /* Find next loop of the smooth fan. */
+ loop_manifold_fan_around_vert_next(
+ mloops, mpolys, loop_to_poly, e2lfan_curr, mv_pivot_index,
+ &mlfan_curr, &mlfan_curr_index, &mlfan_vert_index, &mpfan_curr_index);
+
+ e2lfan_curr = edge_to_loops[mlfan_curr->e];
+
+ if (IS_EDGE_SHARP(e2lfan_curr)) {
+ /* Sharp loop/edge, so not a cyclic smooth fan... */
+ return false;
+ }
+ /* Smooth loop/edge... */
+ else if (BLI_BITMAP_TEST(skip_loops, mlfan_vert_index)) {
+ if (mlfan_vert_index == ml_curr_index) {
+ /* We walked around a whole cyclic smooth fan without finding any already-processed loop, means we can
+ * use initial ml_curr/ml_prev edge as start for this smooth fan. */
+ return true;
+ }
+ /* ... already checked in some previous looping, we can abort. */
+ return false;
+ }
+ else {
+ /* ... we can skip it in future, and keep checking the smooth fan. */
+ BLI_BITMAP_ENABLE(skip_loops, mlfan_vert_index);
+ }
+ }
+}
+
+static void loop_split_generator(TaskPool *pool, LoopSplitTaskDataCommon *common_data)
{
MLoopNorSpaceArray *lnors_spacearr = common_data->lnors_spacearr;
- BLI_bitmap *sharp_verts = common_data->sharp_verts;
float (*loopnors)[3] = common_data->loopnors;
const MLoop *mloops = common_data->mloops;
const MPoly *mpolys = common_data->mpolys;
+ const int *loop_to_poly = common_data->loop_to_poly;
const int (*edge_to_loops)[2] = common_data->edge_to_loops;
+ const int numLoops = common_data->numLoops;
const int numPolys = common_data->numPolys;
const MPoly *mp;
int mp_index;
- LoopSplitTaskData *data, *data_buff = NULL, data_mem;
+ const MLoop *ml_curr;
+ const MLoop *ml_prev;
+ int ml_curr_index;
+ int ml_prev_index;
+
+ BLI_bitmap *skip_loops = BLI_BITMAP_NEW(numLoops, __func__);
+
+ LoopSplitTaskData *data_buff = NULL;
int data_idx = 0;
/* Temp edge vectors stack, only used when computing lnor spacearr (and we are not multi-threading). */
- BLI_Stack *edge_vectors = (lnors_spacearr && !data_buff) ? BLI_stack_new(sizeof(float[3]), __func__) : NULL;
+ BLI_Stack *edge_vectors = NULL;
#ifdef DEBUG_TIME
- TIMEIT_START(loop_split_generator);
+ TIMEIT_START_AVERAGED(loop_split_generator);
#endif
- if (!threaded) {
- memset(&data_mem, 0, sizeof(data_mem));
- data = &data_mem;
+ if (!pool) {
+ if (lnors_spacearr) {
+ edge_vectors = BLI_stack_new(sizeof(float[3]), __func__);
+ }
}
/* We now know edges that can be smoothed (with their vector, and their two loops), and edges that will be hard!
* Now, time to generate the normals.
*/
for (mp = mpolys, mp_index = 0; mp_index < numPolys; mp++, mp_index++) {
- const MLoop *ml_curr, *ml_prev;
float (*lnors)[3];
const int ml_last_index = (mp->loopstart + mp->totloop) - 1;
- int ml_curr_index = mp->loopstart;
- int ml_prev_index = ml_last_index;
+ ml_curr_index = mp->loopstart;
+ ml_prev_index = ml_last_index;
ml_curr = &mloops[ml_curr_index];
ml_prev = &mloops[ml_prev_index];
@@ -1039,23 +1110,40 @@ static void loop_split_generator_do(LoopSplitTaskDataCommon *common_data, const
const int *e2l_curr = edge_to_loops[ml_curr->e];
const int *e2l_prev = edge_to_loops[ml_prev->e];
- if (!IS_EDGE_SHARP(e2l_curr) && (!lnors_spacearr || BLI_BITMAP_TEST_BOOL(sharp_verts, ml_curr->v))) {
- /* A smooth edge, and we are not generating lnor_spacearr, or the related vertex is sharp.
- * We skip it because it is either:
- * - in the middle of a 'smooth fan' already computed (or that will be as soon as we hit
- * one of its ends, i.e. one of its two sharp edges), or...
- * - the related vertex is a "full smooth" one, in which case pre-populated normals from vertex
- * are just fine (or it has already be handled in a previous loop in case of needed lnors spacearr)!
- */
- /* printf("Skipping loop %d / edge %d / vert %d(%d)\n", ml_curr_index, ml_curr->e, ml_curr->v, sharp_verts[ml_curr->v]); */
+// printf("Checking loop %d / edge %u / vert %u (sharp edge: %d, skiploop: %d)...",
+// ml_curr_index, ml_curr->e, ml_curr->v, IS_EDGE_SHARP(e2l_curr), BLI_BITMAP_TEST_BOOL(skip_loops, ml_curr_index));
+
+ /* A smooth edge, we have to check for cyclic smooth fan case.
+ * If we find a new, never-processed cyclic smooth fan, we can do it now using that loop/edge as
+ * 'entry point', otherwise we can skip it. */
+ /* Note: In theory, we could make loop_split_generator_check_cyclic_smooth_fan() store
+ * mlfan_vert_index'es and edge indexes in two stacks, to avoid having to fan again around the vert during
+ * actual computation of clnor & clnorspace. However, this would complicate the code, add more memory usage,
+ * and despite its logical complexity, loop_manifold_fan_around_vert_next() is quite cheap in term of
+ * CPU cycles, so really think it's not worth it. */
+ if (!IS_EDGE_SHARP(e2l_curr) &&
+ (BLI_BITMAP_TEST(skip_loops, ml_curr_index) ||
+ !loop_split_generator_check_cyclic_smooth_fan(
+ mloops, mpolys, edge_to_loops, loop_to_poly, e2l_prev, skip_loops,
+ ml_curr, ml_prev, ml_curr_index, ml_prev_index, mp_index)))
+ {
+// printf("SKIPPING!\n");
}
else {
- if (threaded) {
+ LoopSplitTaskData *data, data_local;
+
+// printf("PROCESSING!\n");
+
+ if (pool) {
if (data_idx == 0) {
data_buff = MEM_callocN(sizeof(*data_buff) * LOOP_SPLIT_TASK_BLOCK_SIZE, __func__);
}
data = &data_buff[data_idx];
}
+ else {
+ data = &data_local;
+ memset(data, 0, sizeof(*data));
+ }
if (IS_EDGE_SHARP(e2l_curr) && IS_EDGE_SHARP(e2l_prev)) {
data->lnor = lnors;
@@ -1091,22 +1179,18 @@ static void loop_split_generator_do(LoopSplitTaskDataCommon *common_data, const
data->mp_index = mp_index;
if (lnors_spacearr) {
data->lnor_space = BKE_lnor_space_create(lnors_spacearr);
- /* Tag related vertex as sharp, to avoid fanning around it again (in case it was a smooth one).
- * This *has* to be done outside of workers tasks! */
- BLI_BITMAP_ENABLE(sharp_verts, ml_curr->v);
}
}
- if (threaded) {
+ if (pool) {
data_idx++;
if (data_idx == LOOP_SPLIT_TASK_BLOCK_SIZE) {
- BLI_thread_queue_push(common_data->task_queue, data_buff);
+ BLI_task_pool_push(pool, loop_split_worker, data_buff, true, TASK_PRIORITY_LOW);
data_idx = 0;
}
}
else {
loop_split_worker_do(common_data, data, edge_vectors);
- memset(data, 0, sizeof(data_mem));
}
}
@@ -1115,44 +1199,32 @@ static void loop_split_generator_do(LoopSplitTaskDataCommon *common_data, const
}
}
- if (threaded) {
- /* Last block of data... Since it is calloc'ed and we use first NULL item as stopper, everything is fine. */
- if (LIKELY(data_idx)) {
- BLI_thread_queue_push(common_data->task_queue, data_buff);
- }
-
- /* This will signal all other worker threads to wake up and finish! */
- BLI_thread_queue_nowait(common_data->task_queue);
+ /* Last block of data... Since it is calloc'ed and we use first NULL item as stopper, everything is fine. */
+ if (pool && data_idx) {
+ BLI_task_pool_push(pool, loop_split_worker, data_buff, true, TASK_PRIORITY_LOW);
}
if (edge_vectors) {
BLI_stack_free(edge_vectors);
}
+ MEM_freeN(skip_loops);
#ifdef DEBUG_TIME
- TIMEIT_END(loop_split_generator);
+ TIMEIT_END_AVERAGED(loop_split_generator);
#endif
}
-static void loop_split_generator(TaskPool * __restrict UNUSED(pool), void *taskdata, int UNUSED(threadid))
-{
- LoopSplitTaskDataCommon *common_data = taskdata;
-
- loop_split_generator_do(common_data, true);
-}
-
/**
* Compute split normals, i.e. vertex normals associated with each poly (hence 'loop normals').
* Useful to materialize sharp edges (or non-smooth faces) without actually modifying the geometry (splitting edges).
*/
void BKE_mesh_normals_loop_split(
- const MVert *mverts, const int numVerts, MEdge *medges, const int numEdges,
+ const MVert *mverts, const int UNUSED(numVerts), MEdge *medges, const int numEdges,
MLoop *mloops, float (*r_loopnors)[3], const int numLoops,
MPoly *mpolys, const float (*polynors)[3], const int numPolys,
const bool use_split_normals, float split_angle,
MLoopNorSpaceArray *r_lnors_spacearr, short (*clnors_data)[2], int *r_loop_to_poly)
{
-
/* For now this is not supported. If we do not use split normals, we do not generate anything fancy! */
BLI_assert(use_split_normals || !(r_lnors_spacearr));
@@ -1185,8 +1257,6 @@ void BKE_mesh_normals_loop_split(
return;
}
- {
-
/* Mapping edge -> loops.
* If that edge is used by more than two loops (polys), it is always sharp (and tagged as such, see below).
* We also use the second loop index as a kind of flag: smooth edge: > 0,
@@ -1196,33 +1266,25 @@ void BKE_mesh_normals_loop_split(
* store the negated value of loop index instead of INDEX_INVALID to retrieve the real value later in code).
* Note also that lose edges always have both values set to 0!
*/
- int (*edge_to_loops)[2] = MEM_callocN(sizeof(int[2]) * (size_t)numEdges, __func__);
+ int (*edge_to_loops)[2] = MEM_callocN(sizeof(*edge_to_loops) * (size_t)numEdges, __func__);
/* Simple mapping from a loop to its polygon index. */
- int *loop_to_poly = r_loop_to_poly ? r_loop_to_poly : MEM_mallocN(sizeof(int) * (size_t)numLoops, __func__);
+ int *loop_to_poly = r_loop_to_poly ? r_loop_to_poly : MEM_mallocN(sizeof(*loop_to_poly) * (size_t)numLoops, __func__);
MPoly *mp;
- int mp_index, me_index;
- bool check_angle = (split_angle < (float)M_PI);
- int i;
+ int mp_index;
- BLI_bitmap *sharp_verts = NULL;
- MLoopNorSpaceArray _lnors_spacearr = {NULL};
+ /* When using custom loop normals, disable the angle feature! */
+ const bool check_angle = (split_angle < (float)M_PI) && (clnors_data == NULL);
- LoopSplitTaskDataCommon common_data = {NULL};
+ MLoopNorSpaceArray _lnors_spacearr = {NULL};
#ifdef DEBUG_TIME
- TIMEIT_START(BKE_mesh_normals_loop_split);
+ TIMEIT_START_AVERAGED(BKE_mesh_normals_loop_split);
#endif
if (check_angle) {
- /* When using custom loop normals, disable the angle feature! */
- if (clnors_data) {
- check_angle = false;
- }
- else {
- split_angle = cosf(split_angle);
- }
+ split_angle = cosf(split_angle);
}
if (!r_lnors_spacearr && clnors_data) {
@@ -1231,7 +1293,6 @@ void BKE_mesh_normals_loop_split(
}
if (r_lnors_spacearr) {
BKE_lnor_spacearr_init(r_lnors_spacearr, numLoops);
- sharp_verts = BLI_BITMAP_NEW((size_t)numVerts, __func__);
}
/* This first loop check which edges are actually smooth, and compute edge vectors. */
@@ -1285,60 +1346,38 @@ void BKE_mesh_normals_loop_split(
}
}
- if (r_lnors_spacearr) {
- /* Tag vertices that have at least one sharp edge as 'sharp' (used for the lnor spacearr computation).
- * XXX This third loop over edges is a bit disappointing, could not find any other way yet.
- * Not really performance-critical anyway.
- */
- for (me_index = 0; me_index < numEdges; me_index++) {
- const int *e2l = edge_to_loops[me_index];
- const MEdge *me = &medges[me_index];
- if (IS_EDGE_SHARP(e2l)) {
- BLI_BITMAP_ENABLE(sharp_verts, me->v1);
- BLI_BITMAP_ENABLE(sharp_verts, me->v2);
- }
- }
- }
-
/* Init data common to all tasks. */
- common_data.lnors_spacearr = r_lnors_spacearr;
- common_data.loopnors = r_loopnors;
- common_data.clnors_data = clnors_data;
-
- common_data.mverts = mverts;
- common_data.medges = medges;
- common_data.mloops = mloops;
- common_data.mpolys = mpolys;
- common_data.sharp_verts = sharp_verts;
- common_data.edge_to_loops = (const int(*)[2])edge_to_loops;
- common_data.loop_to_poly = loop_to_poly;
- common_data.polynors = polynors;
- common_data.numPolys = numPolys;
+ LoopSplitTaskDataCommon common_data = {
+ .lnors_spacearr = r_lnors_spacearr,
+ .loopnors = r_loopnors,
+ .clnors_data = clnors_data,
+ .mverts = mverts,
+ .medges = medges,
+ .mloops = mloops,
+ .mpolys = mpolys,
+ .edge_to_loops = (const int(*)[2])edge_to_loops,
+ .loop_to_poly = loop_to_poly,
+ .polynors = polynors,
+ .numLoops = numLoops,
+ .numPolys = numPolys,
+ };
if (numLoops < LOOP_SPLIT_TASK_BLOCK_SIZE * 8) {
/* Not enough loops to be worth the whole threading overhead... */
- loop_split_generator_do(&common_data, false);
+ loop_split_generator(NULL, &common_data);
}
else {
TaskScheduler *task_scheduler;
TaskPool *task_pool;
- int nbr_workers;
-
- common_data.task_queue = BLI_thread_queue_init();
task_scheduler = BLI_task_scheduler_get();
- task_pool = BLI_task_pool_create(task_scheduler, NULL);
+ task_pool = BLI_task_pool_create(task_scheduler, &common_data);
+
+ loop_split_generator(task_pool, &common_data);
- nbr_workers = max_ii(2, BLI_task_scheduler_num_threads(task_scheduler));
- for (i = 1; i < nbr_workers; i++) {
- BLI_task_pool_push(task_pool, loop_split_worker, &common_data, false, TASK_PRIORITY_HIGH);
- }
- BLI_task_pool_push(task_pool, loop_split_generator, &common_data, false, TASK_PRIORITY_HIGH);
BLI_task_pool_work_and_wait(task_pool);
BLI_task_pool_free(task_pool);
-
- BLI_thread_queue_free(common_data.task_queue);
}
MEM_freeN(edge_to_loops);
@@ -1347,17 +1386,14 @@ void BKE_mesh_normals_loop_split(
}
if (r_lnors_spacearr) {
- MEM_freeN(sharp_verts);
if (r_lnors_spacearr == &_lnors_spacearr) {
BKE_lnor_spacearr_free(r_lnors_spacearr);
}
}
#ifdef DEBUG_TIME
- TIMEIT_END(BKE_mesh_normals_loop_split);
+ TIMEIT_END_AVERAGED(BKE_mesh_normals_loop_split);
#endif
-
- }
}
#undef INDEX_UNSET
diff --git a/source/blender/blenkernel/intern/object.c b/source/blender/blenkernel/intern/object.c
index ff8be5892e9..6e754755cf3 100644
--- a/source/blender/blenkernel/intern/object.c
+++ b/source/blender/blenkernel/intern/object.c
@@ -2236,66 +2236,6 @@ void BKE_boundbox_minmax(const BoundBox *bb, float obmat[4][4], float r_min[3],
}
}
-/**
- * Returns a BBox which each dimensions are at least epsilon.
- * \note In case a given dimension needs to be enlarged, its final value will be in [epsilon, 3 * epsilon] range.
- *
- * \param bb the input bbox to check.
- * \param bb_temp the temp bbox to modify (\a bb content is never changed).
- * \param epsilon the minimum dimension to ensure.
- * \return either bb (if nothing needed to be changed) or bb_temp.
- */
-BoundBox *BKE_boundbox_ensure_minimum_dimensions(BoundBox *bb, BoundBox *bb_temp, const float epsilon)
-{
- if (fabsf(bb->vec[0][0] - bb->vec[4][0]) < epsilon) {
- /* Flat along X axis... */
- *bb_temp = *bb;
- bb = bb_temp;
- bb->vec[0][0] -= epsilon;
- bb->vec[1][0] -= epsilon;
- bb->vec[2][0] -= epsilon;
- bb->vec[3][0] -= epsilon;
- bb->vec[4][0] += epsilon;
- bb->vec[5][0] += epsilon;
- bb->vec[6][0] += epsilon;
- bb->vec[7][0] += epsilon;
- }
-
- if (fabsf(bb->vec[0][1] - bb->vec[3][1]) < epsilon) {
- /* Flat along Y axis... */
- if (bb != bb_temp) {
- *bb_temp = *bb;
- bb = bb_temp;
- }
- bb->vec[0][1] -= epsilon;
- bb->vec[1][1] -= epsilon;
- bb->vec[4][1] -= epsilon;
- bb->vec[5][1] -= epsilon;
- bb->vec[2][1] += epsilon;
- bb->vec[3][1] += epsilon;
- bb->vec[6][1] += epsilon;
- bb->vec[7][1] += epsilon;
- }
-
- if (fabsf(bb->vec[0][2] - bb->vec[1][2]) < epsilon) {
- /* Flat along Z axis... */
- if (bb != bb_temp) {
- *bb_temp = *bb;
- bb = bb_temp;
- }
- bb->vec[0][2] -= epsilon;
- bb->vec[3][2] -= epsilon;
- bb->vec[4][2] -= epsilon;
- bb->vec[7][2] -= epsilon;
- bb->vec[1][2] += epsilon;
- bb->vec[2][2] += epsilon;
- bb->vec[5][2] += epsilon;
- bb->vec[6][2] += epsilon;
- }
-
- return bb;
-}
-
BoundBox *BKE_object_boundbox_get(Object *ob)
{
BoundBox *bb = NULL;
diff --git a/source/blender/blenkernel/intern/object_update.c b/source/blender/blenkernel/intern/object_update.c
index 5cb704e4737..a531466294e 100644
--- a/source/blender/blenkernel/intern/object_update.c
+++ b/source/blender/blenkernel/intern/object_update.c
@@ -54,6 +54,7 @@
#include "BKE_editmesh.h"
#include "BKE_object.h"
#include "BKE_particle.h"
+#include "BKE_pointcache.h"
#include "BKE_scene.h"
#include "BKE_material.h"
#include "BKE_image.h"
@@ -347,3 +348,9 @@ void BKE_object_eval_uber_data(EvaluationContext *eval_ctx,
ob->recalc &= ~(OB_RECALC_DATA | OB_RECALC_TIME);
}
+
+void BKE_object_eval_cloth(EvaluationContext *UNUSED(eval_ctx), Scene *scene, Object *object)
+{
+ DEBUG_PRINT("%s on %s\n", __func__, object->id.name);
+ BKE_ptcache_object_reset(scene, object, PTCACHE_RESET_DEPSGRAPH);
+}
diff --git a/source/blender/blenkernel/intern/particle.c b/source/blender/blenkernel/intern/particle.c
index 1ea27558545..228ae6afaba 100644
--- a/source/blender/blenkernel/intern/particle.c
+++ b/source/blender/blenkernel/intern/particle.c
@@ -633,8 +633,9 @@ void psys_render_set(Object *ob, ParticleSystem *psys, float viewmat[4][4], floa
data->childcachebufs.last = psys->childcachebufs.last;
data->totchildcache = psys->totchildcache;
- if (psmd->dm_final)
- data->dm = CDDM_copy(psmd->dm_final);
+ if (psmd->dm_final) {
+ data->dm = CDDM_copy_with_tessface(psmd->dm_final);
+ }
data->totdmvert = psmd->totdmvert;
data->totdmedge = psmd->totdmedge;
data->totdmface = psmd->totdmface;
diff --git a/source/blender/blenkernel/intern/scene.c b/source/blender/blenkernel/intern/scene.c
index 56bfe5d7ff1..906fa0134a0 100644
--- a/source/blender/blenkernel/intern/scene.c
+++ b/source/blender/blenkernel/intern/scene.c
@@ -1510,8 +1510,6 @@ static void scene_update_object_func(TaskPool * __restrict pool, void *taskdata,
if (add_to_stats) {
StatisicsEntry *entry;
- BLI_assert(threadid < BLI_pool_get_num_threads(pool));
-
entry = MEM_mallocN(sizeof(StatisicsEntry), "update thread statistics");
entry->object = object;
entry->start_time = start_time;
@@ -1631,10 +1629,11 @@ static bool scene_need_update_objects(Main *bmain)
static void scene_update_objects(EvaluationContext *eval_ctx, Main *bmain, Scene *scene, Scene *scene_parent)
{
- TaskScheduler *task_scheduler = BLI_task_scheduler_get();
+ TaskScheduler *task_scheduler;
TaskPool *task_pool;
ThreadedObjectUpdateState state;
bool need_singlethread_pass;
+ bool need_free_scheduler;
/* Early check for whether we need to invoke all the task-based
* things (spawn new ppol, traverse dependency graph and so on).
@@ -1651,6 +1650,15 @@ static void scene_update_objects(EvaluationContext *eval_ctx, Main *bmain, Scene
state.scene = scene;
state.scene_parent = scene_parent;
+ if (G.debug & G_DEBUG_DEPSGRAPH_NO_THREADS) {
+ task_scheduler = BLI_task_scheduler_create(1);
+ need_free_scheduler = true;
+ }
+ else {
+ task_scheduler = BLI_task_scheduler_get();
+ need_free_scheduler = false;
+ }
+
/* Those are only needed when blender is run with --debug argument. */
if (G.debug & G_DEBUG_DEPSGRAPH) {
const int tot_thread = BLI_task_scheduler_num_threads(task_scheduler);
@@ -1665,9 +1673,6 @@ static void scene_update_objects(EvaluationContext *eval_ctx, Main *bmain, Scene
#endif
task_pool = BLI_task_pool_create(task_scheduler, &state);
- if (G.debug & G_DEBUG_DEPSGRAPH_NO_THREADS) {
- BLI_pool_set_num_threads(task_pool, 1);
- }
DAG_threaded_update_begin(scene, scene_update_object_add_task, task_pool);
BLI_task_pool_work_and_wait(task_pool);
@@ -1700,6 +1705,10 @@ static void scene_update_objects(EvaluationContext *eval_ctx, Main *bmain, Scene
if (need_singlethread_pass) {
scene_update_all_bases(eval_ctx, scene, scene_parent);
}
+
+ if (need_free_scheduler) {
+ BLI_task_scheduler_free(task_scheduler);
+ }
}
static void scene_update_tagged_recursive(EvaluationContext *eval_ctx, Main *bmain, Scene *scene, Scene *scene_parent)
diff --git a/source/blender/blenkernel/intern/sequencer.c b/source/blender/blenkernel/intern/sequencer.c
index 1d2f5aee440..2de7cd49901 100644
--- a/source/blender/blenkernel/intern/sequencer.c
+++ b/source/blender/blenkernel/intern/sequencer.c
@@ -480,55 +480,74 @@ void BKE_sequencer_editing_free(Scene *scene)
static void sequencer_imbuf_assign_spaces(Scene *scene, ImBuf *ibuf)
{
- if (ibuf->rect_float) {
+ if (ibuf->rect != NULL) {
+ IMB_colormanagement_assign_rect_colorspace(ibuf, scene->sequencer_colorspace_settings.name);
+ }
+ if (ibuf->rect_float != NULL) {
IMB_colormanagement_assign_float_colorspace(ibuf, scene->sequencer_colorspace_settings.name);
}
}
void BKE_sequencer_imbuf_to_sequencer_space(Scene *scene, ImBuf *ibuf, bool make_float)
{
- const char *from_colorspace = IMB_colormanagement_role_colorspace_name_get(COLOR_ROLE_SCENE_LINEAR);
+ /* Early output check: if both buffers are NULL we have nothing to convert. */
+ if (ibuf->rect_float == NULL && ibuf->rect == NULL) {
+ return;
+ }
+ /* Get common conversion settings. */
const char *to_colorspace = scene->sequencer_colorspace_settings.name;
- const char *float_colorspace = IMB_colormanagement_get_float_colorspace(ibuf);
-
- if (!ibuf->rect_float) {
- if (ibuf->rect) {
- const char *byte_colorspace = IMB_colormanagement_get_rect_colorspace(ibuf);
- if (make_float || !STREQ(to_colorspace, byte_colorspace)) {
- /* If byte space is not in sequencer's working space, we deliver float color space,
- * this is to to prevent data loss.
- */
-
- /* when converting byte buffer to float in sequencer we need to make float
- * buffer be in sequencer's working space, which is currently only doable
- * from linear space.
- */
-
- /*
- * OCIO_TODO: would be nice to support direct single transform from byte to sequencer's
- */
-
- IMB_float_from_rect(ibuf);
- }
- else {
- return;
- }
+ /* Perform actual conversion logic. */
+ if (ibuf->rect_float == NULL) {
+ /* We are not requested to give float buffer and byte buffer is already
+ * in thee required colorspace. Can skip doing anything here.
+ */
+ const char *from_colorspace = IMB_colormanagement_get_rect_colorspace(ibuf);
+ if (!make_float && STREQ(from_colorspace, to_colorspace)) {
+ return;
+ }
+ if (false) {
+ /* The idea here is to provide as fast playback as possible and
+ * enforcing float buffer here (a) uses more cache memory (b) might
+ * make some other effects slower to apply.
+ *
+ * However, this might also have negative effect by adding weird
+ * artifacts which will then not happen in final render.
+ */
+ IMB_colormanagement_transform_byte_threaded(
+ (unsigned char *)ibuf->rect, ibuf->x, ibuf->y, ibuf->channels,
+ from_colorspace, to_colorspace);
}
else {
- return;
+ /* We perform conversion to a float buffer so we don't worry about
+ * precision loss.
+ */
+ imb_addrectfloatImBuf(ibuf);
+ IMB_colormanagement_transform_from_byte_threaded(
+ ibuf->rect_float, (unsigned char *)ibuf->rect,
+ ibuf->x, ibuf->y, ibuf->channels,
+ from_colorspace, to_colorspace);
+ /* We don't need byte buffer anymore. */
+ imb_freerectImBuf(ibuf);
}
}
-
- if (from_colorspace && from_colorspace[0] != '\0') {
- if (ibuf->rect)
+ else {
+ const char *from_colorspace = IMB_colormanagement_get_float_colorspace(ibuf);
+ /* Unknown input color space, can't perform conversion. */
+ if (from_colorspace == NULL || from_colorspace[0] == '\0') {
+ return;
+ }
+ /* We don't want both byte and float buffers around: they'll either run
+ * out of sync or conversion of byte buffer will loose precision in there.
+ */
+ if (ibuf->rect != NULL) {
imb_freerectImBuf(ibuf);
-
- if (!STREQ(float_colorspace, to_colorspace)) {
- IMB_colormanagement_transform_threaded(ibuf->rect_float, ibuf->x, ibuf->y, ibuf->channels,
- from_colorspace, to_colorspace, true);
- sequencer_imbuf_assign_spaces(scene, ibuf);
}
+ IMB_colormanagement_transform_threaded(ibuf->rect_float,
+ ibuf->x, ibuf->y, ibuf->channels,
+ from_colorspace, to_colorspace,
+ true);
}
+ sequencer_imbuf_assign_spaces(scene, ibuf);
}
void BKE_sequencer_imbuf_from_sequencer_space(Scene *scene, ImBuf *ibuf)
diff --git a/source/blender/blenkernel/intern/text.c b/source/blender/blenkernel/intern/text.c
index 88575c7d3be..298790a9e9b 100644
--- a/source/blender/blenkernel/intern/text.c
+++ b/source/blender/blenkernel/intern/text.c
@@ -1935,7 +1935,7 @@ void txt_do_undo(Text *text)
int op = text->undo_buf[text->undo_pos];
int prev_flags;
unsigned int linep;
- unsigned int uchar;
+ unsigned int uni_char;
unsigned int curln, selln;
unsigned short curc, selc;
unsigned short charp;
@@ -1971,14 +1971,14 @@ void txt_do_undo(Text *text)
case UNDO_BS_3:
case UNDO_BS_4:
charp = op - UNDO_BS_1 + 1;
- uchar = txt_undo_read_unicode(text->undo_buf, &text->undo_pos, charp);
+ uni_char = txt_undo_read_unicode(text->undo_buf, &text->undo_pos, charp);
/* get and restore the cursors */
txt_undo_read_cur(text->undo_buf, &text->undo_pos, &curln, &curc);
txt_move_to(text, curln, curc, 0);
txt_move_to(text, curln, curc, 1);
- txt_add_char(text, uchar);
+ txt_add_char(text, uni_char);
text->undo_pos--;
break;
@@ -1988,14 +1988,14 @@ void txt_do_undo(Text *text)
case UNDO_DEL_3:
case UNDO_DEL_4:
charp = op - UNDO_DEL_1 + 1;
- uchar = txt_undo_read_unicode(text->undo_buf, &text->undo_pos, charp);
+ uni_char = txt_undo_read_unicode(text->undo_buf, &text->undo_pos, charp);
/* get and restore the cursors */
txt_undo_read_cur(text->undo_buf, &text->undo_pos, &curln, &curc);
txt_move_to(text, curln, curc, 0);
txt_move_to(text, curln, curc, 1);
- txt_add_char(text, uchar);
+ txt_add_char(text, uni_char);
txt_move_left(text, 0);
@@ -2163,7 +2163,7 @@ void txt_do_redo(Text *text)
char *buf;
unsigned int linep;
unsigned short charp;
- unsigned int uchar;
+ unsigned int uni_uchar;
unsigned int curln, selln;
unsigned short curc, selc;
@@ -2190,9 +2190,9 @@ void txt_do_redo(Text *text)
txt_move_to(text, curln, curc, 1);
charp = op - UNDO_INSERT_1 + 1;
- uchar = txt_redo_read_unicode(text->undo_buf, &text->undo_pos, charp);
+ uni_uchar = txt_redo_read_unicode(text->undo_buf, &text->undo_pos, charp);
- txt_add_char(text, uchar);
+ txt_add_char(text, uni_uchar);
break;
case UNDO_BS_1:
diff --git a/source/blender/blenkernel/intern/texture.c b/source/blender/blenkernel/intern/texture.c
index 2d3ecad19ad..60990c03b0e 100644
--- a/source/blender/blenkernel/intern/texture.c
+++ b/source/blender/blenkernel/intern/texture.c
@@ -1485,9 +1485,11 @@ bool BKE_texture_dependsOnTime(const struct Tex *texture)
/* ------------------------------------------------------------------------- */
-void BKE_texture_get_value(
+void BKE_texture_get_value_ex(
const Scene *scene, Tex *texture,
- float *tex_co, TexResult *texres, bool use_color_management)
+ float *tex_co, TexResult *texres,
+ struct ImagePool *pool,
+ bool use_color_management)
{
int result_type;
bool do_color_manage = false;
@@ -1497,7 +1499,7 @@ void BKE_texture_get_value(
}
/* no node textures for now */
- result_type = multitex_ext_safe(texture, tex_co, texres, NULL, do_color_manage, false);
+ result_type = multitex_ext_safe(texture, tex_co, texres, pool, do_color_manage, false);
/* if the texture gave an RGB value, we assume it didn't give a valid
* intensity, since this is in the context of modifiers don't use perceptual color conversion.
@@ -1510,3 +1512,10 @@ void BKE_texture_get_value(
copy_v3_fl(&texres->tr, texres->tin);
}
}
+
+void BKE_texture_get_value(
+ const Scene *scene, Tex *texture,
+ float *tex_co, TexResult *texres, bool use_color_management)
+{
+ BKE_texture_get_value_ex(scene, texture, tex_co, texres, NULL, use_color_management);
+}
diff --git a/source/blender/blenkernel/intern/tracking_stabilize.c b/source/blender/blenkernel/intern/tracking_stabilize.c
index 36b24fbb2dc..3dfaa1ed77d 100644
--- a/source/blender/blenkernel/intern/tracking_stabilize.c
+++ b/source/blender/blenkernel/intern/tracking_stabilize.c
@@ -755,7 +755,8 @@ static void average_marker_positions(StabContext *ctx, int framenr, float r_ref_
if (ok) {
r_ref_pos[0] /= weight_sum;
r_ref_pos[1] /= weight_sum;
- } else {
+ }
+ else {
/* No usable tracking data on any track on this frame.
* Use data from neighbouring frames to extrapolate...
*/
@@ -784,7 +785,8 @@ static void average_marker_positions(StabContext *ctx, int framenr, float r_ref_
* Also default to this frame when we're in a gap */
average_marker_positions(ctx, next_lower, r_ref_pos);
- } else if (next_higher < MAXFRAME) {
+ }
+ else if (next_higher < MAXFRAME) {
average_marker_positions(ctx, next_higher, r_ref_pos);
}
use_values_from_fcurves(ctx, false);
@@ -1167,7 +1169,8 @@ static void stabilization_calculate_data(StabContext *ctx,
if (ctx->stab->flag & TRACKING_STABILIZE_SCALE) {
*r_scale = expf(scale_step * scaleinf); /* Averaged in log scale */
- } else {
+ }
+ else {
*r_scale = 1.0f;
}
@@ -1180,8 +1183,8 @@ static void stabilization_calculate_data(StabContext *ctx,
*/
get_animated_target_pos(ctx, framenr, target_pos);
sub_v2_v2(r_translation, target_pos);
- *r_angle -= get_animated_target_rot(ctx,framenr);
- target_scale = get_animated_target_scale(ctx,framenr);
+ *r_angle -= get_animated_target_rot(ctx, framenr);
+ target_scale = get_animated_target_scale(ctx, framenr);
if (target_scale != 0.0f) {
*r_scale /= target_scale;
/* target_scale is an expected/intended reference zoom value */
diff --git a/source/blender/blenkernel/intern/writeffmpeg.c b/source/blender/blenkernel/intern/writeffmpeg.c
index 9994d479ce7..156b74f5c3d 100644
--- a/source/blender/blenkernel/intern/writeffmpeg.c
+++ b/source/blender/blenkernel/intern/writeffmpeg.c
@@ -568,7 +568,8 @@ static AVStream *alloc_video_stream(FFMpegContext *context, RenderData *rd, int
if (context->ffmpeg_crf >= 0) {
ffmpeg_dict_set_int(&opts, "crf", context->ffmpeg_crf);
- } else {
+ }
+ else {
c->bit_rate = context->ffmpeg_video_bitrate * 1000;
c->rc_max_rate = rd->ffcodecdata.rc_max_rate * 1000;
c->rc_min_rate = rd->ffcodecdata.rc_min_rate * 1000;
@@ -576,8 +577,8 @@ static AVStream *alloc_video_stream(FFMpegContext *context, RenderData *rd, int
}
if (context->ffmpeg_preset) {
- char const * preset_name;
- switch(context->ffmpeg_preset) {
+ char const *preset_name;
+ switch (context->ffmpeg_preset) {
case FFM_PRESET_ULTRAFAST: preset_name = "ultrafast"; break;
case FFM_PRESET_SUPERFAST: preset_name = "superfast"; break;
case FFM_PRESET_VERYFAST: preset_name = "veryfast"; break;