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.c74
-rw-r--r--source/blender/blenkernel/intern/appdir.c178
-rw-r--r--source/blender/blenkernel/intern/blender.c120
-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.c327
-rw-r--r--source/blender/blenkernel/intern/camera.c4
-rw-r--r--source/blender/blenkernel/intern/cdderivedmesh.c39
-rw-r--r--source/blender/blenkernel/intern/cloth.c37
-rw-r--r--source/blender/blenkernel/intern/collection.c225
-rw-r--r--source/blender/blenkernel/intern/collision.c12
-rw-r--r--source/blender/blenkernel/intern/colortools.c2
-rw-r--r--source/blender/blenkernel/intern/context.c17
-rw-r--r--source/blender/blenkernel/intern/curve.c23
-rw-r--r--source/blender/blenkernel/intern/customdata.c55
-rw-r--r--source/blender/blenkernel/intern/depsgraph.c12
-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.c42
-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.c15
-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/layer.c1014
-rw-r--r--source/blender/blenkernel/intern/library.c2
-rw-r--r--source/blender/blenkernel/intern/library_query.c1
-rw-r--r--source/blender/blenkernel/intern/library_remap.c4
-rw-r--r--source/blender/blenkernel/intern/material.c6
-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/mesh_render.c1202
-rw-r--r--source/blender/blenkernel/intern/object.c125
-rw-r--r--source/blender/blenkernel/intern/object_update.c13
-rw-r--r--source/blender/blenkernel/intern/outliner_treehash.c39
-rw-r--r--source/blender/blenkernel/intern/paint.c30
-rw-r--r--source/blender/blenkernel/intern/pbvh.c26
-rw-r--r--source/blender/blenkernel/intern/pointcache.c2
-rw-r--r--source/blender/blenkernel/intern/scene.c60
-rw-r--r--source/blender/blenkernel/intern/sequencer.c7
-rw-r--r--source/blender/blenkernel/intern/sound.c2
-rw-r--r--source/blender/blenkernel/intern/subsurf_ccg.c31
-rw-r--r--source/blender/blenkernel/intern/tracking_stabilize.c13
-rw-r--r--source/blender/blenkernel/intern/writeffmpeg.c7
44 files changed, 3176 insertions, 1643 deletions
diff --git a/source/blender/blenkernel/intern/DerivedMesh.c b/source/blender/blenkernel/intern/DerivedMesh.c
index 39f1db0b886..b9cc9540cf7 100644
--- a/source/blender/blenkernel/intern/DerivedMesh.c
+++ b/source/blender/blenkernel/intern/DerivedMesh.c
@@ -76,8 +76,8 @@ static DerivedMesh *navmesh_dm_createNavMeshForVisualization(DerivedMesh *dm);
#include "BLI_sys_types.h" /* for intptr_t support */
#include "GPU_buffers.h"
-#include "GPU_glew.h"
#include "GPU_shader.h"
+#include "GPU_immediate.h"
#ifdef WITH_OPENSUBDIV
# include "BKE_depsgraph.h"
@@ -2913,9 +2913,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;
@@ -2923,9 +2920,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;
@@ -3937,7 +3938,6 @@ BLI_INLINE void navmesh_intToCol(int i, float col[3])
static void navmesh_drawColored(DerivedMesh *dm)
{
- int a, glmode;
MVert *mvert = (MVert *)CustomData_get_layer(&dm->vertData, CD_MVERT);
MFace *mface = (MFace *)CustomData_get_layer(&dm->faceData, CD_MFACE);
int *polygonIdx = (int *)CustomData_get_layer(&dm->polyData, CD_RECAST);
@@ -3952,34 +3952,42 @@ static void navmesh_drawColored(DerivedMesh *dm)
dm->drawEdges(dm, 0, 1);
#endif
- /* if (GPU_buffer_legacy(dm) ) */ /* TODO - VBO draw code, not high priority - campbell */
- {
- DEBUG_VBO("Using legacy code. drawNavMeshColored\n");
- glBegin(glmode = GL_QUADS);
- for (a = 0; a < dm->numTessFaceData; a++, mface++) {
- int new_glmode = mface->v4 ? GL_QUADS : GL_TRIANGLES;
- int pi = polygonIdx[a];
- if (pi <= 0) {
- zero_v3(col);
- }
- else {
- navmesh_intToCol(pi, col);
- }
+ VertexFormat *format = immVertexFormat();
+ unsigned pos = add_attrib(format, "pos", COMP_F32, 3, KEEP_FLOAT);
+ unsigned color = add_attrib(format, "color", COMP_F32, 3, KEEP_FLOAT);
- if (new_glmode != glmode) {
- glEnd();
- glBegin(glmode = new_glmode);
- }
- glColor3fv(col);
- glVertex3fv(mvert[mface->v1].co);
- glVertex3fv(mvert[mface->v2].co);
- glVertex3fv(mvert[mface->v3].co);
- if (mface->v4) {
- glVertex3fv(mvert[mface->v4].co);
- }
+ immBindBuiltinProgram(GPU_SHADER_3D_FLAT_COLOR);
+
+ /* Note: batch drawing API would let us share vertices */
+ immBeginAtMost(PRIM_TRIANGLES, dm->numTessFaceData * 6);
+ for (int a = 0; a < dm->numTessFaceData; a++, mface++) {
+ int pi = polygonIdx[a];
+ if (pi <= 0) {
+ zero_v3(col);
+ }
+ else {
+ navmesh_intToCol(pi, col);
+ }
+
+ immSkipAttrib(color);
+ immVertex3fv(pos, mvert[mface->v1].co);
+ immSkipAttrib(color);
+ immVertex3fv(pos, mvert[mface->v2].co);
+ immAttrib3fv(color, col);
+ immVertex3fv(pos, mvert[mface->v3].co);
+
+ if (mface->v4) {
+ /* this tess face is a quad, so draw the other triangle */
+ immSkipAttrib(color);
+ immVertex3fv(pos, mvert[mface->v1].co);
+ immSkipAttrib(color);
+ immVertex3fv(pos, mvert[mface->v3].co);
+ immAttrib3fv(color, col);
+ immVertex3fv(pos, mvert[mface->v4].co);
}
- glEnd();
}
+ immEnd();
+ immUnbindProgram();
}
static void navmesh_DM_drawFacesTex(
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/blender.c b/source/blender/blenkernel/intern/blender.c
index afd60102453..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;
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 d0e0c82e3be..c0e4ef37a93 100644
--- a/source/blender/blenkernel/intern/bvhutils.c
+++ b/source/blender/blenkernel/intern/bvhutils.c
@@ -376,45 +376,6 @@ static void mesh_edges_spherecast(void *userdata, int index, const BVHTreeRay *r
}
}
-#define V3_MUL_ELEM(a, b) \
- (a)[0] * (b)[0], \
- (a)[1] * (b)[1], \
- (a)[2] * (b)[2]
-
-/* Callback to bvh tree nearest edge to ray.
- * The tree must have been built using bvhtree_from_mesh_edges.
- * userdata must be a BVHMeshCallbackUserdata built from the same mesh as the tree. */
-static void mesh_edges_nearest_to_ray(
- void *userdata, const float ray_co[3], const float ray_dir[3],
- const float scale[3], int index, BVHTreeNearest *nearest)
-{
- struct BVHTreeFromMesh *data = userdata;
- const MVert *vert = data->vert;
- const MEdge *e = &data->edge[index];
-
- const float t0[3] = {V3_MUL_ELEM(vert[e->v1].co, scale)};
- const float t1[3] = {V3_MUL_ELEM(vert[e->v2].co, scale)};
- const float origin_sc[3] = {V3_MUL_ELEM(ray_co, scale)};
- const float dir_sc[3] = {V3_MUL_ELEM(ray_dir, scale)};
-
- float depth, point[3];
- const float dist_sq = dist_squared_ray_to_seg_v3(origin_sc, dir_sc, t0, t1, point, &depth);
-
- if (dist_sq < nearest->dist_sq) {
- nearest->dist_sq = dist_sq;
- nearest->index = index;
-
- point[0] /= scale[0];
- point[1] /= scale[1];
- point[2] /= scale[2];
-
- copy_v3_v3(nearest->co, point);
- sub_v3_v3v3(nearest->no, t0, t1);
- }
-}
-
-#undef V3_MUL_ELEM
-
/** \} */
/*
@@ -459,7 +420,7 @@ 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)
{
BLI_assert(vert != NULL);
@@ -488,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 */
@@ -531,7 +484,6 @@ 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;
@@ -588,11 +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;
}
/**
@@ -602,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)
{
@@ -613,7 +572,7 @@ BVHTree *bvhtree_from_mesh_verts_ex(
bvhtree_from_mesh_verts_setup_data(
data, tree, false, epsilon, vert, vert_allocated);
- return data->tree;
+ return tree;
}
/** \} */
@@ -661,7 +620,7 @@ static BVHTree *bvhtree_from_editmesh_edges_create_tree(
}
static BVHTree *bvhtree_from_mesh_edges_create_tree(
- MVert *vert, MEdge *edge, const int edge_num,
+ 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)
{
@@ -694,34 +653,26 @@ static BVHTree *bvhtree_from_mesh_edges_create_tree(
}
static void bvhtree_from_mesh_edges_setup_data(
- BVHTreeFromMesh *data, BVHTree *tree, const bool is_cached, float epsilon,
- MVert *vert, const bool vert_allocated, MEdge *edge, const bool edge_allocated)
+ 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;
- if (data->tree) {
- data->cached = is_cached;
+ data->cached = is_cached;
- data->nearest_callback = mesh_edges_nearest_point;
- data->raycast_callback = mesh_edges_spherecast;
- data->nearest_to_ray_callback = mesh_edges_nearest_to_ray;
+ 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->vert = vert;
+ data->vert_allocated = vert_allocated;
+ data->edge = edge;
+ data->edge_allocated = edge_allocated;
- data->sphere_radius = epsilon;
- }
- else {
- if (vert_allocated) {
- MEM_freeN(vert);
- }
- if (edge_allocated) {
- MEM_freeN(edge);
- }
- }
+ data->sphere_radius = epsilon;
}
/* Builds a bvh tree where nodes are the edges of the given em */
@@ -742,8 +693,6 @@ 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;
@@ -795,11 +744,21 @@ BVHTree *bvhtree_from_mesh_edges(
/* printf("BVHTree is already build, using cached tree\n"); */
}
- /* Setup BVHTreeFromMesh */
- bvhtree_from_mesh_edges_setup_data(
- data, tree, true, epsilon, vert, vert_allocated, edge, edge_allocated);
-
- return data->tree;
+ if (tree) {
+ /* Setup BVHTreeFromMesh */
+ bvhtree_from_mesh_edges_setup_data(
+ data, tree, true, epsilon, vert, vert_allocated, edge, edge_allocated);
+ }
+ else {
+ if (vert_allocated) {
+ MEM_freeN(vert);
+ }
+ if (edge_allocated) {
+ MEM_freeN(edge);
+ }
+ memset(data, 0, sizeof(*data));
+ }
+ return tree;
}
/**
@@ -810,8 +769,8 @@ BVHTree *bvhtree_from_mesh_edges(
*/
BVHTree *bvhtree_from_mesh_edges_ex(
BVHTreeFromMesh *data,
- MVert *vert, const bool vert_allocated,
- MEdge *edge, const int edges_num, const bool edge_allocated,
+ 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)
{
@@ -823,7 +782,7 @@ BVHTree *bvhtree_from_mesh_edges_ex(
bvhtree_from_mesh_edges_setup_data(
data, tree, false, epsilon, vert, vert_allocated, edge, edge_allocated);
- return data->tree;
+ return tree;
}
/** \} */
@@ -836,7 +795,7 @@ BVHTree *bvhtree_from_mesh_edges_ex(
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;
@@ -880,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 */
@@ -950,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;
}
/**
@@ -964,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)
{
@@ -975,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;
}
/** \} */
@@ -1088,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;
}
/**
@@ -1160,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;
@@ -1242,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(
@@ -1272,7 +1231,7 @@ BVHTree *bvhtree_from_mesh_looptri_ex(
mloop, loop_allocated,
looptri, looptri_allocated);
- return data->tree;
+ return tree;
}
/** \} */
@@ -1292,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/camera.c b/source/blender/blenkernel/intern/camera.c
index 978204f1cf5..be75048492c 100644
--- a/source/blender/blenkernel/intern/camera.c
+++ b/source/blender/blenkernel/intern/camera.c
@@ -633,7 +633,7 @@ static bool camera_frame_fit_calc_from_data(
/* don't move the camera, just yield the fit location */
/* r_scale only valid/useful for ortho cameras */
bool BKE_camera_view_frame_fit_to_scene(
- Scene *scene, struct View3D *v3d, Object *camera_ob, float r_co[3], float *r_scale)
+ Scene *scene, SceneLayer *sl, Object *camera_ob, float r_co[3], float *r_scale)
{
CameraParams params;
CameraViewFrameData data_cb;
@@ -644,7 +644,7 @@ bool BKE_camera_view_frame_fit_to_scene(
camera_frame_fit_data_init(scene, camera_ob, &params, &data_cb);
/* run callback on all visible points */
- BKE_scene_foreach_display_point(scene, v3d, BA_SELECT, camera_to_frame_view_cb, &data_cb);
+ BKE_scene_foreach_display_point(scene, sl, camera_to_frame_view_cb, &data_cb);
return camera_frame_fit_calc_from_data(&params, &data_cb, r_co, r_scale);
}
diff --git a/source/blender/blenkernel/intern/cdderivedmesh.c b/source/blender/blenkernel/intern/cdderivedmesh.c
index 483fa977aff..3f5b6ca580f 100644
--- a/source/blender/blenkernel/intern/cdderivedmesh.c
+++ b/source/blender/blenkernel/intern/cdderivedmesh.c
@@ -372,36 +372,6 @@ static void cdDM_drawVerts(DerivedMesh *dm)
GPU_buffers_unbind();
}
-static void cdDM_drawUVEdges(DerivedMesh *dm)
-{
- CDDerivedMesh *cddm = (CDDerivedMesh *) dm;
- const MPoly *mpoly = cddm->mpoly;
- int totpoly = dm->getNumPolys(dm);
- int prevstart = 0;
- bool prevdraw = true;
- int curpos = 0;
- int i;
-
- GPU_uvedge_setup(dm);
- for (i = 0; i < totpoly; i++, mpoly++) {
- const bool draw = (mpoly->flag & ME_HIDE) == 0;
-
- if (prevdraw != draw) {
- if (prevdraw && (curpos != prevstart)) {
- glDrawArrays(GL_LINES, prevstart, curpos - prevstart);
- }
- prevstart = curpos;
- }
-
- curpos += 2 * mpoly->totloop;
- prevdraw = draw;
- }
- if (prevdraw && (curpos != prevstart)) {
- glDrawArrays(GL_LINES, prevstart, curpos - prevstart);
- }
- GPU_buffers_unbind();
-}
-
static void cdDM_drawEdges(DerivedMesh *dm, bool drawLooseEdges, bool drawAllEdges)
{
CDDerivedMesh *cddm = (CDDerivedMesh *) dm;
@@ -2008,7 +1978,6 @@ static CDDerivedMesh *cdDM_create(const char *desc)
dm->drawVerts = cdDM_drawVerts;
- dm->drawUVEdges = cdDM_drawUVEdges;
dm->drawEdges = cdDM_drawEdges;
dm->drawLooseEdges = cdDM_drawLooseEdges;
dm->drawMappedEdges = cdDM_drawMappedEdges;
@@ -2428,8 +2397,12 @@ static DerivedMesh *cddm_copy_ex(DerivedMesh *source,
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);
diff --git a/source/blender/blenkernel/intern/cloth.c b/source/blender/blenkernel/intern/cloth.c
index 162525c7cd5..8190a7c2a8b 100644
--- a/source/blender/blenkernel/intern/cloth.c
+++ b/source/blender/blenkernel/intern/cloth.c
@@ -868,12 +868,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);
@@ -943,37 +937,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/collection.c b/source/blender/blenkernel/intern/collection.c
index 289586153ea..b16162dfbc0 100644
--- a/source/blender/blenkernel/intern/collection.c
+++ b/source/blender/blenkernel/intern/collection.c
@@ -24,6 +24,8 @@
* \ingroup bke
*/
+#include <string.h>
+
#include "BLI_blenlib.h"
#include "BLI_ghash.h"
#include "BLI_iterator.h"
@@ -44,6 +46,7 @@
#include "MEM_guardedalloc.h"
+
/**
* Add a collection to a collection ListBase and syncronize all render layers
* The ListBase is NULL when the collection is to be added to the master collection
@@ -61,9 +64,7 @@ SceneCollection *BKE_collection_add(Scene *scene, SceneCollection *sc_parent, co
sc_parent = sc_master;
}
- BLI_strncpy(sc->name, name, sizeof(sc->name));
- BLI_uniquename(&sc_master->scene_collections, sc, DATA_("Collection"), '.', offsetof(SceneCollection, name), sizeof(sc->name));
-
+ BKE_collection_rename(scene, sc, name);
BLI_addtail(&sc_parent->scene_collections, sc);
BKE_layer_sync_new_scene_collection(scene, sc_parent, sc);
@@ -93,12 +94,11 @@ static void collection_free(SceneCollection *sc)
/**
* Unlink the collection recursively
- * return true if unlinked
+ * \return true if unlinked.
*/
static bool collection_remlink(SceneCollection *sc_parent, SceneCollection *sc_gone)
{
- for (SceneCollection *sc = sc_parent->scene_collections.first; sc; sc = sc->next)
- {
+ for (SceneCollection *sc = sc_parent->scene_collections.first; sc; sc = sc->next) {
if (sc == sc_gone) {
BLI_remlink(&sc_parent->scene_collections, sc_gone);
return true;
@@ -117,9 +117,8 @@ static bool collection_remlink(SceneCollection *sc_parent, SceneCollection *sc_g
static void layer_collection_remove(SceneLayer *sl, ListBase *lb, const SceneCollection *sc)
{
LayerCollection *lc = lb->first;
- while(lc) {
+ while (lc) {
if (lc->scene_collection == sc) {
- BKE_scene_layer_engine_settings_collection_recalculate(sl, lc);
BKE_layer_collection_free(sl, lc);
BLI_remlink(lb, lc);
@@ -165,7 +164,6 @@ bool BKE_collection_remove(Scene *scene, SceneCollection *sc)
/* check all layers that use this collection and clear them */
for (SceneLayer *sl = scene->render_layers.first; sl; sl = sl->next) {
layer_collection_remove(sl, &sl->layer_collections, sc);
- BKE_scene_layer_base_flag_recalculate(sl);
sl->active_collection = 0;
}
@@ -176,20 +174,55 @@ bool BKE_collection_remove(Scene *scene, SceneCollection *sc)
/**
* Returns the master collection
*/
-SceneCollection *BKE_collection_master(Scene *scene)
+SceneCollection *BKE_collection_master(const Scene *scene)
{
return scene->collection;
}
+struct UniqueNameCheckData {
+ ListBase *lb;
+ SceneCollection *lookup_sc;
+};
+
+static bool collection_unique_name_check(void *arg, const char *name)
+{
+ struct UniqueNameCheckData *data = arg;
+
+ for (SceneCollection *sc = data->lb->first; sc; sc = sc->next) {
+ struct UniqueNameCheckData child_data = {.lb = &sc->scene_collections, .lookup_sc = data->lookup_sc};
+
+ if (sc != data->lookup_sc) {
+ if (STREQ(sc->name, name)) {
+ return true;
+ }
+ }
+ if (collection_unique_name_check(&child_data, name)) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+void BKE_collection_rename(const Scene *scene, SceneCollection *sc, const char *name)
+{
+ SceneCollection *sc_master = BKE_collection_master(scene);
+ struct UniqueNameCheckData data = {.lb = &sc_master->scene_collections, .lookup_sc = sc};
+
+ BLI_strncpy(sc->name, name, sizeof(sc->name));
+ BLI_uniquename_cb(collection_unique_name_check, &data, DATA_("Collection"), '.', sc->name, sizeof(sc->name));
+}
+
/**
* Free (or release) any data used by the master collection (does not free the master collection itself).
* Used only to clear the entire scene data since it's not doing re-syncing of the LayerCollection tree
*/
-void BKE_collection_master_free(Scene *scene){
+void BKE_collection_master_free(Scene *scene)
+{
collection_free(BKE_collection_master(scene));
}
-static void collection_object_add(Scene *scene, SceneCollection *sc, Object *ob)
+static void collection_object_add(const Scene *scene, SceneCollection *sc, Object *ob)
{
BLI_addtail(&sc->objects, BLI_genericNodeN(ob));
id_us_plus((ID *)ob);
@@ -199,7 +232,7 @@ static void collection_object_add(Scene *scene, SceneCollection *sc, Object *ob)
/**
* Add object to collection
*/
-void BKE_collection_object_add(Scene *scene, SceneCollection *sc, Object *ob)
+void BKE_collection_object_add(const Scene *scene, SceneCollection *sc, Object *ob)
{
if (BLI_findptr(&sc->objects, ob, offsetof(LinkData, data))) {
/* don't add the same object twice */
@@ -214,7 +247,6 @@ void BKE_collection_object_add(Scene *scene, SceneCollection *sc, Object *ob)
*/
void BKE_collection_object_add_from(Scene *scene, Object *ob_src, Object *ob_dst)
{
- SceneCollection *sc;
FOREACH_SCENE_COLLECTION(scene, sc)
{
if (BLI_findptr(&sc->objects, ob_src, offsetof(LinkData, data))) {
@@ -225,9 +257,10 @@ void BKE_collection_object_add_from(Scene *scene, Object *ob_src, Object *ob_dst
}
/**
- * Remove object from collection
+ * Remove object from collection.
+ * \param bmain: Can be NULL if free_us is false.
*/
-void BKE_collection_object_remove(Main *bmain, Scene *scene, SceneCollection *sc, Object *ob, const bool free_us)
+void BKE_collection_object_remove(Main *bmain, const Scene *scene, SceneCollection *sc, Object *ob, const bool free_us)
{
LinkData *link = BLI_findptr(&sc->objects, ob, offsetof(LinkData, data));
@@ -251,13 +284,21 @@ void BKE_collection_object_remove(Main *bmain, Scene *scene, SceneCollection *sc
}
/**
+ * Move object from a collection into another
+ */
+void BKE_collection_object_move(const Scene *scene, SceneCollection *sc_dst, SceneCollection *sc_src, Object *ob)
+{
+ BKE_collection_object_add(scene, sc_dst, ob);
+ BKE_collection_object_remove(NULL, scene, sc_src, ob, false);
+}
+
+/**
* Remove object from all collections of scene
*/
void BKE_collections_object_remove(Main *bmain, Scene *scene, Object *ob, const bool free_us)
{
BKE_scene_remove_rigidbody_object(scene, ob);
- SceneCollection *sc;
FOREACH_SCENE_COLLECTION(scene, sc)
{
BKE_collection_object_remove(bmain, scene, sc, ob, free_us);
@@ -266,6 +307,152 @@ void BKE_collections_object_remove(Main *bmain, Scene *scene, Object *ob, const
}
/* ---------------------------------------------------------------------- */
+/* Outliner drag and drop */
+
+/**
+ * Find and return the SceneCollection that has \a sc_child as one of its directly
+ * nested SceneCollection.
+ *
+ * \param sc_parent Initial SceneCollection to look into recursively, usually the master collection
+ */
+static SceneCollection *find_collection_parent(const SceneCollection *sc_child, SceneCollection *sc_parent)
+{
+ for (SceneCollection *sc_nested = sc_parent->scene_collections.first; sc_nested; sc_nested = sc_nested->next) {
+ if (sc_nested == sc_child) {
+ return sc_parent;
+ }
+
+ SceneCollection *found = find_collection_parent(sc_child, sc_nested);
+ if (found) {
+ return found;
+ }
+ }
+
+ return NULL;
+}
+
+/**
+ * Check if \a sc_reference is nested to \a sc_parent SceneCollection
+ */
+static bool is_collection_in_tree(const SceneCollection *sc_reference, SceneCollection *sc_parent)
+{
+ return find_collection_parent(sc_reference, sc_parent) != NULL;
+}
+
+bool BKE_collection_move_above(const Scene *scene, SceneCollection *sc_dst, SceneCollection *sc_src)
+{
+ /* Find the SceneCollection the sc_src belongs to */
+ SceneCollection *sc_master = BKE_collection_master(scene);
+
+ /* Master Layer can't be moved around*/
+ if (ELEM(sc_master, sc_src, sc_dst)) {
+ return false;
+ }
+
+ /* collection is already where we wanted it to be */
+ if (sc_dst->prev == sc_src) {
+ return false;
+ }
+
+ /* We can't move a collection fs the destiny collection
+ * is nested to the source collection */
+ if (is_collection_in_tree(sc_dst, sc_src)) {
+ return false;
+ }
+
+ SceneCollection *sc_src_parent = find_collection_parent(sc_src, sc_master);
+ SceneCollection *sc_dst_parent = find_collection_parent(sc_dst, sc_master);
+ BLI_assert(sc_src_parent);
+ BLI_assert(sc_dst_parent);
+
+ /* Remove sc_src from its parent */
+ BLI_remlink(&sc_src_parent->scene_collections, sc_src);
+
+ /* Re-insert it where it belongs */
+ BLI_insertlinkbefore(&sc_dst_parent->scene_collections, sc_dst, sc_src);
+
+ /* Update the tree */
+ BKE_layer_collection_resync(scene, sc_src_parent);
+ BKE_layer_collection_resync(scene, sc_dst_parent);
+
+ return true;
+}
+
+bool BKE_collection_move_below(const Scene *scene, SceneCollection *sc_dst, SceneCollection *sc_src)
+{
+ /* Find the SceneCollection the sc_src belongs to */
+ SceneCollection *sc_master = BKE_collection_master(scene);
+
+ /* Master Layer can't be moved around*/
+ if (ELEM(sc_master, sc_src, sc_dst)) {
+ return false;
+ }
+
+ /* Collection is already where we wanted it to be */
+ if (sc_dst->next == sc_src) {
+ return false;
+ }
+
+ /* We can't move a collection if the destiny collection
+ * is nested to the source collection */
+ if (is_collection_in_tree(sc_dst, sc_src)) {
+ return false;
+ }
+
+ SceneCollection *sc_src_parent = find_collection_parent(sc_src, sc_master);
+ SceneCollection *sc_dst_parent = find_collection_parent(sc_dst, sc_master);
+ BLI_assert(sc_src_parent);
+ BLI_assert(sc_dst_parent);
+
+ /* Remove sc_src from its parent */
+ BLI_remlink(&sc_src_parent->scene_collections, sc_src);
+
+ /* Re-insert it where it belongs */
+ BLI_insertlinkafter(&sc_dst_parent->scene_collections, sc_dst, sc_src);
+
+ /* Update the tree */
+ BKE_layer_collection_resync(scene, sc_src_parent);
+ BKE_layer_collection_resync(scene, sc_dst_parent);
+
+ return true;
+}
+
+bool BKE_collection_move_into(const Scene *scene, SceneCollection *sc_dst, SceneCollection *sc_src)
+{
+ /* Find the SceneCollection the sc_src belongs to */
+ SceneCollection *sc_master = BKE_collection_master(scene);
+ if (sc_src == sc_master) {
+ return false;
+ }
+
+ /* We can't move a collection if the destiny collection
+ * is nested to the source collection */
+ if (is_collection_in_tree(sc_dst, sc_src)) {
+ return false;
+ }
+
+ SceneCollection *sc_src_parent = find_collection_parent(sc_src, sc_master);
+ BLI_assert(sc_src_parent);
+
+ /* collection is already where we wanted it to be */
+ if (sc_dst->scene_collections.last == sc_src) {
+ return false;
+ }
+
+ /* Remove sc_src from it */
+ BLI_remlink(&sc_src_parent->scene_collections, sc_src);
+
+ /* Insert sc_src into sc_dst */
+ BLI_addtail(&sc_dst->scene_collections, sc_src);
+
+ /* Update the tree */
+ BKE_layer_collection_resync(scene, sc_src_parent);
+ BKE_layer_collection_resync(scene, sc_dst);
+
+ return true;
+}
+
+/* ---------------------------------------------------------------------- */
/* Iteractors */
/* scene collection iteractor */
@@ -273,7 +460,7 @@ typedef struct SceneCollectionsIteratorData {
Scene *scene;
void **array;
int tot, cur;
- } SceneCollectionsIteratorData;
+} SceneCollectionsIteratorData;
static void scene_collection_callback(SceneCollection *sc, BKE_scene_collections_Cb callback, void *data)
{
@@ -384,7 +571,7 @@ void BKE_scene_objects_Iterator_begin(Iterator *iter, void *data_in)
BKE_scene_collections_Iterator_begin(&data->scene_collection_iter, scene);
SceneCollection *sc = data->scene_collection_iter.current;
- iter->current = sc->objects.first;
+ iter->current = sc->objects.first ? ((LinkData *)sc->objects.first)->data : NULL;
iter->valid = true;
if (iter->current == NULL) {
diff --git a/source/blender/blenkernel/intern/collision.c b/source/blender/blenkernel/intern/collision.c
index b5f76240c0b..23cfee721ae 100644
--- a/source/blender/blenkernel/intern/collision.c
+++ b/source/blender/blenkernel/intern/collision.c
@@ -512,9 +512,9 @@ static void add_collision_object(Object ***objs, unsigned int *numobj, unsigned
// return all collision objects in scene
// collision object will exclude self
-Object **get_collisionobjects_ext(Scene *scene, Object *self, Group *group, int layer, unsigned int *numcollobj, unsigned int modifier_type, bool dupli)
+Object **get_collisionobjects_ext(Scene *scene, Object *self, Group *group, int UNUSED(layer), unsigned int *numcollobj, unsigned int modifier_type, bool dupli)
{
- BaseLegacy *base;
+ Base *base;
Object **objs;
GroupObject *go;
unsigned int numobj= 0, maxobj= 100;
@@ -532,9 +532,9 @@ Object **get_collisionobjects_ext(Scene *scene, Object *self, Group *group, int
Scene *sce_iter;
/* add objects in same layer in scene */
for (SETLOOPER(scene, sce_iter, base)) {
- if ( base->lay & layer )
+ if ((base->flag & BASE_VISIBLED) != 0) {
add_collision_object(&objs, &numobj, &maxobj, base->object, self, level, modifier_type);
-
+ }
}
}
@@ -596,11 +596,11 @@ ListBase *get_collider_cache(Scene *scene, Object *self, Group *group)
}
else {
Scene *sce_iter;
- BaseLegacy *base;
+ Base *base;
/* add objects in same layer in scene */
for (SETLOOPER(scene, sce_iter, base)) {
- if (!self || (base->lay & self->lay))
+ if (!self || ((base->flag & BASE_VISIBLED) != 0))
add_collider_cache_object(&objs, base->object, self, 0);
}
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/context.c b/source/blender/blenkernel/intern/context.c
index a7c53dda8c7..20a3d4ac7e0 100644
--- a/source/blender/blenkernel/intern/context.c
+++ b/source/blender/blenkernel/intern/context.c
@@ -39,6 +39,8 @@
#include "DNA_linestyle_types.h"
#include "DNA_gpencil_types.h"
+#include "DEG_depsgraph.h"
+
#include "BLI_listbase.h"
#include "BLI_string.h"
#include "BLI_threads.h"
@@ -815,14 +817,6 @@ struct SpaceClip *CTX_wm_space_clip(const bContext *C)
return NULL;
}
-struct SpaceCollections *CTX_wm_space_collections(const bContext *C)
-{
- ScrArea *sa = CTX_wm_area(C);
- if (sa && sa->spacetype == SPACE_COLLECTIONS)
- return sa->spacedata.first;
- return NULL;
-}
-
void CTX_wm_manager_set(bContext *C, wmWindowManager *wm)
{
C->wm.manager = wm;
@@ -914,7 +908,7 @@ SceneLayer *CTX_data_scene_layer(const bContext *C)
return sl;
}
else {
- return BKE_scene_layer_active(CTX_data_scene(C));
+ return BKE_scene_layer_context_active(CTX_data_scene(C));
}
}
@@ -1217,3 +1211,8 @@ int CTX_data_editable_gpencil_strokes(const bContext *C, ListBase *list)
return ctx_data_collection_get(C, "editable_gpencil_strokes", list);
}
+Depsgraph *CTX_data_depsgraph(const bContext *C)
+{
+ Scene *scene = CTX_data_scene(C);
+ return scene->depsgraph;
+}
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 c9f0b8ec9ca..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);
}
}
diff --git a/source/blender/blenkernel/intern/depsgraph.c b/source/blender/blenkernel/intern/depsgraph.c
index c5b8a18fd65..f0b1363e647 100644
--- a/source/blender/blenkernel/intern/depsgraph.c
+++ b/source/blender/blenkernel/intern/depsgraph.c
@@ -228,6 +228,18 @@ bool DAG_is_acyclic(Scene *UNUSED(scene))
return false;
}
+/* ************************ DAG ********************* */
+
+/**
+ * Get the object as properly evaluated by depsgraph.
+ */
+Object *DAG_get_object(Depsgraph *depsgraph, Object *ob)
+{
+ /* XXX TODO */
+ UNUSED_VARS(depsgraph);
+ return ob;
+}
+
/* ************************************
* This functions are to be supported *
* ************************************
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 39d06a13e6e..fe55909bcd5 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..19a27499ff0 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);
}
}
@@ -810,39 +810,6 @@ static void emDM_drawMappedEdgesInterp(
}
}
-static void emDM_drawUVEdges(DerivedMesh *dm)
-{
- EditDerivedBMesh *bmdm = (EditDerivedBMesh *)dm;
- BMesh *bm = bmdm->em->bm;
- BMFace *efa;
- BMIter iter;
-
- const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV);
-
- if (UNLIKELY(cd_loop_uv_offset == -1)) {
- return;
- }
-
- glBegin(GL_LINES);
- BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) {
- BMLoop *l_iter, *l_first;
- const float *uv, *uv_prev;
-
- if (BM_elem_flag_test(efa, BM_ELEM_HIDDEN))
- continue;
-
- l_iter = l_first = BM_FACE_FIRST_LOOP(efa);
- uv_prev = ((MLoopUV *)BM_ELEM_CD_GET_VOID_P(l_iter->prev, cd_loop_uv_offset))->uv;
- do {
- uv = ((MLoopUV *)BM_ELEM_CD_GET_VOID_P(l_iter, cd_loop_uv_offset))->uv;
- glVertex2fv(uv);
- glVertex2fv(uv_prev);
- uv_prev = uv;
- } while ((l_iter = l_iter->next) != l_first);
- }
- glEnd();
-}
-
static void emDM_foreachMappedLoop(
DerivedMesh *dm,
void (*func)(void *userData, int vertex_index, int face_index, const float co[3], const float no[3]),
@@ -2280,7 +2247,6 @@ DerivedMesh *getEditDerivedBMesh(
bmdm->dm.drawMappedFacesMat = emDM_drawMappedFacesMat;
bmdm->dm.drawFacesTex = emDM_drawFacesTex;
bmdm->dm.drawFacesGLSL = emDM_drawFacesGLSL;
- bmdm->dm.drawUVEdges = emDM_drawUVEdges;
bmdm->dm.release = emDM_release;
diff --git a/source/blender/blenkernel/intern/effect.c b/source/blender/blenkernel/intern/effect.c
index 668d4d6c9e2..c58e304db6c 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..65d3f9e93fc 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)
@@ -468,6 +472,7 @@ static IDProperty *IDP_CopyGroup(const IDProperty *prop)
BLI_assert(prop->type == IDP_GROUP);
newp = idp_generic_copy(prop);
newp->len = prop->len;
+ newp->subtype = prop->subtype;
for (link = prop->data.group.first; link; link = link->next) {
BLI_addtail(&newp->data.group, IDP_CopyProperty(link));
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/layer.c b/source/blender/blenkernel/intern/layer.c
index ef4816af54d..caa60450133 100644
--- a/source/blender/blenkernel/intern/layer.c
+++ b/source/blender/blenkernel/intern/layer.c
@@ -24,14 +24,18 @@
* \ingroup bke
*/
+#include <string.h>
+
#include "BLI_listbase.h"
#include "BLI_string.h"
#include "BLI_string_utf8.h"
#include "BLI_string_utils.h"
#include "BLT_translation.h"
-#include "BKE_layer.h"
#include "BKE_collection.h"
+#include "BKE_depsgraph.h"
+#include "BKE_global.h"
+#include "BKE_idprop.h"
#include "BKE_layer.h"
#include "BKE_main.h"
#include "BKE_node.h"
@@ -42,25 +46,29 @@
#include "DNA_node_types.h"
#include "DNA_scene_types.h"
+#include "DRW_engine.h"
+
#include "MEM_guardedalloc.h"
+#define DEBUG_PRINT if (G.debug & G_DEBUG_DEPSGRAPH) printf
+
/* prototype */
struct CollectionEngineSettingsCB_Type;
static void layer_collection_free(SceneLayer *sl, LayerCollection *lc);
-static LayerCollection *layer_collection_add(SceneLayer *sl, ListBase *lb, SceneCollection *sc);
+static LayerCollection *layer_collection_add(SceneLayer *sl, LayerCollection *parent, SceneCollection *sc);
static LayerCollection *find_layer_collection_by_scene_collection(LayerCollection *lc, const SceneCollection *sc);
-static CollectionEngineSettings *collection_engine_settings_create(struct CollectionEngineSettingsCB_Type *ces_type);
-static void layer_collection_engine_settings_free(LayerCollection *lc);
-static void layer_collection_create_engine_settings(LayerCollection *lc);
-static void scene_layer_engine_settings_update(SceneLayer *sl, Object *ob, const char *engine_name);
+static IDProperty *collection_engine_settings_create(struct CollectionEngineSettingsCB_Type *ces_type, const bool populate);
+static IDProperty *collection_engine_get(IDProperty *root, const int type, const char *engine_name);
+static void collection_engine_settings_init(IDProperty *root, const bool populate);
static void object_bases_Iterator_next(Iterator *iter, const int flag);
/* RenderLayer */
/**
* Returns the SceneLayer to be used for rendering
+ * Most of the time BKE_scene_layer_context_active should be used instead
*/
-SceneLayer *BKE_scene_layer_active(struct Scene *scene)
+SceneLayer *BKE_scene_layer_render_active(const Scene *scene)
{
SceneLayer *sl = BLI_findlink(&scene->render_layers, scene->active_layer);
BLI_assert(sl);
@@ -68,6 +76,17 @@ SceneLayer *BKE_scene_layer_active(struct Scene *scene)
}
/**
+ * Returns the SceneLayer to be used for drawing, outliner, and
+ * other context related areas.
+ */
+SceneLayer *BKE_scene_layer_context_active(Scene *scene)
+{
+ /* waiting for workspace to get the layer from context*/
+ TODO_LAYER_CONTEXT;
+ return BKE_scene_layer_render_active(scene);
+}
+
+/**
* Add a new renderlayer
* by default, a renderlayer has the master collection
*/
@@ -87,7 +106,7 @@ SceneLayer *BKE_scene_layer_add(Scene *scene, const char *name)
BLI_uniquename(&scene->render_layers, sl, DATA_("SceneLayer"), '.', offsetof(SceneLayer, name), sizeof(sl->name));
SceneCollection *sc = BKE_collection_master(scene);
- layer_collection_add(sl, &sl->layer_collections, sc);
+ layer_collection_add(sl, NULL, sc);
return sl;
}
@@ -129,6 +148,13 @@ bool BKE_scene_layer_remove(Main *bmain, Scene *scene, SceneLayer *sl)
void BKE_scene_layer_free(SceneLayer *sl)
{
sl->basact = NULL;
+
+ for (Base *base = sl->object_bases.first; base; base = base->next) {
+ if (base->collection_properties) {
+ IDP_FreeProperty(base->collection_properties);
+ MEM_freeN(base->collection_properties);
+ }
+ }
BLI_freelistN(&sl->object_bases);
for (LayerCollection *lc = sl->layer_collections.first; lc; lc = lc->next) {
@@ -176,7 +202,7 @@ static bool find_scene_collection_in_scene_collections(ListBase *lb, const Layer
/**
* Find the SceneLayer a LayerCollection belongs to
*/
-SceneLayer *BKE_scene_layer_find_from_collection(Scene *scene, LayerCollection *lc)
+SceneLayer *BKE_scene_layer_find_from_collection(const Scene *scene, LayerCollection *lc)
{
for (SceneLayer *sl = scene->render_layers.first; sl; sl = sl->next) {
if (find_scene_collection_in_scene_collections(&sl->layer_collections, lc)) {
@@ -210,7 +236,7 @@ void BKE_scene_layer_base_select(struct SceneLayer *sl, Base *selbase)
}
}
-static void scene_layer_object_base_unref(SceneLayer* sl, Base *base)
+static void scene_layer_object_base_unref(SceneLayer *sl, Base *base)
{
base->refcount--;
@@ -220,125 +246,14 @@ static void scene_layer_object_base_unref(SceneLayer* sl, Base *base)
sl->basact = NULL;
}
- BLI_remlink(&sl->object_bases, base);
- MEM_freeN(base);
- }
-}
-
-static void layer_collection_base_flag_recalculate(LayerCollection *lc, const bool tree_is_visible, const bool tree_is_selectable)
-{
- bool is_visible = tree_is_visible && ((lc->flag & COLLECTION_VISIBLE) != 0);
- /* an object can only be selected if it's visible */
- bool is_selectable = tree_is_selectable && is_visible && ((lc->flag & COLLECTION_SELECTABLE) != 0);
-
- for (LinkData *link = lc->object_bases.first; link; link = link->next) {
- Base *base = link->data;
-
- if (is_visible) {
- base->flag |= BASE_VISIBLED;
- }
- else {
- base->flag &= ~BASE_VISIBLED;
+ if (base->collection_properties) {
+ IDP_FreeProperty(base->collection_properties);
+ MEM_freeN(base->collection_properties);
}
- if (is_selectable) {
- base->flag |= BASE_SELECTABLED;
- }
- else {
- base->flag &= ~BASE_SELECTABLED;
- }
- }
-
- for (LayerCollection *lcn = lc->layer_collections.first; lcn; lcn = lcn->next) {
- layer_collection_base_flag_recalculate(lcn, is_visible, is_selectable);
- }
-}
-
-/**
- * Re-evaluate the ObjectBase flags for SceneLayer
- */
-void BKE_scene_layer_base_flag_recalculate(SceneLayer *sl)
-{
- for (LayerCollection *lc = sl->layer_collections.first; lc; lc = lc->next) {
- layer_collection_base_flag_recalculate(lc, true, true);
- }
-
- /* if base is not selectabled, clear select */
- for (Base *base = sl->object_bases.first; base; base = base->next) {
- if ((base->flag & BASE_SELECTABLED) == 0) {
- base->flag &= ~BASE_SELECTED;
- }
- }
-}
-
-/**
- * Tag Scene Layer to recalculation
- *
- * Temporary function, waiting for real depsgraph
- */
-void BKE_scene_layer_engine_settings_recalculate(SceneLayer *sl)
-{
- sl->flag |= SCENE_LAYER_ENGINE_DIRTY;
- for (Base *base = sl->object_bases.first; base; base = base->next) {
- base->flag |= BASE_DIRTY_ENGINE_SETTINGS;
- }
-}
-
-/**
- * Tag Object in SceneLayer to recalculation
- *
- * Temporary function, waiting for real depsgraph
- */
-void BKE_scene_layer_engine_settings_object_recalculate(SceneLayer *sl, Object *ob)
-{
- Base *base = BLI_findptr(&sl->object_bases, ob, offsetof(Base, object));
- if (base) {
- sl->flag |= SCENE_LAYER_ENGINE_DIRTY;
- base->flag |= BASE_DIRTY_ENGINE_SETTINGS;
- }
-}
-
-/**
- * Tag all Objects in LayerCollection to recalculation
- *
- * Temporary function, waiting for real depsgraph
- */
-void BKE_scene_layer_engine_settings_collection_recalculate(SceneLayer *sl, LayerCollection *lc)
-{
- sl->flag |= SCENE_LAYER_ENGINE_DIRTY;
-
- for (LinkData *link = lc->object_bases.first; link; link = link->next) {
- Base *base = (Base *)link->data;
- base->flag |= BASE_DIRTY_ENGINE_SETTINGS;
- }
-
- for (LayerCollection *lcn = lc->layer_collections.first; lcn; lcn = lcn->next) {
- BKE_scene_layer_engine_settings_collection_recalculate(sl, lcn);
- }
-}
-
-/**
- * Re-calculate the engine settings for all the objects in SceneLayer
- *
- * Temporary function, waiting for real depsgraph
- */
-void BKE_scene_layer_engine_settings_update(struct SceneLayer *sl, const char *engine_name)
-{
- if ((sl->flag & SCENE_LAYER_ENGINE_DIRTY) == 0) {
- return;
- }
-
- /* do the complete settings update */
- for (Base *base = sl->object_bases.first; base; base = base->next) {
- if (((base->flag & BASE_DIRTY_ENGINE_SETTINGS) != 0) && \
- (base->flag & BASE_VISIBLED) != 0)
- {
- scene_layer_engine_settings_update(sl, base->object, engine_name);
- base->flag &= ~BASE_DIRTY_ENGINE_SETTINGS;
- }
+ BLI_remlink(&sl->object_bases, base);
+ MEM_freeN(base);
}
-
- sl->flag &= ~SCENE_LAYER_ENGINE_DIRTY;
}
/**
@@ -356,7 +271,11 @@ static Base *object_base_add(SceneLayer *sl, Object *ob)
/* do not bump user count, leave it for SceneCollections */
base->object = ob;
BLI_addtail(&sl->object_bases, base);
+
+ IDPropertyTemplate val = {0};
+ base->collection_properties = IDP_New(IDP_GROUP, &val, ROOT_PROP);
}
+
base->refcount++;
return base;
}
@@ -377,7 +296,16 @@ static void layer_collection_free(SceneLayer *sl, LayerCollection *lc)
BLI_freelistN(&lc->object_bases);
BLI_freelistN(&lc->overrides);
- layer_collection_engine_settings_free(lc);
+
+ if (lc->properties) {
+ IDP_FreeProperty(lc->properties);
+ MEM_freeN(lc->properties);
+ }
+
+ if (lc->properties_evaluated) {
+ IDP_FreeProperty(lc->properties_evaluated);
+ MEM_freeN(lc->properties_evaluated);
+ }
for (LayerCollection *nlc = lc->layer_collections.first; nlc; nlc = nlc->next) {
layer_collection_free(sl, nlc);
@@ -450,7 +378,7 @@ int BKE_layer_collection_count(SceneLayer *sl)
/**
* Recursively get the index for a given collection
*/
-static int index_from_collection(ListBase *lb, LayerCollection *lc, int *i)
+static int index_from_collection(ListBase *lb, const LayerCollection *lc, int *i)
{
for (LayerCollection *lcol = lb->first; lcol; lcol = lcol->next) {
if (lcol == lc) {
@@ -470,19 +398,364 @@ static int index_from_collection(ListBase *lb, LayerCollection *lc, int *i)
/**
* Return -1 if not found
*/
-int BKE_layer_collection_findindex(SceneLayer *sl, LayerCollection *lc)
+int BKE_layer_collection_findindex(SceneLayer *sl, const LayerCollection *lc)
{
int i = 0;
return index_from_collection(&sl->layer_collections, lc, &i);
}
/**
+ * Lookup the listbase that contains \a lc.
+ */
+static ListBase *layer_collection_listbase_find(ListBase *lb, LayerCollection *lc)
+{
+ for (LayerCollection *lc_iter = lb->first; lc_iter; lc_iter = lc_iter->next) {
+ if (lc_iter == lc) {
+ return lb;
+ }
+
+ ListBase *lb_child_result;
+ if ((lb_child_result = layer_collection_listbase_find(&lc_iter->layer_collections, lc))) {
+ return lb_child_result;
+ }
+ }
+
+ return NULL;
+}
+
+#if 0
+/**
+ * Lookup the listbase that contains \a sc.
+ */
+static ListBase *scene_collection_listbase_find(ListBase *lb, SceneCollection *sc)
+{
+ for (SceneCollection *sc_iter = lb->first; sc_iter; sc_iter = sc_iter->next) {
+ if (sc_iter == sc) {
+ return lb;
+ }
+
+ ListBase *lb_child_result;
+ if ((lb_child_result = scene_collection_listbase_find(&sc_iter->scene_collections, sc))) {
+ return lb_child_result;
+ }
+ }
+
+ return NULL;
+}
+#endif
+
+/* ---------------------------------------------------------------------- */
+/* Outliner drag and drop */
+
+/**
+ * Nest a LayerCollection into another one
+ * Both collections must be from the same SceneLayer, return true if succeded.
+ *
+ * The LayerCollection will effectively be moved into the
+ * new (nested) position. So all the settings, overrides, ... go with it, and
+ * if the collection was directly linked to the SceneLayer it's then unlinked.
+ *
+ * For the other SceneLayers we simply resync the tree, without changing directly
+ * linked collections (even if they link to the same SceneCollection)
+ *
+ * \param lc_src LayerCollection to nest into \a lc_dst
+ * \param lc_dst LayerCollection to have \a lc_src inserted into
+ */
+
+static void layer_collection_swap(
+ SceneLayer *sl, ListBase *lb_a, ListBase *lb_b,
+ LayerCollection *lc_a, LayerCollection *lc_b)
+{
+ if (lb_a == NULL) {
+ lb_a = layer_collection_listbase_find(&sl->layer_collections, lc_a);
+ }
+
+ if (lb_b == NULL) {
+ lb_b = layer_collection_listbase_find(&sl->layer_collections, lc_b);
+ }
+
+ BLI_assert(lb_a);
+ BLI_assert(lb_b);
+
+ BLI_listbases_swaplinks(lb_a, lb_b, lc_a, lc_b);
+}
+
+/**
+ * Move \a lc_src into \a lc_dst. Both have to be stored in \a sl.
+ * If \a lc_src is directly linked to the SceneLayer it's unlinked
+ */
+bool BKE_layer_collection_move_into(const Scene *scene, LayerCollection *lc_dst, LayerCollection *lc_src)
+{
+ SceneLayer *sl = BKE_scene_layer_find_from_collection(scene, lc_src);
+ bool is_directly_linked = false;
+
+ if ((!sl) || (sl != BKE_scene_layer_find_from_collection(scene, lc_dst))) {
+ return false;
+ }
+
+ /* We can't nest the collection into itself */
+ if (lc_src->scene_collection == lc_dst->scene_collection) {
+ return false;
+ }
+
+ /* Collection is already where we wanted it to be */
+ if (lc_dst->layer_collections.last == lc_src) {
+ return false;
+ }
+
+ /* Collection is already where we want it to be in the scene tree
+ * but we want to swap it in the layer tree still */
+ if (lc_dst->scene_collection->scene_collections.last == lc_src->scene_collection) {
+ LayerCollection *lc_swap = lc_dst->layer_collections.last;
+ layer_collection_swap(sl, &lc_dst->layer_collections, NULL, lc_dst->layer_collections.last, lc_src);
+
+ if (BLI_findindex(&sl->layer_collections, lc_swap) != -1) {
+ BKE_collection_unlink(sl, lc_swap);
+ }
+ return true;
+ }
+ else {
+ LayerCollection *lc_temp;
+ is_directly_linked = BLI_findindex(&sl->layer_collections, lc_src) != -1;
+
+ if (!is_directly_linked) {
+ /* lc_src will be invalid after BKE_collection_move_into!
+ * so we swap it with lc_temp to preserve its settings */
+ lc_temp = BKE_collection_link(sl, lc_src->scene_collection);
+ layer_collection_swap(sl, &sl->layer_collections, NULL, lc_temp, lc_src);
+ }
+
+ if (!BKE_collection_move_into(scene, lc_dst->scene_collection, lc_src->scene_collection)) {
+ if (!is_directly_linked) {
+ /* Swap back and remove */
+ layer_collection_swap(sl, NULL, NULL, lc_temp, lc_src);
+ BKE_collection_unlink(sl, lc_temp);
+ }
+ return false;
+ }
+ }
+
+ LayerCollection *lc_new = BLI_findptr(&lc_dst->layer_collections, lc_src->scene_collection, offsetof(LayerCollection, scene_collection));
+ BLI_assert(lc_new);
+ layer_collection_swap(sl, &lc_dst->layer_collections, NULL, lc_new, lc_src);
+
+ /* If it's directly linked, unlink it after the swap */
+ if (BLI_findindex(&sl->layer_collections, lc_new) != -1) {
+ BKE_collection_unlink(sl, lc_new);
+ }
+
+ return true;
+}
+
+/**
+ * Move \a lc_src above \a lc_dst. Both have to be stored in \a sl.
+ * If \a lc_src is directly linked to the SceneLayer it's unlinked
+ */
+bool BKE_layer_collection_move_above(const Scene *scene, LayerCollection *lc_dst, LayerCollection *lc_src)
+{
+ SceneLayer *sl = BKE_scene_layer_find_from_collection(scene, lc_src);
+ const bool is_directly_linked_src = BLI_findindex(&sl->layer_collections, lc_src) != -1;
+ const bool is_directly_linked_dst = BLI_findindex(&sl->layer_collections, lc_dst) != -1;
+
+ if ((!sl) || (sl != BKE_scene_layer_find_from_collection(scene, lc_dst))) {
+ return false;
+ }
+
+ /* Collection is already where we wanted it to be */
+ if (lc_dst->prev == lc_src) {
+ return false;
+ }
+
+ /* Collection is already where we want it to be in the scene tree
+ * but we want to swap it in the layer tree still */
+ if (lc_dst->prev && lc_dst->prev->scene_collection == lc_src->scene_collection) {
+ LayerCollection *lc_swap = lc_dst->prev;
+ layer_collection_swap(sl, NULL, NULL, lc_dst->prev, lc_src);
+
+ if (BLI_findindex(&sl->layer_collections, lc_swap) != -1) {
+ BKE_collection_unlink(sl, lc_swap);
+ }
+ return true;
+ }
+ /* We don't allow to move above/below a directly linked collection
+ * unless the source collection is also directly linked */
+ else if (is_directly_linked_dst) {
+ /* Both directly linked to the SceneLayer, just need to swap */
+ if (is_directly_linked_src) {
+ BLI_remlink(&sl->layer_collections, lc_src);
+ BLI_insertlinkbefore(&sl->layer_collections, lc_dst, lc_src);
+ return true;
+ }
+ else {
+ return false;
+ }
+ }
+ else {
+ LayerCollection *lc_temp;
+
+ if (!is_directly_linked_src) {
+ /* lc_src will be invalid after BKE_collection_move_into!
+ * so we swap it with lc_temp to preserve its settings */
+ lc_temp = BKE_collection_link(sl, lc_src->scene_collection);
+ layer_collection_swap(sl, &sl->layer_collections, NULL, lc_temp, lc_src);
+ }
+
+ if (!BKE_collection_move_above(scene, lc_dst->scene_collection, lc_src->scene_collection)) {
+ if (!is_directly_linked_src) {
+ /* Swap back and remove */
+ layer_collection_swap(sl, NULL, NULL, lc_temp, lc_src);
+ BKE_collection_unlink(sl, lc_temp);
+ }
+ return false;
+ }
+ }
+
+ LayerCollection *lc_new = lc_dst->prev;
+ BLI_assert(lc_new);
+ layer_collection_swap(sl, NULL, NULL, lc_new, lc_src);
+
+ /* If it's directly linked, unlink it after the swap */
+ if (BLI_findindex(&sl->layer_collections, lc_new) != -1) {
+ BKE_collection_unlink(sl, lc_new);
+ }
+
+ return true;
+}
+
+/**
+ * Move \a lc_src below \a lc_dst. Both have to be stored in \a sl.
+ * If \a lc_src is directly linked to the SceneLayer it's unlinked
+ */
+bool BKE_layer_collection_move_below(const Scene *scene, LayerCollection *lc_dst, LayerCollection *lc_src)
+{
+ SceneLayer *sl = BKE_scene_layer_find_from_collection(scene, lc_src);
+ const bool is_directly_linked_src = BLI_findindex(&sl->layer_collections, lc_src) != -1;
+ const bool is_directly_linked_dst = BLI_findindex(&sl->layer_collections, lc_dst) != -1;
+
+ if ((!sl) || (sl != BKE_scene_layer_find_from_collection(scene, lc_dst))) {
+ return false;
+ }
+
+ /* Collection is already where we wanted it to be */
+ if (lc_dst->next == lc_src) {
+ return false;
+ }
+
+ /* Collection is already where we want it to be in the scene tree
+ * but we want to swap it in the layer tree still */
+ if (lc_dst->next && lc_dst->next->scene_collection == lc_src->scene_collection) {
+ LayerCollection *lc_swap = lc_dst->next;
+ layer_collection_swap(sl, NULL, NULL, lc_dst->next, lc_src);
+
+ if (BLI_findindex(&sl->layer_collections, lc_swap) != -1) {
+ BKE_collection_unlink(sl, lc_swap);
+ }
+ return true;
+ }
+ /* We don't allow to move above/below a directly linked collection
+ * unless the source collection is also directly linked */
+ else if (is_directly_linked_dst) {
+ /* Both directly linked to the SceneLayer, just need to swap */
+ if (is_directly_linked_src) {
+ BLI_remlink(&sl->layer_collections, lc_src);
+ BLI_insertlinkafter(&sl->layer_collections, lc_dst, lc_src);
+ return true;
+ }
+ else {
+ return false;
+ }
+ }
+ else {
+ LayerCollection *lc_temp;
+
+ if (!is_directly_linked_src) {
+ /* lc_src will be invalid after BKE_collection_move_into!
+ * so we swap it with lc_temp to preserve its settings */
+ lc_temp = BKE_collection_link(sl, lc_src->scene_collection);
+ layer_collection_swap(sl, &sl->layer_collections, NULL, lc_temp, lc_src);
+ }
+
+ if (!BKE_collection_move_below(scene, lc_dst->scene_collection, lc_src->scene_collection)) {
+ if (!is_directly_linked_src) {
+ /* Swap back and remove */
+ layer_collection_swap(sl, NULL, NULL, lc_temp, lc_src);
+ BKE_collection_unlink(sl, lc_temp);
+ }
+ return false;
+ }
+ }
+
+ LayerCollection *lc_new = lc_dst->next;
+ BLI_assert(lc_new);
+ layer_collection_swap(sl, NULL, NULL, lc_new, lc_src);
+
+ /* If it's directly linked, unlink it after the swap */
+ if (BLI_findindex(&sl->layer_collections, lc_new) != -1) {
+ BKE_collection_unlink(sl, lc_new);
+ }
+
+ return true;
+}
+
+static bool layer_collection_resync(SceneLayer *sl, LayerCollection *lc, const SceneCollection *sc)
+{
+ if (lc->scene_collection == sc) {
+ ListBase collections = {NULL};
+ BLI_movelisttolist(&collections, &lc->layer_collections);
+
+ for (SceneCollection *sc_nested = sc->scene_collections.first; sc_nested; sc_nested = sc_nested->next) {
+ LayerCollection *lc_nested = BLI_findptr(&collections, sc_nested, offsetof(LayerCollection, scene_collection));
+ if (lc_nested) {
+ BLI_remlink(&collections, lc_nested);
+ BLI_addtail(&lc->layer_collections, lc_nested);
+ }
+ else {
+ layer_collection_add(sl, lc, sc_nested);
+ }
+ }
+
+ for (LayerCollection *lc_nested = collections.first; lc_nested; lc_nested = lc_nested->next) {
+ layer_collection_free(sl, lc_nested);
+ }
+ BLI_freelistN(&collections);
+
+ BLI_assert(BLI_listbase_count(&lc->layer_collections) ==
+ BLI_listbase_count(&sc->scene_collections));
+
+ return true;
+ }
+
+ for (LayerCollection *lc_nested = lc->layer_collections.first; lc_nested; lc_nested = lc_nested->next) {
+ if (layer_collection_resync(sl, lc_nested, sc)) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+/**
+ * Update the scene layers so that any LayerCollection that points
+ * to \a sc is re-synced again
+ */
+void BKE_layer_collection_resync(const Scene *scene, const SceneCollection *sc)
+{
+ for (SceneLayer *sl = scene->render_layers.first; sl; sl = sl->next) {
+ for (LayerCollection *lc = sl->layer_collections.first; lc; lc = lc->next) {
+ layer_collection_resync(sl, lc, sc);
+ }
+ }
+}
+
+/* ---------------------------------------------------------------------- */
+
+/**
* Link a collection to a renderlayer
* The collection needs to be created separately
*/
LayerCollection *BKE_collection_link(SceneLayer *sl, SceneCollection *sc)
{
- LayerCollection *lc = layer_collection_add(sl, &sl->layer_collections, sc);
+ LayerCollection *lc = layer_collection_add(sl, NULL, sc);
sl->active_collection = BKE_layer_collection_findindex(sl, lc);
return lc;
}
@@ -494,9 +767,6 @@ LayerCollection *BKE_collection_link(SceneLayer *sl, SceneCollection *sc)
void BKE_collection_unlink(SceneLayer *sl, LayerCollection *lc)
{
BKE_layer_collection_free(sl, lc);
- BKE_scene_layer_base_flag_recalculate(sl);
- BKE_scene_layer_engine_settings_collection_recalculate(sl, lc);
-
BLI_remlink(&sl->layer_collections, lc);
MEM_freeN(lc);
sl->active_collection = 0;
@@ -514,9 +784,6 @@ static void layer_collection_object_add(SceneLayer *sl, LayerCollection *lc, Obj
}
BLI_addtail(&lc->object_bases, BLI_genericNodeN(base));
-
- BKE_scene_layer_base_flag_recalculate(sl);
- BKE_scene_layer_engine_settings_object_recalculate(sl, ob);
}
static void layer_collection_object_remove(SceneLayer *sl, LayerCollection *lc, Object *ob)
@@ -544,30 +811,39 @@ static void layer_collection_populate(SceneLayer *sl, LayerCollection *lc, Scene
layer_collection_objects_populate(sl, lc, &sc->filter_objects);
for (SceneCollection *nsc = sc->scene_collections.first; nsc; nsc = nsc->next) {
- layer_collection_add(sl, &lc->layer_collections, nsc);
+ layer_collection_add(sl, lc, nsc);
}
}
-static LayerCollection *layer_collection_add(SceneLayer *sl, ListBase *lb, SceneCollection *sc)
+static LayerCollection *layer_collection_add(SceneLayer *sl, LayerCollection *parent, SceneCollection *sc)
{
+ IDPropertyTemplate val = {0};
LayerCollection *lc = MEM_callocN(sizeof(LayerCollection), "Collection Base");
- BLI_addtail(lb, lc);
lc->scene_collection = sc;
- lc->flag = COLLECTION_VISIBLE + COLLECTION_SELECTABLE + COLLECTION_FOLDED;
+ lc->flag = COLLECTION_VISIBLE | COLLECTION_SELECTABLE;
+
+ lc->properties = IDP_New(IDP_GROUP, &val, ROOT_PROP);
+ collection_engine_settings_init(lc->properties, false);
+
+ if (parent != NULL) {
+ BLI_addtail(&parent->layer_collections, lc);
+ }
+ else {
+ BLI_addtail(&sl->layer_collections, lc);
+ }
- layer_collection_create_engine_settings(lc);
layer_collection_populate(sl, lc, sc);
+
return lc;
}
-
/* ---------------------------------------------------------------------- */
/**
* See if render layer has the scene collection linked directly, or indirectly (nested)
*/
-bool BKE_scene_layer_has_collection(struct SceneLayer *sl, struct SceneCollection *sc)
+bool BKE_scene_layer_has_collection(SceneLayer *sl, const SceneCollection *sc)
{
for (LayerCollection *lc = sl->layer_collections.first; lc; lc = lc->next) {
if (find_layer_collection_by_scene_collection(lc, sc) != NULL) {
@@ -619,7 +895,7 @@ void BKE_layer_sync_new_scene_collection(Scene *scene, const SceneCollection *sc
for (LayerCollection *lc = sl->layer_collections.first; lc; lc = lc->next) {
LayerCollection *lc_parent = find_layer_collection_by_scene_collection(lc, sc_parent);
if (lc_parent) {
- layer_collection_add(sl, &lc_parent->layer_collections, sc);
+ layer_collection_add(sl, lc_parent, sc);
}
}
}
@@ -628,7 +904,7 @@ void BKE_layer_sync_new_scene_collection(Scene *scene, const SceneCollection *sc
/**
* Add a corresponding ObjectBase to all the equivalent LayerCollection
*/
-void BKE_layer_sync_object_link(Scene *scene, SceneCollection *sc, Object *ob)
+void BKE_layer_sync_object_link(const Scene *scene, SceneCollection *sc, Object *ob)
{
for (SceneLayer *sl = scene->render_layers.first; sl; sl = sl->next) {
for (LayerCollection *lc = sl->layer_collections.first; lc; lc = lc->next) {
@@ -644,7 +920,7 @@ void BKE_layer_sync_object_link(Scene *scene, SceneCollection *sc, Object *ob)
* Remove the equivalent object base to all layers that have this collection
* also remove all reference to ob in the filter_objects
*/
-void BKE_layer_sync_object_unlink(Scene *scene, SceneCollection *sc, Object *ob)
+void BKE_layer_sync_object_unlink(const Scene *scene, SceneCollection *sc, Object *ob)
{
for (SceneLayer *sl = scene->render_layers.first; sl; sl = sl->next) {
for (LayerCollection *lc = sl->layer_collections.first; lc; lc = lc->next) {
@@ -653,8 +929,6 @@ void BKE_layer_sync_object_unlink(Scene *scene, SceneCollection *sc, Object *ob)
layer_collection_object_remove(sl, found, ob);
}
}
- BKE_scene_layer_base_flag_recalculate(sl);
- BKE_scene_layer_engine_settings_object_recalculate(sl, ob);
}
}
@@ -683,14 +957,24 @@ typedef struct CollectionEngineSettingsCB_Type {
} CollectionEngineSettingsCB_Type;
+static void create_engine_settings_scene(Scene *scene, CollectionEngineSettingsCB_Type *ces_type)
+{
+ if (collection_engine_get(scene->collection_properties, COLLECTION_MODE_NONE, ces_type->name)) {
+ return;
+ }
+
+ IDProperty *props = collection_engine_settings_create(ces_type, true);
+ IDP_AddToGroup(scene->collection_properties, props);
+}
+
static void create_engine_settings_layer_collection(LayerCollection *lc, CollectionEngineSettingsCB_Type *ces_type)
{
- if (BKE_layer_collection_engine_get(lc, ces_type->name)) {
+ if (BKE_layer_collection_engine_get(lc, COLLECTION_MODE_NONE, ces_type->name)) {
return;
}
- CollectionEngineSettings *ces = collection_engine_settings_create(ces_type);
- BLI_addtail(&lc->engine_settings, ces);
+ IDProperty *props = collection_engine_settings_create(ces_type, false);
+ IDP_AddToGroup(lc->properties, props);
for (LayerCollection *lcn = lc->layer_collections.first; lcn; lcn = lcn->next) {
create_engine_settings_layer_collection(lcn, ces_type);
@@ -699,6 +983,9 @@ static void create_engine_settings_layer_collection(LayerCollection *lc, Collect
static void create_engines_settings_scene(Scene *scene, CollectionEngineSettingsCB_Type *ces_type)
{
+ /* populate the scene with the new settings */
+ create_engine_settings_scene(scene, ces_type);
+
for (SceneLayer *sl = scene->render_layers.first; sl; sl = sl->next) {
for (LayerCollection *lc = sl->layer_collections.first; lc; lc = lc->next) {
create_engine_settings_layer_collection(lc, ces_type);
@@ -712,7 +999,8 @@ void BKE_layer_collection_engine_settings_callback_register(
CollectionEngineSettingsCB_Type *ces_type;
/* cleanup in case it existed */
- ces_type = BLI_findstring(&R_engines_settings_callbacks, engine_name, offsetof(CollectionEngineSettingsCB_Type, name));
+ ces_type = BLI_findstring(&R_engines_settings_callbacks, engine_name,
+ offsetof(CollectionEngineSettingsCB_Type, name));
if (ces_type) {
BLI_remlink(&R_engines_settings_callbacks, ces_type);
@@ -737,257 +1025,214 @@ void BKE_layer_collection_engine_settings_callback_free(void)
BLI_freelistN(&R_engines_settings_callbacks);
}
-static CollectionEngineSettings *collection_engine_settings_create(CollectionEngineSettingsCB_Type *ces_type)
-{
- /* create callback data */
- CollectionEngineSettings *ces = MEM_callocN(sizeof(CollectionEngineSettings), "Collection Engine Settings");
- BLI_strncpy_utf8(ces->name, ces_type->name, sizeof(ces->name));
-
- /* call callback */
- ces_type->callback(NULL, ces);
-
- return ces;
-}
-
/**
- * Initialize a CollectionEngineSettings
+ * Create a root IDProperty for this engine
*
- * Usually we would pass LayerCollection->engine_settings
- * But depsgraph uses this for Object->collection_settings
+ * \param populate whether we want to pre-fill the collection with the default properties
*/
-CollectionEngineSettings *BKE_layer_collection_engine_settings_create(const char *engine_name)
+static IDProperty *collection_engine_settings_create(CollectionEngineSettingsCB_Type *ces_type, const bool populate)
{
- CollectionEngineSettingsCB_Type *ces_type;
- ces_type = BLI_findstring(&R_engines_settings_callbacks, engine_name, offsetof(CollectionEngineSettingsCB_Type, name));
- BLI_assert(ces_type);
+ IDProperty *props;
+ IDPropertyTemplate val = {0};
+
+ props = IDP_New(IDP_GROUP, &val, ces_type->name);
+ props->subtype = IDP_GROUP_SUB_ENGINE_RENDER;
+
+ /* properties */
+ if (populate) {
+ ces_type->callback(NULL, props);
+ }
- CollectionEngineSettings *ces = collection_engine_settings_create(ces_type);
- return ces;
+ return props;
}
-/**
- * Free the CollectionEngineSettings
- */
-void BKE_layer_collection_engine_settings_free(CollectionEngineSettings *ces)
+static void layer_collection_create_mode_settings_object(IDProperty *root, const bool populate)
{
- BLI_freelistN(&ces->properties);
+ IDProperty *props;
+ IDPropertyTemplate val = {0};
+
+ props = IDP_New(IDP_GROUP, &val, "ObjectMode");
+ props->subtype = IDP_GROUP_SUB_MODE_OBJECT;
+
+ /* properties */
+ if (populate) {
+ OBJECT_collection_settings_create(props);
+ }
+
+ IDP_AddToGroup(root, props);
}
-static void layer_collection_engine_settings_free(LayerCollection *lc)
+static void layer_collection_create_mode_settings_edit(IDProperty *root, const bool populate)
{
- for (CollectionEngineSettings *ces = lc->engine_settings.first; ces; ces = ces->next) {
- BKE_layer_collection_engine_settings_free(ces);
+ IDProperty *props;
+ IDPropertyTemplate val = {0};
+
+ props = IDP_New(IDP_GROUP, &val, "EditMode");
+ props->subtype = IDP_GROUP_SUB_MODE_EDIT;
+
+ /* properties */
+ if (populate) {
+ EDIT_MESH_collection_settings_create(props);
}
- BLI_freelistN(&lc->engine_settings);
+
+ IDP_AddToGroup(root, props);
}
-/**
- * Initialize the render settings for a single LayerCollection
- */
-static void layer_collection_create_engine_settings(LayerCollection *lc)
+static void collection_create_render_settings(IDProperty *root, const bool populate)
{
CollectionEngineSettingsCB_Type *ces_type;
for (ces_type = R_engines_settings_callbacks.first; ces_type; ces_type = ces_type->next) {
- create_engine_settings_layer_collection(lc, ces_type);
+ IDProperty *props = collection_engine_settings_create(ces_type, populate);
+ IDP_AddToGroup(root, props);
}
}
-/**
- * Return layer collection engine settings for specified engine
- */
-CollectionEngineSettings *BKE_layer_collection_engine_get(LayerCollection *lc, const char *engine_name)
+static void collection_create_mode_settings(IDProperty *root, const bool populate)
{
- CollectionEngineSettings *ces;
- ces = BLI_findstring(&lc->engine_settings, engine_name, offsetof(CollectionEngineSettings, name));
- return ces;
+ /* XXX TODO: put all those engines in the R_engines_settings_callbacks
+ * and have IDP_AddToGroup outside the callbacks */
+ layer_collection_create_mode_settings_object(root, populate);
+ layer_collection_create_mode_settings_edit(root, populate);
}
-/* ---------------------------------------------------------------------- */
-/* Engine Settings Properties */
-
-void BKE_collection_engine_property_add_float(CollectionEngineSettings *ces, const char *name, float value)
+static int idproperty_group_subtype(const int mode_type)
{
- CollectionEnginePropertyFloat *prop;
- prop = MEM_callocN(sizeof(CollectionEnginePropertyFloat), "collection engine settings float");
- prop->data.type = COLLECTION_PROP_TYPE_FLOAT;
- BLI_strncpy_utf8(prop->data.name, name, sizeof(prop->data.name));
- prop->value = value;
- BLI_addtail(&ces->properties, prop);
-}
+ int idgroup_type;
-void BKE_collection_engine_property_add_int(CollectionEngineSettings *ces, const char *name, int value)
-{
- CollectionEnginePropertyInt *prop;
- prop = MEM_callocN(sizeof(CollectionEnginePropertyInt), "collection engine settings int");
- prop->data.type = COLLECTION_PROP_TYPE_INT;
- BLI_strncpy_utf8(prop->data.name, name, sizeof(prop->data.name));
- prop->value = value;
- BLI_addtail(&ces->properties, prop);
+ switch (mode_type) {
+ case COLLECTION_MODE_OBJECT:
+ idgroup_type = IDP_GROUP_SUB_MODE_OBJECT;
+ break;
+ case COLLECTION_MODE_EDIT:
+ idgroup_type = IDP_GROUP_SUB_MODE_EDIT;
+ break;
+ default:
+ case COLLECTION_MODE_NONE:
+ return IDP_GROUP_SUB_ENGINE_RENDER;
+ break;
+ }
+
+ return idgroup_type;
}
-CollectionEngineProperty *BKE_collection_engine_property_get(CollectionEngineSettings *ces, const char *name)
+/**
+ * Return collection enginne settings for either Object s of LayerCollection s
+ */
+static IDProperty *collection_engine_get(
+ IDProperty *root, const int type, const char *engine_name)
{
- return BLI_findstring(&ces->properties, name, offsetof(CollectionEngineProperty, name));
+ const int subtype = idproperty_group_subtype(type);
+
+ if (subtype == IDP_GROUP_SUB_ENGINE_RENDER) {
+ return IDP_GetPropertyFromGroup(root, engine_name);
+ }
+ else {
+ IDProperty *prop;
+ for (prop = root->data.group.first; prop; prop = prop->next) {
+ if (prop->subtype == subtype) {
+ return prop;
+ }
+ }
+ }
+
+ BLI_assert(false);
+ return NULL;
}
-int BKE_collection_engine_property_value_get_int(CollectionEngineSettings *ces, const char *name)
+/**
+ * Return collection engine settings from Object for specified engine of mode
+ */
+IDProperty *BKE_object_collection_engine_get(Object *ob, const int type, const char *engine_name)
{
- CollectionEnginePropertyInt *prop;
- prop = (CollectionEnginePropertyInt *)BLI_findstring(&ces->properties, name, offsetof(CollectionEngineProperty, name));
- return prop->value;
+ return collection_engine_get(ob->base_collection_properties, type, engine_name);
}
-
-float BKE_collection_engine_property_value_get_float(CollectionEngineSettings *ces, const char *name)
+/**
+ * Return layer collection engine settings for specified engine
+ */
+IDProperty *BKE_layer_collection_engine_get(LayerCollection *lc, const int type, const char *engine_name)
{
- CollectionEnginePropertyFloat *prop;
- prop = (CollectionEnginePropertyFloat *)BLI_findstring(&ces->properties, name, offsetof(CollectionEngineProperty, name));
- return prop->value;
+ return collection_engine_get(lc->properties, type, engine_name);
}
-void BKE_collection_engine_property_value_set_int(CollectionEngineSettings *ces, const char *name, int value)
+/* ---------------------------------------------------------------------- */
+/* Engine Settings Properties */
+
+void BKE_collection_engine_property_add_float(IDProperty *props, const char *name, float value)
{
- CollectionEnginePropertyInt *prop;
- prop = (CollectionEnginePropertyInt *)BLI_findstring(&ces->properties, name, offsetof(CollectionEngineProperty, name));
- prop->value = value;
- prop->data.flag |= COLLECTION_PROP_USE;
+ IDPropertyTemplate val = {0};
+ val.f = value;
+ IDP_AddToGroup(props, IDP_New(IDP_FLOAT, &val, name));
}
-void BKE_collection_engine_property_value_set_float(CollectionEngineSettings *ces, const char *name, float value)
+void BKE_collection_engine_property_add_int(IDProperty *props, const char *name, int value)
{
- CollectionEnginePropertyFloat *prop;
- prop = (CollectionEnginePropertyFloat *)BLI_findstring(&ces->properties, name, offsetof(CollectionEngineProperty, name));
- prop->value = value;
- prop->data.flag |= COLLECTION_PROP_USE;
+ IDPropertyTemplate val = {0};
+ val.i = value;
+ IDP_AddToGroup(props, IDP_New(IDP_INT, &val, name));
}
-bool BKE_collection_engine_property_use_get(CollectionEngineSettings *ces, const char *name)
+void BKE_collection_engine_property_add_bool(IDProperty *props, const char *name, bool value)
{
- CollectionEngineProperty *prop;
- prop = (CollectionEngineProperty *)BLI_findstring(&ces->properties, name, offsetof(CollectionEngineProperty, name));
- return ((prop->flag & COLLECTION_PROP_USE) != 0);
+ IDPropertyTemplate val = {0};
+ val.i = value;
+ IDP_AddToGroup(props, IDP_New(IDP_INT, &val, name));
}
-void BKE_collection_engine_property_use_set(CollectionEngineSettings *ces, const char *name, bool value)
+int BKE_collection_engine_property_value_get_int(IDProperty *props, const char *name)
{
- CollectionEngineProperty *prop;
- prop = (CollectionEngineProperty *)BLI_findstring(&ces->properties, name, offsetof(CollectionEngineProperty, name));
-
- if (value) {
- prop->flag |= COLLECTION_PROP_USE;
- }
- else {
- prop->flag &= ~COLLECTION_PROP_USE;
- }
+ IDProperty *idprop = IDP_GetPropertyFromGroup(props, name);
+ return idprop ? idprop->data.val : 0;
}
-/* Engine Settings recalculate */
-
-static void collection_engine_settings_init(CollectionEngineSettings *ces, const char *engine_name)
+float BKE_collection_engine_property_value_get_float(IDProperty *props, const char *name)
{
- CollectionEngineSettingsCB_Type *ces_type;
- ces_type = BLI_findstring(&R_engines_settings_callbacks, engine_name, offsetof(CollectionEngineSettingsCB_Type, name));
-
- BLI_listbase_clear(&ces->properties);
- BLI_strncpy_utf8(ces->name, ces_type->name, sizeof(ces->name));
-
- /* call callback */
- ces_type->callback(NULL, ces);
+ IDProperty *idprop = IDP_GetPropertyFromGroup(props, name);
+ return idprop ? *((float *)&idprop->data.val) : 0.0f;
}
-static void collection_engine_settings_copy(CollectionEngineSettings *ces_dst, CollectionEngineSettings *ces_src)
+bool BKE_collection_engine_property_value_get_bool(IDProperty *props, const char *name)
{
- BLI_strncpy_utf8(ces_dst->name, ces_src->name, sizeof(ces_dst->name));
- BLI_freelistN(&ces_dst->properties);
-
- for (CollectionEngineProperty *prop = ces_src->properties.first; prop; prop = prop->next) {
- CollectionEngineProperty *prop_new = MEM_dupallocN(prop);
- BLI_addtail(&ces_dst->properties, prop_new);
- }
+ IDProperty *idprop = IDP_GetPropertyFromGroup(props, name);
+ return idprop ? idprop->data.val : 0;
}
-/**
- * Set a value from a CollectionProperty to another
- */
-static void collection_engine_property_set (CollectionEngineProperty *prop_dst, CollectionEngineProperty *prop_src){
- if ((prop_src->flag & COLLECTION_PROP_USE) != 0) {
- /* mark the property as used, so the engine knows if the value was ever set*/
- prop_dst->flag |= COLLECTION_PROP_USE;
- switch (prop_src->type) {
- case COLLECTION_PROP_TYPE_FLOAT:
- ((CollectionEnginePropertyFloat *)prop_dst)->value = ((CollectionEnginePropertyFloat *)prop_src)->value;
- break;
- case COLLECTION_PROP_TYPE_INT:
- ((CollectionEnginePropertyInt *)prop_dst)->value = ((CollectionEnginePropertyInt *)prop_src)->value;
- break;
- default:
- BLI_assert(false);
- break;
- }
- }
+void BKE_collection_engine_property_value_set_int(IDProperty *props, const char *name, int value)
+{
+ IDProperty *idprop = IDP_GetPropertyFromGroup(props, name);
+ idprop->data.val = value;
}
-static void collection_engine_settings_merge(CollectionEngineSettings *ces_dst, CollectionEngineSettings *ces_src)
+void BKE_collection_engine_property_value_set_float(IDProperty *props, const char *name, float value)
{
- CollectionEngineProperty *prop_src, *prop_dst;
-
- prop_dst = ces_dst->properties.first;
- for (prop_src = ces_src->properties.first; prop_src; prop_src = prop_src->next, prop_dst = prop_dst->next) {
- collection_engine_property_set(prop_dst, prop_src);
- }
+ IDProperty *idprop = IDP_GetPropertyFromGroup(props, name);
+ *(float *)&idprop->data.val = value;
}
-static void layer_collection_engine_settings_update(
- LayerCollection *lc, CollectionEngineSettings *ces_parent,
- Base *base, CollectionEngineSettings *ces_ob)
+void BKE_collection_engine_property_value_set_bool(IDProperty *props, const char *name, bool value)
{
- if ((lc->flag & COLLECTION_VISIBLE) == 0) {
- return;
- }
-
- CollectionEngineSettings ces = {NULL};
- collection_engine_settings_copy(&ces, ces_parent);
-
- CollectionEngineSettings *ces_lc = BKE_layer_collection_engine_get(lc, ces.name);
- collection_engine_settings_merge(&ces, ces_lc);
+ IDProperty *idprop = IDP_GetPropertyFromGroup(props, name);
+ idprop->data.val = value;
+}
- if (BLI_findptr(&lc->object_bases, base, offsetof(LinkData, data)) != NULL) {
- collection_engine_settings_merge(ces_ob, &ces);
- }
+/* Engine Settings recalculate */
- /* do it recursively */
- for (LayerCollection *lcn = lc->layer_collections.first; lcn; lcn = lcn->next) {
- layer_collection_engine_settings_update(lcn, &ces, base, ces_ob);
- }
+/* get all the default settings defined in scene and merge them here */
+static void collection_engine_settings_init(IDProperty *root, const bool populate)
+{
+ /* render engines */
+ collection_create_render_settings(root, populate);
- BKE_layer_collection_engine_settings_free(&ces);
+ /* mode engines */
+ collection_create_mode_settings(root, populate);
}
/**
- * Update the collection settings pointer allocated in the object
- * This is to be flushed from the Depsgraph
+ * Initialize the render setings
+ * It's used mainly for scenes
*/
-static void scene_layer_engine_settings_update(SceneLayer *sl, Object *ob, const char *engine_name)
+void BKE_layer_collection_engine_settings_create(IDProperty *root)
{
- Base *base = BKE_scene_layer_base_find(sl, ob);
- CollectionEngineSettings ces_layer = {NULL}, *ces_ob;
-
- collection_engine_settings_init(&ces_layer, engine_name);
-
- if (ob->collection_settings) {
- BKE_layer_collection_engine_settings_free(ob->collection_settings);
- MEM_freeN(ob->collection_settings);
- }
-
- CollectionEngineSettingsCB_Type *ces_type;
- ces_type = BLI_findstring(&R_engines_settings_callbacks, engine_name, offsetof(CollectionEngineSettingsCB_Type, name));
- ces_ob = collection_engine_settings_create(ces_type);
-
- for (LayerCollection *lc = sl->layer_collections.first; lc; lc = lc->next) {
- layer_collection_engine_settings_update(lc, &ces_layer, base, ces_ob);
- }
-
- BKE_layer_collection_engine_settings_free(&ces_layer);
- ob->collection_settings = ces_ob;
+ collection_engine_settings_init(root, true);
}
/* ---------------------------------------------------------------------- */
@@ -1094,3 +1339,100 @@ void BKE_visible_bases_Iterator_end(Iterator *UNUSED(iter))
{
/* do nothing */
}
+
+/* Evaluation */
+
+/**
+ * Reset props
+ *
+ * If props_ref is pasted, copy props from it
+ */
+static void idproperty_reset(IDProperty **props, IDProperty *props_ref)
+{
+ IDPropertyTemplate val = {0};
+
+ if (*props) {
+ IDP_FreeProperty(*props);
+ MEM_freeN(*props);
+ }
+ *props = IDP_New(IDP_GROUP, &val, ROOT_PROP);
+
+ if (props_ref) {
+ IDP_MergeGroup(*props, props_ref, true);
+ }
+}
+
+void BKE_layer_eval_layer_collection_pre(EvaluationContext *UNUSED(eval_ctx),
+ Scene *scene, SceneLayer *scene_layer)
+{
+ DEBUG_PRINT("%s on %s\n", __func__, scene_layer->name);
+ for (Base *base = scene_layer->object_bases.first; base != NULL; base = base->next) {
+ base->flag &= ~(BASE_VISIBLED | BASE_SELECTABLED);
+ idproperty_reset(&base->collection_properties, scene->collection_properties);
+ }
+
+ /* TODO(sergey): Is it always required? */
+ scene_layer->flag |= SCENE_LAYER_ENGINE_DIRTY;
+}
+
+void BKE_layer_eval_layer_collection(EvaluationContext *UNUSED(eval_ctx),
+ Scene *scene,
+ LayerCollection *layer_collection,
+ LayerCollection *parent_layer_collection)
+{
+ DEBUG_PRINT("%s on %s, parent %s\n",
+ __func__,
+ layer_collection->scene_collection->name,
+ (parent_layer_collection != NULL) ? parent_layer_collection->scene_collection->name : "NONE");
+
+ /* visibility */
+ layer_collection->flag_evaluated = layer_collection->flag;
+ bool is_visible = (layer_collection->flag & COLLECTION_VISIBLE) != 0;
+ bool is_selectable = is_visible && ((layer_collection->flag & COLLECTION_SELECTABLE) != 0);
+
+ if (parent_layer_collection != NULL) {
+ is_visible &= (parent_layer_collection->flag_evaluated & COLLECTION_VISIBLE) != 0;
+ is_selectable &= (parent_layer_collection->flag_evaluated & COLLECTION_SELECTABLE) != 0;
+ layer_collection->flag_evaluated &= parent_layer_collection->flag_evaluated;
+ }
+
+ /* overrides */
+ if (parent_layer_collection != NULL) {
+ idproperty_reset(&layer_collection->properties_evaluated, parent_layer_collection->properties_evaluated);
+ }
+ else if (layer_collection->prev != NULL) {
+ idproperty_reset(&layer_collection->properties_evaluated, NULL);
+ }
+ else {
+ idproperty_reset(&layer_collection->properties_evaluated, scene->collection_properties);
+ }
+
+ if (is_visible) {
+ IDP_MergeGroup(layer_collection->properties_evaluated, layer_collection->properties, true);
+ }
+
+ for (LinkData *link = layer_collection->object_bases.first; link != NULL; link = link->next) {
+ Base *base = link->data;
+
+ if (is_visible) {
+ IDP_SyncGroupValues(base->collection_properties, layer_collection->properties_evaluated);
+ base->flag |= BASE_VISIBLED;
+ }
+
+ if (is_selectable) {
+ base->flag |= BASE_SELECTABLED;
+ }
+ }
+}
+
+void BKE_layer_eval_layer_collection_post(EvaluationContext *UNUSED(eval_ctx),
+ SceneLayer *scene_layer)
+{
+ DEBUG_PRINT("%s on %s\n", __func__, scene_layer->name);
+ /* if base is not selectabled, clear select */
+ for (Base *base = scene_layer->object_bases.first; base; base = base->next) {
+ if ((base->flag & BASE_SELECTABLED) == 0) {
+ base->flag &= ~BASE_SELECTED;
+ }
+ }
+}
diff --git a/source/blender/blenkernel/intern/library.c b/source/blender/blenkernel/intern/library.c
index 2398c6724ed..c95d13b7668 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_query.c b/source/blender/blenkernel/intern/library_query.c
index a071b3202be..c9853f791ce 100644
--- a/source/blender/blenkernel/intern/library_query.c
+++ b/source/blender/blenkernel/intern/library_query.c
@@ -416,7 +416,6 @@ void BKE_library_foreach_ID_link(Main *bmain, ID *id, LibraryIDLinkCallback call
CALLBACK_INVOKE(legacy_base->object, IDWALK_CB_USER);
}
- SceneCollection *sc;
FOREACH_SCENE_COLLECTION(scene, sc)
{
for (LinkData *link = sc->objects.first; link; link = link->next) {
diff --git a/source/blender/blenkernel/intern/library_remap.c b/source/blender/blenkernel/intern/library_remap.c
index 9946d1cc81f..7f290590942 100644
--- a/source/blender/blenkernel/intern/library_remap.c
+++ b/source/blender/blenkernel/intern/library_remap.c
@@ -180,6 +180,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);
@@ -232,7 +233,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;
}
}
@@ -289,7 +290,6 @@ static void libblock_remap_data_preprocess(IDRemap *r_id_remap_data)
/* In case we are unlinking... */
if (!r_id_remap_data->old_id) {
/* ... everything from scene. */
- Object *ob_iter;
FOREACH_SCENE_OBJECT(sce, ob_iter)
{
libblock_remap_data_preprocess_scene_object_unlink(
diff --git a/source/blender/blenkernel/intern/material.c b/source/blender/blenkernel/intern/material.c
index 435504859a4..6cab8945779 100644
--- a/source/blender/blenkernel/intern/material.c
+++ b/source/blender/blenkernel/intern/material.c
@@ -111,12 +111,6 @@ void BKE_material_free(Material *ma)
BKE_icon_id_delete((ID *)ma);
BKE_previewimg_free(&ma->preview);
-
- for (MaterialEngineSettings *mes = ma->engines_settings.first; mes; mes = mes->next) {
- if (mes->data)
- MEM_SAFE_FREE(mes->data);
- }
- BLI_freelistN(&ma->engines_settings);
}
void BKE_material_init(Material *ma)
diff --git a/source/blender/blenkernel/intern/mesh.c b/source/blender/blenkernel/intern/mesh.c
index 134173580ae..0f0d84cc87d 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"
@@ -67,6 +69,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,
@@ -2052,7 +2059,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];
@@ -2087,113 +2094,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/mesh_render.c b/source/blender/blenkernel/intern/mesh_render.c
index fd0f49810fb..dbe99acc10b 100644
--- a/source/blender/blenkernel/intern/mesh_render.c
+++ b/source/blender/blenkernel/intern/mesh_render.c
@@ -31,6 +31,10 @@
#include "MEM_guardedalloc.h"
+#include "BLI_utildefines.h"
+#include "BLI_edgehash.h"
+#include "BLI_math_vector.h"
+
#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
@@ -41,182 +45,680 @@
#include "BKE_mesh.h"
#include "BKE_mesh_render.h"
+#include "bmesh.h"
+
#include "GPU_batch.h"
/* ---------------------------------------------------------------------- */
-/* Mesh Interface */
-
-#define MESH_RENDER_FUNCTION(func_name) \
- if (me->edit_btmesh && me->edit_btmesh->derivedFinal) { \
- return mesh_bmesh_##func_name(me); \
- } \
- else { \
- return mesh_struct_##func_name(me); \
- }
-
-
-/* Mesh Implementation */
+/* Mesh/BMesh Interface, direct access to basic data. */
-static int mesh_struct_get_num_edges(Mesh *me)
+static int mesh_render_verts_num_get(Mesh *me)
{
- return me->totedge;
+ return me->edit_btmesh ? me->edit_btmesh->bm->totvert : me->totvert;
}
-static int mesh_struct_get_num_verts(Mesh *me)
+static int mesh_render_edges_num_get(Mesh *me)
{
- return me->totvert;
+ return me->edit_btmesh ? me->edit_btmesh->bm->totedge : me->totedge;
}
-static int mesh_struct_get_num_faces(Mesh *me)
+static int mesh_render_looptri_num_get(Mesh *me)
{
- BKE_mesh_tessface_ensure(me);
- return me->totface;
+ return me->edit_btmesh ? me->edit_btmesh->tottri : poly_to_tri_count(me->totpoly, me->totloop);
}
-static int mesh_struct_get_num_polys(Mesh *me)
+static int mesh_render_polys_num_get(Mesh *me)
{
- return me->totpoly;
+ return me->edit_btmesh ? me->edit_btmesh->bm->totface : me->totpoly;
}
-static MEdge *mesh_struct_get_array_edge(Mesh *me)
+static int UNUSED_FUNCTION(mesh_render_loops_num_get)(Mesh *me)
{
- return CustomData_get_layer(&me->edata, CD_MEDGE);
+ return me->edit_btmesh ? me->edit_btmesh->bm->totloop : me->totloop;
}
-static MFace *mesh_struct_get_array_face(Mesh *me)
+/* ---------------------------------------------------------------------- */
+/* Mesh/BMesh Interface, indirect, partially cached access to complex data. */
+
+typedef struct EdgeAdjacentPolys {
+ int count;
+ int face_index[2];
+} EdgeAdjacentPolys;
+
+typedef struct MeshRenderData {
+ int types;
+
+ int totvert;
+ int totedge;
+ int tottri;
+ int totloop;
+ int totpoly;
+ int totlvert;
+ int totledge;
+
+ BMEditMesh *edit_bmesh;
+ MVert *mvert;
+ MEdge *medge;
+ MLoop *mloop;
+ MPoly *mpoly;
+
+ BMVert *eve_act;
+ BMEdge *eed_act;
+ BMFace *efa_act;
+
+ int crease_ofs;
+ int bweight_ofs;
+
+ /* Data created on-demand (usually not for bmesh-based data). */
+ EdgeHash *ehash;
+ EdgeAdjacentPolys *edges_adjacent_polys;
+ MLoopTri *mlooptri;
+ int *loose_edges;
+ int *loose_verts;
+
+ float (*poly_normals)[3];
+ short (*poly_normals_short)[3];
+ short (*vert_normals_short)[3];
+} MeshRenderData;
+
+enum {
+ MR_DATATYPE_VERT = 1 << 0,
+ MR_DATATYPE_EDGE = 1 << 1,
+ MR_DATATYPE_LOOPTRI = 1 << 2,
+ MR_DATATYPE_LOOP = 1 << 3,
+ MR_DATATYPE_POLY = 1 << 4,
+ MR_DATATYPE_OVERLAY = 1 << 5,
+};
+
+static MeshRenderData *mesh_render_data_create(Mesh *me, const int types)
{
- BKE_mesh_tessface_ensure(me);
- return CustomData_get_layer(&me->fdata, CD_MFACE);
+ MeshRenderData *mrdata = MEM_callocN(sizeof(*mrdata), __func__);
+ mrdata->types = types;
+
+ if (me->edit_btmesh) {
+ BMEditMesh *embm = me->edit_btmesh;
+ BMesh *bm = embm->bm;
+
+ mrdata->edit_bmesh = embm;
+
+ int bm_ensure_types = 0;
+ if (types & (MR_DATATYPE_VERT)) {
+ mrdata->totvert = bm->totvert;
+ bm_ensure_types |= BM_VERT;
+ }
+ if (types & (MR_DATATYPE_EDGE)) {
+ mrdata->totedge = bm->totedge;
+ bm_ensure_types |= BM_EDGE;
+ }
+ if (types & MR_DATATYPE_LOOPTRI) {
+ BKE_editmesh_tessface_calc(embm);
+ mrdata->tottri = embm->tottri;
+ }
+ if (types & MR_DATATYPE_LOOP) {
+ mrdata->totloop = bm->totloop;
+ bm_ensure_types |= BM_LOOP;
+ }
+ if (types & MR_DATATYPE_POLY) {
+ mrdata->totpoly = bm->totface;
+ bm_ensure_types |= BM_FACE;
+ }
+ if (types & MR_DATATYPE_OVERLAY) {
+ mrdata->efa_act = BM_mesh_active_face_get(bm, false, true);
+ mrdata->eed_act = BM_mesh_active_edge_get(bm);
+ mrdata->eve_act = BM_mesh_active_vert_get(bm);
+ mrdata->crease_ofs = CustomData_get_offset(&bm->edata, CD_CREASE);
+ mrdata->bweight_ofs = CustomData_get_offset(&bm->edata, CD_BWEIGHT);
+ }
+ BM_mesh_elem_index_ensure(bm, bm_ensure_types);
+ BM_mesh_elem_table_ensure(bm, bm_ensure_types & ~BM_LOOP);
+ if (types & MR_DATATYPE_OVERLAY) {
+ mrdata->totlvert = mrdata->totledge = 0;
+
+ int *lverts = mrdata->loose_verts = MEM_mallocN(mrdata->totvert * sizeof(int), "Loose Vert");
+ int *ledges = mrdata->loose_edges = MEM_mallocN(mrdata->totedge * sizeof(int), "Loose Edges");
+
+ for (int i = 0; i < mrdata->totvert; ++i) {
+ BMVert *bv = BM_vert_at_index(bm, i);
+
+ /* Loose vert */
+ if (bv->e == NULL) {
+ lverts[mrdata->totlvert] = BM_elem_index_get(bv);
+ mrdata->totlvert++;
+ continue;
+ }
+
+ /* Find Loose Edges */
+ BMEdge *e_iter, *e_first;
+ e_first = e_iter = bv->e;
+ do {
+ if (e_iter->l == NULL) {
+ BMVert *other_vert = BM_edge_other_vert(e_iter, bv);
+
+ /* Verify we do not add the same edge twice */
+ if (BM_elem_index_get(other_vert) > i) {
+ ledges[mrdata->totledge] = BM_elem_index_get(e_iter);
+ mrdata->totledge++;
+ }
+ }
+ } while ((e_iter = BM_DISK_EDGE_NEXT(e_iter, bv)) != e_first);
+ }
+ mrdata->loose_verts = MEM_reallocN(mrdata->loose_verts, mrdata->totlvert * sizeof(int));
+ mrdata->loose_edges = MEM_reallocN(mrdata->loose_edges, mrdata->totledge * sizeof(int));
+ }
+ }
+ else {
+ if (types & (MR_DATATYPE_VERT)) {
+ mrdata->totvert = me->totvert;
+ mrdata->mvert = CustomData_get_layer(&me->vdata, CD_MVERT);
+ }
+ if (types & (MR_DATATYPE_EDGE)) {
+ mrdata->totedge = me->totedge;
+ mrdata->medge = CustomData_get_layer(&me->edata, CD_MEDGE);
+ }
+ if (types & MR_DATATYPE_LOOPTRI) {
+ const int tottri = mrdata->tottri = poly_to_tri_count(me->totpoly, me->totloop);
+ mrdata->mlooptri = MEM_mallocN(sizeof(*mrdata->mlooptri) * tottri, __func__);
+ BKE_mesh_recalc_looptri(me->mloop, me->mpoly, me->mvert, me->totloop, me->totpoly, mrdata->mlooptri);
+ }
+ if (types & MR_DATATYPE_LOOP) {
+ mrdata->totloop = me->totloop;
+ mrdata->mloop = CustomData_get_layer(&me->ldata, CD_MLOOP);
+ }
+ if (types & MR_DATATYPE_POLY) {
+ mrdata->totpoly = me->totpoly;
+ mrdata->mpoly = CustomData_get_layer(&me->pdata, CD_MPOLY);
+ }
+ }
+
+ return mrdata;
}
-static MLoop *mesh_struct_get_array_loop(Mesh *me)
+static void mesh_render_data_free(MeshRenderData *mrdata)
{
- return me->mloop;
+ if (mrdata->ehash) {
+ BLI_edgehash_free(mrdata->ehash, NULL);
+ }
+ if (mrdata->loose_verts) {
+ MEM_freeN(mrdata->loose_verts);
+ }
+ if (mrdata->loose_edges) {
+ MEM_freeN(mrdata->loose_edges);
+ }
+ if (mrdata->edges_adjacent_polys) {
+ MEM_freeN(mrdata->edges_adjacent_polys);
+ }
+ if (mrdata->mlooptri) {
+ MEM_freeN(mrdata->mlooptri);
+ }
+ if (mrdata->poly_normals) {
+ MEM_freeN(mrdata->poly_normals);
+ }
+ if (mrdata->poly_normals_short) {
+ MEM_freeN(mrdata->poly_normals_short);
+ }
+ if (mrdata->vert_normals_short) {
+ MEM_freeN(mrdata->vert_normals_short);
+ }
+ MEM_freeN(mrdata);
}
-static MPoly *mesh_struct_get_array_poly(Mesh *me)
+static int mesh_render_data_verts_num_get(const MeshRenderData *mrdata)
{
- return me->mpoly;
+ BLI_assert(mrdata->types & MR_DATATYPE_VERT);
+ return mrdata->totvert;
}
-static MVert *mesh_struct_get_array_vert(Mesh *me)
+static int mesh_render_data_loose_verts_num_get(const MeshRenderData *mrdata)
{
- return CustomData_get_layer(&me->vdata, CD_MVERT);
+ BLI_assert(mrdata->types & MR_DATATYPE_OVERLAY);
+ return mrdata->totlvert;
}
-/* BMesh Implementation */
-
-/* NOTE: we may want to get rid of Derived Mesh and
- * access BMesh directly */
-
-static int mesh_bmesh_get_num_verts(Mesh *me)
+static int mesh_render_data_edges_num_get(const MeshRenderData *mrdata)
{
- BMEditMesh *bm = me->edit_btmesh;
- DerivedMesh *dm = bm->derivedFinal;
- return dm->getNumVerts(dm);
+ BLI_assert(mrdata->types & MR_DATATYPE_EDGE);
+ return mrdata->totedge;
}
-static int mesh_bmesh_get_num_edges(Mesh *me)
+static int mesh_render_data_loose_edges_num_get(const MeshRenderData *mrdata)
{
- BMEditMesh *bm = me->edit_btmesh;
- DerivedMesh *dm = bm->derivedFinal;
- return dm->getNumEdges(dm);
+ BLI_assert(mrdata->types & MR_DATATYPE_OVERLAY);
+ return mrdata->totledge;
}
-static int mesh_bmesh_get_num_faces(Mesh *me)
+static int mesh_render_data_looptri_num_get(const MeshRenderData *mrdata)
{
- BMEditMesh *bm = me->edit_btmesh;
- DerivedMesh *dm = bm->derivedFinal;
- return dm->getNumTessFaces(dm);
+ BLI_assert(mrdata->types & MR_DATATYPE_LOOPTRI);
+ return mrdata->tottri;
}
-static int mesh_bmesh_get_num_polys(Mesh *me)
+static int UNUSED_FUNCTION(mesh_render_data_loops_num_get)(const MeshRenderData *mrdata)
{
- BMEditMesh *bm = me->edit_btmesh;
- DerivedMesh *dm = bm->derivedFinal;
- return dm->getNumPolys(dm);
+ BLI_assert(mrdata->types & MR_DATATYPE_LOOP);
+ return mrdata->totloop;
}
-static MEdge *mesh_bmesh_get_array_edge(Mesh *me)
+static int mesh_render_data_polys_num_get(const MeshRenderData *mrdata)
{
- BMEditMesh *bm = me->edit_btmesh;
- DerivedMesh *dm = bm->derivedFinal;
- return dm->getEdgeArray(dm);
+ BLI_assert(mrdata->types & MR_DATATYPE_POLY);
+ return mrdata->totpoly;
}
-static MFace *mesh_bmesh_get_array_face(Mesh *me)
+static float *mesh_render_data_vert_co(const MeshRenderData *mrdata, const int vert_idx)
{
- BMEditMesh *bm = me->edit_btmesh;
- DerivedMesh *dm = bm->derivedFinal;
- return dm->getTessFaceArray(dm);
+ BLI_assert(mrdata->types & MR_DATATYPE_VERT);
+
+ if (mrdata->edit_bmesh) {
+ BMesh *bm = mrdata->edit_bmesh->bm;
+ BMVert *bv = BM_vert_at_index(bm, vert_idx);
+ return bv->co;
+ }
+ else {
+ return mrdata->mvert[vert_idx].co;
+ }
}
-static MLoop *mesh_bmesh_get_array_loop(Mesh *me)
+static short *mesh_render_data_vert_nor(const MeshRenderData *mrdata, const int vert_idx)
{
- BMEditMesh *bm = me->edit_btmesh;
- DerivedMesh *dm = bm->derivedFinal;
- return dm->getLoopArray(dm);
+ BLI_assert(mrdata->types & MR_DATATYPE_VERT);
+
+ if (mrdata->edit_bmesh) {
+ static short fno[3];
+ BMesh *bm = mrdata->edit_bmesh->bm;
+ BMVert *bv = BM_vert_at_index(bm, vert_idx);
+ normal_float_to_short_v3(fno, bv->no);
+ return fno;
+ }
+ else {
+ return mrdata->mvert[vert_idx].no;
+ }
}
-static MPoly *mesh_bmesh_get_array_poly(Mesh *me)
+static void mesh_render_data_edge_verts_indices_get(const MeshRenderData *mrdata, const int edge_idx, int r_vert_idx[2])
{
- BMEditMesh *bm = me->edit_btmesh;
- DerivedMesh *dm = bm->derivedFinal;
- return dm->getPolyArray(dm);
+ BLI_assert(mrdata->types & MR_DATATYPE_EDGE);
+
+ if (mrdata->edit_bmesh) {
+ const BMEdge *bm_edge = BM_edge_at_index(mrdata->edit_bmesh->bm, edge_idx);
+ r_vert_idx[0] = BM_elem_index_get(bm_edge->v1);
+ r_vert_idx[1] = BM_elem_index_get(bm_edge->v2);
+ }
+ else {
+ const MEdge *me = &mrdata->medge[edge_idx];
+ r_vert_idx[0] = me->v1;
+ r_vert_idx[1] = me->v2;
+ }
}
-static MVert *mesh_bmesh_get_array_vert(Mesh *me)
+static void mesh_render_data_pnors_pcenter_select_get(MeshRenderData *mrdata, const int poly, float pnors[3], float center[3], bool *selected)
{
- BMEditMesh *bm = me->edit_btmesh;
- DerivedMesh *dm = bm->derivedFinal;
- return dm->getVertArray(dm);
+ BLI_assert(mrdata->types & (MR_DATATYPE_VERT | MR_DATATYPE_LOOP | MR_DATATYPE_POLY));
+
+ if (mrdata->edit_bmesh) {
+ const BMFace *bf = BM_face_at_index(mrdata->edit_bmesh->bm, poly);
+ BM_face_calc_center_mean(bf, center);
+ BM_face_calc_normal(bf, pnors);
+ *selected = (BM_elem_flag_test(bf, BM_ELEM_SELECT) != 0) ? true : false;
+ }
+ else {
+ MVert *mvert = mrdata->mvert;
+ const MPoly *mpoly = mrdata->mpoly + poly;
+ const MLoop *mloop = mrdata->mloop + mpoly->loopstart;
+
+ BKE_mesh_calc_poly_center(mpoly, mloop, mvert, center);
+ BKE_mesh_calc_poly_normal(mpoly, mloop, mvert, pnors);
+
+ *selected = false; /* No selection if not in edit mode */
+ }
}
-/* Mesh API */
+static bool mesh_render_data_edge_exists(MeshRenderData *mrdata, const int v1, const int v2)
+{
+ BLI_assert(mrdata->types & MR_DATATYPE_EDGE);
+
+ if (mrdata->edit_bmesh) {
+ BMesh *bm = mrdata->edit_bmesh->bm;
+ BMVert *bv1 = BM_vert_at_index(bm, v1);
+ BMVert *bv2 = BM_vert_at_index(bm, v2);
+ return BM_edge_exists(bv1, bv2) != NULL;
+ }
+ else {
+ EdgeHash *ehash = mrdata->ehash;
+
+ if (!ehash) {
+ /* Create edge hash on demand. */
+ ehash = mrdata->ehash = BLI_edgehash_new(__func__);
-static int mesh_render_get_num_edges(Mesh *me)
+ MEdge *medge = mrdata->medge;
+ for (int i = 0; i < mrdata->totedge; i++, medge++) {
+ BLI_edgehash_insert(ehash, medge->v1, medge->v2, medge);
+ }
+ }
+
+ return BLI_edgehash_lookup(ehash, v1, v2) != NULL;
+ }
+}
+
+static bool mesh_render_data_edge_vcos_manifold_pnors(
+ MeshRenderData *mrdata, const int edge_index,
+ float **r_vco1, float **r_vco2, float **r_pnor1, float **r_pnor2)
{
- MESH_RENDER_FUNCTION(get_num_edges);
+ BLI_assert(mrdata->types & (MR_DATATYPE_VERT | MR_DATATYPE_EDGE | MR_DATATYPE_LOOP | MR_DATATYPE_POLY));
+
+ if (mrdata->edit_bmesh) {
+ BMesh *bm = mrdata->edit_bmesh->bm;
+ BMEdge *bm_edge = BM_edge_at_index(bm, edge_index);
+ *r_vco1 = bm_edge->v1->co;
+ *r_vco2 = bm_edge->v2->co;
+ if (BM_edge_is_manifold(bm_edge)) {
+ *r_pnor1 = bm_edge->l->f->no;
+ *r_pnor2 = bm_edge->l->radial_next->f->no;
+ return true;
+ }
+ }
+ else {
+ MVert *mvert = mrdata->mvert;
+ MEdge *medge = mrdata->medge;
+ EdgeAdjacentPolys *eap = mrdata->edges_adjacent_polys;
+ float (*pnors)[3] = mrdata->poly_normals;
+
+ if (!eap) {
+ const MLoop *mloop = mrdata->mloop;
+ const MPoly *mpoly = mrdata->mpoly;
+ const int poly_ct = mrdata->totpoly;
+ const bool do_pnors = (pnors == NULL);
+
+ eap = mrdata->edges_adjacent_polys = MEM_callocN(sizeof(*eap) * mrdata->totedge, __func__);
+ if (do_pnors) {
+ pnors = mrdata->poly_normals = MEM_mallocN(sizeof(*pnors) * poly_ct, __func__);
+ }
+
+ for (int i = 0; i < poly_ct; i++, mpoly++) {
+ if (do_pnors) {
+ BKE_mesh_calc_poly_normal(mpoly, mloop + mpoly->loopstart, mvert, pnors[i]);
+ }
+
+ const int loopend = mpoly->loopstart + mpoly->totloop;
+ for (int j = mpoly->loopstart; j < loopend; j++) {
+ const int edge_idx = mloop[j].e;
+ if (eap[edge_idx].count < 2) {
+ eap[edge_idx].face_index[eap[edge_idx].count] = i;
+ }
+ eap[edge_idx].count++;
+ }
+ }
+ }
+ BLI_assert(eap && pnors);
+
+ *r_vco1 = mvert[medge[edge_index].v1].co;
+ *r_vco2 = mvert[medge[edge_index].v2].co;
+ if (eap[edge_index].count == 2) {
+ *r_pnor1 = pnors[eap[edge_index].face_index[0]];
+ *r_pnor2 = pnors[eap[edge_index].face_index[1]];
+ return true;
+ }
+ }
+
+ return false;
}
-static int mesh_render_get_num_faces(Mesh *me)
+static void mesh_render_data_looptri_verts_indices_get(const MeshRenderData *mrdata, const int tri_idx, int r_vert_idx[3])
{
- MESH_RENDER_FUNCTION(get_num_faces);
+ BLI_assert(mrdata->types & (MR_DATATYPE_LOOPTRI | MR_DATATYPE_LOOP));
+
+ if (mrdata->edit_bmesh) {
+ const BMLoop **bm_looptri = (const BMLoop **)mrdata->edit_bmesh->looptris[tri_idx];
+ r_vert_idx[0] = BM_elem_index_get(bm_looptri[0]->v);
+ r_vert_idx[1] = BM_elem_index_get(bm_looptri[1]->v);
+ r_vert_idx[2] = BM_elem_index_get(bm_looptri[2]->v);
+ }
+ else {
+ const MLoopTri *mlt = &mrdata->mlooptri[tri_idx];
+ r_vert_idx[0] = mrdata->mloop[mlt->tri[0]].v;
+ r_vert_idx[1] = mrdata->mloop[mlt->tri[1]].v;
+ r_vert_idx[2] = mrdata->mloop[mlt->tri[2]].v;
+ }
}
-static int mesh_render_get_num_polys(Mesh *me)
+static bool mesh_render_data_looptri_cos_nors_smooth_get(
+ MeshRenderData *mrdata, const int tri_idx, float *(*r_vert_cos)[3], short **r_tri_nor, short *(*r_vert_nors)[3])
{
- MESH_RENDER_FUNCTION(get_num_polys);
+ BLI_assert(mrdata->types & (MR_DATATYPE_VERT | MR_DATATYPE_LOOPTRI | MR_DATATYPE_LOOP | MR_DATATYPE_POLY));
+
+ if (mrdata->edit_bmesh) {
+ const BMLoop **bm_looptri = (const BMLoop **)mrdata->edit_bmesh->looptris[tri_idx];
+ short (*pnors_short)[3] = mrdata->poly_normals_short;
+ short (*vnors_short)[3] = mrdata->vert_normals_short;
+
+ if (!pnors_short) {
+ BMesh *bm = mrdata->edit_bmesh->bm;
+ BMIter fiter;
+ BMFace *face;
+ int i;
+
+ pnors_short = mrdata->poly_normals_short = MEM_mallocN(sizeof(*pnors_short) * mrdata->totpoly, __func__);
+ BM_ITER_MESH_INDEX(face, &fiter, bm, BM_FACES_OF_MESH, i) {
+ normal_float_to_short_v3(pnors_short[i], face->no);
+ }
+ }
+ if (!vnors_short) {
+ BMesh *bm = mrdata->edit_bmesh->bm;
+ BMIter viter;
+ BMVert *vert;
+ int i;
+
+ vnors_short = mrdata->vert_normals_short = MEM_mallocN(sizeof(*vnors_short) * mrdata->totvert, __func__);
+ BM_ITER_MESH_INDEX(vert, &viter, bm, BM_VERT, i) {
+ normal_float_to_short_v3(vnors_short[i], vert->no);
+ }
+ }
+
+ (*r_vert_cos)[0] = bm_looptri[0]->v->co;
+ (*r_vert_cos)[1] = bm_looptri[1]->v->co;
+ (*r_vert_cos)[2] = bm_looptri[2]->v->co;
+ *r_tri_nor = pnors_short[BM_elem_index_get(bm_looptri[0]->f)];
+ (*r_vert_nors)[0] = vnors_short[BM_elem_index_get(bm_looptri[0]->v)];
+ (*r_vert_nors)[1] = vnors_short[BM_elem_index_get(bm_looptri[1]->v)];
+ (*r_vert_nors)[2] = vnors_short[BM_elem_index_get(bm_looptri[2]->v)];
+
+ return BM_elem_flag_test_bool(bm_looptri[0]->f, BM_ELEM_SMOOTH);
+ }
+ else {
+ const MLoopTri *mlt = &mrdata->mlooptri[tri_idx];
+ short (*pnors_short)[3] = mrdata->poly_normals_short;
+
+ if (!pnors_short) {
+ float (*pnors)[3] = mrdata->poly_normals;
+
+ if (!pnors) {
+ pnors = mrdata->poly_normals = MEM_mallocN(sizeof(*pnors) * mrdata->totpoly, __func__);
+ BKE_mesh_calc_normals_poly(
+ mrdata->mvert, NULL, mrdata->totvert,
+ mrdata->mloop, mrdata->mpoly, mrdata->totloop, mrdata->totpoly, pnors, true);
+ }
+
+ pnors_short = mrdata->poly_normals_short = MEM_mallocN(sizeof(*pnors_short) * mrdata->totpoly, __func__);
+ for (int i = 0; i < mrdata->totpoly; i++) {
+ normal_float_to_short_v3(pnors_short[i], pnors[i]);
+ }
+ }
+
+ (*r_vert_cos)[0] = mrdata->mvert[mrdata->mloop[mlt->tri[0]].v].co;
+ (*r_vert_cos)[1] = mrdata->mvert[mrdata->mloop[mlt->tri[1]].v].co;
+ (*r_vert_cos)[2] = mrdata->mvert[mrdata->mloop[mlt->tri[2]].v].co;
+ *r_tri_nor = pnors_short[mlt->poly];
+ (*r_vert_nors)[0] = mrdata->mvert[mrdata->mloop[mlt->tri[0]].v].no;
+ (*r_vert_nors)[1] = mrdata->mvert[mrdata->mloop[mlt->tri[1]].v].no;
+ (*r_vert_nors)[2] = mrdata->mvert[mrdata->mloop[mlt->tri[2]].v].no;
+
+ return (mrdata->mpoly[mlt->poly].flag & ME_SMOOTH) != 0;
+ }
}
-static int mesh_render_get_num_verts(Mesh *me)
+/* First 2 bytes are bit flags
+ * 3rd is for sharp edges
+ * 4rd is for creased edges */
+enum {
+ VFLAG_VERTEX_ACTIVE = 1 << 0,
+ VFLAG_VERTEX_SELECTED = 1 << 1,
+ VFLAG_FACE_ACTIVE = 1 << 2,
+ VFLAG_FACE_SELECTED = 1 << 3,
+};
+
+enum {
+ VFLAG_EDGE_EXISTS = 1 << 0,
+ VFLAG_EDGE_ACTIVE = 1 << 1,
+ VFLAG_EDGE_SELECTED = 1 << 2,
+ VFLAG_EDGE_SEAM = 1 << 3,
+ VFLAG_EDGE_SHARP = 1 << 4,
+ /* Beware to not go over 1 << 7
+ * (see gpu_shader_edit_overlay_geom.glsl) */
+};
+
+static unsigned char mesh_render_data_looptri_flag(MeshRenderData *mrdata, const int f)
{
- MESH_RENDER_FUNCTION(get_num_verts);
+ unsigned char fflag = 0;
+
+ if (mrdata->edit_bmesh) {
+ BMFace *bf = mrdata->edit_bmesh->looptris[f][0]->f;
+
+ if (bf == mrdata->efa_act)
+ fflag |= VFLAG_FACE_ACTIVE;
+
+ if (BM_elem_flag_test(bf, BM_ELEM_SELECT))
+ fflag |= VFLAG_FACE_SELECTED;
+ }
+
+ return fflag;
}
-static MEdge *mesh_render_get_array_edge(Mesh *me)
+static unsigned char *mesh_render_data_edge_flag(
+ MeshRenderData *mrdata, const int v1, const int v2, const int e)
{
- MESH_RENDER_FUNCTION(get_array_edge);
+ static unsigned char eflag[4];
+ memset(eflag, 0, sizeof(char) * 4);
+
+ /* if edge exists */
+ if (mrdata->edit_bmesh) {
+ BMesh *bm = mrdata->edit_bmesh->bm;
+ BMEdge *be = NULL;
+
+ if (e != -1) be = BM_edge_at_index(bm, e);
+ else be = BM_edge_exists(BM_vert_at_index(bm, v1),
+ BM_vert_at_index(bm, v2));
+
+ if (be != NULL) {
+
+ eflag[1] |= VFLAG_EDGE_EXISTS;
+
+ if (be == mrdata->eed_act)
+ eflag[1] |= VFLAG_EDGE_ACTIVE;
+
+ if (BM_elem_flag_test(be, BM_ELEM_SELECT))
+ eflag[1] |= VFLAG_EDGE_SELECTED;
+
+ if (BM_elem_flag_test(be, BM_ELEM_SEAM))
+ eflag[1] |= VFLAG_EDGE_SEAM;
+
+ if (!BM_elem_flag_test(be, BM_ELEM_SMOOTH))
+ eflag[1] |= VFLAG_EDGE_SHARP;
+
+ /* Use a byte for value range */
+ if (mrdata->crease_ofs != -1) {
+ float crease = BM_ELEM_CD_GET_FLOAT(be, mrdata->crease_ofs);
+ if (crease > 0) {
+ eflag[2] = (char)(crease * 255.0f);
+ }
+ }
+
+ /* Use a byte for value range */
+ if (mrdata->bweight_ofs != -1) {
+ float bweight = BM_ELEM_CD_GET_FLOAT(be, mrdata->bweight_ofs);
+ if (bweight > 0) {
+ eflag[3] = (char)(bweight * 255.0f);
+ }
+ }
+ }
+ }
+ else if ((e == -1) && mesh_render_data_edge_exists(mrdata, v1, v2)) {
+ eflag[1] |= VFLAG_EDGE_EXISTS;
+ }
+
+ return eflag;
}
-static MFace *mesh_render_get_array_face(Mesh *me)
+static unsigned char mesh_render_data_vertex_flag(MeshRenderData *mrdata, const int v)
{
- MESH_RENDER_FUNCTION(get_array_face);
+
+ unsigned char vflag = 0;
+
+ if (mrdata->edit_bmesh) {
+ BMesh *bm = mrdata->edit_bmesh->bm;
+ BMVert *bv = BM_vert_at_index(bm, v);
+
+ /* Current vertex */
+ if (bv == mrdata->eve_act)
+ vflag |= VFLAG_VERTEX_ACTIVE;
+
+ if (BM_elem_flag_test(bv, BM_ELEM_SELECT))
+ vflag |= VFLAG_VERTEX_SELECTED;
+ }
+
+ return vflag;
}
-static MLoop *mesh_render_get_array_loop(Mesh *me)
+static void add_overlay_tri(
+ MeshRenderData *mrdata, VertexBuffer *vbo, const unsigned int pos_id, const unsigned int edgeMod_id,
+ const int v1, const int v2, const int v3, const int f, const int base_vert_idx)
{
- MESH_RENDER_FUNCTION(get_array_loop);
+ const float *pos = mesh_render_data_vert_co(mrdata, v1);
+ unsigned char *eflag = mesh_render_data_edge_flag(mrdata, v2, v3, -1);
+ unsigned char fflag = mesh_render_data_looptri_flag(mrdata, f);
+ unsigned char vflag = mesh_render_data_vertex_flag(mrdata, v1);
+ eflag[0] = fflag | vflag;
+ setAttrib(vbo, pos_id, base_vert_idx + 0, pos);
+ setAttrib(vbo, edgeMod_id, base_vert_idx + 0, eflag);
+
+ pos = mesh_render_data_vert_co(mrdata, v2);
+ eflag = mesh_render_data_edge_flag(mrdata, v1, v3, -1);
+ vflag = mesh_render_data_vertex_flag(mrdata, v2);
+ eflag[0] = fflag | vflag;
+ setAttrib(vbo, pos_id, base_vert_idx + 1, pos);
+ setAttrib(vbo, edgeMod_id, base_vert_idx + 1, eflag);
+
+ pos = mesh_render_data_vert_co(mrdata, v3);
+ eflag = mesh_render_data_edge_flag(mrdata, v1, v2, -1);
+ vflag = mesh_render_data_vertex_flag(mrdata, v3);
+ eflag[0] = fflag | vflag;
+ setAttrib(vbo, pos_id, base_vert_idx + 2, pos);
+ setAttrib(vbo, edgeMod_id, base_vert_idx + 2, eflag);
}
-static MPoly *mesh_render_get_array_poly(Mesh *me)
+static void add_overlay_loose_edge(
+ MeshRenderData *mrdata, VertexBuffer *vbo, const unsigned int pos_id, const unsigned int edgeMod_id,
+ const int v1, const int v2, const int e, const int base_vert_idx)
{
- MESH_RENDER_FUNCTION(get_array_poly);
+ unsigned char *eflag = mesh_render_data_edge_flag(mrdata, 0, 0, e);
+ const float *pos = mesh_render_data_vert_co(mrdata, v1);
+ eflag[0] = mesh_render_data_vertex_flag(mrdata, v1);
+ setAttrib(vbo, pos_id, base_vert_idx + 0, pos);
+ setAttrib(vbo, edgeMod_id, base_vert_idx + 0, eflag);
+
+ pos = mesh_render_data_vert_co(mrdata, v2);
+ eflag[0] = mesh_render_data_vertex_flag(mrdata, v2);
+ setAttrib(vbo, pos_id, base_vert_idx + 1, pos);
+ setAttrib(vbo, edgeMod_id, base_vert_idx + 1, eflag);
}
-static MVert *mesh_render_get_array_vert(Mesh *me)
+static void add_overlay_loose_vert(
+ MeshRenderData *mrdata, VertexBuffer *vbo, const unsigned int pos_id, const unsigned int edgeMod_id,
+ const int v, const int base_vert_idx)
{
- MESH_RENDER_FUNCTION(get_array_vert);
+ unsigned char vflag[4] = {0, 0, 0, 0};
+ const float *pos = mesh_render_data_vert_co(mrdata, v);
+ vflag[0] = mesh_render_data_vertex_flag(mrdata, v);
+ setAttrib(vbo, pos_id, base_vert_idx + 0, pos);
+ setAttrib(vbo, edgeMod_id, base_vert_idx + 0, vflag);
}
/* ---------------------------------------------------------------------- */
@@ -224,6 +726,7 @@ static MVert *mesh_render_get_array_vert(Mesh *me)
typedef struct MeshBatchCache {
VertexBuffer *pos_in_order;
+ VertexBuffer *nor_in_order;
ElementList *edges_in_order;
ElementList *triangles_in_order;
@@ -231,18 +734,31 @@ typedef struct MeshBatchCache {
Batch *all_edges;
Batch *all_triangles;
+ VertexBuffer *pos_with_normals;
+ Batch *triangles_with_normals;
+ Batch *points_with_normals;
Batch *fancy_edges; /* owns its vertex buffer (not shared) */
- Batch *overlay_edges; /* owns its vertex buffer */
+
+ /* TODO : split in 2 buffers to avoid unnecessary
+ * data transfer when selecting/deselecting
+ * and combine into one batch and use offsets to render
+ * Tri / edges / verts separately */
+ Batch *overlay_triangles;
+ Batch *overlay_loose_verts;
+ Batch *overlay_loose_edges;
+ Batch *overlay_facedots;
/* settings to determine if cache is invalid */
bool is_dirty;
int tot_edges;
- int tot_faces;
+ int tot_tris;
int tot_polys;
int tot_verts;
bool is_editmode;
} MeshBatchCache;
+/* Batch cache management. */
+
static bool mesh_batch_cache_valid(Mesh *me)
{
MeshBatchCache *cache = me->batch_cache;
@@ -262,10 +778,10 @@ static bool mesh_batch_cache_valid(Mesh *me)
if (cache->is_editmode) {
return false;
}
- else if ((cache->tot_edges != mesh_render_get_num_edges(me)) ||
- (cache->tot_faces != mesh_render_get_num_faces(me)) ||
- (cache->tot_polys != mesh_render_get_num_polys(me)) ||
- (cache->tot_verts != mesh_render_get_num_verts(me)))
+ else if ((cache->tot_verts != mesh_render_verts_num_get(me)) ||
+ (cache->tot_edges != mesh_render_edges_num_get(me)) ||
+ (cache->tot_tris != mesh_render_looptri_num_get(me)) ||
+ (cache->tot_polys != mesh_render_polys_num_get(me)))
{
return false;
}
@@ -277,13 +793,21 @@ static bool mesh_batch_cache_valid(Mesh *me)
static void mesh_batch_cache_init(Mesh *me)
{
MeshBatchCache *cache = me->batch_cache;
+
+ if (!cache) {
+ cache = me->batch_cache = MEM_callocN(sizeof(*cache), __func__);
+ }
+ else {
+ memset(cache, 0, sizeof(*cache));
+ }
+
cache->is_editmode = me->edit_btmesh != NULL;
if (cache->is_editmode == false) {
- cache->tot_edges = mesh_render_get_num_edges(me);
- cache->tot_faces = mesh_render_get_num_faces(me);
- cache->tot_polys = mesh_render_get_num_polys(me);
- cache->tot_verts = mesh_render_get_num_verts(me);
+ cache->tot_edges = mesh_render_edges_num_get(me);
+ cache->tot_tris = mesh_render_looptri_num_get(me);
+ cache->tot_polys = mesh_render_polys_num_get(me);
+ cache->tot_verts = mesh_render_verts_num_get(me);
}
cache->is_dirty = false;
@@ -292,57 +816,167 @@ static void mesh_batch_cache_init(Mesh *me)
static MeshBatchCache *mesh_batch_cache_get(Mesh *me)
{
if (!mesh_batch_cache_valid(me)) {
- BKE_mesh_batch_cache_free(me);
- me->batch_cache = MEM_callocN(sizeof(MeshBatchCache), "MeshBatchCache");
+ BKE_mesh_batch_cache_clear(me);
mesh_batch_cache_init(me);
}
return me->batch_cache;
}
-static VertexBuffer *mesh_batch_cache_get_pos_in_order(Mesh *me)
+void BKE_mesh_batch_cache_dirty(struct Mesh *me)
{
- MeshBatchCache *cache = mesh_batch_cache_get(me);
+ MeshBatchCache *cache = me->batch_cache;
+ if (cache) {
+ cache->is_dirty = true;
+ }
+}
+
+void BKE_mesh_batch_selection_dirty(struct Mesh *me)
+{
+ MeshBatchCache *cache = me->batch_cache;
+ if (cache) {
+ /* TODO Separate Flag vbo */
+ if (cache->overlay_triangles) {
+ Batch_discard_all(cache->overlay_triangles);
+ cache->overlay_triangles = NULL;
+ }
+ if (cache->overlay_loose_verts) {
+ Batch_discard_all(cache->overlay_loose_verts);
+ cache->overlay_loose_verts = NULL;
+ }
+ if (cache->overlay_loose_edges) {
+ Batch_discard_all(cache->overlay_loose_edges);
+ cache->overlay_loose_edges = NULL;
+ }
+ if (cache->overlay_facedots) {
+ Batch_discard_all(cache->overlay_facedots);
+ cache->overlay_facedots = NULL;
+ }
+ }
+}
+
+void BKE_mesh_batch_cache_clear(Mesh *me)
+{
+ MeshBatchCache *cache = me->batch_cache;
+ if (!cache) {
+ return;
+ }
+
+ if (cache->all_verts) Batch_discard(cache->all_verts);
+ if (cache->all_edges) Batch_discard(cache->all_edges);
+ if (cache->all_triangles) Batch_discard(cache->all_triangles);
+
+ if (cache->pos_in_order) VertexBuffer_discard(cache->pos_in_order);
+ if (cache->edges_in_order) ElementList_discard(cache->edges_in_order);
+ if (cache->triangles_in_order) ElementList_discard(cache->triangles_in_order);
+
+ if (cache->overlay_triangles) Batch_discard_all(cache->overlay_triangles);
+ if (cache->overlay_loose_verts) Batch_discard_all(cache->overlay_loose_verts);
+ if (cache->overlay_loose_edges) Batch_discard_all(cache->overlay_loose_edges);
+ if (cache->overlay_facedots) Batch_discard_all(cache->overlay_facedots);
+
+ if (cache->triangles_with_normals) Batch_discard(cache->triangles_with_normals);
+ if (cache->points_with_normals) Batch_discard(cache->points_with_normals);
+ if (cache->pos_with_normals) VertexBuffer_discard(cache->pos_with_normals);
+
+
+ if (cache->fancy_edges) {
+ Batch_discard_all(cache->fancy_edges);
+ }
+}
+
+void BKE_mesh_batch_cache_free(Mesh *me)
+{
+ BKE_mesh_batch_cache_clear(me);
+ MEM_SAFE_FREE(me->batch_cache);
+}
+
+/* Batch cache usage. */
+
+static VertexBuffer *mesh_batch_cache_get_pos_and_normals(MeshRenderData *mrdata, MeshBatchCache *cache)
+{
+ BLI_assert(mrdata->types & (MR_DATATYPE_VERT | MR_DATATYPE_LOOPTRI | MR_DATATYPE_LOOP | MR_DATATYPE_POLY));
+
+ if (cache->pos_with_normals == NULL) {
+ unsigned int vidx = 0, nidx = 0;
+
+ static VertexFormat format = { 0 };
+ static unsigned int pos_id, nor_id;
+ if (format.attrib_ct == 0) {
+ /* initialize vertex format */
+ pos_id = add_attrib(&format, "pos", GL_FLOAT, 3, KEEP_FLOAT);
+ nor_id = add_attrib(&format, "nor", GL_SHORT, 3, NORMALIZE_INT_TO_FLOAT);
+ }
+
+ const int tottri = mesh_render_data_looptri_num_get(mrdata);
+
+ cache->pos_with_normals = VertexBuffer_create_with_format(&format);
+ VertexBuffer_allocate_data(cache->pos_with_normals, tottri * 3);
+
+ for (int i = 0; i < tottri; i++) {
+ float *tri_vert_cos[3];
+ short *tri_nor, *tri_vert_nors[3];
+
+ const bool is_smooth = mesh_render_data_looptri_cos_nors_smooth_get(mrdata, i, &tri_vert_cos, &tri_nor, &tri_vert_nors);
+
+ if (is_smooth) {
+ setAttrib(cache->pos_with_normals, nor_id, nidx++, tri_vert_nors[0]);
+ setAttrib(cache->pos_with_normals, nor_id, nidx++, tri_vert_nors[1]);
+ setAttrib(cache->pos_with_normals, nor_id, nidx++, tri_vert_nors[2]);
+ }
+ else {
+ setAttrib(cache->pos_with_normals, nor_id, nidx++, tri_nor);
+ setAttrib(cache->pos_with_normals, nor_id, nidx++, tri_nor);
+ setAttrib(cache->pos_with_normals, nor_id, nidx++, tri_nor);
+ }
+
+ setAttrib(cache->pos_with_normals, pos_id, vidx++, tri_vert_cos[0]);
+ setAttrib(cache->pos_with_normals, pos_id, vidx++, tri_vert_cos[1]);
+ setAttrib(cache->pos_with_normals, pos_id, vidx++, tri_vert_cos[2]);
+ }
+ }
+ return cache->pos_with_normals;
+}
+static VertexBuffer *mesh_batch_cache_get_pos_and_nor_in_order(MeshRenderData *mrdata, MeshBatchCache *cache)
+{
+ BLI_assert(mrdata->types & MR_DATATYPE_VERT);
if (cache->pos_in_order == NULL) {
static VertexFormat format = { 0 };
- static unsigned pos_id;
+ static unsigned pos_id, nor_id;
if (format.attrib_ct == 0) {
/* initialize vertex format */
pos_id = add_attrib(&format, "pos", GL_FLOAT, 3, KEEP_FLOAT);
+ nor_id = add_attrib(&format, "nor", GL_SHORT, 3, NORMALIZE_INT_TO_FLOAT);
}
- const int vertex_ct = mesh_render_get_num_verts(me);
- const MVert *verts = mesh_render_get_array_vert(me);
+ const int vertex_ct = mesh_render_data_verts_num_get(mrdata);
cache->pos_in_order = VertexBuffer_create_with_format(&format);
VertexBuffer_allocate_data(cache->pos_in_order, vertex_ct);
-#if 0
- const unsigned stride = (verts + 1) - verts; /* or sizeof(MVert) */
- fillAttribStride(cache->pos_in_order, pos_id, stride, &verts[0].co);
-#else
for (int i = 0; i < vertex_ct; ++i) {
- setAttrib(cache->pos_in_order, pos_id, i, &verts[i].co);
+ setAttrib(cache->pos_in_order, pos_id, i, mesh_render_data_vert_co(mrdata, i));
+ setAttrib(cache->pos_in_order, nor_id, i, mesh_render_data_vert_nor(mrdata, i));
}
-#endif
}
return cache->pos_in_order;
}
-static ElementList *mesh_batch_cache_get_edges_in_order(Mesh *me)
+static ElementList *mesh_batch_cache_get_edges_in_order(MeshRenderData *mrdata, MeshBatchCache *cache)
{
- MeshBatchCache *cache = mesh_batch_cache_get(me);
+ BLI_assert(mrdata->types & (MR_DATATYPE_VERT | MR_DATATYPE_EDGE));
if (cache->edges_in_order == NULL) {
- const int vertex_ct = mesh_render_get_num_verts(me);
- const int edge_ct = mesh_render_get_num_edges(me);
- const MEdge *edges = mesh_render_get_array_edge(me);
+ printf("Caching edges in order...\n");
+ const int vertex_ct = mesh_render_data_verts_num_get(mrdata);
+ const int edge_ct = mesh_render_data_edges_num_get(mrdata);
ElementListBuilder elb;
ElementListBuilder_init(&elb, GL_LINES, edge_ct, vertex_ct);
for (int i = 0; i < edge_ct; ++i) {
- const MEdge *edge = edges + i;
- add_line_vertices(&elb, edge->v1, edge->v2);
+ int vert_idx[2];
+ mesh_render_data_edge_verts_indices_get(mrdata, i, vert_idx);
+ add_line_vertices(&elb, vert_idx[0], vert_idx[1]);
}
cache->edges_in_order = ElementList_build(&elb);
}
@@ -350,91 +984,90 @@ static ElementList *mesh_batch_cache_get_edges_in_order(Mesh *me)
return cache->edges_in_order;
}
-static ElementList *mesh_batch_cache_get_triangles_in_order(Mesh *me)
+static ElementList *mesh_batch_cache_get_triangles_in_order(MeshRenderData *mrdata, MeshBatchCache *cache)
{
- MeshBatchCache *cache = mesh_batch_cache_get(me);
+ BLI_assert(mrdata->types & (MR_DATATYPE_VERT | MR_DATATYPE_LOOPTRI));
if (cache->triangles_in_order == NULL) {
- const int vertex_ct = mesh_render_get_num_verts(me);
- const int tessface_ct = mesh_render_get_num_faces(me);
- MFace *tessfaces = mesh_render_get_array_face(me);
+ const int vertex_ct = mesh_render_data_verts_num_get(mrdata);
+ const int tri_ct = mesh_render_data_looptri_num_get(mrdata);
ElementListBuilder elb;
- ElementListBuilder_init(&elb, GL_TRIANGLES, tessface_ct * 2, vertex_ct); /* up to 2 triangles per tessface */
- for (int i = 0; i < tessface_ct; ++i) {
- const MFace *tess = tessfaces + i;
- add_triangle_vertices(&elb, tess->v1, tess->v2, tess->v3);
+ ElementListBuilder_init(&elb, GL_TRIANGLES, tri_ct, vertex_ct);
+ for (int i = 0; i < tri_ct; ++i) {
+ int tri_vert_idx[3];
+ mesh_render_data_looptri_verts_indices_get(mrdata, i, tri_vert_idx);
- if (tess->v4) {
- add_triangle_vertices(&elb, tess->v1, tess->v3, tess->v4);
- }
+ add_triangle_vertices(&elb, tri_vert_idx[0], tri_vert_idx[1], tri_vert_idx[2]);
}
cache->triangles_in_order = ElementList_build(&elb);
}
- /* NOTE: we are reallocating, it would be interesting to reallocating the memory once we
- * know the exactly triangle count (like in BKE_mesh_batch_cache_get_overlay_edges) */
-
return cache->triangles_in_order;
}
-void BKE_mesh_batch_cache_dirty(struct Mesh *me)
+Batch *BKE_mesh_batch_cache_get_all_edges(Mesh *me)
{
- MeshBatchCache *cache = me->batch_cache;
- if (cache) {
- cache->is_dirty = true;
+ MeshBatchCache *cache = mesh_batch_cache_get(me);
+
+ if (cache->all_edges == NULL) {
+ /* create batch from Mesh */
+ MeshRenderData *mrdata = mesh_render_data_create(me, MR_DATATYPE_VERT | MR_DATATYPE_EDGE);
+
+ cache->all_edges = Batch_create(GL_LINES, mesh_batch_cache_get_pos_and_nor_in_order(mrdata, cache),
+ mesh_batch_cache_get_edges_in_order(mrdata, cache));
+
+ mesh_render_data_free(mrdata);
}
+
+ return cache->all_edges;
}
-void BKE_mesh_batch_cache_free(Mesh *me)
+Batch *BKE_mesh_batch_cache_get_all_triangles(Mesh *me)
{
- MeshBatchCache *cache = me->batch_cache;
- if (!cache) {
- return;
- }
-
- if (cache->all_verts) Batch_discard(cache->all_verts);
- if (cache->all_edges) Batch_discard(cache->all_edges);
- if (cache->all_triangles) Batch_discard(cache->all_triangles);
+ MeshBatchCache *cache = mesh_batch_cache_get(me);
- if (cache->pos_in_order) VertexBuffer_discard(cache->pos_in_order);
- if (cache->edges_in_order) ElementList_discard(cache->edges_in_order);
- if (cache->triangles_in_order) ElementList_discard(cache->triangles_in_order);
+ if (cache->all_triangles == NULL) {
+ /* create batch from DM */
+ MeshRenderData *mrdata = mesh_render_data_create(me, MR_DATATYPE_VERT | MR_DATATYPE_LOOPTRI);
- if (cache->fancy_edges) {
- Batch_discard_all(cache->fancy_edges);
- }
+ cache->all_triangles = Batch_create(GL_TRIANGLES, mesh_batch_cache_get_pos_and_nor_in_order(mrdata, cache),
+ mesh_batch_cache_get_triangles_in_order(mrdata, cache));
- if (cache->overlay_edges) {
- Batch_discard_all(cache->overlay_edges);
+ mesh_render_data_free(mrdata);
}
- MEM_freeN(cache);
- me->batch_cache = NULL;
+ return cache->all_triangles;
}
-Batch *BKE_mesh_batch_cache_get_all_edges(Mesh *me)
+Batch *BKE_mesh_batch_cache_get_triangles_with_normals(Mesh *me)
{
MeshBatchCache *cache = mesh_batch_cache_get(me);
- if (cache->all_edges == NULL) {
- /* create batch from Mesh */
- cache->all_edges = Batch_create(GL_LINES, mesh_batch_cache_get_pos_in_order(me), mesh_batch_cache_get_edges_in_order(me));
+ if (cache->triangles_with_normals == NULL) {
+ MeshRenderData *mrdata = mesh_render_data_create(me, MR_DATATYPE_VERT | MR_DATATYPE_LOOPTRI | MR_DATATYPE_LOOP | MR_DATATYPE_POLY);
+
+ cache->triangles_with_normals = Batch_create(GL_TRIANGLES, mesh_batch_cache_get_pos_and_normals(mrdata, cache), NULL);
+
+ mesh_render_data_free(mrdata);
}
- return cache->all_edges;
+ return cache->triangles_with_normals;
}
-Batch *BKE_mesh_batch_cache_get_all_triangles(Mesh *me)
+Batch *BKE_mesh_batch_cache_get_points_with_normals(Mesh *me)
{
MeshBatchCache *cache = mesh_batch_cache_get(me);
- if (cache->all_triangles == NULL) {
- /* create batch from DM */
- cache->all_triangles = Batch_create(GL_TRIANGLES, mesh_batch_cache_get_pos_in_order(me), mesh_batch_cache_get_triangles_in_order(me));
+ if (cache->points_with_normals == NULL) {
+ MeshRenderData *mrdata = mesh_render_data_create(me, MR_DATATYPE_VERT | MR_DATATYPE_LOOPTRI | MR_DATATYPE_LOOP | MR_DATATYPE_POLY);
+
+ cache->points_with_normals = Batch_create(GL_POINTS, mesh_batch_cache_get_pos_and_normals(mrdata, cache), NULL);
+
+ mesh_render_data_free(mrdata);
}
- return cache->all_triangles;
+ return cache->points_with_normals;
}
Batch *BKE_mesh_batch_cache_get_all_verts(Mesh *me)
@@ -443,8 +1076,11 @@ Batch *BKE_mesh_batch_cache_get_all_verts(Mesh *me)
if (cache->all_verts == NULL) {
/* create batch from DM */
- cache->all_verts = Batch_create(GL_POINTS, mesh_batch_cache_get_pos_in_order(me), NULL);
- Batch_set_builtin_program(cache->all_verts, GPU_SHADER_3D_POINT_FIXED_SIZE_UNIFORM_COLOR);
+ MeshRenderData *mrdata = mesh_render_data_create(me, MR_DATATYPE_VERT);
+
+ cache->all_verts = Batch_create(GL_POINTS, mesh_batch_cache_get_pos_and_nor_in_order(mrdata, cache), NULL);
+
+ mesh_render_data_free(mrdata);
}
return cache->all_verts;
@@ -457,7 +1093,7 @@ Batch *BKE_mesh_batch_cache_get_fancy_edges(Mesh *me)
if (cache->fancy_edges == NULL) {
/* create batch from DM */
static VertexFormat format = { 0 };
- static unsigned pos_id, n1_id, n2_id;
+ static unsigned int pos_id, n1_id, n2_id;
if (format.attrib_ct == 0) {
/* initialize vertex format */
pos_id = add_attrib(&format, "pos", COMP_F32, 3, KEEP_FLOAT);
@@ -472,48 +1108,24 @@ Batch *BKE_mesh_batch_cache_get_fancy_edges(Mesh *me)
}
VertexBuffer *vbo = VertexBuffer_create_with_format(&format);
- const MVert *verts = mesh_render_get_array_vert(me);
- const MEdge *edges = mesh_render_get_array_edge(me);
- const MPoly *polys = mesh_render_get_array_poly(me);
- const MLoop *loops = mesh_render_get_array_loop(me);
- const int edge_ct = mesh_render_get_num_edges(me);
- const int poly_ct = mesh_render_get_num_polys(me);
-
- /* need normal of each face, and which faces are adjacent to each edge */
- typedef struct {
- int count;
- int face_index[2];
- } AdjacentFaces;
-
- float (*face_normal)[3] = MEM_mallocN(poly_ct * 3 * sizeof(float), "face_normal");
- AdjacentFaces *adj_faces = MEM_callocN(edge_ct * sizeof(AdjacentFaces), "adj_faces");
+ MeshRenderData *mrdata = mesh_render_data_create(me, MR_DATATYPE_VERT | MR_DATATYPE_EDGE | MR_DATATYPE_LOOP | MR_DATATYPE_POLY);
- for (int i = 0; i < poly_ct; ++i) {
- const MPoly *poly = polys + i;
-
- BKE_mesh_calc_poly_normal(poly, loops + poly->loopstart, verts, face_normal[i]);
-
- for (int j = poly->loopstart; j < (poly->loopstart + poly->totloop); ++j) {
- AdjacentFaces *adj = adj_faces + loops[j].e;
- if (adj->count < 2)
- adj->face_index[adj->count] = i;
- adj->count++;
- }
- }
+ const int edge_ct = mesh_render_data_edges_num_get(mrdata);
const int vertex_ct = edge_ct * 2; /* these are GL_LINE verts, not mesh verts */
VertexBuffer_allocate_data(vbo, vertex_ct);
for (int i = 0; i < edge_ct; ++i) {
- const MEdge *edge = edges + i;
- const AdjacentFaces *adj = adj_faces + i;
+ float *vcos1, *vcos2;
+ float *pnor1 = NULL, *pnor2 = NULL;
+ const bool is_manifold = mesh_render_data_edge_vcos_manifold_pnors(mrdata, i, &vcos1, &vcos2, &pnor1, &pnor2);
#if USE_10_10_10
PackedNormal n1value = { .x = 0, .y = 0, .z = +511 };
PackedNormal n2value = { .x = 0, .y = 0, .z = -511 };
- if (adj->count == 2) {
- n1value = convert_i10_v3(face_normal[adj->face_index[0]]);
- n2value = convert_i10_v3(face_normal[adj->face_index[1]]);
+ if (is_manifold) {
+ n1value = convert_i10_v3(pnor1);
+ n2value = convert_i10_v3(pnor2);
}
const PackedNormal *n1 = &n1value;
@@ -522,106 +1134,176 @@ Batch *BKE_mesh_batch_cache_get_fancy_edges(Mesh *me)
const float dummy1[3] = { 0.0f, 0.0f, +1.0f };
const float dummy2[3] = { 0.0f, 0.0f, -1.0f };
- const float *n1 = (adj->count == 2) ? face_normal[adj->face_index[0]] : dummy1;
- const float *n2 = (adj->count == 2) ? face_normal[adj->face_index[1]] : dummy2;
+ const float *n1 = (is_manifold) ? pnor1 : dummy1;
+ const float *n2 = (is_manifold) ? pnor2 : dummy2;
#endif
- setAttrib(vbo, pos_id, 2 * i, &verts[edge->v1].co);
+ setAttrib(vbo, pos_id, 2 * i, vcos1);
setAttrib(vbo, n1_id, 2 * i, n1);
setAttrib(vbo, n2_id, 2 * i, n2);
- setAttrib(vbo, pos_id, 2 * i + 1, &verts[edge->v2].co);
+ setAttrib(vbo, pos_id, 2 * i + 1, vcos2);
setAttrib(vbo, n1_id, 2 * i + 1, n1);
setAttrib(vbo, n2_id, 2 * i + 1, n2);
}
- MEM_freeN(adj_faces);
- MEM_freeN(face_normal);
-
cache->fancy_edges = Batch_create(GL_LINES, vbo, NULL);
+
+ mesh_render_data_free(mrdata);
}
return cache->fancy_edges;
}
-static bool edge_is_real(const MEdge *edges, int edge_ct, int v1, int v2)
+static void mesh_batch_cache_create_overlay_batches(Mesh *me)
{
- /* TODO: same thing, except not ridiculously slow */
+ /* Since MR_DATATYPE_OVERLAY is slow to generate, generate them all at once */
+ int options = MR_DATATYPE_VERT | MR_DATATYPE_EDGE | MR_DATATYPE_LOOPTRI | MR_DATATYPE_OVERLAY;
- for (int e = 0; e < edge_ct; ++e) {
- const MEdge *edge = edges + e;
- if ((edge->v1 == v1 && edge->v2 == v2) || (edge->v1 == v2 && edge->v2 == v1)) {
- return true;
+ MeshBatchCache *cache = mesh_batch_cache_get(me);
+ MeshRenderData *mrdata = mesh_render_data_create(me, options);
+
+ static VertexFormat format = { 0 };
+ static unsigned pos_id, data_id;
+ if (format.attrib_ct == 0) {
+ /* initialize vertex format */
+ pos_id = add_attrib(&format, "pos", GL_FLOAT, 3, KEEP_FLOAT);
+ data_id = add_attrib(&format, "data", GL_UNSIGNED_BYTE, 4, KEEP_INT);
+ }
+
+ const int tri_ct = mesh_render_data_looptri_num_get(mrdata);
+ const int ledge_ct = mesh_render_data_loose_edges_num_get(mrdata);
+ const int lvert_ct = mesh_render_data_loose_verts_num_get(mrdata);
+
+ if (cache->overlay_triangles == NULL) {
+ VertexBuffer *vbo = VertexBuffer_create_with_format(&format);
+ VertexBuffer_allocate_data(vbo, tri_ct * 3);
+
+ int gpu_vert_idx = 0;
+ for (int i = 0; i < tri_ct; ++i) {
+ int tri_vert_idx[3];
+ mesh_render_data_looptri_verts_indices_get(mrdata, i, tri_vert_idx);
+ add_overlay_tri(mrdata, vbo, pos_id, data_id,
+ tri_vert_idx[0], tri_vert_idx[1], tri_vert_idx[2], i, gpu_vert_idx);
+ gpu_vert_idx += 3;
}
+
+ cache->overlay_triangles = Batch_create(GL_TRIANGLES, vbo, NULL);
}
- return false;
+ if (cache->overlay_loose_edges == NULL) {
+ VertexBuffer *vbo = VertexBuffer_create_with_format(&format);
+ VertexBuffer_allocate_data(vbo, ledge_ct * 2);
+
+ int gpu_vert_idx = 0;
+ for (int i = 0; i < ledge_ct; ++i) {
+ int vert_idx[2];
+ mesh_render_data_edge_verts_indices_get(mrdata, mrdata->loose_edges[i], vert_idx);
+ add_overlay_loose_edge(mrdata, vbo, pos_id, data_id,
+ vert_idx[0], vert_idx[1], mrdata->loose_edges[i], gpu_vert_idx);
+ gpu_vert_idx += 2;
+ }
+ cache->overlay_loose_edges = Batch_create(GL_LINES, vbo, NULL);
+ }
+
+ if (cache->overlay_loose_verts == NULL) {
+ VertexBuffer *vbo = VertexBuffer_create_with_format(&format);
+ VertexBuffer_allocate_data(vbo, lvert_ct);
+
+ int gpu_vert_idx = 0;
+ for (int i = 0; i < lvert_ct; ++i) {
+ add_overlay_loose_vert(mrdata, vbo, pos_id, data_id,
+ mrdata->loose_verts[i], gpu_vert_idx);
+ gpu_vert_idx += 1;
+ }
+ cache->overlay_loose_verts = Batch_create(GL_POINTS, vbo, NULL);
+ }
+
+ mesh_render_data_free(mrdata);
}
-static void add_overlay_tri(
- VertexBuffer *vbo, unsigned pos_id, unsigned edgeMod_id, const MVert *verts,
- const MEdge *edges, int edge_ct, int v1, int v2, int v3, int base_vert_idx)
+Batch *BKE_mesh_batch_cache_get_overlay_triangles(Mesh *me)
{
- const float edgeMods[2] = { 0.0f, 1.0f };
+ MeshBatchCache *cache = mesh_batch_cache_get(me);
- const float *pos = verts[v1].co;
- setAttrib(vbo, pos_id, base_vert_idx + 0, pos);
- setAttrib(vbo, edgeMod_id, base_vert_idx + 0, edgeMods + (edge_is_real(edges, edge_ct, v2, v3) ? 1 : 0));
+ if (cache->overlay_triangles == NULL) {
+ mesh_batch_cache_create_overlay_batches(me);
+ }
- pos = verts[v2].co;
- setAttrib(vbo, pos_id, base_vert_idx + 1, pos);
- setAttrib(vbo, edgeMod_id, base_vert_idx + 1, edgeMods + (edge_is_real(edges, edge_ct, v3, v1) ? 1 : 0));
+ return cache->overlay_triangles;
+}
- pos = verts[v3].co;
- setAttrib(vbo, pos_id, base_vert_idx + 2, pos);
- setAttrib(vbo, edgeMod_id, base_vert_idx + 2, edgeMods + (edge_is_real(edges, edge_ct, v1, v2) ? 1 : 0));
+Batch *BKE_mesh_batch_cache_get_overlay_loose_edges(Mesh *me)
+{
+ MeshBatchCache *cache = mesh_batch_cache_get(me);
+
+ if (cache->overlay_loose_edges == NULL) {
+ mesh_batch_cache_create_overlay_batches(me);
+ }
+
+ return cache->overlay_loose_edges;
}
-Batch *BKE_mesh_batch_cache_get_overlay_edges(Mesh *me)
+Batch *BKE_mesh_batch_cache_get_overlay_loose_verts(Mesh *me)
{
MeshBatchCache *cache = mesh_batch_cache_get(me);
- if (cache->overlay_edges == NULL) {
- /* create batch from DM */
- static VertexFormat format = { 0 };
- static unsigned pos_id, edgeMod_id;
+ if (cache->overlay_loose_verts == NULL) {
+ mesh_batch_cache_create_overlay_batches(me);
+ }
+ return cache->overlay_loose_verts;
+}
+
+Batch *BKE_mesh_batch_cache_get_overlay_facedots(Mesh *me)
+{
+ MeshBatchCache *cache = mesh_batch_cache_get(me);
+
+ if (cache->overlay_facedots == NULL) {
+ MeshRenderData *mrdata = mesh_render_data_create(me, MR_DATATYPE_VERT | MR_DATATYPE_LOOP | MR_DATATYPE_POLY);
+
+ static VertexFormat format = { 0 };
+ static unsigned pos_id, data_id;
if (format.attrib_ct == 0) {
/* initialize vertex format */
pos_id = add_attrib(&format, "pos", GL_FLOAT, 3, KEEP_FLOAT);
- edgeMod_id = add_attrib(&format, "edgeWidthModulator", GL_FLOAT, 1, KEEP_FLOAT);
+#if USE_10_10_10
+ data_id = add_attrib(&format, "norAndFlag", COMP_I10, 4, NORMALIZE_INT_TO_FLOAT);
+#else
+ data_id = add_attrib(&format, "norAndFlag", GL_FLOAT, 4, KEEP_FLOAT);
+#endif
}
+
+ const int poly_ct = mesh_render_data_polys_num_get(mrdata);
+
VertexBuffer *vbo = VertexBuffer_create_with_format(&format);
+ VertexBuffer_allocate_data(vbo, poly_ct);
- const int edge_ct = mesh_render_get_num_edges(me);
- const int tessface_ct = mesh_render_get_num_faces(me);
- const MVert *verts = mesh_render_get_array_vert(me);
- const MEdge *edges = mesh_render_get_array_edge(me);
- const MFace *tessfaces = mesh_render_get_array_face(me);
+ for (int i = 0; i < poly_ct; ++i) {
+ float pcenter[3], pnor[3];
+ int selected = 0;
- VertexBuffer_allocate_data(vbo, tessface_ct * 6); /* up to 2 triangles per tessface */
+ mesh_render_data_pnors_pcenter_select_get(mrdata, i, pnor, pcenter, (bool *)&selected);
- int gpu_vert_idx = 0;
- for (int i = 0; i < tessface_ct; ++i) {
- const MFace *tess = tessfaces + i;
- add_overlay_tri(vbo, pos_id, edgeMod_id, verts, edges, edge_ct, tess->v1, tess->v2, tess->v3, gpu_vert_idx);
- gpu_vert_idx += 3;
- /* tessface can be triangle or quad */
- if (tess->v4) {
- add_overlay_tri(vbo, pos_id, edgeMod_id, verts, edges, edge_ct, tess->v3, tess->v2, tess->v4, gpu_vert_idx);
- gpu_vert_idx += 3;
- }
- }
+#if USE_10_10_10
+ PackedNormal nor = { .x = 0, .y = 0, .z = -511 };
+ nor = convert_i10_v3(pnor);
+ nor.w = selected;
+ setAttrib(vbo, data_id, i, &nor);
+#else
+ float nor[4] = {pnor[0], pnor[1], pnor[2], (float)selected};
+ setAttrib(vbo, data_id, i, nor);
+#endif
- /* in some cases all the faces are quad, so no need to reallocate */
- if (vbo->vertex_ct != gpu_vert_idx) {
- VertexBuffer_resize_data(vbo, gpu_vert_idx);
+ setAttrib(vbo, pos_id, i, pcenter);
}
- cache->overlay_edges = Batch_create(GL_TRIANGLES, vbo, NULL);
+ cache->overlay_facedots = Batch_create(GL_POINTS, vbo, NULL);
+
+ mesh_render_data_free(mrdata);
}
- return cache->overlay_edges;
+ return cache->overlay_facedots;
}
#undef MESH_RENDER_FUNCTION
diff --git a/source/blender/blenkernel/intern/object.c b/source/blender/blenkernel/intern/object.c
index c0540192422..0dbc8f27632 100644
--- a/source/blender/blenkernel/intern/object.c
+++ b/source/blender/blenkernel/intern/object.c
@@ -119,6 +119,8 @@
#include "BKE_camera.h"
#include "BKE_image.h"
+#include "DRW_engine.h"
+
#ifdef WITH_MOD_FLUID
#include "LBM_fluidsim.h"
#endif
@@ -129,7 +131,7 @@
#include "CCGSubSurf.h"
-#include "GPU_material.h"
+#include "GPU_lamp.h"
/* Vertex parent modifies original BMesh which is not safe for threading.
* Ideally such a modification should be handled as a separate DAG update
@@ -443,6 +445,8 @@ void BKE_object_free(Object *ob)
}
GPU_lamp_free(ob);
+ DRW_object_engine_data_free(ob);
+
BKE_sculptsession_free(ob);
BLI_freelistN(&ob->pc_ids);
@@ -460,10 +464,8 @@ void BKE_object_free(Object *ob)
BKE_previewimg_free(&ob->preview);
- if (ob->collection_settings) {
- BKE_layer_collection_engine_settings_free(ob->collection_settings);
- MEM_freeN(ob->collection_settings);
- }
+ /* don't free, let the base free it */
+ ob->base_collection_properties = NULL;
}
/* actual check for internal data, not context or flags */
@@ -695,6 +697,14 @@ Object *BKE_object_add(
ob->data = BKE_object_obdata_add_from_type(bmain, type, name);
lc = BKE_layer_collection_active(sl);
+
+ if (lc == NULL) {
+ BLI_assert(BLI_listbase_count_ex(&sl->layer_collections, 1) == 0);
+ /* when there is no collection linked to this SceneLayer, create one */
+ SceneCollection *sc = BKE_collection_add(scene, NULL, NULL);
+ lc = BKE_collection_link(sl, sc);
+ }
+
BKE_collection_object_add(scene, lc->scene_collection, ob);
base = BKE_scene_layer_base_find(sl, ob);
@@ -796,9 +806,9 @@ static LodLevel *lod_level_select(Object *ob, const float camera_position[3])
return current;
}
-bool BKE_object_lod_is_usable(Object *ob, Scene *scene)
+bool BKE_object_lod_is_usable(Object *ob, SceneLayer *sl)
{
- bool active = (scene) ? ob == OBACT : false;
+ bool active = (sl) ? ob == OBACT_NEW : false;
return (ob->mode == OB_MODE_OBJECT || !active);
}
@@ -812,11 +822,11 @@ void BKE_object_lod_update(Object *ob, const float camera_position[3])
}
}
-static Object *lod_ob_get(Object *ob, Scene *scene, int flag)
+static Object *lod_ob_get(Object *ob, SceneLayer *sl, int flag)
{
LodLevel *current = ob->currentlod;
- if (!current || !BKE_object_lod_is_usable(ob, scene))
+ if (!current || !BKE_object_lod_is_usable(ob, sl))
return ob;
while (current->prev && (!(current->flags & flag) || !current->source || current->source->type != OB_MESH)) {
@@ -826,14 +836,14 @@ static Object *lod_ob_get(Object *ob, Scene *scene, int flag)
return current->source;
}
-struct Object *BKE_object_lod_meshob_get(Object *ob, Scene *scene)
+struct Object *BKE_object_lod_meshob_get(Object *ob, SceneLayer *sl)
{
- return lod_ob_get(ob, scene, OB_LOD_USE_MESH);
+ return lod_ob_get(ob, sl, OB_LOD_USE_MESH);
}
-struct Object *BKE_object_lod_matob_get(Object *ob, Scene *scene)
+struct Object *BKE_object_lod_matob_get(Object *ob, SceneLayer *sl)
{
- return lod_ob_get(ob, scene, OB_LOD_USE_MAT);
+ return lod_ob_get(ob, sl, OB_LOD_USE_MAT);
}
#endif /* WITH_GAMEENGINE */
@@ -1171,6 +1181,7 @@ Object *BKE_object_copy_ex(Main *bmain, Object *ob, bool copy_caches)
BLI_listbase_clear(&obn->gpulamp);
BLI_listbase_clear(&obn->pc_ids);
+ BLI_listbase_clear(&obn->drawdata);
obn->mpath = NULL;
@@ -2244,66 +2255,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;
@@ -2547,14 +2498,14 @@ void BKE_object_foreach_display_point(
}
void BKE_scene_foreach_display_point(
- Scene *scene, View3D *v3d, const short flag,
+ Scene *scene, SceneLayer *sl,
void (*func_cb)(const float[3], void *), void *user_data)
{
- BaseLegacy *base;
+ Base *base;
Object *ob;
- for (base = FIRSTBASE; base; base = base->next) {
- if (BASE_VISIBLE_BGMODE(v3d, scene, base) && (base->flag_legacy & flag) == flag) {
+ for (base = FIRSTBASE_NEW; base; base = base->next) {
+ if (((base->flag & BASE_VISIBLED) != 0) && ((base->flag & BASE_SELECTED) != 0)) {
ob = base->object;
if ((ob->transflag & OB_DUPLI) == 0) {
@@ -3349,33 +3300,33 @@ static void obrel_list_add(LinkNode **links, Object *ob)
}
/*
- * Iterates over all objects of the given scene.
+ * Iterates over all objects of the given scene layer.
* Depending on the eObjectSet flag:
* collect either OB_SET_ALL, OB_SET_VISIBLE or OB_SET_SELECTED objects.
* If OB_SET_VISIBLE or OB_SET_SELECTED are collected,
* then also add related objects according to the given includeFilters.
*/
-LinkNode *BKE_object_relational_superset(struct Scene *scene, eObjectSet objectSet, eObRelationTypes includeFilter)
+LinkNode *BKE_object_relational_superset(struct SceneLayer *scene_layer, eObjectSet objectSet, eObRelationTypes includeFilter)
{
LinkNode *links = NULL;
- BaseLegacy *base;
+ Base *base;
/* Remove markers from all objects */
- for (base = scene->base.first; base; base = base->next) {
+ for (base = scene_layer->object_bases.first; base; base = base->next) {
base->object->id.tag &= ~LIB_TAG_DOIT;
}
/* iterate over all selected and visible objects */
- for (base = scene->base.first; base; base = base->next) {
+ for (base = scene_layer->object_bases.first; base; base = base->next) {
if (objectSet == OB_SET_ALL) {
/* as we get all anyways just add it */
Object *ob = base->object;
obrel_list_add(&links, ob);
}
else {
- if ((objectSet == OB_SET_SELECTED && TESTBASELIB_BGMODE(((View3D *)NULL), scene, base)) ||
- (objectSet == OB_SET_VISIBLE && BASE_EDITABLE_BGMODE(((View3D *)NULL), scene, base)))
+ if ((objectSet == OB_SET_SELECTED && TESTBASELIB_BGMODE_NEW(base)) ||
+ (objectSet == OB_SET_VISIBLE && BASE_EDITABLE_BGMODE_NEW(base)))
{
Object *ob = base->object;
@@ -3403,9 +3354,9 @@ LinkNode *BKE_object_relational_superset(struct Scene *scene, eObjectSet objectS
/* child relationship */
if (includeFilter & (OB_REL_CHILDREN | OB_REL_CHILDREN_RECURSIVE)) {
- BaseLegacy *local_base;
- for (local_base = scene->base.first; local_base; local_base = local_base->next) {
- if (BASE_EDITABLE_BGMODE(((View3D *)NULL), scene, local_base)) {
+ Base *local_base;
+ for (local_base = scene_layer->object_bases.first; local_base; local_base = local_base->next) {
+ if (BASE_EDITABLE_BGMODE_NEW(local_base)) {
Object *child = local_base->object;
if (obrel_list_test(child)) {
diff --git a/source/blender/blenkernel/intern/object_update.c b/source/blender/blenkernel/intern/object_update.c
index 46e6d09294d..c85a91cad68 100644
--- a/source/blender/blenkernel/intern/object_update.c
+++ b/source/blender/blenkernel/intern/object_update.c
@@ -55,6 +55,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"
@@ -342,13 +343,15 @@ void BKE_object_eval_uber_data(EvaluationContext *eval_ctx,
BLI_assert(ob->type != OB_ARMATURE);
BKE_object_handle_data_update(eval_ctx, scene, ob);
+ if (ob->type == OB_MESH) {
+ BKE_mesh_batch_cache_dirty(ob->data);
+ }
+
ob->recalc &= ~(OB_RECALC_DATA | OB_RECALC_TIME);
}
-void BKE_object_eval_shading(EvaluationContext *UNUSED(eval_ctx), Object *ob)
+void BKE_object_eval_cloth(EvaluationContext *UNUSED(eval_ctx), Scene *scene, Object *object)
{
- DEBUG_PRINT("%s on %s\n", __func__, ob->id.name);
- if (ob->type == OB_MESH) {
- BKE_mesh_batch_cache_dirty(ob->data);
- }
+ 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/outliner_treehash.c b/source/blender/blenkernel/intern/outliner_treehash.c
index f31ba34a984..3e99dbe37ca 100644
--- a/source/blender/blenkernel/intern/outliner_treehash.c
+++ b/source/blender/blenkernel/intern/outliner_treehash.c
@@ -27,6 +27,7 @@
*/
#include <stdlib.h>
+#include <string.h>
#include "BKE_outliner_treehash.h"
@@ -56,7 +57,7 @@ static TseGroup *tse_group_create(void)
return tse_group;
}
-static void tse_group_add(TseGroup *tse_group, TreeStoreElem *elem)
+static void tse_group_add_element(TseGroup *tse_group, TreeStoreElem *elem)
{
if (UNLIKELY(tse_group->size == tse_group->allocated)) {
tse_group->allocated *= 2;
@@ -66,6 +67,26 @@ static void tse_group_add(TseGroup *tse_group, TreeStoreElem *elem)
tse_group->size++;
}
+static void tse_group_remove_element(TseGroup *tse_group, TreeStoreElem *elem)
+{
+ int min_allocated = MAX2(1, tse_group->allocated / 2);
+ BLI_assert(tse_group->allocated == 1 || (tse_group->allocated % 2) == 0);
+
+ tse_group->size--;
+ BLI_assert(tse_group->size >= 0);
+ for (int i = 0; i < tse_group->size; i++) {
+ if (tse_group->elems[i] == elem) {
+ memcpy(tse_group->elems[i], tse_group->elems[i + 1], (tse_group->size - (i + 1)) * sizeof(TreeStoreElem *));
+ break;
+ }
+ }
+
+ if (UNLIKELY(tse_group->size > 0 && tse_group->size <= min_allocated)) {
+ tse_group->allocated = min_allocated;
+ tse_group->elems = MEM_reallocN(tse_group->elems, sizeof(TreeStoreElem *) * tse_group->allocated);
+ }
+}
+
static void tse_group_free(TseGroup *tse_group)
{
MEM_freeN(tse_group->elems);
@@ -140,7 +161,21 @@ void BKE_outliner_treehash_add_element(void *treehash, TreeStoreElem *elem)
*val_p = tse_group_create();
}
group = *val_p;
- tse_group_add(group, elem);
+ tse_group_add_element(group, elem);
+}
+
+void BKE_outliner_treehash_remove_element(void *treehash, TreeStoreElem *elem)
+{
+ TseGroup *group = BLI_ghash_lookup(treehash, elem);
+
+ BLI_assert(group != NULL);
+ if (group->size <= 1) {
+ /* one element -> remove group completely */
+ BLI_ghash_remove(treehash, elem, NULL, free_treehash_group);
+ }
+ else {
+ tse_group_remove_element(group, elem);
+ }
}
static TseGroup *BKE_outliner_treehash_lookup_group(GHash *th, short type, short nr, struct ID *id)
diff --git a/source/blender/blenkernel/intern/paint.c b/source/blender/blenkernel/intern/paint.c
index 6b954f060d3..ff29c1c3895 100644
--- a/source/blender/blenkernel/intern/paint.c
+++ b/source/blender/blenkernel/intern/paint.c
@@ -73,9 +73,9 @@ const char PAINT_CURSOR_TEXTURE_PAINT[3] = {255, 255, 255};
static OverlayControlFlags overlay_flags = 0;
-void BKE_paint_invalidate_overlay_tex(Scene *scene, const Tex *tex)
+void BKE_paint_invalidate_overlay_tex(Scene *scene, SceneLayer *sl, const Tex *tex)
{
- Paint *p = BKE_paint_get_active(scene);
+ Paint *p = BKE_paint_get_active(scene, sl);
Brush *br = p->brush;
if (!br)
@@ -87,9 +87,9 @@ void BKE_paint_invalidate_overlay_tex(Scene *scene, const Tex *tex)
overlay_flags |= PAINT_INVALID_OVERLAY_TEXTURE_SECONDARY;
}
-void BKE_paint_invalidate_cursor_overlay(Scene *scene, CurveMapping *curve)
+void BKE_paint_invalidate_cursor_overlay(Scene *scene, SceneLayer *sl, CurveMapping *curve)
{
- Paint *p = BKE_paint_get_active(scene);
+ Paint *p = BKE_paint_get_active(scene, sl);
Brush *br = p->brush;
if (br && br->curve == curve)
@@ -155,13 +155,13 @@ Paint *BKE_paint_get_active_from_paintmode(Scene *sce, PaintMode mode)
return NULL;
}
-Paint *BKE_paint_get_active(Scene *sce)
+Paint *BKE_paint_get_active(Scene *sce, SceneLayer *sl)
{
- if (sce) {
+ if (sce && sl) {
ToolSettings *ts = sce->toolsettings;
- if (sce->basact && sce->basact->object) {
- switch (sce->basact->object->mode) {
+ if (sl->basact && sl->basact->object) {
+ switch (sl->basact->object->mode) {
case OB_MODE_SCULPT:
return &ts->sculpt->paint;
case OB_MODE_VERTEX_PAINT:
@@ -187,14 +187,15 @@ Paint *BKE_paint_get_active(Scene *sce)
Paint *BKE_paint_get_active_from_context(const bContext *C)
{
Scene *sce = CTX_data_scene(C);
+ SceneLayer *sl = CTX_data_scene_layer(C);
SpaceImage *sima;
- if (sce) {
+ if (sce && sl) {
ToolSettings *ts = sce->toolsettings;
Object *obact = NULL;
- if (sce->basact && sce->basact->object)
- obact = sce->basact->object;
+ if (sl->basact && sl->basact->object)
+ obact = sl->basact->object;
if ((sima = CTX_wm_space_image(C)) != NULL) {
if (obact && obact->mode == OB_MODE_EDIT) {
@@ -237,14 +238,15 @@ Paint *BKE_paint_get_active_from_context(const bContext *C)
PaintMode BKE_paintmode_get_active_from_context(const bContext *C)
{
Scene *sce = CTX_data_scene(C);
+ SceneLayer *sl = CTX_data_scene_layer(C);
SpaceImage *sima;
- if (sce) {
+ if (sce && sl) {
ToolSettings *ts = sce->toolsettings;
Object *obact = NULL;
- if (sce->basact && sce->basact->object)
- obact = sce->basact->object;
+ if (sl->basact && sl->basact->object)
+ obact = sl->basact->object;
if ((sima = CTX_wm_space_image(C)) != NULL) {
if (obact && obact->mode == OB_MODE_EDIT) {
diff --git a/source/blender/blenkernel/intern/pbvh.c b/source/blender/blenkernel/intern/pbvh.c
index 4fe4d6e75a6..b0f9875eaac 100644
--- a/source/blender/blenkernel/intern/pbvh.c
+++ b/source/blender/blenkernel/intern/pbvh.c
@@ -40,6 +40,7 @@
#include "BKE_paint.h"
#include "GPU_buffers.h"
+#include "GPU_immediate.h"
#include "bmesh.h"
@@ -1156,15 +1157,16 @@ static void pbvh_update_draw_buffers(PBVH *bvh, PBVHNode **nodes, int totnode)
static void pbvh_draw_BB(PBVH *bvh)
{
- GPU_init_draw_pbvh_BB();
+ unsigned int pos = add_attrib(immVertexFormat(), "pos", COMP_F32, 3, KEEP_FLOAT);
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
for (int a = 0; a < bvh->totnode; a++) {
PBVHNode *node = &bvh->nodes[a];
- GPU_draw_pbvh_BB(node->vb.bmin, node->vb.bmax, ((node->flag & PBVH_Leaf) != 0));
+ GPU_draw_pbvh_BB(node->vb.bmin, node->vb.bmax, ((node->flag & PBVH_Leaf) != 0), pos);
}
- GPU_end_draw_pbvh_BB();
+ immUnbindProgram();
}
static int pbvh_flush_bb(PBVH *bvh, PBVHNode *node, int flag)
@@ -1737,24 +1739,6 @@ void BKE_pbvh_node_draw(PBVHNode *node, void *data_v)
{
PBVHNodeDrawData *data = data_v;
-#if 0
- /* XXX: Just some quick code to show leaf nodes in different colors */
- float col[3];
- float spec[3] = {0.0f, 0.0f, 0.0f};
-
- if (0) { //is_partial) {
- col[0] = (rand() / (float)RAND_MAX); col[1] = col[2] = 0.6;
- }
- else {
- srand((long long)node);
- for (int i = 0; i < 3; ++i)
- col[i] = (rand() / (float)RAND_MAX) * 0.3 + 0.7;
- }
-
- GPU_basic_shader_colors(col, spec, 0, 1.0f);
- glColor3f(1, 0, 0);
-#endif
-
if (!(node->flag & PBVH_FullyHidden)) {
GPU_draw_pbvh_buffers(node->draw_buffers,
data->setMaterial,
diff --git a/source/blender/blenkernel/intern/pointcache.c b/source/blender/blenkernel/intern/pointcache.c
index c3f2107c5af..30eb8dcb287 100644
--- a/source/blender/blenkernel/intern/pointcache.c
+++ b/source/blender/blenkernel/intern/pointcache.c
@@ -3541,7 +3541,7 @@ void BKE_ptcache_bake(PTCacheBaker *baker)
Main *bmain = baker->main;
Scene *scene = baker->scene;
Scene *sce_iter; /* SETLOOPER macro only */
- BaseLegacy *base;
+ Base *base;
ListBase pidlist;
PTCacheID *pid = &baker->pid;
PointCache *cache = NULL;
diff --git a/source/blender/blenkernel/intern/scene.c b/source/blender/blenkernel/intern/scene.c
index dc81dac134b..f8a91f63727 100644
--- a/source/blender/blenkernel/intern/scene.c
+++ b/source/blender/blenkernel/intern/scene.c
@@ -330,6 +330,9 @@ Scene *BKE_scene_copy(Main *bmain, Scene *sce, int type)
}
new_sl = new_sl->next;
}
+
+ IDPropertyTemplate val = {0};
+ scen->collection_properties = IDP_New(IDP_GROUP, &val, ROOT_PROP);
}
/* copy color management settings */
@@ -443,6 +446,12 @@ Scene *BKE_scene_copy(Main *bmain, Scene *sce, int type)
BKE_previewimg_id_copy(&scen->id, &sce->id);
+ if (type != SCE_COPY_NEW) {
+ if (sce->collection_properties) {
+ IDP_MergeGroup(scen->collection_properties, sce->collection_properties, true);
+ }
+ }
+
return scen;
}
@@ -569,11 +578,11 @@ void BKE_scene_free(Scene *sce)
sce->collection = NULL;
/* Runtime Engine Data */
- for (RenderEngineSettings *res = sce->engines_settings.first; res; res = res->next) {
- if (res->data)
- MEM_freeN(res->data);
+ if (sce->collection_properties) {
+ IDP_FreeProperty(sce->collection_properties);
+ MEM_freeN(sce->collection_properties);
+ sce->collection_properties = NULL;
}
- BLI_freelistN(&sce->engines_settings);
}
void BKE_scene_init(Scene *sce)
@@ -928,6 +937,10 @@ void BKE_scene_init(Scene *sce)
sce->collection = MEM_callocN(sizeof(SceneCollection), "Master Collection");
BLI_strncpy(sce->collection->name, "Master Collection", sizeof(sce->collection->name));
+ IDPropertyTemplate val = {0};
+ sce->collection_properties = IDP_New(IDP_GROUP, &val, ROOT_PROP);
+ BKE_layer_collection_engine_settings_create(sce->collection_properties);
+
BKE_scene_layer_add(sce, "Render Layer");
}
@@ -1152,6 +1165,19 @@ int BKE_scene_base_iter_next(EvaluationContext *eval_ctx, SceneBaseIter *iter,
return iter->phase;
}
+Scene *BKE_scene_find_from_collection(const Main *bmain, const SceneCollection *scene_collection)
+{
+ for (Scene *scene = bmain->scene.first; scene; scene = scene->id.next) {
+ for (SceneLayer *layer = scene->render_layers.first; layer; layer = layer->next) {
+ if (BKE_scene_layer_has_collection(layer, scene_collection)) {
+ return scene;
+ }
+ }
+ }
+
+ return NULL;
+}
+
Object *BKE_scene_camera_find(Scene *sc)
{
BaseLegacy *base;
@@ -1688,21 +1714,37 @@ float get_render_aosss_error(const RenderData *r, float error)
return error;
}
-/* helper function for the SETLOOPER macro */
-BaseLegacy *_setlooper_base_step(Scene **sce_iter, BaseLegacy *base)
+/**
+ * Helper function for the SETLOOPER macro
+ *
+ * It iterates over the bases of the active layer and then the bases
+ * of the active layer of the background (set) scenes recursively.
+ */
+Base *_setlooper_base_step(Scene **sce_iter, Base *base)
{
if (base && base->next) {
/* common case, step to the next */
return base->next;
}
- else if (base == NULL && (*sce_iter)->base.first) {
+ else if (base == NULL) {
/* first time looping, return the scenes first base */
- return (BaseLegacy *)(*sce_iter)->base.first;
+
+ /* for the first loop we should get the layer from context */
+ SceneLayer *sl = BKE_scene_layer_context_active((*sce_iter));
+
+ if (sl->object_bases.first) {
+ return (Base *)sl->object_bases.first;
+ }
+ /* no base on this scene layer */
+ goto next_set;
}
else {
+next_set:
/* reached the end, get the next base in the set */
while ((*sce_iter = (*sce_iter)->set)) {
- base = (BaseLegacy *)(*sce_iter)->base.first;
+ SceneLayer *sl = BKE_scene_layer_render_active((*sce_iter));
+ base = (Base *)sl->object_bases.first;
+
if (base) {
return base;
}
diff --git a/source/blender/blenkernel/intern/sequencer.c b/source/blender/blenkernel/intern/sequencer.c
index 6a491ba5ec4..69454744dc6 100644
--- a/source/blender/blenkernel/intern/sequencer.c
+++ b/source/blender/blenkernel/intern/sequencer.c
@@ -66,6 +66,7 @@
#include "BKE_depsgraph.h"
#include "BKE_global.h"
#include "BKE_image.h"
+#include "BKE_layer.h"
#include "BKE_main.h"
#include "BKE_sequencer.h"
#include "BKE_movieclip.h"
@@ -514,7 +515,7 @@ void BKE_sequencer_imbuf_to_sequencer_space(Scene *scene, ImBuf *ibuf, bool make
* artifacts which will then not happen in final render.
*/
IMB_colormanagement_transform_byte_threaded(
- (unsigned char*)ibuf->rect, ibuf->x, ibuf->y, ibuf->channels,
+ (unsigned char *)ibuf->rect, ibuf->x, ibuf->y, ibuf->channels,
from_colorspace, to_colorspace);
}
else {
@@ -523,7 +524,7 @@ void BKE_sequencer_imbuf_to_sequencer_space(Scene *scene, ImBuf *ibuf, bool make
*/
imb_addrectfloatImBuf(ibuf);
IMB_colormanagement_transform_from_byte_threaded(
- ibuf->rect_float, (unsigned char*)ibuf->rect,
+ ibuf->rect_float, (unsigned char *)ibuf->rect,
ibuf->x, ibuf->y, ibuf->channels,
from_colorspace, to_colorspace);
/* We don't need byte buffer anymore. */
@@ -3304,7 +3305,7 @@ static ImBuf *seq_render_scene_strip(const SeqRenderData *context, Sequence *seq
BKE_scene_update_for_newframe(context->eval_ctx, context->bmain, scene, scene->lay);
ibuf = sequencer_view3d_cb(
/* set for OpenGL render (NULL when scrubbing) */
- scene, camera, width, height, IB_rect,
+ scene, BKE_scene_layer_render_active(scene), camera, width, height, IB_rect,
context->scene->r.seq_prev_type,
(context->scene->r.seq_flag & R_SEQ_SOLID_TEX) != 0,
use_gpencil, use_background, scene->r.alphamode,
diff --git a/source/blender/blenkernel/intern/sound.c b/source/blender/blenkernel/intern/sound.c
index fe4bcc738c6..8469351c54a 100644
--- a/source/blender/blenkernel/intern/sound.c
+++ b/source/blender/blenkernel/intern/sound.c
@@ -782,7 +782,7 @@ void BKE_sound_read_waveform(bSound *sound, short *stop)
void BKE_sound_update_scene(Main *bmain, struct Scene *scene)
{
Object *ob;
- BaseLegacy *base;
+ Base *base;
NlaTrack *track;
NlaStrip *strip;
Speaker *speaker;
diff --git a/source/blender/blenkernel/intern/subsurf_ccg.c b/source/blender/blenkernel/intern/subsurf_ccg.c
index c4665c40ec4..9a06fa9e848 100644
--- a/source/blender/blenkernel/intern/subsurf_ccg.c
+++ b/source/blender/blenkernel/intern/subsurf_ccg.c
@@ -3634,36 +3634,6 @@ static void ccgDM_drawMappedFacesTex(DerivedMesh *dm,
ccgDM_drawFacesTex_common(dm, NULL, setDrawOptions, compareDrawOptions, userData, flag);
}
-/* same as cdDM_drawUVEdges */
-static void ccgDM_drawUVEdges(DerivedMesh *dm)
-{
- MPoly *mpoly = dm->getPolyArray(dm);
- int totpoly = dm->getNumPolys(dm);
- int prevstart = 0;
- bool prevdraw = true;
- int curpos = 0;
- int i;
-
- GPU_uvedge_setup(dm);
- for (i = 0; i < totpoly; i++, mpoly++) {
- const bool draw = (mpoly->flag & ME_HIDE) == 0;
-
- if (prevdraw != draw) {
- if (prevdraw && (curpos != prevstart)) {
- glDrawArrays(GL_LINES, prevstart, curpos - prevstart);
- }
- prevstart = curpos;
- }
-
- curpos += 2 * mpoly->totloop;
- prevdraw = draw;
- }
- if (prevdraw && (curpos != prevstart)) {
- glDrawArrays(GL_LINES, prevstart, curpos - prevstart);
- }
- GPU_buffers_unbind();
-}
-
static void ccgDM_drawMappedFaces(DerivedMesh *dm,
DMSetDrawOptions setDrawOptions,
DMSetMaterial setMaterial,
@@ -4589,7 +4559,6 @@ static void set_default_ccgdm_callbacks(CCGDerivedMesh *ccgdm)
ccgdm->dm.drawMappedFacesTex = ccgDM_drawMappedFacesTex;
ccgdm->dm.drawMappedFacesGLSL = ccgDM_drawMappedFacesGLSL;
ccgdm->dm.drawMappedFacesMat = ccgDM_drawMappedFacesMat;
- ccgdm->dm.drawUVEdges = ccgDM_drawUVEdges;
ccgdm->dm.drawMappedEdgesInterp = ccgDM_drawMappedEdgesInterp;
ccgdm->dm.drawMappedEdges = ccgDM_drawMappedEdges;
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;