diff options
Diffstat (limited to 'source/blender/blenkernel/intern')
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, ¶ms, &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(¶ms, &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; |