diff options
author | Sergey Sharybin <sergey.vfx@gmail.com> | 2015-06-08 15:20:07 +0300 |
---|---|---|
committer | Sergey Sharybin <sergey.vfx@gmail.com> | 2015-06-08 15:20:07 +0300 |
commit | f1cd1e650354dd9096cd35914234441047cc393b (patch) | |
tree | 0c0ec8c9d269a8485eba3e8e46c5116c9a0f17d9 /source/blender/blenkernel/intern | |
parent | 8b9d1818a57f538ec1c629ce94871351601ffa4c (diff) | |
parent | 303c91209311cade10edf1678900e2d1ba812ffb (diff) |
Merge branch 'master' into cycles_memory_experiments
Conflicts:
intern/cycles/blender/blender_object.cpp
intern/cycles/blender/blender_sync.h
intern/cycles/render/graph.h
intern/cycles/render/mesh.cpp
Diffstat (limited to 'source/blender/blenkernel/intern')
64 files changed, 3796 insertions, 1526 deletions
diff --git a/source/blender/blenkernel/intern/DerivedMesh.c b/source/blender/blenkernel/intern/DerivedMesh.c index 38ae0461c84..d850dd3ee26 100644 --- a/source/blender/blenkernel/intern/DerivedMesh.c +++ b/source/blender/blenkernel/intern/DerivedMesh.c @@ -295,11 +295,11 @@ void DM_init(DerivedMesh *dm, DerivedMeshType type, int numVerts, int numEdges, dm->dirty = 0; /* don't use CustomData_reset(...); because we dont want to touch customdata */ - fill_vn_i(dm->vertData.typemap, CD_NUMTYPES, -1); - fill_vn_i(dm->edgeData.typemap, CD_NUMTYPES, -1); - fill_vn_i(dm->faceData.typemap, CD_NUMTYPES, -1); - fill_vn_i(dm->loopData.typemap, CD_NUMTYPES, -1); - fill_vn_i(dm->polyData.typemap, CD_NUMTYPES, -1); + copy_vn_i(dm->vertData.typemap, CD_NUMTYPES, -1); + copy_vn_i(dm->edgeData.typemap, CD_NUMTYPES, -1); + copy_vn_i(dm->faceData.typemap, CD_NUMTYPES, -1); + copy_vn_i(dm->loopData.typemap, CD_NUMTYPES, -1); + copy_vn_i(dm->polyData.typemap, CD_NUMTYPES, -1); } void DM_from_template(DerivedMesh *dm, DerivedMesh *source, DerivedMeshType type, @@ -1276,7 +1276,7 @@ static void calc_weightpaint_vert_array(Object *ob, DerivedMesh *dm, int const d else { weightpaint_color(col, dm_wcinfo, 0.0f); } - fill_vn_i((int *)r_wtcol_v, numVerts, *((int *)col)); + copy_vn_i((int *)r_wtcol_v, numVerts, *((int *)col)); } } @@ -2292,13 +2292,8 @@ static void editbmesh_calc_modifiers(Scene *scene, Object *ob, BMEditMesh *em, D } static void mesh_build_data(Scene *scene, Object *ob, CustomDataMask dataMask, - int build_shapekey_layers) + int build_shapekey_layers, int needMapping) { - Object *obact = scene->basact ? scene->basact->object : NULL; - bool editing = BKE_paint_select_face_test(ob); - /* weight paint and face select need original indices because of selection buffer drawing */ - int needMapping = (ob == obact) && (editing || (ob->mode & (OB_MODE_WEIGHT_PAINT | OB_MODE_VERTEX_PAINT | OB_MODE_TEXTURE_PAINT))); - BLI_assert(ob->type == OB_MESH); BKE_object_free_derived_caches(ob); @@ -2313,6 +2308,7 @@ static void mesh_build_data(Scene *scene, Object *ob, CustomDataMask dataMask, ob->derivedFinal->needsFree = 0; ob->derivedDeform->needsFree = 0; ob->lastDataMask = dataMask; + ob->lastNeedMapping = needMapping; if ((ob->mode & OB_MODE_SCULPT) && ob->sculpt) { /* create PBVH immediately (would be created on the fly too, @@ -2341,14 +2337,23 @@ static void editbmesh_build_data(Scene *scene, Object *obedit, BMEditMesh *em, C BLI_assert(!(em->derivedFinal->dirty & DM_DIRTY_NORMALS)); } -static CustomDataMask object_get_datamask(const Scene *scene, Object *ob) +static CustomDataMask object_get_datamask(const Scene *scene, Object *ob, int *r_needmapping) { Object *actob = scene->basact ? scene->basact->object : NULL; CustomDataMask mask = ob->customdata_mask; + bool editing = BKE_paint_select_face_test(ob); + + if (r_needmapping) + *r_needmapping = 0; if (ob == actob) { + + /* weight paint and face select need original indices because of selection buffer drawing */ + if (r_needmapping) + *r_needmapping = (editing || (ob->mode & (OB_MODE_WEIGHT_PAINT | OB_MODE_VERTEX_PAINT))); + /* check if we need tfaces & mcols due to face select or texture paint */ - if ((ob->mode & OB_MODE_TEXTURE_PAINT) || BKE_paint_select_face_test(ob)) { + if ((ob->mode & OB_MODE_TEXTURE_PAINT) || editing) { mask |= CD_MASK_MTFACE | CD_MASK_MCOL; } @@ -2371,13 +2376,14 @@ static CustomDataMask object_get_datamask(const Scene *scene, Object *ob) void makeDerivedMesh(Scene *scene, Object *ob, BMEditMesh *em, CustomDataMask dataMask, int build_shapekey_layers) { - dataMask |= object_get_datamask(scene, ob); + int needMapping; + dataMask |= object_get_datamask(scene, ob, &needMapping); if (em) { editbmesh_build_data(scene, ob, em, dataMask); } else { - mesh_build_data(scene, ob, dataMask, build_shapekey_layers); + mesh_build_data(scene, ob, dataMask, build_shapekey_layers, needMapping); } } @@ -2388,10 +2394,11 @@ DerivedMesh *mesh_get_derived_final(Scene *scene, Object *ob, CustomDataMask dat /* if there's no derived mesh or the last data mask used doesn't include * the data we need, rebuild the derived mesh */ - dataMask |= object_get_datamask(scene, ob); + int needMapping; + dataMask |= object_get_datamask(scene, ob, &needMapping); - if (!ob->derivedFinal || (dataMask & ob->lastDataMask) != dataMask) - mesh_build_data(scene, ob, dataMask, 0); + if (!ob->derivedFinal || (dataMask & ob->lastDataMask) != dataMask || (needMapping != ob->lastNeedMapping)) + mesh_build_data(scene, ob, dataMask, 0, needMapping); if (ob->derivedFinal) { BLI_assert(!(ob->derivedFinal->dirty & DM_DIRTY_NORMALS)); } return ob->derivedFinal; @@ -2402,10 +2409,12 @@ DerivedMesh *mesh_get_derived_deform(Scene *scene, Object *ob, CustomDataMask da /* if there's no derived mesh or the last data mask used doesn't include * the data we need, rebuild the derived mesh */ - dataMask |= object_get_datamask(scene, ob); + int needmapping; + + dataMask |= object_get_datamask(scene, ob, &needmapping); - if (!ob->derivedDeform || (dataMask & ob->lastDataMask) != dataMask) - mesh_build_data(scene, ob, dataMask, 0); + if (!ob->derivedDeform || (dataMask & ob->lastDataMask) != dataMask || (needmapping != ob->lastNeedMapping)) + mesh_build_data(scene, ob, dataMask, 0, needmapping); return ob->derivedDeform; } @@ -2494,7 +2503,7 @@ DerivedMesh *editbmesh_get_derived_cage_and_final(Scene *scene, Object *obedit, /* if there's no derived mesh or the last data mask used doesn't include * the data we need, rebuild the derived mesh */ - dataMask |= object_get_datamask(scene, obedit); + dataMask |= object_get_datamask(scene, obedit, NULL); if (!em->derivedCage || (em->lastDataMask & dataMask) != dataMask) @@ -2512,7 +2521,7 @@ DerivedMesh *editbmesh_get_derived_cage(Scene *scene, Object *obedit, BMEditMesh /* if there's no derived mesh or the last data mask used doesn't include * the data we need, rebuild the derived mesh */ - dataMask |= object_get_datamask(scene, obedit); + dataMask |= object_get_datamask(scene, obedit, NULL); if (!em->derivedCage || (em->lastDataMask & dataMask) != dataMask) diff --git a/source/blender/blenkernel/intern/action.c b/source/blender/blenkernel/intern/action.c index 9ce198bd687..7e09ad355a7 100644 --- a/source/blender/blenkernel/intern/action.c +++ b/source/blender/blenkernel/intern/action.c @@ -54,6 +54,7 @@ #include "BKE_animsys.h" #include "BKE_constraint.h" #include "BKE_deform.h" +#include "BKE_depsgraph.h" #include "BKE_fcurve.h" #include "BKE_global.h" #include "BKE_idprop.h" @@ -1317,6 +1318,16 @@ bool BKE_pose_copy_result(bPose *to, bPose *from) return true; } +/* Tag pose for recalc. Also tag all related data to be recalc. */ +void BKE_pose_tag_recalc(Main *bmain, bPose *pose) +{ + pose->flag |= POSE_RECALC; + /* Depsgraph components depends on actual pose state, + * if pose was changed depsgraph is to be updated as well. + */ + DAG_relations_tag_update(bmain); +} + /* For the calculation of the effects of an Action at the given frame on an object * This is currently only used for the Action Constraint */ diff --git a/source/blender/blenkernel/intern/addon.c b/source/blender/blenkernel/intern/addon.c index 28667d458b8..811461b84c1 100644 --- a/source/blender/blenkernel/intern/addon.c +++ b/source/blender/blenkernel/intern/addon.c @@ -62,12 +62,12 @@ bAddonPrefType *BKE_addon_pref_type_find(const char *idname, bool quiet) void BKE_addon_pref_type_add(bAddonPrefType *apt) { - BLI_ghash_insert(global_addonpreftype_hash, (void *)apt->idname, apt); + BLI_ghash_insert(global_addonpreftype_hash, apt->idname, apt); } -void BKE_addon_pref_type_remove(bAddonPrefType *apt) +void BKE_addon_pref_type_remove(const bAddonPrefType *apt) { - BLI_ghash_remove(global_addonpreftype_hash, (void *)apt->idname, NULL, MEM_freeN); + BLI_ghash_remove(global_addonpreftype_hash, apt->idname, NULL, MEM_freeN); } void BKE_addon_pref_type_init(void) diff --git a/source/blender/blenkernel/intern/anim_sys.c b/source/blender/blenkernel/intern/anim_sys.c index 3c98d11dbdb..d5a8b8f857c 100644 --- a/source/blender/blenkernel/intern/anim_sys.c +++ b/source/blender/blenkernel/intern/anim_sys.c @@ -1620,7 +1620,7 @@ static bool animsys_write_rna_setting(PointerRNA *ptr, char *path, int array_ind } /* Simple replacement based data-setting of the FCurve using RNA */ -static bool animsys_execute_fcurve(PointerRNA *ptr, AnimMapper *remap, FCurve *fcu) +bool BKE_animsys_execute_fcurve(PointerRNA *ptr, AnimMapper *remap, FCurve *fcu) { char *path = NULL; bool free_path = false; @@ -1655,7 +1655,7 @@ static void animsys_evaluate_fcurves(PointerRNA *ptr, ListBase *list, AnimMapper /* check if this curve should be skipped */ if ((fcu->flag & (FCURVE_MUTED | FCURVE_DISABLED)) == 0) { calculate_fcurve(fcu, ctime); - animsys_execute_fcurve(ptr, remap, fcu); + BKE_animsys_execute_fcurve(ptr, remap, fcu); } } } @@ -1685,7 +1685,7 @@ static void animsys_evaluate_drivers(PointerRNA *ptr, AnimData *adt, float ctime * NOTE: for 'layering' option later on, we should check if we should remove old value before adding * new to only be done when drivers only changed */ calculate_fcurve(fcu, ctime); - ok = animsys_execute_fcurve(ptr, NULL, fcu); + ok = BKE_animsys_execute_fcurve(ptr, NULL, fcu); /* clear recalc flag */ driver->flag &= ~DRIVER_FLAG_RECALC; @@ -1754,7 +1754,7 @@ void animsys_evaluate_action_group(PointerRNA *ptr, bAction *act, bActionGroup * /* check if this curve should be skipped */ if ((fcu->flag & (FCURVE_MUTED | FCURVE_DISABLED)) == 0) { calculate_fcurve(fcu, ctime); - animsys_execute_fcurve(ptr, remap, fcu); + BKE_animsys_execute_fcurve(ptr, remap, fcu); } } } @@ -2846,3 +2846,62 @@ void BKE_animsys_evaluate_all_animation(Main *main, Scene *scene, float ctime) } /* ***************************************** */ + +/* ************** */ +/* Evaluation API */ + +#define DEBUG_PRINT if (G.debug & G_DEBUG_DEPSGRAPH) printf + +void BKE_animsys_eval_animdata(EvaluationContext *eval_ctx, ID *id) +{ + AnimData *adt = BKE_animdata_from_id(id); + Scene *scene = NULL; /* XXX: this is only needed for flushing RNA updates, + * which should get handled as part of the graph instead... + */ + DEBUG_PRINT("%s on %s, time=%f\n\n", __func__, id->name, (double)eval_ctx->ctime); + BKE_animsys_evaluate_animdata(scene, id, adt, eval_ctx->ctime, ADT_RECALC_ANIM); +} + +void BKE_animsys_eval_driver(EvaluationContext *eval_ctx, + ID *id, + FCurve *fcu) +{ + /* TODO(sergey): De-duplicate with BKE animsys. */ + ChannelDriver *driver = fcu->driver; + PointerRNA id_ptr; + bool ok = false; + + DEBUG_PRINT("%s on %s (%s[%d])\n", + __func__, + id->name, + fcu->rna_path, + fcu->array_index); + + RNA_id_pointer_create(id, &id_ptr); + + /* check if this driver's curve should be skipped */ + if ((fcu->flag & (FCURVE_MUTED | FCURVE_DISABLED)) == 0) { + /* check if driver itself is tagged for recalculation */ + /* XXX driver recalc flag is not set yet by depsgraph! */ + if ((driver) && !(driver->flag & DRIVER_FLAG_INVALID) /*&& (driver->flag & DRIVER_FLAG_RECALC)*/) { + /* evaluate this using values set already in other places + * NOTE: for 'layering' option later on, we should check if we should remove old value before adding + * new to only be done when drivers only changed */ + //printf("\told val = %f\n", fcu->curval); + calculate_fcurve(fcu, eval_ctx->ctime); + ok = BKE_animsys_execute_fcurve(&id_ptr, NULL, fcu); + //printf("\tnew val = %f\n", fcu->curval); + + /* clear recalc flag */ + driver->flag &= ~DRIVER_FLAG_RECALC; + + /* set error-flag if evaluation failed */ + if (ok == 0) { + printf("invalid driver - %s[%d]\n", fcu->rna_path, fcu->array_index); + driver->flag |= DRIVER_FLAG_INVALID; + } + } + } +} + +#undef DEBUG_PRINT diff --git a/source/blender/blenkernel/intern/appdir.c b/source/blender/blenkernel/intern/appdir.c index 60e81003c40..b1b32e75f59 100644 --- a/source/blender/blenkernel/intern/appdir.c +++ b/source/blender/blenkernel/intern/appdir.c @@ -501,54 +501,6 @@ const char *BKE_appdir_folder_id_version(const int folder_id, const int ver, con /* Preset paths */ /** - * Tries appending each of the semicolon-separated extensions in the PATHEXT - * environment variable (Windows-only) onto *name in turn until such a file is found. - * Returns success/failure. - */ -static int add_win32_extension(char *name) -{ - int retval = 0; - int type; - - type = BLI_exists(name); - if ((type == 0) || S_ISDIR(type)) { -#ifdef _WIN32 - char filename[FILE_MAX]; - char ext[FILE_MAX]; - const char *extensions = getenv("PATHEXT"); - if (extensions) { - char *temp; - do { - strcpy(filename, name); - temp = strstr(extensions, ";"); - if (temp) { - strncpy(ext, extensions, temp - extensions); - ext[temp - extensions] = 0; - extensions = temp + 1; - strcat(filename, ext); - } - else { - strcat(filename, extensions); - } - - type = BLI_exists(filename); - if (type && (!S_ISDIR(type))) { - retval = 1; - strcpy(name, filename); - break; - } - } while (temp); - } -#endif - } - else { - retval = 1; - } - - return (retval); -} - -/** * Checks if name is a fully qualified filename to an executable. * If not it searches $PATH for the file. On Windows it also * adds the correct extension (.com .exe etc) from @@ -562,39 +514,34 @@ static int add_win32_extension(char *name) */ static void bli_where_am_i(char *fullname, const size_t maxlen, const char *name) { - char filename[FILE_MAX]; - const char *path = NULL, *temp; - -#ifdef _WIN32 - const char *separator = ";"; -#else - const char *separator = ":"; -#endif - - #ifdef WITH_BINRELOC /* linux uses binreloc since argv[0] is not reliable, call br_init( NULL ) first */ - path = br_find_exe(NULL); - if (path) { - BLI_strncpy(fullname, path, maxlen); - free((void *)path); - return; + { + const char *path = NULL; + path = br_find_exe(NULL); + if (path) { + BLI_strncpy(fullname, path, maxlen); + free((void *)path); + return; + } } #endif #ifdef _WIN32 - wchar_t *fullname_16 = MEM_mallocN(maxlen * sizeof(wchar_t), "ProgramPath"); - if (GetModuleFileNameW(0, fullname_16, maxlen)) { - conv_utf_16_to_8(fullname_16, fullname, maxlen); - if (!BLI_exists(fullname)) { - printf("path can't be found: \"%.*s\"\n", (int)maxlen, fullname); - MessageBox(NULL, "path contains invalid characters or is too long (see console)", "Error", MB_OK); + { + wchar_t *fullname_16 = MEM_mallocN(maxlen * sizeof(wchar_t), "ProgramPath"); + if (GetModuleFileNameW(0, fullname_16, maxlen)) { + conv_utf_16_to_8(fullname_16, fullname, maxlen); + if (!BLI_exists(fullname)) { + printf("path can't be found: \"%.*s\"\n", (int)maxlen, fullname); + MessageBox(NULL, "path contains invalid characters or is too long (see console)", "Error", MB_OK); + } + MEM_freeN(fullname_16); + return; } + MEM_freeN(fullname_16); - return; } - - MEM_freeN(fullname_16); #endif /* unix and non linux */ @@ -611,34 +558,19 @@ static void bli_where_am_i(char *fullname, const size_t maxlen, const char *name else BLI_join_dirfile(fullname, maxlen, wdir, name); - add_win32_extension(fullname); /* XXX, doesnt respect length */ +#ifdef _WIN32 + BLI_path_program_extensions_add_win32(fullname, maxlen); +#endif } else if (BLI_last_slash(name)) { // full path BLI_strncpy(fullname, name, maxlen); - add_win32_extension(fullname); +#ifdef _WIN32 + BLI_path_program_extensions_add_win32(fullname, maxlen); +#endif } else { - // search for binary in $PATH - path = getenv("PATH"); - if (path) { - do { - temp = strstr(path, separator); - if (temp) { - strncpy(filename, path, temp - path); - filename[temp - path] = 0; - path = temp + 1; - } - else { - strncpy(filename, path, sizeof(filename)); - } - BLI_path_append(fullname, maxlen, name); - if (add_win32_extension(filename)) { - BLI_strncpy(fullname, filename, maxlen); - break; - } - } while (temp); - } + BLI_path_program_search(fullname, maxlen, name); } #if defined(DEBUG) if (!STREQ(name, fullname)) { @@ -670,6 +602,58 @@ const char *BKE_appdir_program_dir(void) return bprogdir; } +bool BKE_appdir_program_python_search( + char *fullpath, const size_t fullpath_len, + const int version_major, const int version_minor) +{ + const char *basename = "python"; + char python_ver[16]; + /* check both possible names */ + const char *python_names[] = {basename, python_ver}; + int i; + + bool is_found = false; + + BLI_snprintf(python_ver, sizeof(python_ver), "%s%d.%d", basename, version_major, version_minor); + + { + const char *python_bin_dir = BKE_appdir_folder_id(BLENDER_SYSTEM_PYTHON, "bin"); + if (python_bin_dir) { + + for (i = 0; i < ARRAY_SIZE(python_names); i++) { + BLI_join_dirfile(fullpath, fullpath_len, python_bin_dir, python_names[i]); + + if ( +#ifdef _WIN32 + BLI_path_program_extensions_add_win32(fullpath, fullpath_len) +#else + BLI_exists(fullpath) +#endif + ) + { + is_found = true; + break; + } + } + } + } + + if (is_found == false) { + for (i = 0; i < ARRAY_SIZE(python_names); i++) { + if (BLI_path_program_search(fullpath, fullpath_len, python_names[i])) { + is_found = true; + break; + } + } + } + + if (is_found == false) { + *fullpath = '\0'; + } + + return is_found; +} + /** * Gets the temp directory when blender first runs. * If the default path is not found, use try $TEMP diff --git a/source/blender/blenkernel/intern/armature.c b/source/blender/blenkernel/intern/armature.c index dc11bcb00aa..27d3d1c50fb 100644 --- a/source/blender/blenkernel/intern/armature.c +++ b/source/blender/blenkernel/intern/armature.c @@ -1825,9 +1825,12 @@ void BKE_pose_rebuild(Object *ob, bArmature *arm) BKE_pose_update_constraint_flags(ob->pose); /* for IK detection for example */ +#ifdef WITH_LEGACY_DEPSGRAPH /* the sorting */ + /* Sorting for new dependnecy graph is done on the scene graph level. */ if (counter > 1) DAG_pose_sort(ob); +#endif ob->pose->flag &= ~POSE_RECALC; ob->pose->flag |= POSE_WAS_REBUILT; @@ -1835,494 +1838,6 @@ void BKE_pose_rebuild(Object *ob, bArmature *arm) BKE_pose_channels_hash_make(ob->pose); } - -/* ********************** SPLINE IK SOLVER ******************* */ - -/* Temporary evaluation tree data used for Spline IK */ -typedef struct tSplineIK_Tree { - struct tSplineIK_Tree *next, *prev; - - int type; /* type of IK that this serves (CONSTRAINT_TYPE_KINEMATIC or ..._SPLINEIK) */ - - bool free_points; /* free the point positions array */ - short chainlen; /* number of bones in the chain */ - - float *points; /* parametric positions for the joints along the curve */ - bPoseChannel **chain; /* chain of bones to affect using Spline IK (ordered from the tip) */ - - bPoseChannel *root; /* bone that is the root node of the chain */ - - bConstraint *con; /* constraint for this chain */ - bSplineIKConstraint *ikData; /* constraint settings for this chain */ -} tSplineIK_Tree; - -/* ----------- */ - -/* Tag the bones in the chain formed by the given bone for IK */ -static void splineik_init_tree_from_pchan(Scene *scene, Object *UNUSED(ob), bPoseChannel *pchan_tip) -{ - bPoseChannel *pchan, *pchanRoot = NULL; - bPoseChannel *pchanChain[255]; - bConstraint *con = NULL; - bSplineIKConstraint *ikData = NULL; - float boneLengths[255], *jointPoints; - float totLength = 0.0f; - bool free_joints = 0; - int segcount = 0; - - /* find the SplineIK constraint */ - for (con = pchan_tip->constraints.first; con; con = con->next) { - if (con->type == CONSTRAINT_TYPE_SPLINEIK) { - ikData = con->data; - - /* target can only be curve */ - if ((ikData->tar == NULL) || (ikData->tar->type != OB_CURVE)) - continue; - /* skip if disabled */ - if ((con->enforce == 0.0f) || (con->flag & (CONSTRAINT_DISABLE | CONSTRAINT_OFF))) - continue; - - /* otherwise, constraint is ok... */ - break; - } - } - if (con == NULL) - return; - - /* make sure that the constraint targets are ok - * - this is a workaround for a depsgraph bug... - */ - if (ikData->tar) { - /* note: when creating constraints that follow path, the curve gets the CU_PATH set now, - * currently for paths to work it needs to go through the bevlist/displist system (ton) - */ - - /* only happens on reload file, but violates depsgraph still... fix! */ - if (ELEM(NULL, ikData->tar->curve_cache, ikData->tar->curve_cache->path, ikData->tar->curve_cache->path->data)) { - BKE_displist_make_curveTypes(scene, ikData->tar, 0); - - /* path building may fail in EditMode after removing verts [#33268]*/ - if (ELEM(NULL, ikData->tar->curve_cache->path, ikData->tar->curve_cache->path->data)) { - /* BLI_assert(cu->path != NULL); */ - return; - } - } - } - - /* find the root bone and the chain of bones from the root to the tip - * NOTE: this assumes that the bones are connected, but that may not be true... */ - for (pchan = pchan_tip; pchan && (segcount < ikData->chainlen); pchan = pchan->parent, segcount++) { - /* store this segment in the chain */ - pchanChain[segcount] = pchan; - - /* if performing rebinding, calculate the length of the bone */ - boneLengths[segcount] = pchan->bone->length; - totLength += boneLengths[segcount]; - } - - if (segcount == 0) - return; - else - pchanRoot = pchanChain[segcount - 1]; - - /* perform binding step if required */ - if ((ikData->flag & CONSTRAINT_SPLINEIK_BOUND) == 0) { - float segmentLen = (1.0f / (float)segcount); - int i; - - /* setup new empty array for the points list */ - if (ikData->points) - MEM_freeN(ikData->points); - ikData->numpoints = ikData->chainlen + 1; - ikData->points = MEM_mallocN(sizeof(float) * ikData->numpoints, "Spline IK Binding"); - - /* bind 'tip' of chain (i.e. first joint = tip of bone with the Spline IK Constraint) */ - ikData->points[0] = 1.0f; - - /* perform binding of the joints to parametric positions along the curve based - * proportion of the total length that each bone occupies - */ - for (i = 0; i < segcount; i++) { - /* 'head' joints, traveling towards the root of the chain - * - 2 methods; the one chosen depends on whether we've got usable lengths - */ - if ((ikData->flag & CONSTRAINT_SPLINEIK_EVENSPLITS) || (totLength == 0.0f)) { - /* 1) equi-spaced joints */ - ikData->points[i + 1] = ikData->points[i] - segmentLen; - } - else { - /* 2) to find this point on the curve, we take a step from the previous joint - * a distance given by the proportion that this bone takes - */ - ikData->points[i + 1] = ikData->points[i] - (boneLengths[i] / totLength); - } - } - - /* spline has now been bound */ - ikData->flag |= CONSTRAINT_SPLINEIK_BOUND; - } - - /* disallow negative values (happens with float precision) */ - CLAMP_MIN(ikData->points[segcount], 0.0f); - - /* apply corrections for sensitivity to scaling on a copy of the bind points, - * since it's easier to determine the positions of all the joints beforehand this way - */ - if ((ikData->flag & CONSTRAINT_SPLINEIK_SCALE_LIMITED) && (totLength != 0.0f)) { - float splineLen, maxScale; - int i; - - /* make a copy of the points array, that we'll store in the tree - * - although we could just multiply the points on the fly, this approach means that - * we can introduce per-segment stretchiness later if it is necessary - */ - jointPoints = MEM_dupallocN(ikData->points); - free_joints = 1; - - /* get the current length of the curve */ - /* NOTE: this is assumed to be correct even after the curve was resized */ - splineLen = ikData->tar->curve_cache->path->totdist; - - /* calculate the scale factor to multiply all the path values by so that the - * bone chain retains its current length, such that - * maxScale * splineLen = totLength - */ - maxScale = totLength / splineLen; - - /* apply scaling correction to all of the temporary points */ - /* TODO: this is really not adequate enough on really short chains */ - for (i = 0; i < segcount; i++) - jointPoints[i] *= maxScale; - } - else { - /* just use the existing points array */ - jointPoints = ikData->points; - free_joints = 0; - } - - /* make a new Spline-IK chain, and store it in the IK chains */ - /* TODO: we should check if there is already an IK chain on this, since that would take presidence... */ - { - /* make new tree */ - tSplineIK_Tree *tree = MEM_callocN(sizeof(tSplineIK_Tree), "SplineIK Tree"); - tree->type = CONSTRAINT_TYPE_SPLINEIK; - - tree->chainlen = segcount; - - /* copy over the array of links to bones in the chain (from tip to root) */ - tree->chain = MEM_mallocN(sizeof(bPoseChannel *) * segcount, "SplineIK Chain"); - memcpy(tree->chain, pchanChain, sizeof(bPoseChannel *) * segcount); - - /* store reference to joint position array */ - tree->points = jointPoints; - tree->free_points = free_joints; - - /* store references to different parts of the chain */ - tree->root = pchanRoot; - tree->con = con; - tree->ikData = ikData; - - /* AND! link the tree to the root */ - BLI_addtail(&pchanRoot->siktree, tree); - } - - /* mark root channel having an IK tree */ - pchanRoot->flag |= POSE_IKSPLINE; -} - -/* Tag which bones are members of Spline IK chains */ -static void splineik_init_tree(Scene *scene, Object *ob, float UNUSED(ctime)) -{ - bPoseChannel *pchan; - - /* find the tips of Spline IK chains, which are simply the bones which have been tagged as such */ - for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) { - if (pchan->constflag & PCHAN_HAS_SPLINEIK) - splineik_init_tree_from_pchan(scene, ob, pchan); - } -} - -/* ----------- */ - -/* Evaluate spline IK for a given bone */ -static void splineik_evaluate_bone(tSplineIK_Tree *tree, Scene *scene, Object *ob, bPoseChannel *pchan, - int index, float ctime) -{ - bSplineIKConstraint *ikData = tree->ikData; - float poseHead[3], poseTail[3], poseMat[4][4]; - float splineVec[3], scaleFac, radius = 1.0f; - - /* firstly, calculate the bone matrix the standard way, since this is needed for roll control */ - BKE_pose_where_is_bone(scene, ob, pchan, ctime, 1); - - copy_v3_v3(poseHead, pchan->pose_head); - copy_v3_v3(poseTail, pchan->pose_tail); - - /* step 1: determine the positions for the endpoints of the bone */ - { - float vec[4], dir[3], rad; - float tailBlendFac = 1.0f; - - /* determine if the bone should still be affected by SplineIK */ - if (tree->points[index + 1] >= 1.0f) { - /* spline doesn't affect the bone anymore, so done... */ - pchan->flag |= POSE_DONE; - return; - } - else if ((tree->points[index] >= 1.0f) && (tree->points[index + 1] < 1.0f)) { - /* blending factor depends on the amount of the bone still left on the chain */ - tailBlendFac = (1.0f - tree->points[index + 1]) / (tree->points[index] - tree->points[index + 1]); - } - - /* tail endpoint */ - if (where_on_path(ikData->tar, tree->points[index], vec, dir, NULL, &rad, NULL)) { - /* apply curve's object-mode transforms to the position - * unless the option to allow curve to be positioned elsewhere is activated (i.e. no root) - */ - if ((ikData->flag & CONSTRAINT_SPLINEIK_NO_ROOT) == 0) - mul_m4_v3(ikData->tar->obmat, vec); - - /* convert the position to pose-space, then store it */ - mul_m4_v3(ob->imat, vec); - interp_v3_v3v3(poseTail, pchan->pose_tail, vec, tailBlendFac); - - /* set the new radius */ - radius = rad; - } - - /* head endpoint */ - if (where_on_path(ikData->tar, tree->points[index + 1], vec, dir, NULL, &rad, NULL)) { - /* apply curve's object-mode transforms to the position - * unless the option to allow curve to be positioned elsewhere is activated (i.e. no root) - */ - if ((ikData->flag & CONSTRAINT_SPLINEIK_NO_ROOT) == 0) - mul_m4_v3(ikData->tar->obmat, vec); - - /* store the position, and convert it to pose space */ - mul_m4_v3(ob->imat, vec); - copy_v3_v3(poseHead, vec); - - /* set the new radius (it should be the average value) */ - radius = (radius + rad) / 2; - } - } - - /* step 2: determine the implied transform from these endpoints - * - splineVec: the vector direction that the spline applies on the bone - * - scaleFac: the factor that the bone length is scaled by to get the desired amount - */ - sub_v3_v3v3(splineVec, poseTail, poseHead); - scaleFac = len_v3(splineVec) / pchan->bone->length; - - /* step 3: compute the shortest rotation needed to map from the bone rotation to the current axis - * - this uses the same method as is used for the Damped Track Constraint (see the code there for details) - */ - { - float dmat[3][3], rmat[3][3], tmat[3][3]; - float raxis[3], rangle; - - /* compute the raw rotation matrix from the bone's current matrix by extracting only the - * orientation-relevant axes, and normalizing them - */ - copy_v3_v3(rmat[0], pchan->pose_mat[0]); - copy_v3_v3(rmat[1], pchan->pose_mat[1]); - copy_v3_v3(rmat[2], pchan->pose_mat[2]); - normalize_m3(rmat); - - /* also, normalize the orientation imposed by the bone, now that we've extracted the scale factor */ - normalize_v3(splineVec); - - /* calculate smallest axis-angle rotation necessary for getting from the - * current orientation of the bone, to the spline-imposed direction - */ - cross_v3_v3v3(raxis, rmat[1], splineVec); - - rangle = dot_v3v3(rmat[1], splineVec); - CLAMP(rangle, -1.0f, 1.0f); - rangle = acosf(rangle); - - /* multiply the magnitude of the angle by the influence of the constraint to - * control the influence of the SplineIK effect - */ - rangle *= tree->con->enforce; - - /* construct rotation matrix from the axis-angle rotation found above - * - this call takes care to make sure that the axis provided is a unit vector first - */ - axis_angle_to_mat3(dmat, raxis, rangle); - - /* combine these rotations so that the y-axis of the bone is now aligned as the spline dictates, - * while still maintaining roll control from the existing bone animation - */ - mul_m3_m3m3(tmat, dmat, rmat); /* m1, m3, m2 */ - normalize_m3(tmat); /* attempt to reduce shearing, though I doubt this'll really help too much now... */ - copy_m4_m3(poseMat, tmat); - } - - /* step 4: set the scaling factors for the axes */ - { - /* only multiply the y-axis by the scaling factor to get nice volume-preservation */ - mul_v3_fl(poseMat[1], scaleFac); - - /* set the scaling factors of the x and z axes from... */ - switch (ikData->xzScaleMode) { - case CONSTRAINT_SPLINEIK_XZS_ORIGINAL: - { - /* original scales get used */ - float scale; - - /* x-axis scale */ - scale = len_v3(pchan->pose_mat[0]); - mul_v3_fl(poseMat[0], scale); - /* z-axis scale */ - scale = len_v3(pchan->pose_mat[2]); - mul_v3_fl(poseMat[2], scale); - break; - } - case CONSTRAINT_SPLINEIK_XZS_INVERSE: - { - /* old 'volume preservation' method using the inverse scale */ - float scale; - - /* calculate volume preservation factor which is - * basically the inverse of the y-scaling factor - */ - if (fabsf(scaleFac) != 0.0f) { - scale = 1.0f / fabsf(scaleFac); - - /* we need to clamp this within sensible values */ - /* NOTE: these should be fine for now, but should get sanitised in future */ - CLAMP(scale, 0.0001f, 100000.0f); - } - else - scale = 1.0f; - - /* apply the scaling */ - mul_v3_fl(poseMat[0], scale); - mul_v3_fl(poseMat[2], scale); - break; - } - case CONSTRAINT_SPLINEIK_XZS_VOLUMETRIC: - { - /* improved volume preservation based on the Stretch To constraint */ - float final_scale; - - /* as the basis for volume preservation, we use the inverse scale factor... */ - if (fabsf(scaleFac) != 0.0f) { - /* NOTE: The method here is taken wholesale from the Stretch To constraint */ - float bulge = powf(1.0f / fabsf(scaleFac), ikData->bulge); - - if (bulge > 1.0f) { - if (ikData->flag & CONSTRAINT_SPLINEIK_USE_BULGE_MAX) { - float bulge_max = max_ff(ikData->bulge_max, 1.0f); - float hard = min_ff(bulge, bulge_max); - - float range = bulge_max - 1.0f; - float scale = (range > 0.0f) ? 1.0f / range : 0.0f; - float soft = 1.0f + range * atanf((bulge - 1.0f) * scale) / (float)M_PI_2; - - bulge = interpf(soft, hard, ikData->bulge_smooth); - } - } - if (bulge < 1.0f) { - if (ikData->flag & CONSTRAINT_SPLINEIK_USE_BULGE_MIN) { - float bulge_min = CLAMPIS(ikData->bulge_min, 0.0f, 1.0f); - float hard = max_ff(bulge, bulge_min); - - float range = 1.0f - bulge_min; - float scale = (range > 0.0f) ? 1.0f / range : 0.0f; - float soft = 1.0f - range * atanf((1.0f - bulge) * scale) / (float)M_PI_2; - - bulge = interpf(soft, hard, ikData->bulge_smooth); - } - } - - /* compute scale factor for xz axes from this value */ - final_scale = sqrtf(bulge); - } - else { - /* no scaling, so scale factor is simple */ - final_scale = 1.0f; - } - - /* apply the scaling (assuming normalised scale) */ - mul_v3_fl(poseMat[0], final_scale); - mul_v3_fl(poseMat[2], final_scale); - break; - } - } - - /* finally, multiply the x and z scaling by the radius of the curve too, - * to allow automatic scales to get tweaked still - */ - if ((ikData->flag & CONSTRAINT_SPLINEIK_NO_CURVERAD) == 0) { - mul_v3_fl(poseMat[0], radius); - mul_v3_fl(poseMat[2], radius); - } - } - - /* step 5: set the location of the bone in the matrix */ - if (ikData->flag & CONSTRAINT_SPLINEIK_NO_ROOT) { - /* when the 'no-root' option is affected, the chain can retain - * the shape but be moved elsewhere - */ - copy_v3_v3(poseHead, pchan->pose_head); - } - else if (tree->con->enforce < 1.0f) { - /* when the influence is too low - * - blend the positions for the 'root' bone - * - stick to the parent for any other - */ - if (pchan->parent) { - copy_v3_v3(poseHead, pchan->pose_head); - } - else { - /* FIXME: this introduces popping artifacts when we reach 0.0 */ - interp_v3_v3v3(poseHead, pchan->pose_head, poseHead, tree->con->enforce); - } - } - copy_v3_v3(poseMat[3], poseHead); - - /* finally, store the new transform */ - copy_m4_m4(pchan->pose_mat, poseMat); - copy_v3_v3(pchan->pose_head, poseHead); - - /* recalculate tail, as it's now outdated after the head gets adjusted above! */ - BKE_pose_where_is_bone_tail(pchan); - - /* done! */ - pchan->flag |= POSE_DONE; -} - -/* Evaluate the chain starting from the nominated bone */ -static void splineik_execute_tree(Scene *scene, Object *ob, bPoseChannel *pchan_root, float ctime) -{ - tSplineIK_Tree *tree; - - /* for each pose-tree, execute it if it is spline, otherwise just free it */ - while ((tree = pchan_root->siktree.first) != NULL) { - int i; - - /* walk over each bone in the chain, calculating the effects of spline IK - * - the chain is traversed in the opposite order to storage order (i.e. parent to children) - * so that dependencies are correct - */ - for (i = tree->chainlen - 1; i >= 0; i--) { - bPoseChannel *pchan = tree->chain[i]; - splineik_evaluate_bone(tree, scene, ob, pchan, i, ctime); - } - - /* free the tree info specific to SplineIK trees now */ - if (tree->chain) - MEM_freeN(tree->chain); - if (tree->free_points) - MEM_freeN(tree->points); - - /* free this tree */ - BLI_freelinkN(&pchan_root->siktree, tree); - } -} - /* ********************** THE POSE SOLVER ******************* */ /* loc/rot/size to given mat4 */ @@ -2623,7 +2138,7 @@ void BKE_pose_where_is(Scene *scene, Object *ob) * - this is not integrated as an IK plugin, since it should be able * to function in conjunction with standard IK */ - splineik_init_tree(scene, ob, ctime); + BKE_pose_splineik_init_tree(scene, ob, ctime); /* 3. the main loop, channels are already hierarchical sorted from root to children */ for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) { @@ -2633,7 +2148,7 @@ void BKE_pose_where_is(Scene *scene, Object *ob) } /* 4b. if we find a Spline IK root, we handle it separated too */ else if (pchan->flag & POSE_IKSPLINE) { - splineik_execute_tree(scene, ob, pchan, ctime); + BKE_splineik_execute_tree(scene, ob, pchan, ctime); } /* 5. otherwise just call the normal solver */ else if (!(pchan->flag & POSE_DONE)) { @@ -2703,3 +2218,46 @@ BoundBox *BKE_armature_boundbox_get(Object *ob) return ob->bb; } + +/************** Graph evaluation ********************/ + +bPoseChannel *BKE_armature_ik_solver_find_root( + bPoseChannel *pchan, + bKinematicConstraint *data) +{ + bPoseChannel *rootchan = pchan; + if (!(data->flag & CONSTRAINT_IK_TIP)) { + /* Exclude tip from chain. */ + rootchan = rootchan->parent; + } + if (rootchan != NULL) { + int segcount = 0; + while (rootchan->parent) { + /* Continue up chain, until we reach target number of items. */ + segcount++; + if (segcount == data->rootbone) { + break; + } + rootchan = rootchan->parent; + } + } + return rootchan; +} + +bPoseChannel *BKE_armature_splineik_solver_find_root( + bPoseChannel *pchan, + bSplineIKConstraint *data) +{ + bPoseChannel *rootchan = pchan; + int segcount = 0; + BLI_assert(rootchan != NULL); + while (rootchan->parent) { + /* Continue up chain, until we reach target number of items. */ + segcount++; + if (segcount == data->chainlen) { + break; + } + rootchan = rootchan->parent; + } + return rootchan; +} diff --git a/source/blender/blenkernel/intern/armature_update.c b/source/blender/blenkernel/intern/armature_update.c new file mode 100644 index 00000000000..ceda9f056bb --- /dev/null +++ b/source/blender/blenkernel/intern/armature_update.c @@ -0,0 +1,697 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2015 Blender Foundation. + * All rights reserved. + * + * Original Author: Joshua Leung + * Contributor(s): None Yet + * + * ***** END GPL LICENSE BLOCK ***** + * + * Defines and code for core node types + */ + +#include "MEM_guardedalloc.h" + +#include "BLI_utildefines.h" +#include "BLI_listbase.h" +#include "BLI_math.h" + +#include "DNA_armature_types.h" +#include "DNA_constraint_types.h" +#include "DNA_object_types.h" +#include "DNA_scene_types.h" + +#include "BKE_action.h" +#include "BKE_anim.h" +#include "BKE_armature.h" +#include "BKE_curve.h" +#include "BKE_depsgraph.h" +#include "BKE_displist.h" +#include "BKE_fcurve.h" +#include "BKE_scene.h" + +#include "BIK_api.h" + +#include "BKE_global.h" +#include "BKE_main.h" + +#include "DEG_depsgraph.h" + +#ifdef WITH_LEGACY_DEPSGRAPH +# define DEBUG_PRINT if (!DEG_depsgraph_use_legacy() && G.debug & G_DEBUG_DEPSGRAPH) printf +#else +# define DEBUG_PRINT if (G.debug & G_DEBUG_DEPSGRAPH) printf +#endif + +/* ********************** SPLINE IK SOLVER ******************* */ + +/* Temporary evaluation tree data used for Spline IK */ +typedef struct tSplineIK_Tree { + struct tSplineIK_Tree *next, *prev; + + int type; /* type of IK that this serves (CONSTRAINT_TYPE_KINEMATIC or ..._SPLINEIK) */ + + bool free_points; /* free the point positions array */ + short chainlen; /* number of bones in the chain */ + + float *points; /* parametric positions for the joints along the curve */ + bPoseChannel **chain; /* chain of bones to affect using Spline IK (ordered from the tip) */ + + bPoseChannel *root; /* bone that is the root node of the chain */ + + bConstraint *con; /* constraint for this chain */ + bSplineIKConstraint *ikData; /* constraint settings for this chain */ +} tSplineIK_Tree; + +/* ----------- */ + +/* Tag the bones in the chain formed by the given bone for IK */ +static void splineik_init_tree_from_pchan(Scene *scene, Object *UNUSED(ob), bPoseChannel *pchan_tip) +{ + bPoseChannel *pchan, *pchanRoot = NULL; + bPoseChannel *pchanChain[255]; + bConstraint *con = NULL; + bSplineIKConstraint *ikData = NULL; + float boneLengths[255], *jointPoints; + float totLength = 0.0f; + bool free_joints = 0; + int segcount = 0; + + /* find the SplineIK constraint */ + for (con = pchan_tip->constraints.first; con; con = con->next) { + if (con->type == CONSTRAINT_TYPE_SPLINEIK) { + ikData = con->data; + + /* target can only be curve */ + if ((ikData->tar == NULL) || (ikData->tar->type != OB_CURVE)) + continue; + /* skip if disabled */ + if ((con->enforce == 0.0f) || (con->flag & (CONSTRAINT_DISABLE | CONSTRAINT_OFF))) + continue; + + /* otherwise, constraint is ok... */ + break; + } + } + if (con == NULL) + return; + + /* make sure that the constraint targets are ok + * - this is a workaround for a depsgraph bug... + */ + if (ikData->tar) { + /* note: when creating constraints that follow path, the curve gets the CU_PATH set now, + * currently for paths to work it needs to go through the bevlist/displist system (ton) + */ + + /* only happens on reload file, but violates depsgraph still... fix! */ + if (ELEM(NULL, ikData->tar->curve_cache, ikData->tar->curve_cache->path, ikData->tar->curve_cache->path->data)) { + BKE_displist_make_curveTypes(scene, ikData->tar, 0); + + /* path building may fail in EditMode after removing verts [#33268]*/ + if (ELEM(NULL, ikData->tar->curve_cache->path, ikData->tar->curve_cache->path->data)) { + /* BLI_assert(cu->path != NULL); */ + return; + } + } + } + + /* find the root bone and the chain of bones from the root to the tip + * NOTE: this assumes that the bones are connected, but that may not be true... */ + for (pchan = pchan_tip; pchan && (segcount < ikData->chainlen); pchan = pchan->parent, segcount++) { + /* store this segment in the chain */ + pchanChain[segcount] = pchan; + + /* if performing rebinding, calculate the length of the bone */ + boneLengths[segcount] = pchan->bone->length; + totLength += boneLengths[segcount]; + } + + if (segcount == 0) + return; + else + pchanRoot = pchanChain[segcount - 1]; + + /* perform binding step if required */ + if ((ikData->flag & CONSTRAINT_SPLINEIK_BOUND) == 0) { + float segmentLen = (1.0f / (float)segcount); + int i; + + /* setup new empty array for the points list */ + if (ikData->points) + MEM_freeN(ikData->points); + ikData->numpoints = ikData->chainlen + 1; + ikData->points = MEM_mallocN(sizeof(float) * ikData->numpoints, "Spline IK Binding"); + + /* bind 'tip' of chain (i.e. first joint = tip of bone with the Spline IK Constraint) */ + ikData->points[0] = 1.0f; + + /* perform binding of the joints to parametric positions along the curve based + * proportion of the total length that each bone occupies + */ + for (i = 0; i < segcount; i++) { + /* 'head' joints, traveling towards the root of the chain + * - 2 methods; the one chosen depends on whether we've got usable lengths + */ + if ((ikData->flag & CONSTRAINT_SPLINEIK_EVENSPLITS) || (totLength == 0.0f)) { + /* 1) equi-spaced joints */ + ikData->points[i + 1] = ikData->points[i] - segmentLen; + } + else { + /* 2) to find this point on the curve, we take a step from the previous joint + * a distance given by the proportion that this bone takes + */ + ikData->points[i + 1] = ikData->points[i] - (boneLengths[i] / totLength); + } + } + + /* spline has now been bound */ + ikData->flag |= CONSTRAINT_SPLINEIK_BOUND; + } + + /* disallow negative values (happens with float precision) */ + CLAMP_MIN(ikData->points[segcount], 0.0f); + + /* apply corrections for sensitivity to scaling on a copy of the bind points, + * since it's easier to determine the positions of all the joints beforehand this way + */ + if ((ikData->flag & CONSTRAINT_SPLINEIK_SCALE_LIMITED) && (totLength != 0.0f)) { + float splineLen, maxScale; + int i; + + /* make a copy of the points array, that we'll store in the tree + * - although we could just multiply the points on the fly, this approach means that + * we can introduce per-segment stretchiness later if it is necessary + */ + jointPoints = MEM_dupallocN(ikData->points); + free_joints = 1; + + /* get the current length of the curve */ + /* NOTE: this is assumed to be correct even after the curve was resized */ + splineLen = ikData->tar->curve_cache->path->totdist; + + /* calculate the scale factor to multiply all the path values by so that the + * bone chain retains its current length, such that + * maxScale * splineLen = totLength + */ + maxScale = totLength / splineLen; + + /* apply scaling correction to all of the temporary points */ + /* TODO: this is really not adequate enough on really short chains */ + for (i = 0; i < segcount; i++) + jointPoints[i] *= maxScale; + } + else { + /* just use the existing points array */ + jointPoints = ikData->points; + free_joints = 0; + } + + /* make a new Spline-IK chain, and store it in the IK chains */ + /* TODO: we should check if there is already an IK chain on this, since that would take presidence... */ + { + /* make new tree */ + tSplineIK_Tree *tree = MEM_callocN(sizeof(tSplineIK_Tree), "SplineIK Tree"); + tree->type = CONSTRAINT_TYPE_SPLINEIK; + + tree->chainlen = segcount; + + /* copy over the array of links to bones in the chain (from tip to root) */ + tree->chain = MEM_mallocN(sizeof(bPoseChannel *) * segcount, "SplineIK Chain"); + memcpy(tree->chain, pchanChain, sizeof(bPoseChannel *) * segcount); + + /* store reference to joint position array */ + tree->points = jointPoints; + tree->free_points = free_joints; + + /* store references to different parts of the chain */ + tree->root = pchanRoot; + tree->con = con; + tree->ikData = ikData; + + /* AND! link the tree to the root */ + BLI_addtail(&pchanRoot->siktree, tree); + } + + /* mark root channel having an IK tree */ + pchanRoot->flag |= POSE_IKSPLINE; +} + +/* Tag which bones are members of Spline IK chains */ +static void splineik_init_tree(Scene *scene, Object *ob, float UNUSED(ctime)) +{ + bPoseChannel *pchan; + + /* find the tips of Spline IK chains, which are simply the bones which have been tagged as such */ + for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) { + if (pchan->constflag & PCHAN_HAS_SPLINEIK) + splineik_init_tree_from_pchan(scene, ob, pchan); + } +} + +/* ----------- */ + +/* Evaluate spline IK for a given bone */ +static void splineik_evaluate_bone(tSplineIK_Tree *tree, Scene *scene, Object *ob, bPoseChannel *pchan, + int index, float ctime) +{ + bSplineIKConstraint *ikData = tree->ikData; + float poseHead[3], poseTail[3], poseMat[4][4]; + float splineVec[3], scaleFac, radius = 1.0f; + + /* firstly, calculate the bone matrix the standard way, since this is needed for roll control */ + BKE_pose_where_is_bone(scene, ob, pchan, ctime, 1); + + copy_v3_v3(poseHead, pchan->pose_head); + copy_v3_v3(poseTail, pchan->pose_tail); + + /* step 1: determine the positions for the endpoints of the bone */ + { + float vec[4], dir[3], rad; + float tailBlendFac = 1.0f; + + /* determine if the bone should still be affected by SplineIK */ + if (tree->points[index + 1] >= 1.0f) { + /* spline doesn't affect the bone anymore, so done... */ + pchan->flag |= POSE_DONE; + return; + } + else if ((tree->points[index] >= 1.0f) && (tree->points[index + 1] < 1.0f)) { + /* blending factor depends on the amount of the bone still left on the chain */ + tailBlendFac = (1.0f - tree->points[index + 1]) / (tree->points[index] - tree->points[index + 1]); + } + + /* tail endpoint */ + if (where_on_path(ikData->tar, tree->points[index], vec, dir, NULL, &rad, NULL)) { + /* apply curve's object-mode transforms to the position + * unless the option to allow curve to be positioned elsewhere is activated (i.e. no root) + */ + if ((ikData->flag & CONSTRAINT_SPLINEIK_NO_ROOT) == 0) + mul_m4_v3(ikData->tar->obmat, vec); + + /* convert the position to pose-space, then store it */ + mul_m4_v3(ob->imat, vec); + interp_v3_v3v3(poseTail, pchan->pose_tail, vec, tailBlendFac); + + /* set the new radius */ + radius = rad; + } + + /* head endpoint */ + if (where_on_path(ikData->tar, tree->points[index + 1], vec, dir, NULL, &rad, NULL)) { + /* apply curve's object-mode transforms to the position + * unless the option to allow curve to be positioned elsewhere is activated (i.e. no root) + */ + if ((ikData->flag & CONSTRAINT_SPLINEIK_NO_ROOT) == 0) + mul_m4_v3(ikData->tar->obmat, vec); + + /* store the position, and convert it to pose space */ + mul_m4_v3(ob->imat, vec); + copy_v3_v3(poseHead, vec); + + /* set the new radius (it should be the average value) */ + radius = (radius + rad) / 2; + } + } + + /* step 2: determine the implied transform from these endpoints + * - splineVec: the vector direction that the spline applies on the bone + * - scaleFac: the factor that the bone length is scaled by to get the desired amount + */ + sub_v3_v3v3(splineVec, poseTail, poseHead); + scaleFac = len_v3(splineVec) / pchan->bone->length; + + /* step 3: compute the shortest rotation needed to map from the bone rotation to the current axis + * - this uses the same method as is used for the Damped Track Constraint (see the code there for details) + */ + { + float dmat[3][3], rmat[3][3], tmat[3][3]; + float raxis[3], rangle; + + /* compute the raw rotation matrix from the bone's current matrix by extracting only the + * orientation-relevant axes, and normalizing them + */ + copy_v3_v3(rmat[0], pchan->pose_mat[0]); + copy_v3_v3(rmat[1], pchan->pose_mat[1]); + copy_v3_v3(rmat[2], pchan->pose_mat[2]); + normalize_m3(rmat); + + /* also, normalize the orientation imposed by the bone, now that we've extracted the scale factor */ + normalize_v3(splineVec); + + /* calculate smallest axis-angle rotation necessary for getting from the + * current orientation of the bone, to the spline-imposed direction + */ + cross_v3_v3v3(raxis, rmat[1], splineVec); + + rangle = dot_v3v3(rmat[1], splineVec); + CLAMP(rangle, -1.0f, 1.0f); + rangle = acosf(rangle); + + /* multiply the magnitude of the angle by the influence of the constraint to + * control the influence of the SplineIK effect + */ + rangle *= tree->con->enforce; + + /* construct rotation matrix from the axis-angle rotation found above + * - this call takes care to make sure that the axis provided is a unit vector first + */ + axis_angle_to_mat3(dmat, raxis, rangle); + + /* combine these rotations so that the y-axis of the bone is now aligned as the spline dictates, + * while still maintaining roll control from the existing bone animation + */ + mul_m3_m3m3(tmat, dmat, rmat); /* m1, m3, m2 */ + normalize_m3(tmat); /* attempt to reduce shearing, though I doubt this'll really help too much now... */ + copy_m4_m3(poseMat, tmat); + } + + /* step 4: set the scaling factors for the axes */ + { + /* only multiply the y-axis by the scaling factor to get nice volume-preservation */ + mul_v3_fl(poseMat[1], scaleFac); + + /* set the scaling factors of the x and z axes from... */ + switch (ikData->xzScaleMode) { + case CONSTRAINT_SPLINEIK_XZS_ORIGINAL: + { + /* original scales get used */ + float scale; + + /* x-axis scale */ + scale = len_v3(pchan->pose_mat[0]); + mul_v3_fl(poseMat[0], scale); + /* z-axis scale */ + scale = len_v3(pchan->pose_mat[2]); + mul_v3_fl(poseMat[2], scale); + break; + } + case CONSTRAINT_SPLINEIK_XZS_INVERSE: + { + /* old 'volume preservation' method using the inverse scale */ + float scale; + + /* calculate volume preservation factor which is + * basically the inverse of the y-scaling factor + */ + if (fabsf(scaleFac) != 0.0f) { + scale = 1.0f / fabsf(scaleFac); + + /* we need to clamp this within sensible values */ + /* NOTE: these should be fine for now, but should get sanitised in future */ + CLAMP(scale, 0.0001f, 100000.0f); + } + else + scale = 1.0f; + + /* apply the scaling */ + mul_v3_fl(poseMat[0], scale); + mul_v3_fl(poseMat[2], scale); + break; + } + case CONSTRAINT_SPLINEIK_XZS_VOLUMETRIC: + { + /* improved volume preservation based on the Stretch To constraint */ + float final_scale; + + /* as the basis for volume preservation, we use the inverse scale factor... */ + if (fabsf(scaleFac) != 0.0f) { + /* NOTE: The method here is taken wholesale from the Stretch To constraint */ + float bulge = powf(1.0f / fabsf(scaleFac), ikData->bulge); + + if (bulge > 1.0f) { + if (ikData->flag & CONSTRAINT_SPLINEIK_USE_BULGE_MAX) { + float bulge_max = max_ff(ikData->bulge_max, 1.0f); + float hard = min_ff(bulge, bulge_max); + + float range = bulge_max - 1.0f; + float scale = (range > 0.0f) ? 1.0f / range : 0.0f; + float soft = 1.0f + range * atanf((bulge - 1.0f) * scale) / (float)M_PI_2; + + bulge = interpf(soft, hard, ikData->bulge_smooth); + } + } + if (bulge < 1.0f) { + if (ikData->flag & CONSTRAINT_SPLINEIK_USE_BULGE_MIN) { + float bulge_min = CLAMPIS(ikData->bulge_min, 0.0f, 1.0f); + float hard = max_ff(bulge, bulge_min); + + float range = 1.0f - bulge_min; + float scale = (range > 0.0f) ? 1.0f / range : 0.0f; + float soft = 1.0f - range * atanf((1.0f - bulge) * scale) / (float)M_PI_2; + + bulge = interpf(soft, hard, ikData->bulge_smooth); + } + } + + /* compute scale factor for xz axes from this value */ + final_scale = sqrtf(bulge); + } + else { + /* no scaling, so scale factor is simple */ + final_scale = 1.0f; + } + + /* apply the scaling (assuming normalised scale) */ + mul_v3_fl(poseMat[0], final_scale); + mul_v3_fl(poseMat[2], final_scale); + break; + } + } + + /* finally, multiply the x and z scaling by the radius of the curve too, + * to allow automatic scales to get tweaked still + */ + if ((ikData->flag & CONSTRAINT_SPLINEIK_NO_CURVERAD) == 0) { + mul_v3_fl(poseMat[0], radius); + mul_v3_fl(poseMat[2], radius); + } + } + + /* step 5: set the location of the bone in the matrix */ + if (ikData->flag & CONSTRAINT_SPLINEIK_NO_ROOT) { + /* when the 'no-root' option is affected, the chain can retain + * the shape but be moved elsewhere + */ + copy_v3_v3(poseHead, pchan->pose_head); + } + else if (tree->con->enforce < 1.0f) { + /* when the influence is too low + * - blend the positions for the 'root' bone + * - stick to the parent for any other + */ + if (pchan->parent) { + copy_v3_v3(poseHead, pchan->pose_head); + } + else { + /* FIXME: this introduces popping artifacts when we reach 0.0 */ + interp_v3_v3v3(poseHead, pchan->pose_head, poseHead, tree->con->enforce); + } + } + copy_v3_v3(poseMat[3], poseHead); + + /* finally, store the new transform */ + copy_m4_m4(pchan->pose_mat, poseMat); + copy_v3_v3(pchan->pose_head, poseHead); + + /* recalculate tail, as it's now outdated after the head gets adjusted above! */ + BKE_pose_where_is_bone_tail(pchan); + + /* done! */ + pchan->flag |= POSE_DONE; +} + +/* Evaluate the chain starting from the nominated bone */ +static void splineik_execute_tree(Scene *scene, Object *ob, bPoseChannel *pchan_root, float ctime) +{ + tSplineIK_Tree *tree; + + /* for each pose-tree, execute it if it is spline, otherwise just free it */ + while ((tree = pchan_root->siktree.first) != NULL) { + int i; + + /* walk over each bone in the chain, calculating the effects of spline IK + * - the chain is traversed in the opposite order to storage order (i.e. parent to children) + * so that dependencies are correct + */ + for (i = tree->chainlen - 1; i >= 0; i--) { + bPoseChannel *pchan = tree->chain[i]; + splineik_evaluate_bone(tree, scene, ob, pchan, i, ctime); + } + + /* free the tree info specific to SplineIK trees now */ + if (tree->chain) + MEM_freeN(tree->chain); + if (tree->free_points) + MEM_freeN(tree->points); + + /* free this tree */ + BLI_freelinkN(&pchan_root->siktree, tree); + } +} + +void BKE_pose_splineik_init_tree(Scene *scene, Object *ob, float ctime) +{ + splineik_init_tree(scene, ob, ctime); +} + +void BKE_splineik_execute_tree(Scene *scene, Object *ob, bPoseChannel *pchan_root, float ctime) +{ + splineik_execute_tree(scene, ob, pchan_root, ctime); +} + +/* *************** Depsgraph evaluation callbacks ************ */ + +void BKE_pose_eval_init(EvaluationContext *UNUSED(eval_ctx), + Scene *scene, + Object *ob, + bPose *pose) +{ + float ctime = BKE_scene_frame_get(scene); /* not accurate... */ + bPoseChannel *pchan; + + DEBUG_PRINT("%s on %s\n", __func__, ob->id.name); + + BLI_assert(ob->type == OB_ARMATURE); + + /* We demand having proper pose. */ + BLI_assert(ob->pose != NULL); + BLI_assert((ob->pose->flag & POSE_RECALC) == 0); + + /* imat is needed for solvers. */ + invert_m4_m4(ob->imat, ob->obmat); + + /* 1. clear flags */ + for (pchan = pose->chanbase.first; pchan != NULL; pchan = pchan->next) { + pchan->flag &= ~(POSE_DONE | POSE_CHAIN | POSE_IKTREE | POSE_IKSPLINE); + } + + /* 2a. construct the IK tree (standard IK) */ + BIK_initialize_tree(scene, ob, ctime); + + /* 2b. construct the Spline IK trees + * - this is not integrated as an IK plugin, since it should be able + * to function in conjunction with standard IK + */ + BKE_pose_splineik_init_tree(scene, ob, ctime); +} + +void BKE_pose_eval_bone(EvaluationContext *UNUSED(eval_ctx), + Scene *scene, + Object *ob, + bPoseChannel *pchan) +{ + bArmature *arm = (bArmature *)ob->data; + DEBUG_PRINT("%s on %s pchan %s\n", __func__, ob->id.name, pchan->name); + BLI_assert(ob->type == OB_ARMATURE); + if (arm->edbo || (arm->flag & ARM_RESTPOS)) { + Bone *bone = pchan->bone; + if (bone) { + copy_m4_m4(pchan->pose_mat, bone->arm_mat); + copy_v3_v3(pchan->pose_head, bone->arm_head); + copy_v3_v3(pchan->pose_tail, bone->arm_tail); + } + } + else { + /* TODO(sergey): Currently if there are constraints full transform is being + * evaluated in BKE_pose_constraints_evaluate. + */ + if (pchan->constraints.first == NULL) { + if (pchan->flag & POSE_IKTREE || pchan->flag & POSE_IKSPLINE) { + /* pass */ + } + else { + /* TODO(sergey): Use time source node for time. */ + float ctime = BKE_scene_frame_get(scene); /* not accurate... */ + BKE_pose_where_is_bone(scene, ob, pchan, ctime, 1); + } + } + } +} + +void BKE_pose_constraints_evaluate(EvaluationContext *UNUSED(eval_ctx), + Object *ob, + bPoseChannel *pchan) +{ + Scene *scene = G.main->scene.first; + DEBUG_PRINT("%s on %s pchan %s\n", __func__, ob->id.name, pchan->name); + if (pchan->flag & POSE_IKTREE || pchan->flag & POSE_IKSPLINE) { + /* IK are being solved separately/ */ + } + else { + float ctime = BKE_scene_frame_get(scene); /* not accurate... */ + BKE_pose_where_is_bone(scene, ob, pchan, ctime, 1); + } +} + +void BKE_pose_bone_done(EvaluationContext *UNUSED(eval_ctx), + bPoseChannel *pchan) +{ + float imat[4][4]; + DEBUG_PRINT("%s on pchan %s\n", __func__, pchan->name); + if (pchan->bone) { + invert_m4_m4(imat, pchan->bone->arm_mat); + mul_m4_m4m4(pchan->chan_mat, pchan->pose_mat, imat); + } +} + +void BKE_pose_iktree_evaluate(EvaluationContext *UNUSED(eval_ctx), + Scene *scene, + Object *ob, + bPoseChannel *rootchan) +{ + float ctime = BKE_scene_frame_get(scene); /* not accurate... */ + DEBUG_PRINT("%s on %s pchan %s\n", __func__, ob->id.name, rootchan->name); + BIK_execute_tree(scene, ob, rootchan, ctime); +} + +void BKE_pose_splineik_evaluate(EvaluationContext *UNUSED(eval_ctx), + Scene *scene, + Object *ob, + bPoseChannel *rootchan) +{ + float ctime = BKE_scene_frame_get(scene); /* not accurate... */ + DEBUG_PRINT("%s on %s pchan %s\n", __func__, ob->id.name, rootchan->name); + BKE_splineik_execute_tree(scene, ob, rootchan, ctime); +} + +void BKE_pose_eval_flush(EvaluationContext *UNUSED(eval_ctx), + Scene *scene, + Object *ob, + bPose *UNUSED(pose)) +{ + float ctime = BKE_scene_frame_get(scene); /* not accurate... */ + DEBUG_PRINT("%s on %s\n", __func__, ob->id.name); + BLI_assert(ob->type == OB_ARMATURE); + + /* 6. release the IK tree */ + BIK_release_tree(scene, ob, ctime); + + ob->recalc &= ~OB_RECALC_ALL; +} + +void BKE_pose_eval_proxy_copy(EvaluationContext *UNUSED(eval_ctx), Object *ob) +{ + BLI_assert(ob->id.lib != NULL && ob->proxy_from != NULL); + DEBUG_PRINT("%s on %s\n", __func__, ob->id.name); + if (BKE_pose_copy_result(ob->pose, ob->proxy_from->pose) == false) { + printf("Proxy copy error, lib Object: %s proxy Object: %s\n", + ob->id.name + 2, ob->proxy_from->id.name + 2); + } +} diff --git a/source/blender/blenkernel/intern/blender.c b/source/blender/blenkernel/intern/blender.c index 2085fefdb93..37bd9c5db5c 100644 --- a/source/blender/blenkernel/intern/blender.c +++ b/source/blender/blenkernel/intern/blender.c @@ -623,7 +623,7 @@ int BKE_write_file_userdef(const char *filepath, ReportList *reports) static void (*blender_test_break_cb)(void) = NULL; -void set_blender_test_break_cb(void (*func)(void)) +void BKE_blender_callback_test_break_set(void (*func)(void)) { blender_test_break_cb = func; } diff --git a/source/blender/blenkernel/intern/bpath.c b/source/blender/blenkernel/intern/bpath.c index 7c2b0a8a840..76544e5ed42 100644 --- a/source/blender/blenkernel/intern/bpath.c +++ b/source/blender/blenkernel/intern/bpath.c @@ -322,13 +322,14 @@ void BKE_bpath_missing_files_find(Main *bmain, const char *searchpath, ReportLis const bool find_all) { struct BPathFind_Data data = {NULL}; + const int flag = BKE_BPATH_TRAVERSE_ABS | BKE_BPATH_TRAVERSE_RELOAD_EDITED; data.basedir = bmain->name; data.reports = reports; data.searchdir = searchpath; data.find_all = find_all; - BKE_bpath_traverse_main(bmain, missing_files_find__visit_cb, BKE_BPATH_TRAVERSE_ABS, (void *)&data); + BKE_bpath_traverse_main(bmain, missing_files_find__visit_cb, flag, (void *)&data); } /* Run a visitor on a string, replacing the contents of the string as needed. */ @@ -370,6 +371,9 @@ static bool rewrite_path_fixed_dirfile(char path_dir[FILE_MAXDIR], BLI_join_dirfile(path_src, sizeof(path_src), path_dir, path_file); + /* so functions can check old value */ + BLI_strncpy(path_dst, path_src, FILE_MAX); + if (absbase) { BLI_path_abs(path_src, absbase); } @@ -432,9 +436,14 @@ void BKE_bpath_traverse_id(Main *bmain, ID *id, BPathVisitor visit_cb, const int if (BKE_image_has_packedfile(ima) == false || (flag & BKE_BPATH_TRAVERSE_SKIP_PACKED) == 0) { if (ELEM(ima->source, IMA_SRC_FILE, IMA_SRC_MOVIE, IMA_SRC_SEQUENCE)) { if (rewrite_path_fixed(ima->name, visit_cb, absbase, bpath_user_data)) { - if (!BKE_image_has_packedfile(ima)) { - BKE_image_signal(ima, NULL, IMA_SIGNAL_RELOAD); - BKE_image_walk_all_users(bmain, ima, bpath_traverse_image_user_cb); + if (flag & BKE_BPATH_TRAVERSE_RELOAD_EDITED) { + if (!BKE_image_has_packedfile(ima) && + /* image may have been painted onto (and not saved, T44543) */ + !BKE_image_is_dirty(ima)) + { + BKE_image_signal(ima, NULL, IMA_SIGNAL_RELOAD); + BKE_image_walk_all_users(bmain, ima, bpath_traverse_image_user_cb); + } } } } diff --git a/source/blender/blenkernel/intern/cdderivedmesh.c b/source/blender/blenkernel/intern/cdderivedmesh.c index e4a5dbb9d24..3feea12f017 100644 --- a/source/blender/blenkernel/intern/cdderivedmesh.c +++ b/source/blender/blenkernel/intern/cdderivedmesh.c @@ -793,7 +793,7 @@ static void cdDM_drawMappedFaces(DerivedMesh *dm, else { /* we need to check if the next material changes */ int next_actualFace = dm->drawObject->triangle_to_mface[0]; - int prev_mat_nr = -1; + short prev_mat_nr = -1; for (i = 0; i < tottri; i++) { //int actualFace = dm->drawObject->triangle_to_mface[i]; diff --git a/source/blender/blenkernel/intern/colortools.c b/source/blender/blenkernel/intern/colortools.c index 616e8a0486b..c5f7e12c9d0 100644 --- a/source/blender/blenkernel/intern/colortools.c +++ b/source/blender/blenkernel/intern/colortools.c @@ -1303,3 +1303,9 @@ void BKE_color_managed_colorspace_settings_copy(ColorManagedColorspaceSettings * { BLI_strncpy(colorspace_settings->name, settings->name, sizeof(colorspace_settings->name)); } + +bool BKE_color_managed_colorspace_settings_equals(const ColorManagedColorspaceSettings *settings1, + const ColorManagedColorspaceSettings *settings2) +{ + return STREQ(settings1->name, settings2->name); +} diff --git a/source/blender/blenkernel/intern/curve.c b/source/blender/blenkernel/intern/curve.c index 5fcdc9c2e78..6322570d562 100644 --- a/source/blender/blenkernel/intern/curve.c +++ b/source/blender/blenkernel/intern/curve.c @@ -1384,6 +1384,30 @@ void BKE_curve_forward_diff_bezier(float q0, float q1, float q2, float q3, float } } +/* forward differencing method for first derivative of cubic bezier curve */ +void BKE_curve_forward_diff_tangent_bezier(float q0, float q1, float q2, float q3, float *p, int it, int stride) +{ + float rt0, rt1, rt2, f; + int a; + + f = 1.0f / (float)it; + + rt0 = 3.0f * (q1 - q0); + rt1 = f * (3.0f * (q3 - q0) + 9.0f * (q1 - q2)); + rt2 = 6.0f * (q0 + q2) - 12.0f * q1; + + q0 = rt0; + q1 = f * (rt1 + rt2); + q2 = 2.0f * f * rt1; + + for (a = 0; a <= it; a++) { + *p = q0; + p = (float *)(((char *)p) + stride); + q0 += q1; + q1 += q2; + } +} + static void forward_diff_bezier_cotangent(const float p0[3], const float p1[3], const float p2[3], const float p3[3], float p[3], int it, int stride) { @@ -4344,8 +4368,10 @@ void BKE_curve_transform_ex(Curve *cu, float mat[4][4], const bool do_keys, cons } else { i = nu->pntsu * nu->pntsv; - for (bp = nu->bp; i--; bp++) + for (bp = nu->bp; i--; bp++) { mul_m4_v3(mat, bp->vec); + bp->radius *= unit_scale; + } } } @@ -4422,9 +4448,6 @@ void BKE_curve_material_index_remove(Curve *cu, int index) for (nu = cu->nurb.first; nu; nu = nu->next) { if (nu->mat_nr && nu->mat_nr >= index) { nu->mat_nr--; - if (curvetype == OB_CURVE) { - nu->charidx--; - } } } } @@ -4446,9 +4469,6 @@ void BKE_curve_material_index_clear(Curve *cu) for (nu = cu->nurb.first; nu; nu = nu->next) { nu->mat_nr = 0; - if (curvetype == OB_CURVE) { - nu->charidx = 0; - } } } } @@ -4475,9 +4495,6 @@ int BKE_curve_material_index_validate(Curve *cu) for (nu = cu->nurb.first; nu; nu = nu->next) { if (nu->mat_nr > max_idx) { nu->mat_nr = 0; - if (curvetype == OB_CURVE) { - nu->charidx = 0; - } is_valid = false; } } @@ -4492,6 +4509,54 @@ int BKE_curve_material_index_validate(Curve *cu) } } +void BKE_curve_material_remap(Curve *cu, const unsigned int *remap, unsigned int remap_len) +{ + const int curvetype = BKE_curve_type_get(cu); + const short remap_len_short = (short)remap_len; + +#define MAT_NR_REMAP(n) \ + if (n < remap_len_short) { \ + BLI_assert(n >= 0 && remap[n] < remap_len_short); \ + n = remap[n]; \ + } ((void)0) + + if (curvetype == OB_FONT) { + struct CharInfo *strinfo; + int charinfo_len, i; + + if (cu->editfont) { + EditFont *ef = cu->editfont; + strinfo = ef->textbufinfo; + charinfo_len = ef->len; + } + else { + strinfo = cu->strinfo; + charinfo_len = cu->len_wchar; + } + + for (i = 0; i <= charinfo_len; i++) { + if (strinfo[i].mat_nr > 0) { + strinfo[i].mat_nr -= 1; + MAT_NR_REMAP(strinfo[i].mat_nr); + strinfo[i].mat_nr += 1; + } + } + } + else { + Nurb *nu; + ListBase *nurbs = BKE_curve_editNurbs_get(cu); + + if (nurbs) { + for (nu = nurbs->first; nu; nu = nu->next) { + MAT_NR_REMAP(nu->mat_nr); + } + } + } + +#undef MAT_NR_REMAP + +} + void BKE_curve_rect_from_textbox(const struct Curve *cu, const struct TextBox *tb, struct rctf *r_rect) { r_rect->xmin = cu->xof + tb->x; @@ -4500,3 +4565,27 @@ void BKE_curve_rect_from_textbox(const struct Curve *cu, const struct TextBox *t r_rect->xmax = r_rect->xmin + tb->w; r_rect->ymin = r_rect->ymax - tb->h; } + +/* **** Depsgraph evaluation **** */ + +void BKE_curve_eval_geometry(EvaluationContext *UNUSED(eval_ctx), + Curve *curve) +{ + if (G.debug & G_DEBUG_DEPSGRAPH) { + printf("%s on %s\n", __func__, curve->id.name); + } + if (curve->bb == NULL || (curve->bb->flag & BOUNDBOX_DIRTY)) { + BKE_curve_texspace_calc(curve); + } +} + +void BKE_curve_eval_path(EvaluationContext *UNUSED(eval_ctx), + Curve *curve) +{ + /* TODO(sergey): This will probably need to be a part of + * the modifier stack still. + */ + if (G.debug & G_DEBUG_DEPSGRAPH) { + printf("%s on %s\n", __func__, curve->id.name); + } +} diff --git a/source/blender/blenkernel/intern/customdata.c b/source/blender/blenkernel/intern/customdata.c index add6bb0fd0b..eced263d493 100644 --- a/source/blender/blenkernel/intern/customdata.c +++ b/source/blender/blenkernel/intern/customdata.c @@ -1091,7 +1091,7 @@ static void layerDefault_mcol(void *data, int count) static void layerDefault_origindex(void *data, int count) { - fill_vn_i((int *)data, count, ORIGINDEX_NONE); + copy_vn_i((int *)data, count, ORIGINDEX_NONE); } static void layerInterp_bweight( @@ -1542,7 +1542,7 @@ static void CustomData_external_free(CustomData *data) void CustomData_reset(CustomData *data) { memset(data, 0, sizeof(*data)); - fill_vn_i(data->typemap, CD_NUMTYPES, -1); + copy_vn_i(data->typemap, CD_NUMTYPES, -1); } void CustomData_free(CustomData *data, int totelem) diff --git a/source/blender/blenkernel/intern/deform.c b/source/blender/blenkernel/intern/deform.c index 72133cf6460..88885da474b 100644 --- a/source/blender/blenkernel/intern/deform.c +++ b/source/blender/blenkernel/intern/deform.c @@ -982,7 +982,7 @@ void BKE_defvert_extract_vgroup_to_vertweights( } } else { - fill_vn_fl(r_weights, num_verts, invert_vgroup ? 1.0f : 0.0f); + copy_vn_fl(r_weights, num_verts, invert_vgroup ? 1.0f : 0.0f); } } @@ -1008,7 +1008,7 @@ void BKE_defvert_extract_vgroup_to_edgeweights( MEM_freeN(tmp_weights); } else { - fill_vn_fl(r_weights, num_edges, 0.0f); + copy_vn_fl(r_weights, num_edges, 0.0f); } } @@ -1031,7 +1031,7 @@ void BKE_defvert_extract_vgroup_to_loopweights( MEM_freeN(tmp_weights); } else { - fill_vn_fl(r_weights, num_loops, 0.0f); + copy_vn_fl(r_weights, num_loops, 0.0f); } } @@ -1060,7 +1060,7 @@ void BKE_defvert_extract_vgroup_to_polyweights( MEM_freeN(tmp_weights); } else { - fill_vn_fl(r_weights, num_polys, 0.0f); + copy_vn_fl(r_weights, num_polys, 0.0f); } } diff --git a/source/blender/blenkernel/intern/depsgraph.c b/source/blender/blenkernel/intern/depsgraph.c index 869404ae4a6..2fd53045e29 100644 --- a/source/blender/blenkernel/intern/depsgraph.c +++ b/source/blender/blenkernel/intern/depsgraph.c @@ -88,16 +88,25 @@ #include "depsgraph_private.h" +#include "DEG_depsgraph.h" +#include "DEG_depsgraph_build.h" +#include "DEG_depsgraph_debug.h" +#include "DEG_depsgraph_query.h" + +#ifdef WITH_LEGACY_DEPSGRAPH + static SpinLock threaded_update_lock; void DAG_init(void) { BLI_spin_init(&threaded_update_lock); + DEG_register_node_types(); } void DAG_exit(void) { BLI_spin_end(&threaded_update_lock); + DEG_free_node_types(); } /* Queue and stack operations for dag traversal @@ -1329,8 +1338,14 @@ static void (*EditorsUpdateSceneCb)(Main *bmain, Scene *scene, int updated) = NU void DAG_editors_update_cb(void (*id_func)(Main *bmain, ID *id), void (*scene_func)(Main *bmain, Scene *scene, int updated)) { - EditorsUpdateIDCb = id_func; - EditorsUpdateSceneCb = scene_func; + if (DEG_depsgraph_use_legacy()) { + EditorsUpdateIDCb = id_func; + EditorsUpdateSceneCb = scene_func; + } + else { + /* New dependency graph. */ + DEG_editors_set_update_cb(id_func, scene_func); + } } static void dag_editors_id_update(Main *bmain, ID *id) @@ -1529,7 +1544,7 @@ static void dag_scene_build(Main *bmain, Scene *sce) Base *base; BLI_listbase_clear(&tempbase); - + build_dag(bmain, sce, DAG_RL_ALL_BUT_DATA); dag_check_cycle(sce->theDag); @@ -1621,32 +1636,65 @@ static void dag_scene_build(Main *bmain, Scene *sce) /* clear all dependency graphs */ void DAG_relations_tag_update(Main *bmain) { - Scene *sce; - - for (sce = bmain->scene.first; sce; sce = sce->id.next) - dag_scene_free(sce); + if (DEG_depsgraph_use_legacy()) { + Scene *sce; + for (sce = bmain->scene.first; sce; sce = sce->id.next) { + dag_scene_free(sce); + } + } + else { + /* New dependency graph. */ + DEG_relations_tag_update(bmain); + } } /* rebuild dependency graph only for a given scene */ void DAG_scene_relations_rebuild(Main *bmain, Scene *sce) { - dag_scene_free(sce); - DAG_scene_relations_update(bmain, sce); + if (DEG_depsgraph_use_legacy()) { + dag_scene_free(sce); + DAG_scene_relations_update(bmain, sce); + } + else { + /* New dependency graph. */ + DEG_scene_relations_rebuild(bmain, sce); + } } /* create dependency graph if it was cleared or didn't exist yet */ void DAG_scene_relations_update(Main *bmain, Scene *sce) { - if (!sce->theDag) - dag_scene_build(bmain, sce); + if (DEG_depsgraph_use_legacy()) { + if (!sce->theDag) + dag_scene_build(bmain, sce); + } + else { + /* New dependency graph. */ + DEG_scene_relations_update(bmain, sce); + } +} + +void DAG_scene_relations_validate(Main *bmain, Scene *sce) +{ + if (!DEG_depsgraph_use_legacy()) { + DEG_debug_scene_relations_validate(bmain, sce); + } } void DAG_scene_free(Scene *sce) { - if (sce->theDag) { - free_forest(sce->theDag); - MEM_freeN(sce->theDag); - sce->theDag = NULL; + if (DEG_depsgraph_use_legacy()) { + if (sce->theDag) { + free_forest(sce->theDag); + MEM_freeN(sce->theDag); + sce->theDag = NULL; + } + } + else { + if (sce->depsgraph) { + DEG_graph_free(sce->depsgraph); + sce->depsgraph = NULL; + } } } @@ -1889,7 +1937,11 @@ void DAG_scene_flush_update(Main *bmain, Scene *sce, unsigned int lay, const sho DagAdjList *itA; Object *ob; int lasttime; - + + if (!DEG_depsgraph_use_legacy()) { + return; + } + if (sce->theDag == NULL) { printf("DAG zero... not allowed to happen!\n"); DAG_scene_relations_update(bmain, sce); @@ -2300,7 +2352,7 @@ static void dag_current_scene_layers(Main *bmain, ListBase *lb) } } -static void dag_group_on_visible_update(Group *group) +static void dag_group_on_visible_update(Scene *scene, Group *group) { GroupObject *go; @@ -2322,7 +2374,7 @@ static void dag_group_on_visible_update(Group *group) } if (go->ob->dup_group) - dag_group_on_visible_update(go->ob->dup_group); + dag_group_on_visible_update(scene, go->ob->dup_group); } } @@ -2330,7 +2382,13 @@ void DAG_on_visible_update(Main *bmain, const bool do_time) { ListBase listbase; DagSceneLayer *dsl; - + + if (!DEG_depsgraph_use_legacy()) { + /* Inform new dependnecy graphs about visibility changes. */ + DEG_on_visible_update(bmain, do_time); + return; + } + /* get list of visible scenes and layers */ dag_current_scene_layers(bmain, &listbase); @@ -2357,7 +2415,8 @@ void DAG_on_visible_update(Main *bmain, const bool do_time) oblay = (node) ? node->lay : ob->lay; if ((oblay & lay) & ~scene->lay_updated) { - if (ELEM(ob->type, OB_MESH, OB_CURVE, OB_SURF, OB_FONT, OB_MBALL, OB_LATTICE)) { + /* TODO(sergey): Why do we need armature here now but didn't need before? */ + if (ELEM(ob->type, OB_MESH, OB_CURVE, OB_SURF, OB_FONT, OB_MBALL, OB_LATTICE, OB_ARMATURE)) { ob->recalc |= OB_RECALC_DATA; lib_id_recalc_tag(bmain, &ob->id); } @@ -2375,7 +2434,7 @@ void DAG_on_visible_update(Main *bmain, const bool do_time) lib_id_recalc_tag(bmain, &ob->id); } if (ob->dup_group) - dag_group_on_visible_update(ob->dup_group); + dag_group_on_visible_update(scene, ob->dup_group); } } @@ -2609,7 +2668,12 @@ void DAG_ids_flush_tagged(Main *bmain) ListBase *lbarray[MAX_LIBARRAY]; int a; bool do_flush = false; - + + if (!DEG_depsgraph_use_legacy()) { + DEG_ids_flush_tagged(bmain); + return; + } + /* get list of visible scenes and layers */ dag_current_scene_layers(bmain, &listbase); @@ -2653,6 +2717,11 @@ void DAG_ids_check_recalc(Main *bmain, Scene *scene, bool time) int a; bool updated = false; + if (!DEG_depsgraph_use_legacy()) { + DEG_ids_check_recalc(bmain, scene, time); + return; + } + /* loop over all ID types */ a = set_listbasepointers(bmain, lbarray); @@ -2769,6 +2838,11 @@ void DAG_ids_clear_recalc(Main *bmain) void DAG_id_tag_update_ex(Main *bmain, ID *id, short flag) { + if (!DEG_depsgraph_use_legacy()) { + DEG_id_tag_update_ex(bmain, id, flag); + return; + } + if (id == NULL) return; if (G.debug & G_DEBUG_DEPSGRAPH) { @@ -3160,6 +3234,10 @@ short DAG_get_eval_flags_for_object(Scene *scene, void *object) { DagNode *node; + if (!DEG_depsgraph_use_legacy()) { + return DEG_get_eval_flags_for_id(scene->depsgraph, (ID *)object); + } + if (scene->theDag == NULL) { /* Happens when converting objects to mesh from a python script * after modifying scene graph. @@ -3198,3 +3276,286 @@ bool DAG_is_acyclic(Scene *scene) { return scene->theDag->is_acyclic; } + +#else + +/* ********************************************************************* + * Stubs to avoid linking issues and make sure legacy crap is not used * + * ********************************************************************* + */ + +DagNodeQueue *queue_create(int UNUSED(slots)) +{ + BLI_assert(!"Should not be used with new dependnecy graph"); + return NULL; +} + +void queue_raz(DagNodeQueue *UNUSED(queue)) +{ + BLI_assert(!"Should not be used with new dependnecy graph"); +} + +void queue_delete(DagNodeQueue *UNUSED(queue)) +{ + BLI_assert(!"Should not be used with new dependnecy graph"); +} + +void push_queue(DagNodeQueue *UNUSED(queue), DagNode *UNUSED(node)) +{ + BLI_assert(!"Should not be used with new dependnecy graph"); +} + +void push_stack(DagNodeQueue *UNUSED(queue), DagNode *UNUSED(node)) +{ + BLI_assert(!"Should not be used with new dependnecy graph"); +} + +DagNode *pop_queue(DagNodeQueue *UNUSED(queue)) +{ + BLI_assert(!"Should not be used with new dependnecy graph"); + return NULL; +} + +DagNode *get_top_node_queue(DagNodeQueue *UNUSED(queue)) +{ + BLI_assert(!"Should not be used with new dependnecy graph"); + return NULL; +} + +DagForest *dag_init(void) +{ + BLI_assert(!"Should not be used with new dependnecy graph"); + return NULL; +} + +DagForest *build_dag(Main *UNUSED(bmain), + Scene *UNUSED(sce), + short UNUSED(mask)) +{ + BLI_assert(!"Should not be used with new dependnecy graph"); + return NULL; +} + +void free_forest(DagForest *UNUSED(Dag)) +{ + BLI_assert(!"Should not be used with new dependnecy graph"); +} + +DagNode *dag_find_node(DagForest *UNUSED(forest), void *UNUSED(fob)) +{ + BLI_assert(!"Should not be used with new dependnecy graph"); + return NULL; +} + +DagNode *dag_add_node(DagForest *UNUSED(forest), void *UNUSED(fob)) +{ + BLI_assert(!"Should not be used with new dependnecy graph"); + return NULL; +} + +DagNode *dag_get_node(DagForest *UNUSED(forest), void *UNUSED(fob)) +{ + BLI_assert(!"Should not be used with new dependnecy graph"); + return NULL; +} + +DagNode *dag_get_sub_node(DagForest *UNUSED(forest), void *UNUSED(fob)) +{ + BLI_assert(!"Should not be used with new dependnecy graph"); + return NULL; +} + +void dag_add_relation(DagForest *UNUSED(forest), + DagNode *UNUSED(fob1), + DagNode *UNUSED(fob2), + short UNUSED(rel), + const char *UNUSED(name)) +{ + BLI_assert(!"Should not be used with new dependnecy graph"); +} + +/* debug test functions */ + +void graph_print_queue(DagNodeQueue *UNUSED(nqueue)) +{ + BLI_assert(!"Should not be used with new dependnecy graph"); +} + +void graph_print_queue_dist(DagNodeQueue *UNUSED(nqueue)) +{ + BLI_assert(!"Should not be used with new dependnecy graph"); +} + +void graph_print_adj_list(DagForest *UNUSED(dag)) +{ + BLI_assert(!"Should not be used with new dependnecy graph"); +} + +void DAG_scene_flush_update(Main *UNUSED(bmain), + Scene *UNUSED(sce), + unsigned int UNUSED(lay), + const short UNUSED(time)) +{ + BLI_assert(!"Should not be used with new dependnecy graph"); +} + +void DAG_scene_update_flags(Main *UNUSED(bmain), + Scene *UNUSED(scene), + unsigned int UNUSED(lay), + const bool UNUSED(do_time), + const bool UNUSED(do_invisible_flush)) +{ + BLI_assert(!"Should not be used with new dependnecy graph"); +} + +/* ******************* DAG FOR ARMATURE POSE ***************** */ + +void DAG_pose_sort(Object *UNUSED(ob)) +{ + BLI_assert(!"Should not be used with new dependnecy graph"); +} + +/* ************************ DAG FOR THREADED UPDATE ********************* */ + +void DAG_threaded_update_begin(Scene *UNUSED(scene), + void (*func)(void *node, void *user_data), + void *UNUSED(user_data)) +{ + BLI_assert(!"Should not be used with new dependnecy graph"); + (void)func; +} + +void DAG_threaded_update_handle_node_updated(void *UNUSED(node_v), + void (*func)(void *node, void *user_data), + void *UNUSED(user_data)) +{ + BLI_assert(!"Should not be used with new dependnecy graph"); + (void)func; +} + +/* ************************ DAG querying ********************* */ + +Object *DAG_get_node_object(void *UNUSED(node_v)) +{ + BLI_assert(!"Should not be used with new dependnecy graph"); + return NULL; +} + +const char *DAG_get_node_name(Scene *UNUSED(scene), void *UNUSED(node_v)) +{ + BLI_assert(!"Should not be used with new dependnecy graph"); + return "INVALID"; +} + +bool DAG_is_acyclic(Scene *UNUSED(scene)) +{ + BLI_assert(!"Should not be used with new dependnecy graph"); + return false; +} + +/* ************************************ + * This functions are to be supported * + * ************************************ + */ + +void DAG_init(void) +{ + DEG_register_node_types(); +} + +void DAG_exit(void) +{ + DEG_free_node_types(); +} + +/* ************************ API *********************** */ + +void DAG_editors_update_cb(DEG_EditorUpdateIDCb id_func, + DEG_EditorUpdateSceneCb scene_func) +{ + DEG_editors_set_update_cb(id_func, scene_func); +} + +/* Tag all relations for update. */ +void DAG_relations_tag_update(Main *bmain) +{ + DEG_relations_tag_update(bmain); +} + +/* Rebuild dependency graph only for a given scene. */ +void DAG_scene_relations_rebuild(Main *bmain, Scene *scene) +{ + DEG_scene_relations_rebuild(bmain, scene); +} + +/* Create dependency graph if it was cleared or didn't exist yet. */ +void DAG_scene_relations_update(Main *bmain, Scene *scene) +{ + DEG_scene_relations_update(bmain, scene); +} + +void DAG_scene_relations_validate(Main *bmain, Scene *scene) +{ + DEG_debug_scene_relations_validate(bmain, scene); +} + +void DAG_scene_free(Scene *scene) +{ + DEG_scene_graph_free(scene); +} + +void DAG_on_visible_update(Main *bmain, const bool do_time) +{ + DEG_on_visible_update(bmain, do_time); +} + +void DAG_ids_check_recalc(Main *bmain, Scene *scene, bool time) +{ + DEG_ids_check_recalc(bmain, scene, time); +} + +void DAG_id_tag_update(ID *id, short flag) +{ + DEG_id_tag_update_ex(G.main, id, flag); +} + +void DAG_id_tag_update_ex(Main *bmain, ID *id, short flag) +{ + DEG_id_tag_update_ex(bmain, id, flag); +} + +void DAG_id_type_tag(Main *bmain, short idtype) +{ + DEG_id_type_tag(bmain, idtype); +} + +int DAG_id_type_tagged(Main *bmain, short idtype) +{ + return DEG_id_type_tagged(bmain, idtype); +} + +void DAG_ids_clear_recalc(Main *bmain) +{ + DEG_ids_clear_recalc(bmain); +} + +short DAG_get_eval_flags_for_object(Scene *scene, void *object) +{ + return DEG_get_eval_flags_for_id(scene->depsgraph, (ID *)object); +} + +void DAG_ids_flush_tagged(Main *bmain) +{ + DEG_ids_flush_tagged(bmain); +} + +/* ************************ DAG DEBUGGING ********************* */ + +void DAG_print_dependencies(Main *UNUSED(bmain), + Scene *scene, + Object *UNUSED(ob)) +{ + DEG_debug_graphviz(scene->depsgraph, stdout, "Depsgraph", false); +} + +#endif diff --git a/source/blender/blenkernel/intern/dynamicpaint.c b/source/blender/blenkernel/intern/dynamicpaint.c index 5c9e516aee9..8dac578ac0a 100644 --- a/source/blender/blenkernel/intern/dynamicpaint.c +++ b/source/blender/blenkernel/intern/dynamicpaint.c @@ -2964,15 +2964,16 @@ static void mesh_faces_nearest_point_dp(void *userdata, int index, const float c /** * Mix color values to canvas point. * - * \param surface canvas surface - * \param index surface point index - * \param paintFlags paint object flags - * \param paintColor,Alpha,Wetness to be mixed paint values - * \param timescale value used to adjust time dependent + * \param surface: Canvas surface + * \param index: Surface point index + * \param paintFlags: paint object flags + * \param paintColor,paintAlpha,paintWetness: To be mixed paint values + * \param timescale: Value used to adjust time dependent * operations when using substeps */ -static void dynamicPaint_mixPaintColors(DynamicPaintSurface *surface, int index, int paintFlags, - const float paintColor[3], float *paintAlpha, float *paintWetness, float *timescale) +static void dynamicPaint_mixPaintColors( + DynamicPaintSurface *surface, int index, int paintFlags, + const float paintColor[3], float *paintAlpha, float *paintWetness, float *timescale) { PaintPoint *pPoint = &((PaintPoint *)surface->data->type_data)[index]; diff --git a/source/blender/blenkernel/intern/editderivedmesh.c b/source/blender/blenkernel/intern/editderivedmesh.c index 40f3022c192..fbce501f57f 100644 --- a/source/blender/blenkernel/intern/editderivedmesh.c +++ b/source/blender/blenkernel/intern/editderivedmesh.c @@ -521,8 +521,6 @@ static void emDM_drawMappedFaces(DerivedMesh *dm, GLenum poly_prev = GL_ZERO; GLenum shade_prev = GL_ZERO; - (void)setMaterial; /* UNUSED */ - /* currently unused -- each original face is handled separately */ (void)compareDrawOptions; @@ -539,6 +537,8 @@ static void emDM_drawMappedFaces(DerivedMesh *dm, } if (bmdm->vertexCos) { + short prev_mat_nr = -1; + /* add direct access */ const float (*vertexCos)[3] = bmdm->vertexCos; const float (*vertexNos)[3]; @@ -569,8 +569,14 @@ static void emDM_drawMappedFaces(DerivedMesh *dm, setDrawOptions(userData, BM_elem_index_get(efa))); if (draw_option != DM_DRAW_OPTION_SKIP) { const GLenum poly_type = GL_TRIANGLES; /* BMESH NOTE, this is odd but keep it for now to match trunk */ - if (setMaterial) - setMaterial(efa->mat_nr + 1, NULL); + + if (efa->mat_nr != prev_mat_nr) { + if (setMaterial) { + setMaterial(efa->mat_nr + 1, NULL); + } + prev_mat_nr = efa->mat_nr; + } + if (draw_option == DM_DRAW_OPTION_STIPPLE) { /* enabled with stipple */ if (poly_prev != GL_ZERO) glEnd(); @@ -645,6 +651,8 @@ static void emDM_drawMappedFaces(DerivedMesh *dm, } } else { + short prev_mat_nr = -1; + BM_mesh_elem_index_ensure(bm, lnors ? BM_FACE | BM_LOOP : BM_FACE); for (i = 0; i < tottri; i++) { @@ -661,8 +669,12 @@ static void emDM_drawMappedFaces(DerivedMesh *dm, if (draw_option != DM_DRAW_OPTION_SKIP) { const GLenum poly_type = GL_TRIANGLES; /* BMESH NOTE, this is odd but keep it for now to match trunk */ - if (setMaterial) - setMaterial(efa->mat_nr + 1, NULL); + if (efa->mat_nr != prev_mat_nr) { + if (setMaterial) { + setMaterial(efa->mat_nr + 1, NULL); + } + prev_mat_nr = efa->mat_nr; + } if (draw_option == DM_DRAW_OPTION_STIPPLE) { /* enabled with stipple */ @@ -985,7 +997,7 @@ static void emDM_drawMappedFacesTex(DerivedMesh *dm, * ... because the material may use layer names to select different UV's * see: [#34378] */ -static void emdm_pass_attrib_vertex_glsl(const DMVertexAttribs *attribs, const BMLoop *loop, const int index_in_face) +static void emdm_pass_attrib_vertex_glsl(const DMVertexAttribs *attribs, const BMLoop *loop, const int index_in_face, const int face_index) { BMVert *eve = loop->v; int i; @@ -1028,7 +1040,7 @@ static void emdm_pass_attrib_vertex_glsl(const DMVertexAttribs *attribs, const B glVertexAttrib4ubvARB(attribs->mcol[i].gl_index, col); } if (attribs->tottang) { - int index = i * 4 + index_in_face; + int index = face_index * 4 + index_in_face; const float *tang = (attribs->tang.array) ? attribs->tang.array[index] : zero; glVertexAttrib4fvARB(attribs->tang.gl_index, tang); } @@ -1100,14 +1112,14 @@ static void emDM_drawMappedFacesGLSL(DerivedMesh *dm, if (vertexCos) { glNormal3fv(polyNos[BM_elem_index_get(efa)]); for (fi = 0; fi < 3; fi++) { - emdm_pass_attrib_vertex_glsl(&attribs, ltri[fi], fi); + emdm_pass_attrib_vertex_glsl(&attribs, ltri[fi], fi, i); glVertex3fv(vertexCos[BM_elem_index_get(ltri[fi]->v)]); } } else { glNormal3fv(efa->no); for (fi = 0; fi < 3; fi++) { - emdm_pass_attrib_vertex_glsl(&attribs, ltri[fi], fi); + emdm_pass_attrib_vertex_glsl(&attribs, ltri[fi], fi, i); glVertex3fv(ltri[fi]->v->co); } } @@ -1116,7 +1128,7 @@ static void emDM_drawMappedFacesGLSL(DerivedMesh *dm, if (vertexCos) { for (fi = 0; fi < 3; fi++) { const int j = BM_elem_index_get(ltri[fi]->v); - emdm_pass_attrib_vertex_glsl(&attribs, ltri[fi], fi); + emdm_pass_attrib_vertex_glsl(&attribs, ltri[fi], fi, i); if (lnors) glNormal3fv(lnors[BM_elem_index_get(ltri[fi])]); else glNormal3fv(vertexNos[j]); glVertex3fv(vertexCos[j]); @@ -1124,7 +1136,7 @@ static void emDM_drawMappedFacesGLSL(DerivedMesh *dm, } else { for (fi = 0; fi < 3; fi++) { - emdm_pass_attrib_vertex_glsl(&attribs, ltri[fi], fi); + emdm_pass_attrib_vertex_glsl(&attribs, ltri[fi], fi, i); if (lnors) glNormal3fv(lnors[BM_elem_index_get(ltri[fi])]); else glNormal3fv(ltri[fi]->v->no); glVertex3fv(ltri[fi]->v->co); @@ -1204,14 +1216,14 @@ static void emDM_drawMappedFacesMat(DerivedMesh *dm, if (vertexCos) { glNormal3fv(polyNos[BM_elem_index_get(efa)]); for (fi = 0; fi < 3; fi++) { - emdm_pass_attrib_vertex_glsl(&attribs, ltri[fi], fi); + emdm_pass_attrib_vertex_glsl(&attribs, ltri[fi], fi, i); glVertex3fv(vertexCos[BM_elem_index_get(ltri[fi]->v)]); } } else { glNormal3fv(efa->no); for (fi = 0; fi < 3; fi++) { - emdm_pass_attrib_vertex_glsl(&attribs, ltri[fi], fi); + emdm_pass_attrib_vertex_glsl(&attribs, ltri[fi], fi, i); glVertex3fv(ltri[fi]->v->co); } } @@ -1220,7 +1232,7 @@ static void emDM_drawMappedFacesMat(DerivedMesh *dm, if (vertexCos) { for (fi = 0; fi < 3; fi++) { const int j = BM_elem_index_get(ltri[fi]->v); - emdm_pass_attrib_vertex_glsl(&attribs, ltri[fi], fi); + emdm_pass_attrib_vertex_glsl(&attribs, ltri[fi], fi, i); if (lnors) glNormal3fv(lnors[BM_elem_index_get(ltri[fi])]); else glNormal3fv(vertexNos[j]); glVertex3fv(vertexCos[j]); @@ -1228,7 +1240,7 @@ static void emDM_drawMappedFacesMat(DerivedMesh *dm, } else { for (fi = 0; fi < 3; fi++) { - emdm_pass_attrib_vertex_glsl(&attribs, ltri[fi], fi); + emdm_pass_attrib_vertex_glsl(&attribs, ltri[fi], fi, i); if (lnors) glNormal3fv(lnors[BM_elem_index_get(ltri[fi])]); else glNormal3fv(ltri[fi]->v->no); glVertex3fv(ltri[fi]->v->co); @@ -1968,7 +1980,7 @@ static void statvis_calc_thickness( BLI_assert(min <= max); - fill_vn_fl(face_dists, em->bm->totface, max); + copy_vn_fl(face_dists, em->bm->totface, max); if (use_jit) { int j; @@ -2223,7 +2235,7 @@ static void statvis_calc_sharp( (void)vertexCos; /* TODO */ - fill_vn_fl(vert_angles, em->bm->totvert, -M_PI); + copy_vn_fl(vert_angles, em->bm->totvert, -M_PI); /* first assign float values to verts */ BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) { diff --git a/source/blender/blenkernel/intern/effect.c b/source/blender/blenkernel/intern/effect.c index 296a56ada5d..785561d8239 100644 --- a/source/blender/blenkernel/intern/effect.c +++ b/source/blender/blenkernel/intern/effect.c @@ -1176,7 +1176,7 @@ void BKE_sim_debug_data_clear_category(const char *category) GHashIterator iter; BLI_ghashIterator_init(&iter, _sim_debug_data->gh); while (!BLI_ghashIterator_done(&iter)) { - SimDebugElement *elem = BLI_ghashIterator_getValue(&iter); + const SimDebugElement *elem = BLI_ghashIterator_getValue(&iter); BLI_ghashIterator_step(&iter); /* removing invalidates the current iterator, so step before removing */ if (elem->category_hash == category_hash) diff --git a/source/blender/blenkernel/intern/fcurve.c b/source/blender/blenkernel/intern/fcurve.c index 413e34e72a8..6e58513e38e 100644 --- a/source/blender/blenkernel/intern/fcurve.c +++ b/source/blender/blenkernel/intern/fcurve.c @@ -46,6 +46,7 @@ #include "BLI_blenlib.h" #include "BLI_math.h" #include "BLI_easing.h" +#include "BLI_threads.h" #include "BLI_utildefines.h" #include "BLF_translation.h" @@ -69,6 +70,10 @@ #define SMALL -1.0e-10 #define SELECT 1 +#ifdef WITH_PYTHON +static ThreadMutex python_driver_lock = BLI_MUTEX_INITIALIZER; +#endif + /* ************************** Data-Level Functions ************************* */ /* ---------------------- Freeing --------------------------- */ @@ -1807,7 +1812,9 @@ static float evaluate_driver(ChannelDriver *driver, const float evaltime) /* this evaluates the expression using Python, and returns its result: * - on errors it reports, then returns 0.0f */ + BLI_mutex_lock(&python_driver_lock); driver->curval = BPY_driver_exec(driver, evaltime); + BLI_mutex_unlock(&python_driver_lock); } #else /* WITH_PYTHON*/ (void)evaltime; diff --git a/source/blender/blenkernel/intern/icons.c b/source/blender/blenkernel/intern/icons.c index d3225f3fa35..daf39116d76 100644 --- a/source/blender/blenkernel/intern/icons.c +++ b/source/blender/blenkernel/intern/icons.c @@ -45,6 +45,7 @@ #include "BLI_utildefines.h" #include "BLI_ghash.h" +#include "BLI_string.h" #include "BKE_icons.h" #include "BKE_global.h" /* only for G.background test */ @@ -53,6 +54,10 @@ #include "GPU_extensions.h" +#include "IMB_imbuf.h" +#include "IMB_imbuf_types.h" +#include "IMB_thumbs.h" + /* GLOBALS */ static GHash *gIcons = NULL; @@ -61,6 +66,7 @@ static int gNextIconId = 1; static int gFirstIconId = 1; +static GHash *gCachedPreviews = NULL; static void icon_free(void *val) { @@ -105,30 +111,50 @@ void BKE_icons_init(int first_dyn_id) gFirstIconId = first_dyn_id; if (!gIcons) - gIcons = BLI_ghash_int_new("icons_init gh"); + gIcons = BLI_ghash_int_new(__func__); + + if (!gCachedPreviews) { + gCachedPreviews = BLI_ghash_str_new(__func__); + } } void BKE_icons_free(void) { - if (gIcons) + if (gIcons) { BLI_ghash_free(gIcons, NULL, icon_free); - gIcons = NULL; + gIcons = NULL; + } + + if (gCachedPreviews) { + BLI_ghash_free(gCachedPreviews, MEM_freeN, BKE_previewimg_freefunc); + gCachedPreviews = NULL; + } } -PreviewImage *BKE_previewimg_create(void) +static PreviewImage *previewimg_create_ex(size_t deferred_data_size) { PreviewImage *prv_img = NULL; int i; - prv_img = MEM_callocN(sizeof(PreviewImage), "img_prv"); + prv_img = MEM_mallocN(sizeof(PreviewImage) + deferred_data_size, "img_prv"); + memset(prv_img, 0, sizeof(*prv_img)); /* leave deferred data dirty */ + + if (deferred_data_size) { + prv_img->use_deferred = true; + } for (i = 0; i < NUM_ICON_SIZES; ++i) { - prv_img->changed[i] = 1; + prv_img->flag[i] |= PRV_CHANGED; prv_img->changed_timestamp[i] = 0; } return prv_img; } +PreviewImage *BKE_previewimg_create(void) +{ + return previewimg_create_ex(0); +} + void BKE_previewimg_freefunc(void *link) { PreviewImage *prv = (PreviewImage *)link; @@ -138,7 +164,6 @@ void BKE_previewimg_freefunc(void *link) for (i = 0; i < NUM_ICON_SIZES; ++i) { if (prv->rect[i]) { MEM_freeN(prv->rect[i]); - prv->rect[i] = NULL; } if (prv->gputexture[i]) GPU_texture_free(prv->gputexture[i]); @@ -156,6 +181,26 @@ void BKE_previewimg_free(PreviewImage **prv) } } +void BKE_previewimg_clear_single(struct PreviewImage *prv, enum eIconSizes size) +{ + MEM_SAFE_FREE(prv->rect[size]); + if (prv->gputexture[size]) { + GPU_texture_free(prv->gputexture[size]); + } + prv->h[size] = prv->w[size] = 0; + prv->flag[size] |= PRV_CHANGED; + prv->flag[size] &= ~PRV_USER_EDITED; + prv->changed_timestamp[size] = 0; +} + +void BKE_previewimg_clear(struct PreviewImage *prv) +{ + int i; + for (i = 0; i < NUM_ICON_SIZES; ++i) { + BKE_previewimg_clear_single(prv, i); + } +} + PreviewImage *BKE_previewimg_copy(PreviewImage *prv) { PreviewImage *prv_img = NULL; @@ -167,79 +212,186 @@ PreviewImage *BKE_previewimg_copy(PreviewImage *prv) if (prv->rect[i]) { prv_img->rect[i] = MEM_dupallocN(prv->rect[i]); } - else { - prv_img->rect[i] = NULL; - } prv_img->gputexture[i] = NULL; } } return prv_img; } -void BKE_previewimg_free_id(ID *id) +PreviewImage **BKE_previewimg_id_get_p(ID *id) { - if (GS(id->name) == ID_MA) { - Material *mat = (Material *)id; - BKE_previewimg_free(&mat->preview); - } - else if (GS(id->name) == ID_TE) { - Tex *tex = (Tex *)id; - BKE_previewimg_free(&tex->preview); - } - else if (GS(id->name) == ID_WO) { - World *wo = (World *)id; - BKE_previewimg_free(&wo->preview); + switch (GS(id->name)) { +#define ID_PRV_CASE(id_code, id_struct) case id_code: { return &((id_struct *)id)->preview; } + ID_PRV_CASE(ID_MA, Material); + ID_PRV_CASE(ID_TE, Tex); + ID_PRV_CASE(ID_WO, World); + ID_PRV_CASE(ID_LA, Lamp); + ID_PRV_CASE(ID_IM, Image); + ID_PRV_CASE(ID_BR, Brush); +#undef ID_PRV_CASE } - else if (GS(id->name) == ID_LA) { - Lamp *la = (Lamp *)id; - BKE_previewimg_free(&la->preview); - } - else if (GS(id->name) == ID_IM) { - Image *img = (Image *)id; - BKE_previewimg_free(&img->preview); + + return NULL; +} + +void BKE_previewimg_id_free(ID *id) +{ + PreviewImage **prv_p = BKE_previewimg_id_get_p(id); + if (prv_p) { + BKE_previewimg_free(prv_p); } - else if (GS(id->name) == ID_BR) { - Brush *br = (Brush *)id; - BKE_previewimg_free(&br->preview); +} + +PreviewImage *BKE_previewimg_id_ensure(ID *id) +{ + PreviewImage **prv_p = BKE_previewimg_id_get_p(id); + + if (prv_p) { + if (*prv_p == NULL) { + *prv_p = BKE_previewimg_create(); + } + return *prv_p; } + + return NULL; } -PreviewImage *BKE_previewimg_get(ID *id) +PreviewImage *BKE_previewimg_cached_get(const char *name) { - PreviewImage *prv_img = NULL; + return BLI_ghash_lookup(gCachedPreviews, name); +} - if (GS(id->name) == ID_MA) { - Material *mat = (Material *)id; - if (!mat->preview) mat->preview = BKE_previewimg_create(); - prv_img = mat->preview; +/** + * Generate an empty PreviewImage, if not yet existing. + */ +PreviewImage *BKE_previewimg_cached_ensure(const char *name) +{ + PreviewImage *prv = NULL; + void **prv_p; + + if (!BLI_ghash_ensure_p_ex(gCachedPreviews, name, &prv_p, (GHashKeyCopyFP)BLI_strdup)) { + *prv_p = BKE_previewimg_create(); } - else if (GS(id->name) == ID_TE) { - Tex *tex = (Tex *)id; - if (!tex->preview) tex->preview = BKE_previewimg_create(); - prv_img = tex->preview; + prv = *prv_p; + BLI_assert(prv); + + return prv; +} + +/** + * Generate a PreviewImage from given file path, using thumbnails management, if not yet existing. + */ +PreviewImage *BKE_previewimg_cached_thumbnail_read( + const char *name, const char *path, const int source, bool force_update) +{ + PreviewImage *prv = NULL; + void **prv_p; + + prv_p = BLI_ghash_lookup_p(gCachedPreviews, name); + + if (prv_p) { + prv = *prv_p; + BLI_assert(prv); } - else if (GS(id->name) == ID_WO) { - World *wo = (World *)id; - if (!wo->preview) wo->preview = BKE_previewimg_create(); - prv_img = wo->preview; + + if (prv && force_update) { + const char *prv_deferred_data = PRV_DEFERRED_DATA(prv); + if (((int)prv_deferred_data[0] == source) && STREQ(&prv_deferred_data[1], path)) { + /* If same path, no need to re-allocate preview, just clear it up. */ + BKE_previewimg_clear(prv); + } + else { + BKE_previewimg_free(&prv); + } } - else if (GS(id->name) == ID_LA) { - Lamp *la = (Lamp *)id; - if (!la->preview) la->preview = BKE_previewimg_create(); - prv_img = la->preview; + + if (!prv) { + /* We pack needed data for lazy loading (source type, in a single char, and path). */ + const size_t deferred_data_size = strlen(path) + 2; + char *deferred_data; + + prv = previewimg_create_ex(deferred_data_size); + deferred_data = PRV_DEFERRED_DATA(prv); + deferred_data[0] = source; + memcpy(&deferred_data[1], path, deferred_data_size - 1); + + force_update = true; } - else if (GS(id->name) == ID_IM) { - Image *img = (Image *)id; - if (!img->preview) img->preview = BKE_previewimg_create(); - prv_img = img->preview; + + if (force_update) { + if (prv_p) { + *prv_p = prv; + } + else { + BLI_ghash_insert(gCachedPreviews, BLI_strdup(name), prv); + } } - else if (GS(id->name) == ID_BR) { - Brush *br = (Brush *)id; - if (!br->preview) br->preview = BKE_previewimg_create(); - prv_img = br->preview; + + return prv; +} + +void BKE_previewimg_cached_release(const char *name) +{ + PreviewImage *prv = BLI_ghash_popkey(gCachedPreviews, name, MEM_freeN); + + if (prv) { + if (prv->icon_id) { + BKE_icon_delete(prv->icon_id); + } + BKE_previewimg_freefunc(prv); } +} - return prv_img; +/** Handle deferred (lazy) loading/generation of preview image, if needed. + * For now, only used with file thumbnails. */ +void BKE_previewimg_ensure(PreviewImage *prv, const int size) +{ + if (prv->use_deferred) { + const bool do_icon = ((size == ICON_SIZE_ICON) && !prv->rect[ICON_SIZE_ICON]); + const bool do_preview = ((size == ICON_SIZE_PREVIEW) && !prv->rect[ICON_SIZE_PREVIEW]); + + if (do_icon || do_preview) { + ImBuf *thumb; + char *prv_deferred_data = PRV_DEFERRED_DATA(prv); + int source = prv_deferred_data[0]; + char *path = &prv_deferred_data[1]; + int icon_w, icon_h; + + thumb = IMB_thumb_manage(path, THB_LARGE, source); + + if (thumb) { + /* PreviewImage assumes premultiplied alhpa... */ + IMB_premultiply_alpha(thumb); + + if (do_preview) { + prv->w[ICON_SIZE_PREVIEW] = thumb->x; + prv->h[ICON_SIZE_PREVIEW] = thumb->y; + prv->rect[ICON_SIZE_PREVIEW] = MEM_dupallocN(thumb->rect); + prv->flag[ICON_SIZE_PREVIEW] &= ~(PRV_CHANGED | PRV_USER_EDITED); + } + if (do_icon) { + if (thumb->x > thumb->y) { + icon_w = ICON_RENDER_DEFAULT_HEIGHT; + icon_h = (thumb->y * icon_w) / thumb->x + 1; + } + else if (thumb->x < thumb->y) { + icon_h = ICON_RENDER_DEFAULT_HEIGHT; + icon_w = (thumb->x * icon_h) / thumb->y + 1; + } + else { + icon_w = icon_h = ICON_RENDER_DEFAULT_HEIGHT; + } + + IMB_scaleImBuf(thumb, icon_w, icon_h); + prv->w[ICON_SIZE_ICON] = icon_w; + prv->h[ICON_SIZE_ICON] = icon_h; + prv->rect[ICON_SIZE_ICON] = MEM_dupallocN(thumb->rect); + prv->flag[ICON_SIZE_ICON] &= ~(PRV_CHANGED | PRV_USER_EDITED); + } + IMB_freeImBuf(thumb); + } + } + } } void BKE_icon_changed(int id) @@ -251,20 +403,20 @@ void BKE_icon_changed(int id) icon = BLI_ghash_lookup(gIcons, SET_INT_IN_POINTER(id)); if (icon) { - PreviewImage *prv = BKE_previewimg_get((ID *)icon->obj); + PreviewImage *prv = BKE_previewimg_id_ensure((ID *)icon->obj); /* all previews changed */ if (prv) { int i; for (i = 0; i < NUM_ICON_SIZES; ++i) { - prv->changed[i] = 1; + prv->flag[i] |= PRV_CHANGED; prv->changed_timestamp[i]++; } } } } -int BKE_icon_getid(struct ID *id) +int BKE_icon_id_ensure(struct ID *id) { Icon *new_icon = NULL; @@ -277,11 +429,11 @@ int BKE_icon_getid(struct ID *id) id->icon_id = get_next_free_id(); if (!id->icon_id) { - printf("BKE_icon_getid: Internal error - not enough IDs\n"); + printf("%s: Internal error - not enough IDs\n", __func__); return 0; } - new_icon = MEM_callocN(sizeof(Icon), "texicon"); + new_icon = MEM_mallocN(sizeof(Icon), __func__); new_icon->obj = id; new_icon->type = GS(id->name); @@ -295,6 +447,40 @@ int BKE_icon_getid(struct ID *id) return id->icon_id; } +/** + * Return icon id of given preview, or create new icon if not found. + */ +int BKE_icon_preview_ensure(PreviewImage *preview) +{ + Icon *new_icon = NULL; + + if (!preview || G.background) + return 0; + + if (preview->icon_id) + return preview->icon_id; + + preview->icon_id = get_next_free_id(); + + if (!preview->icon_id) { + printf("%s: Internal error - not enough IDs\n", __func__); + return 0; + } + + new_icon = MEM_mallocN(sizeof(Icon), __func__); + + new_icon->obj = preview; + new_icon->type = 0; /* Special, tags as non-ID icon/preview. */ + + /* next two lines make sure image gets created */ + new_icon->drawinfo = NULL; + new_icon->drawinfo_free = NULL; + + BLI_ghash_insert(gIcons, SET_INT_IN_POINTER(preview->icon_id), new_icon); + + return preview->icon_id; +} + Icon *BKE_icon_get(int icon_id) { Icon *icon = NULL; @@ -302,7 +488,7 @@ Icon *BKE_icon_get(int icon_id) icon = BLI_ghash_lookup(gIcons, SET_INT_IN_POINTER(icon_id)); if (!icon) { - printf("BKE_icon_get: Internal error, no icon for icon ID: %d\n", icon_id); + printf("%s: Internal error, no icon for icon ID: %d\n", __func__, icon_id); return NULL; } @@ -314,18 +500,39 @@ void BKE_icon_set(int icon_id, struct Icon *icon) void **val_p; if (BLI_ghash_ensure_p(gIcons, SET_INT_IN_POINTER(icon_id), &val_p)) { - printf("BKE_icon_set: Internal error, icon already set: %d\n", icon_id); + printf("%s: Internal error, icon already set: %d\n", __func__, icon_id); return; } *val_p = icon; } -void BKE_icon_delete(struct ID *id) +void BKE_icon_id_delete(struct ID *id) { - if (!id->icon_id) return; /* no icon defined for library object */ BLI_ghash_remove(gIcons, SET_INT_IN_POINTER(id->icon_id), NULL, icon_free); id->icon_id = 0; } + +/** + * Remove icon and free data. + */ +void BKE_icon_delete(int icon_id) +{ + Icon *icon; + + if (!icon_id) return; /* no icon defined for library object */ + + icon = BLI_ghash_popkey(gIcons, SET_INT_IN_POINTER(icon_id), NULL); + + if (icon) { + if (icon->type) { + ((ID *)(icon->obj))->icon_id = 0; + } + else { + ((PreviewImage *)(icon->obj))->icon_id = 0; + } + icon_free(icon); + } +} diff --git a/source/blender/blenkernel/intern/image.c b/source/blender/blenkernel/intern/image.c index a09c42e9178..09934c872f7 100644 --- a/source/blender/blenkernel/intern/image.c +++ b/source/blender/blenkernel/intern/image.c @@ -75,6 +75,7 @@ #include "BKE_library.h" #include "BKE_main.h" #include "BKE_packedFile.h" +#include "BKE_report.h" #include "BKE_scene.h" #include "BKE_node.h" #include "BKE_sequencer.h" /* seq_foreground_frame_get() */ @@ -101,7 +102,7 @@ static SpinLock image_spin; /* prototypes */ static size_t image_num_files(struct Image *ima); -static ImBuf *image_acquire_ibuf(Image *ima, ImageUser *iuser, void **lock_r); +static ImBuf *image_acquire_ibuf(Image *ima, ImageUser *iuser, void **r_lock); static void image_update_views_format(Image *ima, ImageUser *iuser); static void image_add_view(Image *ima, const char *viewname, const char *filepath); @@ -338,7 +339,7 @@ void BKE_image_free(Image *ima) image_free_packedfiles(ima); - BKE_icon_delete(&ima->id); + BKE_icon_id_delete(&ima->id); ima->id.icon_id = 0; BKE_previewimg_free(&ima->preview); @@ -883,12 +884,16 @@ Image *BKE_image_add_generated(Main *bmain, unsigned int width, unsigned int hei /* Create an image image from ibuf. The refcount of ibuf is increased, * caller should take care to drop its reference by calling * IMB_freeImBuf if needed. */ -Image *BKE_image_add_from_imbuf(ImBuf *ibuf) +Image *BKE_image_add_from_imbuf(ImBuf *ibuf, const char *name) { /* on save, type is changed to FILE in editsima.c */ Image *ima; - ima = image_alloc(G.main, BLI_path_basename(ibuf->name), IMA_SRC_FILE, IMA_TYPE_IMAGE); + if (name == NULL) { + name = BLI_path_basename(ibuf->name); + } + + ima = image_alloc(G.main, name, IMA_SRC_FILE, IMA_TYPE_IMAGE); if (ima) { BLI_strncpy(ima->name, ibuf->name, FILE_MAX); @@ -1012,7 +1017,12 @@ void BKE_image_packfiles(ReportList *reports, Image *ima, const char *basepath) ImagePackedFile *imapf = MEM_mallocN(sizeof(ImagePackedFile), "Image packed file"); BLI_addtail(&ima->packedfiles, imapf); imapf->packedfile = newPackedFile(reports, ima->name, basepath); - BLI_strncpy(imapf->filepath, ima->name, sizeof(imapf->filepath)); + if (imapf->packedfile) { + BLI_strncpy(imapf->filepath, ima->name, sizeof(imapf->filepath)); + } + else { + BLI_freelinkN(&ima->packedfiles, imapf); + } } else { ImageView *iv; @@ -1021,11 +1031,31 @@ void BKE_image_packfiles(ReportList *reports, Image *ima, const char *basepath) BLI_addtail(&ima->packedfiles, imapf); imapf->packedfile = newPackedFile(reports, iv->filepath, basepath); - BLI_strncpy(imapf->filepath, iv->filepath, sizeof(imapf->filepath)); + if (imapf->packedfile) { + BLI_strncpy(imapf->filepath, iv->filepath, sizeof(imapf->filepath)); + } + else { + BLI_freelinkN(&ima->packedfiles, imapf); + } } } } +void BKE_image_packfiles_from_mem(ReportList *reports, Image *ima, char *data, const size_t data_len) +{ + const size_t totfiles = image_num_files(ima); + + if (totfiles != 1) { + BKE_report(reports, RPT_ERROR, "Cannot pack multiview images from raw data currently..."); + } + else { + ImagePackedFile *imapf = MEM_mallocN(sizeof(ImagePackedFile), __func__); + BLI_addtail(&ima->packedfiles, imapf); + imapf->packedfile = newPackedFileMemory(data, data_len); + BLI_strncpy(imapf->filepath, ima->name, sizeof(imapf->filepath)); + } +} + void BKE_image_tag_time(Image *ima) { ima->lastused = PIL_check_seconds_timer_i(); @@ -2028,28 +2058,65 @@ void BKE_image_stamp_buf( #undef BUFF_MARGIN_Y } -void BKE_imbuf_stamp_info(Scene *scene, Object *camera, struct ImBuf *ibuf) +void BKE_render_result_stamp_info(Scene *scene, Object *camera, struct RenderResult *rr) { - struct StampData stamp_data; + struct StampData *stamp_data; - if (!ibuf) return; + if (!(scene && scene->r.stamp & R_STAMP_ALL)) + return; - /* fill all the data values, no prefix */ - stampdata(scene, camera, &stamp_data, 0); + if (!rr->stamp_data) { + stamp_data = MEM_callocN(sizeof(StampData), "RenderResult.stamp_data"); + } + else { + stamp_data = rr->stamp_data; + } + + stampdata(scene, camera, stamp_data, 0); - if (stamp_data.file[0]) IMB_metadata_change_field(ibuf, "File", stamp_data.file); - if (stamp_data.note[0]) IMB_metadata_change_field(ibuf, "Note", stamp_data.note); - if (stamp_data.date[0]) IMB_metadata_change_field(ibuf, "Date", stamp_data.date); - if (stamp_data.marker[0]) IMB_metadata_change_field(ibuf, "Marker", stamp_data.marker); - if (stamp_data.time[0]) IMB_metadata_change_field(ibuf, "Time", stamp_data.time); - if (stamp_data.frame[0]) IMB_metadata_change_field(ibuf, "Frame", stamp_data.frame); - if (stamp_data.camera[0]) IMB_metadata_change_field(ibuf, "Camera", stamp_data.camera); - if (stamp_data.cameralens[0]) IMB_metadata_change_field(ibuf, "Lens", stamp_data.cameralens); - if (stamp_data.scene[0]) IMB_metadata_change_field(ibuf, "Scene", stamp_data.scene); - if (stamp_data.strip[0]) IMB_metadata_change_field(ibuf, "Strip", stamp_data.strip); - if (stamp_data.rendertime[0]) IMB_metadata_change_field(ibuf, "RenderTime", stamp_data.rendertime); + if (!rr->stamp_data) { + rr->stamp_data = stamp_data; + } } + +void BKE_imbuf_stamp_info(RenderResult *rr, struct ImBuf *ibuf) +{ + struct StampData *stamp_data = rr->stamp_data; + + if (!ibuf || !stamp_data) return; + + if (stamp_data->file[0]) IMB_metadata_change_field(ibuf, "File", stamp_data->file); + if (stamp_data->note[0]) IMB_metadata_change_field(ibuf, "Note", stamp_data->note); + if (stamp_data->date[0]) IMB_metadata_change_field(ibuf, "Date", stamp_data->date); + if (stamp_data->marker[0]) IMB_metadata_change_field(ibuf, "Marker", stamp_data->marker); + if (stamp_data->time[0]) IMB_metadata_change_field(ibuf, "Time", stamp_data->time); + if (stamp_data->frame[0]) IMB_metadata_change_field(ibuf, "Frame", stamp_data->frame); + if (stamp_data->camera[0]) IMB_metadata_change_field(ibuf, "Camera", stamp_data->camera); + if (stamp_data->cameralens[0]) IMB_metadata_change_field(ibuf, "Lens", stamp_data->cameralens); + if (stamp_data->scene[0]) IMB_metadata_change_field(ibuf, "Scene", stamp_data->scene); + if (stamp_data->strip[0]) IMB_metadata_change_field(ibuf, "Strip", stamp_data->strip); + if (stamp_data->rendertime[0]) IMB_metadata_change_field(ibuf, "RenderTime", stamp_data->rendertime); +} + +void BKE_stamp_info_callback(void *data, const struct StampData *stamp_data, StampCallback callback) +{ + if (!callback || !stamp_data) return; + + if (stamp_data->file[0]) callback(data, "File", stamp_data->file); + if (stamp_data->note[0]) callback(data, "Note", stamp_data->note); + if (stamp_data->date[0]) callback(data, "Date", stamp_data->date); + if (stamp_data->marker[0]) callback(data, "Marker", stamp_data->marker); + if (stamp_data->time[0]) callback(data, "Time", stamp_data->time); + if (stamp_data->frame[0]) callback(data, "Frame", stamp_data->frame); + if (stamp_data->camera[0]) callback(data, "Camera", stamp_data->camera); + if (stamp_data->cameralens[0]) callback(data, "Lens", stamp_data->cameralens); + if (stamp_data->scene[0]) callback(data, "Scene", stamp_data->scene); + if (stamp_data->strip[0]) callback(data, "Strip", stamp_data->strip); + if (stamp_data->rendertime[0]) callback(data, "RenderTime", stamp_data->rendertime); +} + + bool BKE_imbuf_alpha_test(ImBuf *ibuf) { int tot; @@ -2242,15 +2309,14 @@ int BKE_imbuf_write_as(ImBuf *ibuf, const char *name, ImageFormatData *imf, return ok; } -int BKE_imbuf_write_stamp(Scene *scene, struct Object *camera, ImBuf *ibuf, const char *name, struct ImageFormatData *imf) +int BKE_imbuf_write_stamp(Scene *scene, struct RenderResult *rr, ImBuf *ibuf, const char *name, struct ImageFormatData *imf) { if (scene && scene->r.stamp & R_STAMP_ALL) - BKE_imbuf_stamp_info(scene, camera, ibuf); + BKE_imbuf_stamp_info(rr, ibuf); return BKE_imbuf_write(ibuf, name, imf); } - static void do_makepicstring( char *string, const char *base, const char *relbase, int frame, const char imtype, const ImageFormatData *im_format, const short use_ext, const short use_frames, @@ -2376,6 +2442,7 @@ static void image_viewer_create_views(const RenderData *rd, Image *ima) void BKE_image_verify_viewer_views(const RenderData *rd, Image *ima, ImageUser *iuser) { bool do_reset; + const bool is_multiview = (rd->scemode & R_MULTIVIEW) != 0; BLI_lock_thread(LOCK_DRAW_IMAGE); @@ -2391,7 +2458,9 @@ void BKE_image_verify_viewer_views(const RenderData *rd, Image *ima, ImageUser * /* see if all scene render views are in the image view list */ do_reset = (BKE_scene_multiview_num_views_get(rd) != BLI_listbase_count(&ima->views)); - if (!do_reset) { + + /* multiview also needs to be sure all the views are synced */ + if (is_multiview && !do_reset) { SceneRenderView *srv; ImageView *iv; @@ -2405,11 +2474,15 @@ void BKE_image_verify_viewer_views(const RenderData *rd, Image *ima, ImageUser * } if (do_reset) { + BLI_spin_lock(&image_spin); + image_free_cached_frames(ima); BKE_image_free_views(ima); /* add new views */ image_viewer_create_views(rd, ima); + + BLI_spin_unlock(&image_spin); } BLI_unlock_thread(LOCK_DRAW_IMAGE); @@ -2975,7 +3048,7 @@ static void image_initialize_after_load(Image *ima, ImBuf *ibuf) { /* preview is NULL when it has never been used as an icon before */ if (G.background == 0 && ima->preview == NULL) - BKE_icon_changed(BKE_icon_getid(&ima->id)); + BKE_icon_changed(BKE_icon_id_ensure(&ima->id)); /* fields */ if (ima->flag & IMA_FIELDS) { @@ -3321,9 +3394,11 @@ static ImBuf *load_image_single( flag |= imbuf_alpha_flags_for_image(ima); imapf = BLI_findlink(&ima->packedfiles, view_id); - ibuf = IMB_ibImageFromMemory( - (unsigned char *)imapf->packedfile->data, imapf->packedfile->size, flag, - ima->colorspace_settings.name, "<packed data>"); + if (imapf->packedfile) { + ibuf = IMB_ibImageFromMemory( + (unsigned char *)imapf->packedfile->data, imapf->packedfile->size, flag, + ima->colorspace_settings.name, "<packed data>"); + } } else { ImageUser iuser_t; @@ -3500,10 +3575,11 @@ static ImBuf *image_get_ibuf_multilayer(Image *ima, ImageUser *iuser) /* showing RGBA result itself (from compo/sequence) or * like exr, using layers etc */ /* always returns a single ibuf, also during render progress */ -static ImBuf *image_get_render_result(Image *ima, ImageUser *iuser, void **lock_r) +static ImBuf *image_get_render_result(Image *ima, ImageUser *iuser, void **r_lock) { Render *re; RenderResult rres; + RenderView *rv; float *rectf, *rectz; unsigned int *rect; float dither; @@ -3517,7 +3593,7 @@ static ImBuf *image_get_render_result(Image *ima, ImageUser *iuser, void **lock_ return NULL; /* if we the caller is not going to release the lock, don't give the image */ - if (!lock_r) + if (!r_lock) return NULL; re = RE_GetRender(iuser->scene->id.name); @@ -3535,7 +3611,7 @@ static ImBuf *image_get_render_result(Image *ima, ImageUser *iuser, void **lock_ } else if (ima->renders[ima->render_slot]) { rres = *(ima->renders[ima->render_slot]); - rres.have_combined = RE_RenderViewGetRectf(&rres, actview) != NULL; + rres.have_combined = ((RenderView *)rres.views.first)->rectf != NULL; } else memset(&rres, 0, sizeof(RenderResult)); @@ -3546,16 +3622,30 @@ static ImBuf *image_get_render_result(Image *ima, ImageUser *iuser, void **lock_ return NULL; } - /* release is done in BKE_image_release_ibuf using lock_r */ + /* release is done in BKE_image_release_ibuf using r_lock */ if (from_render) { BLI_lock_thread(LOCK_VIEWER); - *lock_r = re; + *r_lock = re; + rv = NULL; + } + else { + rv = BLI_findlink(&rres.views, actview); + if (rv == NULL) + rv = rres.views.first; } /* this gives active layer, composite or sequence result */ - rect = (unsigned int *)rres.rect32; - rectf = rres.rectf; - rectz = rres.rectz; + if (rv == NULL) { + rect = (unsigned int *)rres.rect32; + rectf = rres.rectf; + rectz = rres.rectz; + } + else { + rect = (unsigned int *)rv->rect32; + rectf = rv->rectf; + rectz = rv->rectz; + } + dither = iuser->scene->r.dither_intensity; /* combined layer gets added as first layer */ @@ -3586,6 +3676,15 @@ static ImBuf *image_get_render_result(Image *ima, ImageUser *iuser, void **lock_ if (rpass) { channels = rpass->channels; rectf = rpass->rect; + + if (!rectf) { + /* Happens when Save Buffers is enabled. + * Use display buffer stored in the render layer. + */ + rect = (unsigned int *) rl->display_buffer; + byte_buffer_in_display_space = true; + } + dither = 0.0f; /* don't dither passes */ } @@ -3679,9 +3778,10 @@ static size_t image_get_multiview_index(Image *ima, ImageUser *iuser) { const bool is_multilayer = BKE_image_is_multilayer(ima); const bool is_backdrop = (ima->source == IMA_SRC_VIEWER) && (ima->type == IMA_TYPE_COMPOSITE) && (iuser == NULL); + int index = BKE_image_is_animated(ima) ? 0 : IMA_NO_INDEX; if (is_multilayer) { - return iuser ? iuser->multi_index : IMA_NO_INDEX; + return iuser ? iuser->multi_index : index; } else if (is_backdrop) { if ((ima->flag & IMA_IS_STEREO)) { @@ -3690,16 +3790,15 @@ static size_t image_get_multiview_index(Image *ima, ImageUser *iuser) } } else if ((ima->flag & IMA_IS_MULTIVIEW)) { - return iuser ? iuser->multi_index : 0; + return iuser ? iuser->multi_index : index; } - return IMA_NO_INDEX; + return index; } static void image_get_frame_and_index(Image *ima, ImageUser *iuser, int *r_frame, int *r_index) { - int frame = 0, index = 0; - index = image_get_multiview_index(ima, iuser); + int frame = 0, index = image_get_multiview_index(ima, iuser); /* see if we already have an appropriate ibuf, with image source and type */ if (ima->source == IMA_SRC_MOVIE) { @@ -3727,9 +3826,7 @@ static void image_get_frame_and_index(Image *ima, ImageUser *iuser, int *r_frame static ImBuf *image_get_cached_ibuf(Image *ima, ImageUser *iuser, int *r_frame, int *r_index) { ImBuf *ibuf = NULL; - int frame = 0, index = 0; - - index = image_get_multiview_index(ima, iuser); + int frame = 0, index = image_get_multiview_index(ima, iuser); /* see if we already have an appropriate ibuf, with image source and type */ if (ima->source == IMA_SRC_MOVIE) { @@ -3809,13 +3906,13 @@ BLI_INLINE bool image_quick_test(Image *ima, ImageUser *iuser) * * not thread-safe, so callee should worry about thread locks */ -static ImBuf *image_acquire_ibuf(Image *ima, ImageUser *iuser, void **lock_r) +static ImBuf *image_acquire_ibuf(Image *ima, ImageUser *iuser, void **r_lock) { ImBuf *ibuf = NULL; int frame = 0, index = 0; - if (lock_r) - *lock_r = NULL; + if (r_lock) + *r_lock = NULL; /* quick reject tests */ if (!image_quick_test(ima, iuser)) @@ -3864,14 +3961,14 @@ static ImBuf *image_acquire_ibuf(Image *ima, ImageUser *iuser, void **lock_r) if (ima->type == IMA_TYPE_R_RESULT) { /* always verify entirely, and potentially * returns pointer to release later */ - ibuf = image_get_render_result(ima, iuser, lock_r); + ibuf = image_get_render_result(ima, iuser, r_lock); } else if (ima->type == IMA_TYPE_COMPOSITE) { /* requires lock/unlock, otherwise don't return image */ - if (lock_r) { + if (r_lock) { /* unlock in BKE_image_release_ibuf */ BLI_lock_thread(LOCK_VIEWER); - *lock_r = ima; + *r_lock = ima; /* XXX anim play for viewer nodes not yet supported */ frame = 0; // XXX iuser ? iuser->framenr : 0; @@ -3905,13 +4002,13 @@ static ImBuf *image_acquire_ibuf(Image *ima, ImageUser *iuser, void **lock_r) * * references the result, BKE_image_release_ibuf should be used to de-reference */ -ImBuf *BKE_image_acquire_ibuf(Image *ima, ImageUser *iuser, void **lock_r) +ImBuf *BKE_image_acquire_ibuf(Image *ima, ImageUser *iuser, void **r_lock) { ImBuf *ibuf; BLI_spin_lock(&image_spin); - ibuf = image_acquire_ibuf(ima, iuser, lock_r); + ibuf = image_acquire_ibuf(ima, iuser, r_lock); BLI_spin_unlock(&image_spin); diff --git a/source/blender/blenkernel/intern/key.c b/source/blender/blenkernel/intern/key.c index 3aea343ec5a..8427b17c01a 100644 --- a/source/blender/blenkernel/intern/key.c +++ b/source/blender/blenkernel/intern/key.c @@ -1002,7 +1002,9 @@ static void do_key(const int start, int end, const int tot, char *poin, Key *key k1 += elemsize; } } - else k1 += elemsize; + else { + k1 += elemsize; + } } if (flagdo & 2) { if (flagflo & 2) { @@ -1390,25 +1392,37 @@ float *BKE_key_evaluate_object(Object *ob, int *r_totelem) return BKE_key_evaluate_object_ex(ob, r_totelem, NULL, 0); } -Key *BKE_key_from_object(Object *ob) +Key **BKE_key_from_object_p(Object *ob) { - if (ob == NULL) return NULL; - + if (ob == NULL) + return NULL; + if (ob->type == OB_MESH) { Mesh *me = ob->data; - return me->key; + return &me->key; } else if (ELEM(ob->type, OB_CURVE, OB_SURF)) { Curve *cu = ob->data; - return cu->key; + return &cu->key; } else if (ob->type == OB_LATTICE) { Lattice *lt = ob->data; - return lt->key; + return <->key; } return NULL; } +Key *BKE_key_from_object(Object *ob) +{ + Key **key_p; + key_p = BKE_key_from_object_p(ob); + if (key_p) { + return *key_p; + } + + return NULL; +} + KeyBlock *BKE_keyblock_add(Key *key, const char *name) { KeyBlock *kb; diff --git a/source/blender/blenkernel/intern/lamp.c b/source/blender/blenkernel/intern/lamp.c index 96b0b95adf3..44e35c645de 100644 --- a/source/blender/blenkernel/intern/lamp.c +++ b/source/blender/blenkernel/intern/lamp.c @@ -232,7 +232,7 @@ void BKE_lamp_free(Lamp *la) } BKE_previewimg_free(&la->preview); - BKE_icon_delete(&la->id); + BKE_icon_id_delete(&la->id); la->id.icon_id = 0; } diff --git a/source/blender/blenkernel/intern/lattice.c b/source/blender/blenkernel/intern/lattice.c index 73dca9436ef..86927609ff6 100644 --- a/source/blender/blenkernel/intern/lattice.c +++ b/source/blender/blenkernel/intern/lattice.c @@ -53,6 +53,7 @@ #include "BKE_anim.h" #include "BKE_cdderivedmesh.h" #include "BKE_curve.h" +#include "BKE_depsgraph.h" #include "BKE_displist.h" #include "BKE_global.h" #include "BKE_key.h" @@ -1206,3 +1207,10 @@ void BKE_lattice_translate(Lattice *lt, float offset[3], bool do_keys) } } +/* **** Depsgraph evaluation **** */ + +void BKE_lattice_eval_geometry(EvaluationContext *UNUSED(eval_ctx), + Lattice *UNUSED(latt)) +{ +} + diff --git a/source/blender/blenkernel/intern/library.c b/source/blender/blenkernel/intern/library.c index 2cee08a821b..bf6f7a5f22c 100644 --- a/source/blender/blenkernel/intern/library.c +++ b/source/blender/blenkernel/intern/library.c @@ -115,6 +115,8 @@ #include "BKE_texture.h" #include "BKE_world.h" +#include "DEG_depsgraph.h" + #include "RNA_access.h" #ifdef WITH_PYTHON @@ -291,7 +293,7 @@ bool id_make_local(ID *id, bool test) /** * Invokes the appropriate copy method for the block and returns the result in - * newid, unless test. Returns true iff the block can be copied. + * newid, unless test. Returns true if the block can be copied. */ bool id_copy(ID *id, ID **newid, bool test) { @@ -865,18 +867,24 @@ static void BKE_library_free(Library *lib) static void (*free_windowmanager_cb)(bContext *, wmWindowManager *) = NULL; -void set_free_windowmanager_cb(void (*func)(bContext *C, wmWindowManager *) ) +void BKE_library_callback_free_window_manager_set(void (*func)(bContext *C, wmWindowManager *) ) { free_windowmanager_cb = func; } static void (*free_notifier_reference_cb)(const void *) = NULL; -void set_free_notifier_reference_cb(void (*func)(const void *) ) +void BKE_library_callback_free_notifier_reference_set(void (*func)(const void *) ) { free_notifier_reference_cb = func; } +static void (*free_editor_id_reference_cb)(const ID *) = NULL; + +void BKE_library_callback_free_editor_id_reference_set(void (*func)(const ID *)) +{ + free_editor_id_reference_cb = func; +} static void animdata_dtar_clear_cb(ID *UNUSED(id), AnimData *adt, void *userdata) { @@ -1034,8 +1042,13 @@ void BKE_libblock_free_ex(Main *bmain, void *idv, bool do_id_user) /* avoid notifying on removed data */ BKE_main_lock(bmain); - if (free_notifier_reference_cb) + if (free_notifier_reference_cb) { free_notifier_reference_cb(id); + } + + if (free_editor_id_reference_cb) { + free_editor_id_reference_cb(id); + } BLI_remlink(lb, id); @@ -1070,8 +1083,7 @@ void BKE_libblock_free_us(Main *bmain, void *idv) /* test users */ Main *BKE_main_new(void) { Main *bmain = MEM_callocN(sizeof(Main), "new main"); - bmain->eval_ctx = MEM_callocN(sizeof(EvaluationContext), - "EvaluationContext"); + bmain->eval_ctx = DEG_evaluation_context_new(DAG_EVAL_VIEWPORT); bmain->lock = MEM_mallocN(sizeof(SpinLock), "main lock"); BLI_spin_init((SpinLock *)bmain->lock); return bmain; @@ -1138,7 +1150,7 @@ void BKE_main_free(Main *mainvar) BLI_spin_end((SpinLock *)mainvar->lock); MEM_freeN(mainvar->lock); - MEM_freeN(mainvar->eval_ctx); + DEG_evaluation_context_free(mainvar->eval_ctx); MEM_freeN(mainvar); } @@ -1404,16 +1416,11 @@ void id_clear_lib_data(Main *bmain, ID *id) /* internal bNodeTree blocks inside ID types below * also stores id->lib, make sure this stays in sync. */ - switch (GS(id->name)) { - case ID_SCE: ntree = ((Scene *)id)->nodetree; break; - case ID_MA: ntree = ((Material *)id)->nodetree; break; - case ID_LA: ntree = ((Lamp *)id)->nodetree; break; - case ID_WO: ntree = ((World *)id)->nodetree; break; - case ID_TE: ntree = ((Tex *)id)->nodetree; break; - case ID_LS: ntree = ((FreestyleLineStyle *)id)->nodetree; break; - } - if (ntree) + ntree = ntreeFromID(id); + + if (ntree) { ntree->id.lib = NULL; + } } /* next to indirect usage in read/writefile also in editobject.c scene.c */ @@ -1603,7 +1610,7 @@ void rename_id(ID *id, const char *name) void name_uiprefix_id(char *name, const ID *id) { name[0] = id->lib ? 'L' : ' '; - name[1] = id->flag & LIB_FAKEUSER ? 'F' : (id->us == 0) ? '0' : ' '; + name[1] = (id->flag & LIB_FAKEUSER) ? 'F' : ((id->us == 0) ? '0' : ' '); name[2] = ' '; strcpy(name + 3, id->name + 2); diff --git a/source/blender/blenkernel/intern/mask_rasterize.c b/source/blender/blenkernel/intern/mask_rasterize.c index 387d093051e..13ec970c65c 100644 --- a/source/blender/blenkernel/intern/mask_rasterize.c +++ b/source/blender/blenkernel/intern/mask_rasterize.c @@ -1360,6 +1360,9 @@ float BKE_maskrasterize_handle_sample(MaskRasterHandle *mr_handle, const float x case PROP_SHARP: value_layer = value_layer * value_layer; break; + case PROP_INVSQUARE: + value_layer = value_layer * (2.0f - value_layer); + break; case PROP_LIN: default: /* nothing */ diff --git a/source/blender/blenkernel/intern/material.c b/source/blender/blenkernel/intern/material.c index b5b7f3d06aa..283c7a6fc88 100644 --- a/source/blender/blenkernel/intern/material.c +++ b/source/blender/blenkernel/intern/material.c @@ -53,6 +53,7 @@ #include "BLI_listbase.h" #include "BLI_utildefines.h" #include "BLI_string.h" +#include "BLI_array_utils.h" #include "BKE_animsys.h" #include "BKE_displist.h" @@ -66,6 +67,8 @@ #include "BKE_scene.h" #include "BKE_node.h" #include "BKE_curve.h" +#include "BKE_editmesh.h" +#include "BKE_font.h" #include "GPU_material.h" @@ -103,7 +106,7 @@ void BKE_material_free_ex(Material *ma, bool do_id_user) if (ma->preview) BKE_previewimg_free(&ma->preview); - BKE_icon_delete((struct ID *)ma); + BKE_icon_id_delete((struct ID *)ma); ma->id.icon_id = 0; /* is no lib link block, but material extension */ @@ -806,9 +809,13 @@ void assign_material_id(ID *id, Material *ma, short act) if (act > MAXMAT) return; if (act < 1) act = 1; + /* this is needed for Python overrides, + * we just have to take care that the UI can't do this */ +#if 0 /* prevent crashing when using accidentally */ BLI_assert(id->lib == NULL); if (id->lib) return; +#endif /* test arraylens */ @@ -918,6 +925,35 @@ void assign_material(Object *ob, Material *ma, short act, int assign_type) test_object_materials(G.main, ob->data); } + +void BKE_material_remap_object(Object *ob, const unsigned int *remap) +{ + Material ***matar = give_matarar(ob); + const short *totcol_p = give_totcolp(ob); + + BLI_array_permute(ob->mat, ob->totcol, remap); + + if (ob->matbits) { + BLI_array_permute(ob->matbits, ob->totcol, remap); + } + + if (matar) { + BLI_array_permute(*matar, *totcol_p, remap); + } + + if (ob->type == OB_MESH) { + BKE_mesh_material_remap(ob->data, remap, ob->totcol); + } + else if (ELEM(ob->type, OB_CURVE, OB_SURF, OB_FONT)) { + BKE_curve_material_remap(ob->data, remap, ob->totcol); + } + else { + /* add support for this object data! */ + BLI_assert(matar == NULL); + } +} + + /* XXX - this calls many more update calls per object then are needed, could be optimized */ void assign_matarar(struct Object *ob, struct Material ***matar, short totcol) { diff --git a/source/blender/blenkernel/intern/mball.c b/source/blender/blenkernel/intern/mball.c index 8728e6f98d5..c09cd1aabdc 100644 --- a/source/blender/blenkernel/intern/mball.c +++ b/source/blender/blenkernel/intern/mball.c @@ -586,3 +586,9 @@ void BKE_mball_select_swap(struct MetaBall *mb) } } +/* **** Depsgraph evaluation **** */ + +void BKE_mball_eval_geometry(EvaluationContext *UNUSED(eval_ctx), + MetaBall *UNUSED(mball)) +{ +} diff --git a/source/blender/blenkernel/intern/mball_tessellate.c b/source/blender/blenkernel/intern/mball_tessellate.c index 080a8cead7b..e8418e876bb 100644 --- a/source/blender/blenkernel/intern/mball_tessellate.c +++ b/source/blender/blenkernel/intern/mball_tessellate.c @@ -1233,14 +1233,9 @@ static void init_meta(EvaluationContext *eval_ctx, PROCESS *process, Scene *scen copy_v3_v3(new_ml->bb->vec[6], tempmax); /* add new_ml to mainb[] */ - if (process->totelem == process->mem) { - MetaElem **newelem; + if (UNLIKELY(process->totelem == process->mem)) { process->mem = process->mem * 2 + 10; - newelem = MEM_mallocN(sizeof(MetaElem *) * process->mem, "metaballs"); - - memcpy(newelem, process->mainb, sizeof(MetaElem *) * process->totelem); - if (process->mainb) MEM_freeN(process->mainb); - process->mainb = newelem; + process->mainb = MEM_reallocN(process->mainb, sizeof(MetaElem *) * process->mem); } process->mainb[process->totelem++] = new_ml; } diff --git a/source/blender/blenkernel/intern/mesh.c b/source/blender/blenkernel/intern/mesh.c index eec2b108ca3..37a98eae58b 100644 --- a/source/blender/blenkernel/intern/mesh.c +++ b/source/blender/blenkernel/intern/mesh.c @@ -61,6 +61,7 @@ #include "BKE_object.h" #include "BKE_editmesh.h" +#include "DEG_depsgraph.h" enum { MESHCMP_DVERT_WEIGHTMISMATCH = 1, @@ -1265,7 +1266,7 @@ int BKE_mesh_nurbs_displist_to_mdata(Object *ob, ListBase *dispbase, dl = dispbase->first; while (dl) { - int smooth = dl->rt & CU_SMOOTH ? 1 : 0; + const bool is_smooth = (dl->rt & CU_SMOOTH) != 0; if (dl->type == DL_SEGM) { startvert = vertcount; @@ -1344,7 +1345,7 @@ int BKE_mesh_nurbs_displist_to_mdata(Object *ob, ListBase *dispbase, } } - if (smooth) mpoly->flag |= ME_SMOOTH; + if (is_smooth) mpoly->flag |= ME_SMOOTH; mpoly++; mloop += 3; index += 3; @@ -1423,7 +1424,7 @@ int BKE_mesh_nurbs_displist_to_mdata(Object *ob, ListBase *dispbase, } } - if (smooth) mpoly->flag |= ME_SMOOTH; + if (is_smooth) mpoly->flag |= ME_SMOOTH; mpoly++; mloop += 4; @@ -1773,6 +1774,36 @@ void BKE_mesh_material_index_clear(Mesh *me) } } +void BKE_mesh_material_remap(Mesh *me, const unsigned int *remap, unsigned int remap_len) +{ + const short remap_len_short = (short)remap_len; + +#define MAT_NR_REMAP(n) \ + if (n < remap_len_short) { \ + BLI_assert(n >= 0 && remap[n] < remap_len_short); \ + n = remap[n]; \ + } ((void)0) + + if (me->edit_btmesh) { + BMEditMesh *em = me->edit_btmesh; + BMIter iter; + BMFace *efa; + + BM_ITER_MESH(efa, &iter, em->bm, BM_FACES_OF_MESH) { + MAT_NR_REMAP(efa->mat_nr); + } + } + else { + int i; + for (i = 0; i < me->totpoly; i++) { + MAT_NR_REMAP(me->mpoly[i].mat_nr); + } + } + +#undef MAT_NR_REMAP + +} + void BKE_mesh_smooth_flag_set(Object *meshOb, int enableSmooth) { Mesh *me = meshOb->data; @@ -1890,6 +1921,7 @@ void BKE_mesh_transform(Mesh *me, float mat[4][4], bool do_keys) { int i; MVert *mvert = me->mvert; + float (*lnors)[3] = CustomData_get_layer(&me->ldata, CD_NORMAL); for (i = 0; i < me->totvert; i++, mvert++) mul_m4_v3(mat, mvert->co); @@ -1904,7 +1936,17 @@ void BKE_mesh_transform(Mesh *me, float mat[4][4], bool do_keys) } } - /* don't update normals, caller can do this explicitly */ + /* don't update normals, caller can do this explicitly. + * We do update loop normals though, those may not be auto-generated (see e.g. STL import script)! */ + if (lnors) { + float m3[3][3]; + + copy_m3_m4(m3, mat); + normalize_m3(m3); + for (i = 0; i < me->totloop; i++, lnors++) { + mul_m3_v3(m3, *lnors); + } + } } void BKE_mesh_translate(Mesh *me, const float offset[3], const bool do_keys) @@ -2356,8 +2398,8 @@ Mesh *BKE_mesh_new_from_object( * only contains for_render flag. As soon as CoW is * implemented, this is to be rethinked. */ - EvaluationContext eval_ctx = {0}; - eval_ctx.mode = DAG_EVAL_RENDER; + EvaluationContext eval_ctx; + DEG_evaluation_context_init(&eval_ctx, DAG_EVAL_RENDER); BKE_displist_make_mball_forRender(&eval_ctx, sce, ob, &disp); BKE_mesh_from_metaball(&disp, tmpmesh); BKE_displist_free(&disp); @@ -2482,3 +2524,15 @@ Mesh *BKE_mesh_new_from_object( return tmpmesh; } +/* **** Depsgraph evaluation **** */ + +void BKE_mesh_eval_geometry(EvaluationContext *UNUSED(eval_ctx), + Mesh *mesh) +{ + if (G.debug & G_DEBUG_DEPSGRAPH) { + printf("%s on %s\n", __func__, mesh->id.name); + } + if (mesh->bb == NULL || (mesh->bb->flag & BOUNDBOX_DIRTY)) { + BKE_mesh_texspace_calc(mesh); + } +} diff --git a/source/blender/blenkernel/intern/mesh_evaluate.c b/source/blender/blenkernel/intern/mesh_evaluate.c index bbc175fefcd..d17ca751c5e 100644 --- a/source/blender/blenkernel/intern/mesh_evaluate.c +++ b/source/blender/blenkernel/intern/mesh_evaluate.c @@ -372,6 +372,10 @@ void BKE_lnor_space_define(MLoopNorSpace *lnor_space, const float lnor[3], /* If vec_ref or vec_other are too much aligned with lnor, we can't build lnor space, * tag it as invalid and abort. */ lnor_space->ref_alpha = lnor_space->ref_beta = 0.0f; + + if (edge_vectors) { + BLI_stack_clear(edge_vectors); + } return; } @@ -2253,12 +2257,15 @@ void BKE_mesh_loops_to_tessdata(CustomData *fdata, CustomData *ldata, CustomData /** * Recreate tessellation. * - * \param do_face_nor_copy controls whether the normals from the poly are copied to the tessellated faces. + * \param do_face_nor_copy: Controls whether the normals from the poly are copied to the tessellated faces. * * \return number of tessellation faces. */ -int BKE_mesh_recalc_tessellation(CustomData *fdata, CustomData *ldata, CustomData *pdata, - MVert *mvert, int totface, int totloop, int totpoly, const bool do_face_nor_cpy) +int BKE_mesh_recalc_tessellation( + CustomData *fdata, CustomData *ldata, CustomData *pdata, + MVert *mvert, + int totface, int totloop, int totpoly, + const bool do_face_nor_copy) { /* use this to avoid locking pthread for _every_ polygon * and calling the fill function */ @@ -2468,7 +2475,7 @@ int BKE_mesh_recalc_tessellation(CustomData *fdata, CustomData *ldata, CustomDat CustomData_add_layer(fdata, CD_ORIGINDEX, CD_ASSIGN, mface_to_poly_map, totface); CustomData_from_bmeshpoly(fdata, pdata, ldata, totface); - if (do_face_nor_cpy) { + if (do_face_nor_copy) { /* If polys have a normals layer, copying that to faces can help * avoid the need to recalculate normals later */ if (CustomData_has_layer(pdata, CD_NORMAL)) { diff --git a/source/blender/blenkernel/intern/mesh_mapping.c b/source/blender/blenkernel/intern/mesh_mapping.c index ebdbd3aac8a..8b41aded3d9 100644 --- a/source/blender/blenkernel/intern/mesh_mapping.c +++ b/source/blender/blenkernel/intern/mesh_mapping.c @@ -54,8 +54,10 @@ /* this replaces the non bmesh function (in trunk) which takes MTFace's, if we ever need it back we could * but for now this replaces it because its unused. */ -UvVertMap *BKE_mesh_uv_vert_map_create(struct MPoly *mpoly, struct MLoop *mloop, struct MLoopUV *mloopuv, - unsigned int totpoly, unsigned int totvert, int selected, float *limit) +UvVertMap *BKE_mesh_uv_vert_map_create( + struct MPoly *mpoly, struct MLoop *mloop, struct MLoopUV *mloopuv, + unsigned int totpoly, unsigned int totvert, + const float limit[2], const bool selected, const bool use_winding) { UvVertMap *vmap; UvMapVert *buf; @@ -109,7 +111,10 @@ UvVertMap *BKE_mesh_uv_vert_map_create(struct MPoly *mpoly, struct MLoop *mloop, buf++; } - winding[a] = cross_poly_v2((const float (*)[2])tf_uv, (unsigned int)nverts) > 0; + if (use_winding) + winding[a] = cross_poly_v2((const float (*)[2])tf_uv, (unsigned int)nverts) > 0; + else + winding[a] = 0; } } @@ -177,8 +182,6 @@ void BKE_mesh_uv_vert_map_free(UvVertMap *vmap) } /** - - * Generates a map where the key is the vertex and the value is a list * of polys or loops that use that vertex as a corner. The lists are allocated * from one memory pool. @@ -251,9 +254,10 @@ void BKE_mesh_vert_loop_map_create(MeshElemMap **r_map, int **r_mem, mesh_vert_poly_or_loop_map_create(r_map, r_mem, mpoly, mloop, totvert, totpoly, totloop, true); } -/* Generates a map where the key is the vertex and the value is a list - * of edges that use that vertex as an endpoint. The lists are allocated - * from one memory pool. */ +/** + * Generates a map where the key is the vertex and the value is a list of edges that use that vertex as an endpoint. + * The lists are allocated from one memory pool. + */ void BKE_mesh_vert_edge_map_create(MeshElemMap **r_map, int **r_mem, const MEdge *medge, int totvert, int totedge) { @@ -293,6 +297,10 @@ void BKE_mesh_vert_edge_map_create(MeshElemMap **r_map, int **r_mem, *r_mem = indices; } +/** + * Generates a map where the key is the edge and the value is a list of polygons that use that edge. + * The lists are allocated from one memory pool. + */ void BKE_mesh_edge_poly_map_create(MeshElemMap **r_map, int **r_mem, const MEdge *UNUSED(medge), const int totedge, const MPoly *mpoly, const int totpoly, @@ -400,7 +408,8 @@ void BKE_mesh_origindex_map_create(MeshElemMap **r_map, int **r_mem, * Used currently for UVs and 'smooth groups'. * \{ */ -/** Callback deciding whether the given poly/loop/edge define an island boundary or not. +/** + * Callback deciding whether the given poly/loop/edge define an island boundary or not. */ typedef bool (*MeshRemap_CheckIslandBoundary)( const struct MPoly *mpoly, const struct MLoop *mloop, const struct MEdge *medge, @@ -583,8 +592,7 @@ static void poly_edge_loop_islands_calc( } static bool poly_is_island_boundary_smooth_cb( - const MPoly *mp, const MLoop *UNUSED(ml), const MEdge *me, - const int nbr_egde_users) + const MPoly *mp, const MLoop *UNUSED(ml), const MEdge *me, const int nbr_egde_users) { /* Edge is sharp if its poly is sharp, or edge itself is sharp, or edge is not used by exactly two polygons. */ return (!(mp->flag & ME_SMOOTH) || (me->flag & ME_SHARP) || (nbr_egde_users != 2)); @@ -681,7 +689,6 @@ void BKE_mesh_loop_islands_add( const size_t curr_num_islands = (size_t)island_store->islands_num; int i = item_num; - island_store->items_to_islands_num = item_num; while (i--) { island_store->items_to_islands[items_indices[i]] = curr_island_idx; } @@ -716,17 +723,21 @@ void BKE_mesh_loop_islands_add( * not sure we want that at all! */ static bool mesh_check_island_boundary_uv( - const MPoly *UNUSED(mp), const MLoop *UNUSED(ml), const MEdge *me, - const int UNUSED(nbr_egde_users)) + const MPoly *UNUSED(mp), const MLoop *UNUSED(ml), const MEdge *me, const int UNUSED(nbr_egde_users)) { /* Edge is UV boundary if tagged as seam. */ return (me->flag & ME_SEAM) != 0; } /** - * \note all this could be optimized... - * Not sure it would be worth the more complex code, though, those loops - * are supposed to be really quick to do... + * Calculate UV islands. + * + * \note Currently we only consider edges tagges as seams as UV boundaries. This has the advantages of simplicity, + * and being valid/common to all UV maps. However, it means actual UV islands whithout matching UV seams + * will not be handled correctly... + * + * \note All this could be optimized... + * Not sure it would be worth the more complex code, though, those loops are supposed to be really quick to do... */ bool BKE_mesh_calc_islands_loop_poly_uv( MVert *UNUSED(verts), const int UNUSED(totvert), diff --git a/source/blender/blenkernel/intern/mesh_remap.c b/source/blender/blenkernel/intern/mesh_remap.c index aca72614094..0ed10687fae 100644 --- a/source/blender/blenkernel/intern/mesh_remap.c +++ b/source/blender/blenkernel/intern/mesh_remap.c @@ -707,7 +707,7 @@ void BKE_mesh_remap_calc_edges_from_dm( BLI_space_transform_apply_normal(space_transform, v2_no); } - fill_vn_fl(weights, (int)numedges_src, 0.0f); + copy_vn_fl(weights, (int)numedges_src, 0.0f); /* We adjust our ray-casting grid to ray_radius (the smaller, the more rays are cast), * with lower/upper bounds. */ @@ -977,6 +977,8 @@ void BKE_mesh_remap_calc_loops_from_dm( float (*poly_nors_dst)[3] = NULL; float (*loop_nors_dst)[3] = NULL; + float (*poly_cents_src)[3] = NULL; + MeshElemMap *vert_to_loop_map_src = NULL; int *vert_to_loop_map_src_buff = NULL; MeshElemMap *vert_to_poly_map_src = NULL; @@ -1012,6 +1014,8 @@ void BKE_mesh_remap_calc_loops_from_dm( int *indices_interp = NULL; float *weights_interp = NULL; + MLoop *ml_src, *ml_dst; + MPoly *mp_src, *mp_dst; int tindex, pidx_dst, lidx_dst, plidx_dst, pidx_src, lidx_src, plidx_src; IslandResult **islands_res; @@ -1089,11 +1093,13 @@ void BKE_mesh_remap_calc_loops_from_dm( edges_src, num_edges_src, polys_src, num_polys_src, loops_src, num_loops_src); if (use_from_vert) { loop_to_poly_map_src = MEM_mallocN(sizeof(*loop_to_poly_map_src) * (size_t)num_loops_src, __func__); - for (pidx_src = 0; pidx_src < num_polys_src; pidx_src++) { - MPoly *mp = &polys_src[pidx_src]; - for (plidx_src = 0, lidx_src = mp->loopstart; plidx_src < mp->totloop; plidx_src++, lidx_src++) { + poly_cents_src = MEM_mallocN(sizeof(*poly_cents_src) * (size_t)num_polys_src, __func__); + for (pidx_src = 0, mp_src = polys_src; pidx_src < num_polys_src; pidx_src++, mp_src++) { + ml_src = &loops_src[mp_src->loopstart]; + for (plidx_src = 0, lidx_src = mp_src->loopstart; plidx_src < mp_src->totloop; plidx_src++, lidx_src++) { loop_to_poly_map_src[lidx_src] = pidx_src; } + BKE_mesh_calc_poly_center(mp_src, ml_src, verts_src, poly_cents_src[pidx_src]); } } @@ -1155,10 +1161,13 @@ void BKE_mesh_remap_calc_loops_from_dm( int num_verts_active = 0; BLI_BITMAP_SET_ALL(verts_active, false, (size_t)num_verts_src); for (i = 0; i < isld->count; i++) { - MPoly *mp_src = &polys_src[isld->indices[i]]; + mp_src = &polys_src[isld->indices[i]]; for (lidx_src = mp_src->loopstart; lidx_src < mp_src->loopstart + mp_src->totloop; lidx_src++) { - BLI_BITMAP_ENABLE(verts_active, loops_src[lidx_src].v); - num_verts_active++; + const unsigned int vidx_src = loops_src[lidx_src].v; + if (!BLI_BITMAP_TEST(verts_active, vidx_src)) { + BLI_BITMAP_ENABLE(verts_active, loops_src[lidx_src].v); + num_verts_active++; + } } } /* verts 'ownership' is transfered to treedata here, which will handle its freeing. */ @@ -1199,13 +1208,13 @@ void BKE_mesh_remap_calc_loops_from_dm( int num_faces_active = 0; BLI_BITMAP_SET_ALL(faces_active, false, (size_t)num_faces_src); for (i = 0; i < num_faces_src; i++) { - MPoly *mp_src = &polys_src[tessface_to_poly_map_src[i]]; + mp_src = &polys_src[tessface_to_poly_map_src[i]]; if (island_store.items_to_islands[mp_src->loopstart] == tindex) { BLI_BITMAP_ENABLE(faces_active, i); num_faces_active++; } } - /* verts 'ownership' is transfered to treedata here, which will handle its freeing. */ + /* verts and faces 'ownership' is transfered to treedata here, which will handle its freeing. */ bvhtree_from_mesh_faces_ex( &treedata[tindex], verts_src, verts_allocated_src, faces_src, num_faces_src, faces_allocated_src, @@ -1233,10 +1242,14 @@ void BKE_mesh_remap_calc_loops_from_dm( islands_res[tindex] = MEM_mallocN(sizeof(**islands_res) * islands_res_buff_size, __func__); } - for (pidx_dst = 0; pidx_dst < numpolys_dst; pidx_dst++) { - MPoly *mp_dst = &polys_dst[pidx_dst]; + for (pidx_dst = 0, mp_dst = polys_dst; pidx_dst < numpolys_dst; pidx_dst++, mp_dst++) { float (*pnor_dst)[3] = &poly_nors_dst[pidx_dst]; + /* Only in use_from_vert case, we may need polys' centers as fallback in case we cannot decide which + * corner to use from normals only. */ + float pcent_dst[3]; + bool pcent_dst_valid = false; + if ((size_t)mp_dst->totloop > islands_res_buff_size) { islands_res_buff_size = (size_t)mp_dst->totloop; for (tindex = 0; tindex < num_trees; tindex++) { @@ -1246,8 +1259,8 @@ void BKE_mesh_remap_calc_loops_from_dm( for (tindex = 0; tindex < num_trees; tindex++) { BVHTreeFromMesh *tdata = &treedata[tindex]; - MLoop *ml_dst = &loops_dst[mp_dst->loopstart]; + ml_dst = &loops_dst[mp_dst->loopstart]; for (plidx_dst = 0; plidx_dst < mp_dst->totloop; plidx_dst++, ml_dst++) { if (use_from_vert) { float tmp_co[3]; @@ -1263,6 +1276,7 @@ void BKE_mesh_remap_calc_loops_from_dm( float (*nor_dst)[3]; float (*nors_src)[3]; float best_nor_dot = -2.0f; + float best_sqdist_fallback = FLT_MAX; int best_index_src = -1; if (mode == MREMAP_MODE_LOOP_NEAREST_LOOPNOR) { @@ -1279,16 +1293,50 @@ void BKE_mesh_remap_calc_loops_from_dm( for (i = vert_to_refelem_map_src[nearest.index].count; i--;) { const int index_src = vert_to_refelem_map_src[nearest.index].indices[i]; const float dot = dot_v3v3(nors_src[index_src], *nor_dst); - if (dot > best_nor_dot) { - best_nor_dot = dot; - best_index_src = index_src; + + pidx_src = (mode == MREMAP_MODE_LOOP_NEAREST_LOOPNOR) ? + loop_to_poly_map_src[index_src] : index_src; + /* WARNING! This is not the *real* lidx_src in case of POLYNOR, we only use it + * to check we stay on current island (all loops from a given poly are + * on same island!). */ + lidx_src = (mode == MREMAP_MODE_LOOP_NEAREST_LOOPNOR) ? + index_src : polys_src[pidx_src].loopstart; + + /* A same vert may be at the boundary of several islands! Hence, we have to ensure + * poly/loop we are currently considering *belongs* to current island! */ + if (use_islands && island_store.items_to_islands[lidx_src] != tindex) { + continue; + } + + if (dot > best_nor_dot - 1e-6f) { + /* We need something as fallback decision in case dest normal matches several + * source normals (see T44522), using distance between polys' centers here. */ + float *pcent_src; + float sqdist; + + mp_src = &polys_src[pidx_src]; + ml_src = &loops_src[mp_src->loopstart]; + + if (!pcent_dst_valid) { + BKE_mesh_calc_poly_center( + mp_dst, &loops_dst[mp_dst->loopstart], verts_dst, pcent_dst); + pcent_dst_valid = true; + } + pcent_src = poly_cents_src[pidx_src]; + sqdist = len_squared_v3v3(pcent_dst, pcent_src); + + if ((dot > best_nor_dot + 1e-6f) || (sqdist < best_sqdist_fallback)) { + best_nor_dot = dot; + best_sqdist_fallback = sqdist; + best_index_src = index_src; + } } } if (mode == MREMAP_MODE_LOOP_NEAREST_POLYNOR) { /* Our best_index_src is a poly one for now! * Have to find its loop matching our closest vertex. */ - MPoly *mp_src = &polys_src[best_index_src]; - MLoop *ml_src = &loops_src[mp_src->loopstart]; + mp_src = &polys_src[best_index_src]; + ml_src = &loops_src[mp_src->loopstart]; for (plidx_src = 0; plidx_src < mp_src->totloop; plidx_src++, ml_src++) { if ((int)ml_src->v == nearest.index) { best_index_src = plidx_src + mp_src->loopstart; @@ -1296,7 +1344,8 @@ void BKE_mesh_remap_calc_loops_from_dm( } } } - islands_res[tindex][plidx_dst].factor = hit_dist ? (1.0f / (hit_dist * best_nor_dot)) : 1e18f; + best_nor_dot = (best_nor_dot + 1.0f) * 0.5f; + islands_res[tindex][plidx_dst].factor = hit_dist ? (1.0f / hit_dist * best_nor_dot) : 1e18f; islands_res[tindex][plidx_dst].hit_dist = hit_dist; islands_res[tindex][plidx_dst].index_src = best_index_src; } @@ -1488,12 +1537,11 @@ void BKE_mesh_remap_calc_loops_from_dm( if (last_valid_pidx_isld_src != -1) { /* Find a new valid loop in that new poly (nearest one for now). * Note we could be much more subtle here, again that's for later... */ - MPoly *mp_src; - MLoop *ml_src, *ml_dst = &loops_dst[lidx_dst]; int j; float best_dist_sq = FLT_MAX; float tmp_co[3]; + ml_dst = &loops_dst[lidx_dst]; copy_v3_v3(tmp_co, verts_dst[ml_dst->v].co); /* We do our transform here, since we may do several raycast/nearest queries. */ @@ -1532,10 +1580,10 @@ void BKE_mesh_remap_calc_loops_from_dm( /* Else, we use source poly, indices stored in islands_res are those of polygons. */ pidx_src = isld_res->index_src; if (pidx_src >= 0) { - MPoly *mp_src = &polys_src[pidx_src]; float *hit_co = isld_res->hit_point; int best_loop_index_src; + mp_src = &polys_src[pidx_src]; /* If prev and curr poly are the same, no need to do anything more!!! */ if (!ELEM(pidx_src_prev, -1, pidx_src) && isld_steps_src) { int pidx_isld_src, pidx_isld_src_prev; @@ -1575,11 +1623,11 @@ void BKE_mesh_remap_calc_loops_from_dm( if (last_valid_pidx_isld_src != -1) { /* Find a new valid loop in that new poly (nearest point on poly for now). * Note we could be much more subtle here, again that's for later... */ - MLoop *ml_dst = &loops_dst[lidx_dst]; float best_dist_sq = FLT_MAX; float tmp_co[3]; int j; + ml_dst = &loops_dst[lidx_dst]; copy_v3_v3(tmp_co, verts_dst[ml_dst->v].co); /* We do our transform here, since we may do several raycast/nearest queries. */ @@ -1710,6 +1758,9 @@ void BKE_mesh_remap_calc_loops_from_dm( if (loop_to_poly_map_src) { MEM_freeN(loop_to_poly_map_src); } + if (poly_cents_src) { + MEM_freeN(poly_cents_src); + } if (vcos_interp) { MEM_freeN(vcos_interp); } @@ -1865,7 +1916,7 @@ void BKE_mesh_remap_calc_polys_from_dm( BLI_space_transform_apply_normal(space_transform, tmp_no); } - fill_vn_fl(weights, (int)numpolys_src, 0.0f); + copy_vn_fl(weights, (int)numpolys_src, 0.0f); if (UNLIKELY((size_t)mp->totloop > tmp_poly_size)) { tmp_poly_size = (size_t)mp->totloop; diff --git a/source/blender/blenkernel/intern/modifiers_bmesh.c b/source/blender/blenkernel/intern/modifiers_bmesh.c index 645567eea67..18f3db6bd15 100644 --- a/source/blender/blenkernel/intern/modifiers_bmesh.c +++ b/source/blender/blenkernel/intern/modifiers_bmesh.c @@ -37,8 +37,9 @@ #include "BKE_editmesh.h" /* Static function for alloc */ -static BMFace *bm_face_create_from_mpoly(MPoly *mp, MLoop *ml, - BMesh *bm, BMVert **vtable, BMEdge **etable) +static BMFace *bm_face_create_from_mpoly( + MPoly *mp, MLoop *ml, + BMesh *bm, BMVert **vtable, BMEdge **etable) { BMVert **verts = BLI_array_alloca(verts, mp->totloop); BMEdge **edges = BLI_array_alloca(edges, mp->totloop); diff --git a/source/blender/blenkernel/intern/movieclip.c b/source/blender/blenkernel/intern/movieclip.c index 1aeb7bed86c..f063933f3f9 100644 --- a/source/blender/blenkernel/intern/movieclip.c +++ b/source/blender/blenkernel/intern/movieclip.c @@ -1129,15 +1129,15 @@ void BKE_movieclip_get_aspect(MovieClip *clip, float *aspx, float *aspy) } /* get segments of cached frames. useful for debugging cache policies */ -void BKE_movieclip_get_cache_segments(MovieClip *clip, MovieClipUser *user, int *totseg_r, int **points_r) +void BKE_movieclip_get_cache_segments(MovieClip *clip, MovieClipUser *user, int *r_totseg, int **r_points) { - *totseg_r = 0; - *points_r = NULL; + *r_totseg = 0; + *r_points = NULL; if (clip->cache) { int proxy = rendersize_to_proxy(user, clip->flag); - IMB_moviecache_get_cache_segments(clip->cache->moviecache, proxy, user->render_flag, totseg_r, points_r); + IMB_moviecache_get_cache_segments(clip->cache->moviecache, proxy, user->render_flag, r_totseg, r_points); } } diff --git a/source/blender/blenkernel/intern/multires.c b/source/blender/blenkernel/intern/multires.c index 4ac96405fbf..0c984c38b8e 100644 --- a/source/blender/blenkernel/intern/multires.c +++ b/source/blender/blenkernel/intern/multires.c @@ -340,13 +340,13 @@ static int multires_get_level(Object *ob, MultiresModifierData *mmd, bool render, bool ignore_simplify) { if (render) - return (mmd->modifier.scene) ? get_render_subsurf_level(&mmd->modifier.scene->r, mmd->renderlvl) : mmd->renderlvl; + return (mmd->modifier.scene) ? get_render_subsurf_level(&mmd->modifier.scene->r, mmd->renderlvl, true) : mmd->renderlvl; else if (ob->mode == OB_MODE_SCULPT) return mmd->sculptlvl; else if (ignore_simplify) return mmd->lvl; else - return (mmd->modifier.scene) ? get_render_subsurf_level(&mmd->modifier.scene->r, mmd->lvl) : mmd->lvl; + return (mmd->modifier.scene) ? get_render_subsurf_level(&mmd->modifier.scene->r, mmd->lvl, false) : mmd->lvl; } void multires_set_tot_level(Object *ob, MultiresModifierData *mmd, int lvl) @@ -882,18 +882,20 @@ static void multires_subdivide(MultiresModifierData *mmd, Object *ob, int totlvl { Mesh *me = ob->data; MDisps *mdisps; - int lvl = mmd->totlvl; + const int lvl = mmd->totlvl; if ((totlvl > multires_max_levels) || (me->totpoly == 0)) return; + BLI_assert(totlvl > lvl); + multires_force_update(ob); mdisps = CustomData_get_layer(&me->ldata, CD_MDISPS); if (!mdisps) mdisps = multires_mdisps_initialize_hidden(me, totlvl); - if (mdisps->disps && !updateblock && totlvl > 1) { + if (mdisps->disps && !updateblock && lvl != 0) { /* upsample */ DerivedMesh *lowdm, *cddm, *highdm; CCGElem **highGridData, **lowGridData, **subGridData; @@ -910,6 +912,7 @@ static void multires_subdivide(MultiresModifierData *mmd, Object *ob, int totlvl /* create multires DM from original mesh at low level */ lowdm = multires_dm_create_local(ob, cddm, lvl, lvl, simple, has_mask); + BLI_assert(lowdm != cddm); cddm->release(cddm); /* copy subsurf grids and replace them with low displaced grids */ @@ -2137,27 +2140,38 @@ void multires_load_old(Object *ob, Mesh *me) me->mr = NULL; } -/* If 'ob' and 'to_ob' both have multires modifiers, synchronize them - * such that 'ob' has the same total number of levels as 'to_ob'. */ -static void multires_sync_levels(Scene *scene, Object *ob, Object *to_ob) +/* If 'ob_src' and 'ob_dst' both have multires modifiers, synchronize them + * such that 'ob_dst' has the same total number of levels as 'ob_src'. */ +void multiresModifier_sync_levels_ex(Object *ob_dst, MultiresModifierData *mmd_src, MultiresModifierData *mmd_dst) { - MultiresModifierData *mmd = get_multires_modifier(scene, ob, 1); - MultiresModifierData *to_mmd = get_multires_modifier(scene, to_ob, 1); + if (mmd_src->totlvl == mmd_dst->totlvl) { + return; + } + + if (mmd_src->totlvl > mmd_dst->totlvl) { + multires_subdivide(mmd_dst, ob_dst, mmd_src->totlvl, false, mmd_dst->simple); + } + else { + multires_del_higher(mmd_dst, ob_dst, mmd_src->totlvl); + } +} - if (!mmd) { +static void multires_sync_levels(Scene *scene, Object *ob_src, Object *ob_dst) +{ + MultiresModifierData *mmd_src = get_multires_modifier(scene, ob_src, true); + MultiresModifierData *mmd_dst = get_multires_modifier(scene, ob_dst, true); + + if (!mmd_src) { /* object could have MDISP even when there is no multires modifier * this could lead to troubles due to i've got no idea how mdisp could be * upsampled correct without modifier data. * just remove mdisps if no multires present (nazgul) */ - multires_customdata_delete(ob->data); + multires_customdata_delete(ob_src->data); } - if (mmd && to_mmd) { - if (mmd->totlvl > to_mmd->totlvl) - multires_del_higher(mmd, ob, to_mmd->totlvl); - else - multires_subdivide(mmd, ob, to_mmd->totlvl, 0, mmd->simple); + if (mmd_src && mmd_dst) { + multiresModifier_sync_levels_ex(ob_dst, mmd_src, mmd_dst); } } @@ -2276,7 +2290,7 @@ void multiresModifier_scale_disp(Scene *scene, Object *ob) void multiresModifier_prepare_join(Scene *scene, Object *ob, Object *to_ob) { float smat[3][3], tmat[3][3], mat[3][3]; - multires_sync_levels(scene, ob, to_ob); + multires_sync_levels(scene, to_ob, ob); /* construct scale matrix for displacement */ BKE_object_scale_to_mat3(to_ob, tmat); diff --git a/source/blender/blenkernel/intern/node.c b/source/blender/blenkernel/intern/node.c index 0d375b0dbeb..c1fa6c55d59 100644 --- a/source/blender/blenkernel/intern/node.c +++ b/source/blender/blenkernel/intern/node.c @@ -303,7 +303,7 @@ bNodeTreeType *ntreeTypeFind(const char *idname) void ntreeTypeAdd(bNodeTreeType *nt) { - BLI_ghash_insert(nodetreetypes_hash, (void *)nt->idname, nt); + BLI_ghash_insert(nodetreetypes_hash, nt->idname, nt); /* XXX pass Main to register function? */ update_typeinfo(G.main, NULL, nt, NULL, NULL, false); } @@ -317,7 +317,7 @@ static void ntree_free_type(void *treetype_v) MEM_freeN(treetype); } -void ntreeTypeFreeLink(bNodeTreeType *nt) +void ntreeTypeFreeLink(const bNodeTreeType *nt) { BLI_ghash_remove(nodetreetypes_hash, nt->idname, NULL, ntree_free_type); } @@ -378,7 +378,7 @@ void nodeRegisterType(bNodeType *nt) BLI_assert(nt->idname[0] != '\0'); BLI_assert(nt->poll != NULL); - BLI_ghash_insert(nodetypes_hash, (void *)nt->idname, nt); + BLI_ghash_insert(nodetypes_hash, nt->idname, nt); /* XXX pass Main to register function? */ update_typeinfo(G.main, NULL, NULL, nt, NULL, false); } @@ -1109,7 +1109,7 @@ bNodeTree *ntreeAddTree(Main *bmain, const char *name, const char *idname) * copying for internal use (threads for eg), where you wont want it to modify the * scene data. */ -static bNodeTree *ntreeCopyTree_internal(bNodeTree *ntree, Main *bmain, bool do_id_user, bool do_make_extern, bool copy_previews) +static bNodeTree *ntreeCopyTree_internal(bNodeTree *ntree, Main *bmain, bool skip_database, bool do_id_user, bool do_make_extern, bool copy_previews) { bNodeTree *newtree; bNode *node /*, *nnode */ /* UNUSED */, *last; @@ -1119,7 +1119,7 @@ static bNodeTree *ntreeCopyTree_internal(bNodeTree *ntree, Main *bmain, bool do_ if (ntree == NULL) return NULL; /* is ntree part of library? */ - if (bmain && BLI_findindex(&bmain->nodetree, ntree) >= 0) { + if (bmain && !skip_database && BLI_findindex(&bmain->nodetree, ntree) >= 0) { newtree = BKE_libblock_copy(&ntree->id); } else { @@ -1211,7 +1211,7 @@ static bNodeTree *ntreeCopyTree_internal(bNodeTree *ntree, Main *bmain, bool do_ bNodeTree *ntreeCopyTree_ex(bNodeTree *ntree, Main *bmain, const bool do_id_user) { - return ntreeCopyTree_internal(ntree, bmain, do_id_user, true, true); + return ntreeCopyTree_internal(ntree, bmain, false, do_id_user, true, true); } bNodeTree *ntreeCopyTree(bNodeTree *ntree) { @@ -1980,7 +1980,7 @@ bNodeTree *ntreeLocalize(bNodeTree *ntree) /* Make full copy. * Note: previews are not copied here. */ - ltree = ntreeCopyTree_internal(ntree, NULL, false, false, false); + ltree = ntreeCopyTree_internal(ntree, G.main, true, false, false, false); ltree->flag |= NTREE_IS_LOCALIZED; for (node = ltree->nodes.first; node; node = node->next) { @@ -3082,10 +3082,14 @@ void nodeSynchronizeID(bNode *node, bool copy_to_id) bNodeSocket *sock; Material *ma = (Material *)node->id; int a; + short check_flags = SOCK_UNAVAIL; + + if (!copy_to_id) + check_flags |= SOCK_HIDDEN; /* hrmf, case in loop isn't super fast, but we don't edit 100s of material at same time either! */ for (a = 0, sock = node->inputs.first; sock; sock = sock->next, a++) { - if (!nodeSocketIsHidden(sock)) { + if (!(sock->flag & check_flags)) { if (copy_to_id) { switch (a) { case MAT_IN_COLOR: diff --git a/source/blender/blenkernel/intern/object.c b/source/blender/blenkernel/intern/object.c index f14f72614f4..f8fe53063bc 100644 --- a/source/blender/blenkernel/intern/object.c +++ b/source/blender/blenkernel/intern/object.c @@ -96,6 +96,7 @@ #include "BKE_editmesh.h" #include "BKE_mball.h" #include "BKE_modifier.h" +#include "BKE_multires.h" #include "BKE_node.h" #include "BKE_object.h" #include "BKE_paint.h" @@ -247,7 +248,7 @@ bool BKE_object_support_modifier_type_check(Object *ob, int modifier_type) return true; } -void BKE_object_link_modifiers(struct Object *ob_dst, struct Object *ob_src) +void BKE_object_link_modifiers(struct Object *ob_dst, const struct Object *ob_src) { ModifierData *md; BKE_object_free_modifiers(ob_dst); @@ -263,8 +264,6 @@ void BKE_object_link_modifiers(struct Object *ob_dst, struct Object *ob_src) if (ELEM(md->type, eModifierType_Hook, - eModifierType_Softbody, - eModifierType_ParticleInstance, eModifierType_Collision)) { continue; @@ -272,21 +271,31 @@ void BKE_object_link_modifiers(struct Object *ob_dst, struct Object *ob_src) if (!BKE_object_support_modifier_type_check(ob_dst, md->type)) continue; - - if (md->type == eModifierType_Skin) { - /* ensure skin-node customdata exists */ - BKE_mesh_ensure_skin_customdata(ob_dst->data); + + switch (md->type) { + case eModifierType_Softbody: + BKE_object_copy_softbody(ob_dst, ob_src); + break; + case eModifierType_Skin: + /* ensure skin-node customdata exists */ + BKE_mesh_ensure_skin_customdata(ob_dst->data); + break; } nmd = modifier_new(md->type); BLI_strncpy(nmd->name, md->name, sizeof(nmd->name)); + + if (md->type == eModifierType_Multires) { + /* Has to be done after mod creation, but *before* we actually copy its settings! */ + multiresModifier_sync_levels_ex(ob_dst, (MultiresModifierData *)md, (MultiresModifierData *)nmd); + } + modifier_copyData(md, nmd); BLI_addtail(&ob_dst->modifiers, nmd); modifier_unique_name(&ob_dst->modifiers, nmd); } BKE_object_copy_particlesystems(ob_dst, ob_src); - BKE_object_copy_softbody(ob_dst, ob_src); /* TODO: smoke?, cloth? */ } @@ -808,34 +817,11 @@ void BKE_object_unlink(Object *ob) } } } - else if (sl->spacetype == SPACE_OUTLINER) { - SpaceOops *so = (SpaceOops *)sl; - - if (so->treestore) { - TreeStoreElem *tselem; - BLI_mempool_iter iter; - BLI_mempool_iternew(so->treestore, &iter); - while ((tselem = BLI_mempool_iterstep(&iter))) { - if (tselem->id == (ID *)ob) tselem->id = NULL; - } - } - } - else if (sl->spacetype == SPACE_BUTS) { - SpaceButs *sbuts = (SpaceButs *)sl; - - if (sbuts->pinid == (ID *)ob) { - sbuts->flag &= ~SB_PIN_CONTEXT; - sbuts->pinid = NULL; - } - } - else if (sl->spacetype == SPACE_NODE) { - SpaceNode *snode = (SpaceNode *)sl; - - if (snode->from == (ID *)ob) { - snode->flag &= ~SNODE_PIN; - snode->from = NULL; - } +#if 0 + else if (ELEM(sl->spacetype, SPACE_OUTLINER, SPACE_BUTS, SPACE_NODE)) { + /* now handled by WM_main_remove_editor_id_reference */ } +#endif } sa = sa->next; @@ -938,26 +924,6 @@ bool BKE_object_exists_check(Object *obtest) /* *************************************************** */ -void *BKE_object_obdata_add_from_type(Main *bmain, int type) -{ - switch (type) { - case OB_MESH: return BKE_mesh_add(bmain, "Mesh"); - case OB_CURVE: return BKE_curve_add(bmain, "Curve", OB_CURVE); - case OB_SURF: return BKE_curve_add(bmain, "Surf", OB_SURF); - case OB_FONT: return BKE_curve_add(bmain, "Text", OB_FONT); - case OB_MBALL: return BKE_mball_add(bmain, "Meta"); - case OB_CAMERA: return BKE_camera_add(bmain, "Camera"); - case OB_LAMP: return BKE_lamp_add(bmain, "Lamp"); - case OB_LATTICE: return BKE_lattice_add(bmain, "Lattice"); - case OB_ARMATURE: return BKE_armature_add(bmain, "Armature"); - case OB_SPEAKER: return BKE_speaker_add(bmain, "Speaker"); - case OB_EMPTY: return NULL; - default: - printf("BKE_object_obdata_add_from_type: Internal error, bad type: %d\n", type); - return NULL; - } -} - static const char *get_obdata_defname(int type) { switch (type) { @@ -978,6 +944,30 @@ static const char *get_obdata_defname(int type) } } +void *BKE_object_obdata_add_from_type(Main *bmain, int type, const char *name) +{ + if (name == NULL) { + name = get_obdata_defname(type); + } + + switch (type) { + case OB_MESH: return BKE_mesh_add(bmain, name); + case OB_CURVE: return BKE_curve_add(bmain, name, OB_CURVE); + case OB_SURF: return BKE_curve_add(bmain, name, OB_SURF); + case OB_FONT: return BKE_curve_add(bmain, name, OB_FONT); + case OB_MBALL: return BKE_mball_add(bmain, name); + case OB_CAMERA: return BKE_camera_add(bmain, name); + case OB_LAMP: return BKE_lamp_add(bmain, name); + case OB_LATTICE: return BKE_lattice_add(bmain, name); + case OB_ARMATURE: return BKE_armature_add(bmain, name); + case OB_SPEAKER: return BKE_speaker_add(bmain, name); + case OB_EMPTY: return NULL; + default: + printf("%s: Internal error, bad type: %d\n", __func__, type); + return NULL; + } +} + /* more general add: creates minimum required data, but without vertices etc. */ Object *BKE_object_add_only_object(Main *bmain, int type, const char *name) { @@ -1063,16 +1053,16 @@ Object *BKE_object_add_only_object(Main *bmain, int type, const char *name) /* general add: to scene, with layer from area and default name */ /* creates minimum required data, but without vertices etc. */ -Object *BKE_object_add(Main *bmain, Scene *scene, int type) +Object *BKE_object_add( + Main *bmain, Scene *scene, + int type, const char *name) { Object *ob; Base *base; - char name[MAX_ID_NAME]; - BLI_strncpy(name, get_obdata_defname(type), sizeof(name)); ob = BKE_object_add_only_object(bmain, type, name); - ob->data = BKE_object_obdata_add_from_type(bmain, type); + ob->data = BKE_object_obdata_add_from_type(bmain, type, name); ob->lay = scene->lay; @@ -1219,7 +1209,7 @@ struct Object *BKE_object_lod_matob_get(Object *ob, Scene *scene) #endif /* WITH_GAMEENGINE */ -SoftBody *copy_softbody(SoftBody *sb, bool copy_caches) +SoftBody *copy_softbody(const SoftBody *sb, bool copy_caches) { SoftBody *sbn; @@ -1343,24 +1333,24 @@ ParticleSystem *BKE_object_copy_particlesystem(ParticleSystem *psys) return psysn; } -void BKE_object_copy_particlesystems(Object *obn, Object *ob) +void BKE_object_copy_particlesystems(Object *ob_dst, const Object *ob_src) { ParticleSystem *psys, *npsys; ModifierData *md; - if (obn->type != OB_MESH) { + if (ob_dst->type != OB_MESH) { /* currently only mesh objects can have soft body */ return; } - BLI_listbase_clear(&obn->particlesystem); - for (psys = ob->particlesystem.first; psys; psys = psys->next) { + BLI_listbase_clear(&ob_dst->particlesystem); + for (psys = ob_src->particlesystem.first; psys; psys = psys->next) { npsys = BKE_object_copy_particlesystem(psys); - BLI_addtail(&obn->particlesystem, npsys); + BLI_addtail(&ob_dst->particlesystem, npsys); /* need to update particle modifiers too */ - for (md = obn->modifiers.first; md; md = md->next) { + for (md = ob_dst->modifiers.first; md; md = md->next) { if (md->type == eModifierType_ParticleSystem) { ParticleSystemModifierData *psmd = (ParticleSystemModifierData *)md; if (psmd->psys == psys) @@ -1388,10 +1378,12 @@ void BKE_object_copy_particlesystems(Object *obn, Object *ob) } } -void BKE_object_copy_softbody(Object *obn, Object *ob) +void BKE_object_copy_softbody(Object *ob_dst, const Object *ob_src) { - if (ob->soft) - obn->soft = copy_softbody(ob->soft, false); + if (ob_src->soft) { + ob_dst->softflag = ob_src->softflag; + ob_dst->soft = copy_softbody(ob_src->soft, false); + } } static void copy_object_pose(Object *obn, Object *ob) @@ -1769,8 +1761,7 @@ void BKE_object_make_proxy(Object *ob, Object *target, Object *gob) mul_m4_m4m4(ob->obmat, gob->obmat, target->obmat); if (gob->dup_group) { /* should always be true */ float tvec[3]; - copy_v3_v3(tvec, gob->dup_group->dupli_ofs); - mul_mat3_m4_v3(ob->obmat, tvec); + mul_v3_mat3_m4v3(tvec, ob->obmat, gob->dup_group->dupli_ofs); sub_v3_v3(ob->obmat[3], tvec); } BKE_object_apply_mat4(ob, ob->obmat, false, true); @@ -2065,14 +2056,12 @@ void BKE_object_to_mat4(Object *ob, float mat[4][4]) add_v3_v3v3(mat[3], ob->loc, ob->dloc); } -static void ob_get_parent_matrix(Scene *scene, Object *ob, Object *par, float parentmat[4][4]); - void BKE_object_matrix_local_get(struct Object *ob, float mat[4][4]) { if (ob->parent) { float par_imat[4][4]; - ob_get_parent_matrix(NULL, ob, ob->parent, par_imat); + BKE_object_get_parent_matrix(NULL, ob, ob->parent, par_imat); invert_m4(par_imat); mul_m4_m4m4(mat, par_imat, ob->obmat); } @@ -2092,7 +2081,7 @@ static void ob_parcurve(Scene *scene, Object *ob, Object *par, float mat[4][4]) unit_m4(mat); cu = par->data; - if (ELEM(NULL, par->curve_cache, par->curve_cache->path, par->curve_cache->path->data)) /* only happens on reload file, but violates depsgraph still... fix! */ + if (par->curve_cache == NULL) /* only happens on reload file, but violates depsgraph still... fix! */ BKE_displist_make_curveTypes(scene, par, 0); if (par->curve_cache->path == NULL) return; @@ -2127,7 +2116,7 @@ static void ob_parcurve(Scene *scene, Object *ob, Object *par, float mat[4][4]) } /* vec: 4 items! */ - if (where_on_path(par, ctime, vec, dir, cu->flag & CU_FOLLOW ? quat : NULL, &radius, NULL)) { + if (where_on_path(par, ctime, vec, dir, (cu->flag & CU_FOLLOW) ? quat : NULL, &radius, NULL)) { if (cu->flag & CU_FOLLOW) { #if 0 @@ -2364,7 +2353,8 @@ static void ob_parvert3(Object *ob, Object *par, float mat[4][4]) } } -static void ob_get_parent_matrix(Scene *scene, Object *ob, Object *par, float parentmat[4][4]) + +void BKE_object_get_parent_matrix(Scene *scene, Object *ob, Object *par, float parentmat[4][4]) { float tmat[4][4]; float vec[3]; @@ -2421,7 +2411,7 @@ static void solve_parenting(Scene *scene, Object *ob, Object *par, float obmat[4 if (ob->partype & PARSLOW) copy_m4_m4(slowmat, obmat); - ob_get_parent_matrix(scene, ob, par, totmat); + BKE_object_get_parent_matrix(scene, ob, par, totmat); /* total */ mul_m4_m4m4(tmat, totmat, ob->parentinv); @@ -2579,7 +2569,7 @@ void BKE_object_apply_mat4(Object *ob, float mat[4][4], const bool use_compat, c if (use_parent && ob->parent) { float rmat[4][4], diff_mat[4][4], imat[4][4], parent_mat[4][4]; - ob_get_parent_matrix(NULL, ob, ob->parent, parent_mat); + BKE_object_get_parent_matrix(NULL, ob, ob->parent, parent_mat); mul_m4_m4m4(diff_mat, parent_mat, ob->parentinv); invert_m4_m4(imat, diff_mat); @@ -3045,8 +3035,9 @@ void BKE_object_handle_update_ex(EvaluationContext *eval_ctx, // printf("ob proxy copy, lib ob %s proxy %s\n", ob->id.name, ob->proxy_from->id.name); if (ob->proxy_from->proxy_group) { /* transform proxy into group space */ Object *obg = ob->proxy_from->proxy_group; - invert_m4_m4(obg->imat, obg->obmat); - mul_m4_m4m4(ob->obmat, obg->imat, ob->proxy_from->obmat); + float imat[4][4]; + invert_m4_m4(imat, obg->obmat); + mul_m4_m4m4(ob->obmat, imat, ob->proxy_from->obmat); if (obg->dup_group) { /* should always be true */ add_v3_v3(ob->obmat[3], obg->dup_group->dupli_ofs); } @@ -3059,147 +3050,7 @@ void BKE_object_handle_update_ex(EvaluationContext *eval_ctx, } if (ob->recalc & OB_RECALC_DATA) { - ID *data_id = (ID *)ob->data; - AnimData *adt = BKE_animdata_from_id(data_id); - Key *key; - float ctime = BKE_scene_frame_get(scene); - - if (G.debug & G_DEBUG_DEPSGRAPH) - printf("recalcdata %s\n", ob->id.name + 2); - - if (adt) { - /* evaluate drivers - datalevel */ - /* XXX: for mesh types, should we push this to derivedmesh instead? */ - BKE_animsys_evaluate_animdata(scene, data_id, adt, ctime, ADT_RECALC_DRIVERS); - } - - key = BKE_key_from_object(ob); - if (key && key->block.first) { - if (!(ob->shapeflag & OB_SHAPE_LOCK)) - BKE_animsys_evaluate_animdata(scene, &key->id, key->adt, ctime, ADT_RECALC_DRIVERS); - } - - /* includes all keys and modifiers */ - switch (ob->type) { - case OB_MESH: - { - BMEditMesh *em = (ob == scene->obedit) ? BKE_editmesh_from_object(ob) : NULL; - uint64_t data_mask = scene->customdata_mask | CD_MASK_BAREMESH; -#ifdef WITH_FREESTYLE - /* make sure Freestyle edge/face marks appear in DM for render (see T40315) */ - if (eval_ctx->mode != DAG_EVAL_VIEWPORT) { - data_mask |= CD_MASK_FREESTYLE_EDGE | CD_MASK_FREESTYLE_FACE; - } -#endif - if (em) { - makeDerivedMesh(scene, ob, em, data_mask, 0); /* was CD_MASK_BAREMESH */ - } - else { - makeDerivedMesh(scene, ob, NULL, data_mask, 0); - } - break; - } - case OB_ARMATURE: - if (ob->id.lib && ob->proxy_from) { - if (BKE_pose_copy_result(ob->pose, ob->proxy_from->pose) == false) { - printf("Proxy copy error, lib Object: %s proxy Object: %s\n", - ob->id.name + 2, ob->proxy_from->id.name + 2); - } - } - else { - BKE_pose_where_is(scene, ob); - } - break; - - case OB_MBALL: - BKE_displist_make_mball(eval_ctx, scene, ob); - break; - - case OB_CURVE: - case OB_SURF: - case OB_FONT: - BKE_displist_make_curveTypes(scene, ob, 0); - break; - - case OB_LATTICE: - BKE_lattice_modifiers_calc(scene, ob); - break; - - case OB_EMPTY: - if (ob->empty_drawtype == OB_EMPTY_IMAGE && ob->data) - if (BKE_image_is_animated(ob->data)) - BKE_image_user_check_frame_calc(ob->iuser, (int)ctime, 0); - break; - } - - /* related materials */ - /* XXX: without depsgraph tagging, this will always need to be run, which will be slow! - * However, not doing anything (or trying to hack around this lack) is not an option - * anymore, especially due to Cycles [#31834] - */ - if (ob->totcol) { - int a; - - for (a = 1; a <= ob->totcol; a++) { - Material *ma = give_current_material(ob, a); - - if (ma) { - /* recursively update drivers for this material */ - material_drivers_update(scene, ma, ctime); - } - } - } - else if (ob->type == OB_LAMP) - lamp_drivers_update(scene, ob->data, ctime); - - /* particles */ - if (ob != scene->obedit && ob->particlesystem.first) { - ParticleSystem *tpsys, *psys; - DerivedMesh *dm; - ob->transflag &= ~OB_DUPLIPARTS; - - psys = ob->particlesystem.first; - while (psys) { - /* ensure this update always happens even if psys is disabled */ - if (psys->recalc & PSYS_RECALC_TYPE) { - psys_changed_type(ob, psys); - } - - if (psys_check_enabled(ob, psys)) { - /* check use of dupli objects here */ - if (psys->part && (psys->part->draw_as == PART_DRAW_REND || eval_ctx->mode == DAG_EVAL_RENDER) && - ((psys->part->ren_as == PART_DRAW_OB && psys->part->dup_ob) || - (psys->part->ren_as == PART_DRAW_GR && psys->part->dup_group))) - { - ob->transflag |= OB_DUPLIPARTS; - } - - particle_system_update(scene, ob, psys); - psys = psys->next; - } - else if (psys->flag & PSYS_DELETE) { - tpsys = psys->next; - BLI_remlink(&ob->particlesystem, psys); - psys_free(ob, psys); - psys = tpsys; - } - else - psys = psys->next; - } - - if (eval_ctx->mode == DAG_EVAL_RENDER && ob->transflag & OB_DUPLIPARTS) { - /* this is to make sure we get render level duplis in groups: - * the derivedmesh must be created before init_render_mesh, - * since object_duplilist does dupliparticles before that */ - dm = mesh_create_derived_render(scene, ob, CD_MASK_BAREMESH | CD_MASK_MTFACE | CD_MASK_MCOL); - dm->release(dm); - - for (psys = ob->particlesystem.first; psys; psys = psys->next) - psys_get_modifier(ob, psys)->flag &= ~eParticleSystemFlag_psys_updated; - } - } - - /* quick cache removed */ + BKE_object_handle_data_update(eval_ctx, scene, ob); } ob->recalc &= ~OB_RECALC_ALL; @@ -3507,7 +3358,7 @@ static KeyBlock *insert_curvekey(Object *ob, const char *name, const bool from_m return kb; } -KeyBlock *BKE_object_insert_shape_key(Object *ob, const char *name, const bool from_mix) +KeyBlock *BKE_object_shapekey_insert(Object *ob, const char *name, const bool from_mix) { switch (ob->type) { case OB_MESH: @@ -3523,6 +3374,85 @@ KeyBlock *BKE_object_insert_shape_key(Object *ob, const char *name, const bool f } +bool BKE_object_shapekey_free(Main *bmain, Object *ob) +{ + Key **key_p, *key; + + key_p = BKE_key_from_object_p(ob); + if (ELEM(NULL, key_p, *key_p)) { + return false; + } + + key = *key_p; + *key_p = NULL; + + BKE_libblock_free_us(bmain, key); + + return false; +} + +bool BKE_object_shapekey_remove(Main *bmain, Object *ob, KeyBlock *kb) +{ + KeyBlock *rkb; + Key *key = BKE_key_from_object(ob); + short kb_index; + + if (key == NULL) { + return false; + } + + kb_index = BLI_findindex(&key->block, kb); + BLI_assert(kb_index != -1); + + for (rkb = key->block.first; rkb; rkb = rkb->next) { + if (rkb->relative == kb_index) { + /* remap to the 'Basis' */ + rkb->relative = 0; + } + else if (rkb->relative >= kb_index) { + /* Fix positional shift of the keys when kb is deleted from the list */ + rkb->relative -= 1; + } + } + + BLI_remlink(&key->block, kb); + key->totkey--; + if (key->refkey == kb) { + key->refkey = key->block.first; + + if (key->refkey) { + /* apply new basis key on original data */ + switch (ob->type) { + case OB_MESH: + BKE_keyblock_convert_to_mesh(key->refkey, ob->data); + break; + case OB_CURVE: + case OB_SURF: + BKE_keyblock_convert_to_curve(key->refkey, ob->data, BKE_curve_nurbs_get(ob->data)); + break; + case OB_LATTICE: + BKE_keyblock_convert_to_lattice(key->refkey, ob->data); + break; + } + } + } + + if (kb->data) { + MEM_freeN(kb->data); + } + MEM_freeN(kb); + + if (ob->shapenr > 1) { + ob->shapenr--; + } + + if (key->totkey == 0) { + BKE_object_shapekey_free(bmain, ob); + } + + return true; +} + bool BKE_object_flag_test_recursive(const Object *ob, short flag) { if (ob->flag & flag) { @@ -4044,3 +3974,51 @@ KDTree *BKE_object_as_kdtree(Object *ob, int *r_tot) *r_tot = tot; return tree; } + +bool BKE_object_modifier_use_time(Object *ob, ModifierData *md) +{ + if (modifier_dependsOnTime(md)) { + return true; + } + + /* Check whether modifier is animated. */ + /* TODO: this should be handled as part of build_animdata() -- Aligorith */ + if (ob->adt) { + AnimData *adt = ob->adt; + FCurve *fcu; + + char pattern[MAX_NAME + 10]; + /* TODO(sergey): Escape modifier name. */ + BLI_snprintf(pattern, sizeof(pattern), "modifiers[%s", md->name); + + /* action - check for F-Curves with paths containing 'modifiers[' */ + if (adt->action) { + for (fcu = (FCurve *)adt->action->curves.first; + fcu != NULL; + fcu = (FCurve *)fcu->next) + { + if (fcu->rna_path && strstr(fcu->rna_path, pattern)) + return true; + } + } + + /* This here allows modifier properties to get driven and still update properly + * + * Workaround to get [#26764] (e.g. subsurf levels not updating when animated/driven) + * working, without the updating problems ([#28525] [#28690] [#28774] [#28777]) caused + * by the RNA updates cache introduced in r.38649 + */ + for (fcu = (FCurve *)adt->drivers.first; + fcu != NULL; + fcu = (FCurve *)fcu->next) + { + if (fcu->rna_path && strstr(fcu->rna_path, pattern)) + return true; + } + + /* XXX: also, should check NLA strips, though for now assume that nobody uses + * that and we can omit that for performance reasons... */ + } + + return false; +} diff --git a/source/blender/blenkernel/intern/object_deform.c b/source/blender/blenkernel/intern/object_deform.c index e46929dde4a..f6e939a103e 100644 --- a/source/blender/blenkernel/intern/object_deform.c +++ b/source/blender/blenkernel/intern/object_deform.c @@ -163,7 +163,7 @@ MDeformVert *BKE_object_defgroup_data_create(ID *id) /** * Remove all verts (or only selected ones) from given vgroup. Work in Object and Edit modes. * - * \param allverts If true, remove all vertices, else only selected ones. + * \param use_selection: Only operate on selection. * \return True if any vertex was removed, false otherwise. */ bool BKE_object_defgroup_clear(Object *ob, bDeformGroup *dg, const bool use_selection) @@ -241,7 +241,7 @@ bool BKE_object_defgroup_clear(Object *ob, bDeformGroup *dg, const bool use_sele /** * Remove all verts (or only selected ones) from all vgroups. Work in Object and Edit modes. * - * \param allverts If true, remove all vertices, else only selected ones. + * \param use_selection: Only operate on selection. * \return True if any vertex was removed, false otherwise. */ bool BKE_object_defgroup_clear_all(Object *ob, const bool use_selection) diff --git a/source/blender/blenkernel/intern/object_update.c b/source/blender/blenkernel/intern/object_update.c new file mode 100644 index 00000000000..483968c6bd9 --- /dev/null +++ b/source/blender/blenkernel/intern/object_update.c @@ -0,0 +1,348 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 20014 by Blender Foundation. + * All rights reserved. + * + * Contributor(s): Sergey Sharybin. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/blenkernel/intern/object_update.c + * \ingroup bke + */ + +#include "DNA_anim_types.h" +#include "DNA_constraint_types.h" +#include "DNA_group_types.h" +#include "DNA_key_types.h" +#include "DNA_material_types.h" +#include "DNA_scene_types.h" + +#include "BLI_blenlib.h" +#include "BLI_utildefines.h" +#include "BLI_math.h" +#include "BLI_threads.h" + +#include "BKE_global.h" +#include "BKE_armature.h" +#include "BKE_action.h" +#include "BKE_constraint.h" +#include "BKE_depsgraph.h" +#include "BKE_DerivedMesh.h" +#include "BKE_animsys.h" +#include "BKE_displist.h" +#include "BKE_effect.h" +#include "BKE_key.h" +#include "BKE_lamp.h" +#include "BKE_lattice.h" +#include "BKE_editmesh.h" +#include "BKE_object.h" +#include "BKE_particle.h" +#include "BKE_scene.h" +#include "BKE_material.h" +#include "BKE_image.h" + +#include "DEG_depsgraph.h" + +#ifdef WITH_LEGACY_DEPSGRAPH +# define DEBUG_PRINT if (!DEG_depsgraph_use_legacy() && G.debug & G_DEBUG_DEPSGRAPH) printf +#else +# define DEBUG_PRINT if (G.debug & G_DEBUG_DEPSGRAPH) printf +#endif + +static ThreadMutex material_lock = BLI_MUTEX_INITIALIZER; + +void BKE_object_eval_local_transform(EvaluationContext *UNUSED(eval_ctx), + Scene *UNUSED(scene), + Object *ob) +{ + DEBUG_PRINT("%s on %s\n", __func__, ob->id.name); + + /* calculate local matrix */ + BKE_object_to_mat4(ob, ob->obmat); +} + +/* Evaluate parent */ +/* NOTE: based on solve_parenting(), but with the cruft stripped out */ +void BKE_object_eval_parent(EvaluationContext *UNUSED(eval_ctx), + Scene *scene, + Object *ob) +{ + Object *par = ob->parent; + + float totmat[4][4]; + float tmat[4][4]; + float locmat[4][4]; + + DEBUG_PRINT("%s on %s\n", __func__, ob->id.name); + + /* get local matrix (but don't calculate it, as that was done already!) */ + // XXX: redundant? + copy_m4_m4(locmat, ob->obmat); + + /* get parent effect matrix */ + BKE_object_get_parent_matrix(scene, ob, par, totmat); + + /* total */ + mul_m4_m4m4(tmat, totmat, ob->parentinv); + mul_m4_m4m4(ob->obmat, tmat, locmat); + + /* origin, for help line */ + if ((ob->partype & PARTYPE) == PARSKEL) { + copy_v3_v3(ob->orig, par->obmat[3]); + } + else { + copy_v3_v3(ob->orig, totmat[3]); + } +} + +void BKE_object_eval_constraints(EvaluationContext *UNUSED(eval_ctx), + Scene *scene, + Object *ob) +{ + bConstraintOb *cob; + float ctime = BKE_scene_frame_get(scene); + + DEBUG_PRINT("%s on %s\n", __func__, ob->id.name); + + /* evaluate constraints stack */ + /* TODO: split this into: + * - pre (i.e. BKE_constraints_make_evalob, per-constraint (i.e. + * - inner body of BKE_constraints_solve), + * - post (i.e. BKE_constraints_clear_evalob) + * + * Not sure why, this is from Joshua - sergey + * + */ + cob = BKE_constraints_make_evalob(scene, ob, NULL, CONSTRAINT_OBTYPE_OBJECT); + BKE_constraints_solve(&ob->constraints, cob, ctime); + BKE_constraints_clear_evalob(cob); +} + +void BKE_object_eval_done(EvaluationContext *UNUSED(eval_ctx), Object *ob) +{ + DEBUG_PRINT("%s on %s\n", __func__, ob->id.name); + + /* Set negative scale flag in object. */ + if (is_negative_m4(ob->obmat)) ob->transflag |= OB_NEG_SCALE; + else ob->transflag &= ~OB_NEG_SCALE; +} + +void BKE_object_eval_modifier(struct EvaluationContext *eval_ctx, + struct Scene *scene, + struct Object *ob, + struct ModifierData *md) +{ + DEBUG_PRINT("%s on %s\n", __func__, ob->id.name); + (void) eval_ctx; /* Ignored. */ + (void) scene; /* Ignored. */ + (void) ob; /* Ignored. */ + (void) md; /* Ignored. */ +} + +void BKE_object_handle_data_update(EvaluationContext *eval_ctx, + Scene *scene, + Object *ob) +{ + ID *data_id = (ID *)ob->data; + AnimData *adt = BKE_animdata_from_id(data_id); + Key *key; + float ctime = BKE_scene_frame_get(scene); + + if (G.debug & G_DEBUG_DEPSGRAPH) + printf("recalcdata %s\n", ob->id.name + 2); + + /* TODO(sergey): Only used by legacy depsgraph. */ + if (adt) { + /* evaluate drivers - datalevel */ + /* XXX: for mesh types, should we push this to derivedmesh instead? */ + BKE_animsys_evaluate_animdata(scene, data_id, adt, ctime, ADT_RECALC_DRIVERS); + } + + /* TODO(sergey): Only used by legacy depsgraph. */ + key = BKE_key_from_object(ob); + if (key && key->block.first) { + if (!(ob->shapeflag & OB_SHAPE_LOCK)) + BKE_animsys_evaluate_animdata(scene, &key->id, key->adt, ctime, ADT_RECALC_DRIVERS); + } + + /* includes all keys and modifiers */ + switch (ob->type) { + case OB_MESH: + { + BMEditMesh *em = (ob == scene->obedit) ? BKE_editmesh_from_object(ob) : NULL; + uint64_t data_mask = scene->customdata_mask | CD_MASK_BAREMESH; +#ifdef WITH_FREESTYLE + /* make sure Freestyle edge/face marks appear in DM for render (see T40315) */ + if (eval_ctx->mode != DAG_EVAL_VIEWPORT) { + data_mask |= CD_MASK_FREESTYLE_EDGE | CD_MASK_FREESTYLE_FACE; + } +#endif + if (em) { + makeDerivedMesh(scene, ob, em, data_mask, 0); /* was CD_MASK_BAREMESH */ + } + else { + makeDerivedMesh(scene, ob, NULL, data_mask, 0); + } + break; + } + case OB_ARMATURE: + if (ob->id.lib && ob->proxy_from) { + if (BKE_pose_copy_result(ob->pose, ob->proxy_from->pose) == false) { + printf("Proxy copy error, lib Object: %s proxy Object: %s\n", + ob->id.name + 2, ob->proxy_from->id.name + 2); + } + } + else { + BKE_pose_where_is(scene, ob); + } + break; + + case OB_MBALL: + BKE_displist_make_mball(eval_ctx, scene, ob); + break; + + case OB_CURVE: + case OB_SURF: + case OB_FONT: + BKE_displist_make_curveTypes(scene, ob, 0); + break; + + case OB_LATTICE: + BKE_lattice_modifiers_calc(scene, ob); + break; + + case OB_EMPTY: + if (ob->empty_drawtype == OB_EMPTY_IMAGE && ob->data) + if (BKE_image_is_animated(ob->data)) + BKE_image_user_check_frame_calc(ob->iuser, (int)ctime, 0); + break; + } + + /* related materials */ + /* XXX: without depsgraph tagging, this will always need to be run, which will be slow! + * However, not doing anything (or trying to hack around this lack) is not an option + * anymore, especially due to Cycles [#31834] + */ + if (ob->totcol) { + int a; + if (ob->totcol != 0) { + BLI_mutex_lock(&material_lock); + for (a = 1; a <= ob->totcol; a++) { + Material *ma = give_current_material(ob, a); + if (ma) { + /* recursively update drivers for this material */ + material_drivers_update(scene, ma, ctime); + } + } + BLI_mutex_unlock(&material_lock); + } + } + else if (ob->type == OB_LAMP) + lamp_drivers_update(scene, ob->data, ctime); + + /* particles */ + if (ob != scene->obedit && ob->particlesystem.first) { + ParticleSystem *tpsys, *psys; + DerivedMesh *dm; + ob->transflag &= ~OB_DUPLIPARTS; + psys = ob->particlesystem.first; + while (psys) { + /* ensure this update always happens even if psys is disabled */ + if (psys->recalc & PSYS_RECALC_TYPE) { + psys_changed_type(ob, psys); + } + + if (psys_check_enabled(ob, psys)) { + /* check use of dupli objects here */ + if (psys->part && (psys->part->draw_as == PART_DRAW_REND || eval_ctx->mode == DAG_EVAL_RENDER) && + ((psys->part->ren_as == PART_DRAW_OB && psys->part->dup_ob) || + (psys->part->ren_as == PART_DRAW_GR && psys->part->dup_group))) + { + ob->transflag |= OB_DUPLIPARTS; + } + + particle_system_update(scene, ob, psys); + psys = psys->next; + } + else if (psys->flag & PSYS_DELETE) { + tpsys = psys->next; + BLI_remlink(&ob->particlesystem, psys); + psys_free(ob, psys); + psys = tpsys; + } + else + psys = psys->next; + } + + if (eval_ctx->mode == DAG_EVAL_RENDER && ob->transflag & OB_DUPLIPARTS) { + /* this is to make sure we get render level duplis in groups: + * the derivedmesh must be created before init_render_mesh, + * since object_duplilist does dupliparticles before that */ + dm = mesh_create_derived_render(scene, ob, CD_MASK_BAREMESH | CD_MASK_MTFACE | CD_MASK_MCOL); + dm->release(dm); + + for (psys = ob->particlesystem.first; psys; psys = psys->next) + psys_get_modifier(ob, psys)->flag &= ~eParticleSystemFlag_psys_updated; + } + } + + /* quick cache removed */ +} + +void BKE_object_eval_uber_transform(EvaluationContext *UNUSED(eval_ctx), + Scene *UNUSED(scene), + Object *ob) +{ + /* TODO(sergey): Currently it's a duplicate of logic in BKE_object_handle_update_ex(). */ + // XXX: it's almost redundant now... + + /* Handle proxy copy for target, */ + if (ob->id.lib && ob->proxy_from) { + if (ob->proxy_from->proxy_group) { + /* Transform proxy into group space. */ + Object *obg = ob->proxy_from->proxy_group; + float imat[4][4]; + invert_m4_m4(imat, obg->obmat); + mul_m4_m4m4(ob->obmat, imat, ob->proxy_from->obmat); + /* Should always be true. */ + if (obg->dup_group) { + add_v3_v3(ob->obmat[3], obg->dup_group->dupli_ofs); + } + } + else + copy_m4_m4(ob->obmat, ob->proxy_from->obmat); + } + + ob->recalc &= ~(OB_RECALC_OB | OB_RECALC_TIME); + if (ob->data == NULL) { + ob->recalc &= ~OB_RECALC_DATA; + } +} + +void BKE_object_eval_uber_data(EvaluationContext *eval_ctx, + Scene *scene, + Object *ob) +{ + DEBUG_PRINT("%s on %s\n", __func__, ob->id.name); + BLI_assert(ob->type != OB_ARMATURE); + BKE_object_handle_data_update(eval_ctx, scene, ob); + + ob->recalc &= ~(OB_RECALC_DATA | OB_RECALC_TIME); +} diff --git a/source/blender/blenkernel/intern/ocean.c b/source/blender/blenkernel/intern/ocean.c index b89b5ab4bbc..1a178fb2bdf 100644 --- a/source/blender/blenkernel/intern/ocean.c +++ b/source/blender/blenkernel/intern/ocean.c @@ -738,8 +738,8 @@ static void set_height_normalize_factor(struct Ocean *oc) for (i = 0; i < oc->_M; ++i) { for (j = 0; j < oc->_N; ++j) { - if (max_h < fabsf(oc->_disp_y[i * oc->_N + j])) { - max_h = fabsf(oc->_disp_y[i * oc->_N + j]); + if (max_h < fabs(oc->_disp_y[i * oc->_N + j])) { + max_h = fabs(oc->_disp_y[i * oc->_N + j]); } } } diff --git a/source/blender/blenkernel/intern/outliner_treehash.c b/source/blender/blenkernel/intern/outliner_treehash.c index 21664bfd285..f31ba34a984 100644 --- a/source/blender/blenkernel/intern/outliner_treehash.c +++ b/source/blender/blenkernel/intern/outliner_treehash.c @@ -102,6 +102,9 @@ static void fill_treehash(void *treehash, BLI_mempool *treestore) TreeStoreElem *tselem; BLI_mempool_iter iter; BLI_mempool_iternew(treestore, &iter); + + BLI_assert(treehash); + while ((tselem = BLI_mempool_iterstep(&iter))) { BKE_outliner_treehash_add_element(treehash, tselem); } @@ -121,6 +124,8 @@ static void free_treehash_group(void *key) void *BKE_outliner_treehash_rebuild_from_treestore(void *treehash, BLI_mempool *treestore) { + BLI_assert(treehash); + BLI_ghash_clear_ex(treehash, NULL, free_treehash_group, BLI_mempool_count(treestore)); fill_treehash(treehash, treestore); return treehash; @@ -144,12 +149,19 @@ static TseGroup *BKE_outliner_treehash_lookup_group(GHash *th, short type, short tse_template.type = type; tse_template.nr = type ? nr : 0; // we're picky! :) tse_template.id = id; + + BLI_assert(th); + return BLI_ghash_lookup(th, &tse_template); } TreeStoreElem *BKE_outliner_treehash_lookup_unused(void *treehash, short type, short nr, struct ID *id) { - TseGroup *group = BKE_outliner_treehash_lookup_group(treehash, type, nr, id); + TseGroup *group; + + BLI_assert(treehash); + + group = BKE_outliner_treehash_lookup_group(treehash, type, nr, id); if (group) { int i; for (i = 0; i < group->size; i++) { @@ -163,11 +175,17 @@ TreeStoreElem *BKE_outliner_treehash_lookup_unused(void *treehash, short type, s TreeStoreElem *BKE_outliner_treehash_lookup_any(void *treehash, short type, short nr, struct ID *id) { - TseGroup *group = BKE_outliner_treehash_lookup_group(treehash, type, nr, id); + TseGroup *group; + + BLI_assert(treehash); + + group = BKE_outliner_treehash_lookup_group(treehash, type, nr, id); return group ? group->elems[0] : NULL; } void BKE_outliner_treehash_free(void *treehash) { + BLI_assert(treehash); + BLI_ghash_free(treehash, NULL, free_treehash_group); } diff --git a/source/blender/blenkernel/intern/packedFile.c b/source/blender/blenkernel/intern/packedFile.c index 61e39d0ad47..800df252c69 100644 --- a/source/blender/blenkernel/intern/packedFile.c +++ b/source/blender/blenkernel/intern/packedFile.c @@ -224,7 +224,7 @@ PackedFile *newPackedFile(ReportList *reports, const char *filename, const char } /* no libraries for now */ -void packAll(Main *bmain, ReportList *reports) +void packAll(Main *bmain, ReportList *reports, bool verbose) { Image *ima; VFont *vfont; @@ -237,7 +237,7 @@ void packAll(Main *bmain, ReportList *reports) BKE_image_packfiles(reports, ima, ID_BLEND_PATH(bmain, &ima->id)); tot ++; } - else if (BKE_image_is_animated(ima)) { + else if (BKE_image_is_animated(ima) && verbose) { BKE_reportf(reports, RPT_WARNING, "Image '%s' skipped, movies and image sequences not supported", ima->id.name + 2); } @@ -258,10 +258,10 @@ void packAll(Main *bmain, ReportList *reports) } } - if (tot == 0) - BKE_report(reports, RPT_INFO, "No new files have been packed"); - else + if (tot > 0) BKE_reportf(reports, RPT_INFO, "Packed %d files", tot); + else if (verbose) + BKE_report(reports, RPT_INFO, "No new files have been packed"); } @@ -478,7 +478,7 @@ char *unpackFile(ReportList *reports, const char *abs_name, const char *local_na } static void unpack_generate_paths( - const char *name, ID *id, char *abspath_r, char *relpath_r, size_t abspathlen, size_t relpathlen) + const char *name, ID *id, char *r_abspath, char *r_relpath, size_t abspathlen, size_t relpathlen) { char tempname[FILE_MAX]; char tempdir[FILE_MAXDIR]; @@ -500,19 +500,19 @@ static void unpack_generate_paths( switch (GS(id->name)) { case ID_VF: - BLI_snprintf(relpath_r, relpathlen, "//fonts/%s", tempname); + BLI_snprintf(r_relpath, relpathlen, "//fonts/%s", tempname); break; case ID_SO: - BLI_snprintf(relpath_r, relpathlen, "//sounds/%s", tempname); + BLI_snprintf(r_relpath, relpathlen, "//sounds/%s", tempname); break; case ID_IM: - BLI_snprintf(relpath_r, relpathlen, "//textures/%s", tempname); + BLI_snprintf(r_relpath, relpathlen, "//textures/%s", tempname); break; } { - size_t len = BLI_strncpy_rlen(abspath_r, tempdir, abspathlen); - BLI_strncpy(abspath_r + len, tempname, abspathlen - len); + size_t len = BLI_strncpy_rlen(r_abspath, tempdir, abspathlen); + BLI_strncpy(r_abspath + len, tempname, abspathlen - len); } } diff --git a/source/blender/blenkernel/intern/paint.c b/source/blender/blenkernel/intern/paint.c index 3900ba8b5ea..0bda740af53 100644 --- a/source/blender/blenkernel/intern/paint.c +++ b/source/blender/blenkernel/intern/paint.c @@ -519,7 +519,7 @@ float paint_grid_paint_mask(const GridPaintMask *gpm, unsigned level, /* threshold to move before updating the brush rotation */ #define RAKE_THRESHHOLD 20 -static void update_brush_rake_rotation(UnifiedPaintSettings *ups, Brush *brush, float rotation) +void paint_update_brush_rake_rotation(UnifiedPaintSettings *ups, Brush *brush, float rotation) { if (brush->mtex.brush_angle_mode & MTEX_ANGLE_RAKE) ups->brush_rotation = rotation; @@ -527,7 +527,6 @@ static void update_brush_rake_rotation(UnifiedPaintSettings *ups, Brush *brush, ups->brush_rotation = 0.0f; if (brush->mask_mtex.brush_angle_mode & MTEX_ANGLE_RAKE) - /* here, translation contains the mouse coordinates. */ ups->brush_rotation_sec = rotation; else ups->brush_rotation_sec = 0.0f; @@ -536,7 +535,6 @@ static void update_brush_rake_rotation(UnifiedPaintSettings *ups, Brush *brush, void paint_calculate_rake_rotation(UnifiedPaintSettings *ups, Brush *brush, const float mouse_pos[2]) { if ((brush->mtex.brush_angle_mode & MTEX_ANGLE_RAKE) || (brush->mask_mtex.brush_angle_mode & MTEX_ANGLE_RAKE)) { - const float u = 0.5f; const float r = RAKE_THRESHHOLD; float rotation; @@ -546,17 +544,16 @@ void paint_calculate_rake_rotation(UnifiedPaintSettings *ups, Brush *brush, cons if (len_squared_v2(dpos) >= r * r) { rotation = atan2f(dpos[0], dpos[1]); - interp_v2_v2v2(ups->last_rake, ups->last_rake, - mouse_pos, u); + copy_v2_v2(ups->last_rake, mouse_pos); ups->last_rake_angle = rotation; - update_brush_rake_rotation(ups, brush, rotation); + paint_update_brush_rake_rotation(ups, brush, rotation); } /* make sure we reset here to the last rotation to avoid accumulating * values in case a random rotation is also added */ else { - update_brush_rake_rotation(ups, brush, ups->last_rake_angle); + paint_update_brush_rake_rotation(ups, brush, ups->last_rake_angle); } } else { diff --git a/source/blender/blenkernel/intern/particle_distribute.c b/source/blender/blenkernel/intern/particle_distribute.c index 1429d3b1cdc..50634460028 100644 --- a/source/blender/blenkernel/intern/particle_distribute.c +++ b/source/blender/blenkernel/intern/particle_distribute.c @@ -332,7 +332,7 @@ static void init_mv_jit(float *jit, int num, int seed2, float amount) rng = BLI_rng_new(31415926 + num + seed2); x= 0; - num2 = 2 * num; + num2 = 2 * num; for (i=0; i<num2; i+=2) { jit[i] = x + amount*rad1*(0.5f - BLI_rng_get_float(rng)); @@ -490,7 +490,7 @@ static void distribute_from_faces_exec(ParticleTask *thread, ParticleData *pa, i static void distribute_from_volume_exec(ParticleTask *thread, ParticleData *pa, int p) { ParticleThreadContext *ctx= thread->ctx; DerivedMesh *dm= ctx->dm; - float *v1, *v2, *v3, *v4, nor[3], co1[3], co2[3]; + float *v1, *v2, *v3, *v4, nor[3], co[3]; float cur_d, min_d, randu, randv; int distr= ctx->distr; int i, intersect, tot; @@ -530,14 +530,12 @@ static void distribute_from_volume_exec(ParticleTask *thread, ParticleData *pa, /* experimental */ tot=dm->getNumTessFaces(dm); - psys_interpolate_face(mvert,mface,0,0,pa->fuv,co1,nor,0,0,0,0); + psys_interpolate_face(mvert,mface,0,0,pa->fuv,co,nor,0,0,0,0); normalize_v3(nor); - mul_v3_fl(nor,-100.0); + negate_v3(nor); - add_v3_v3v3(co2,co1,nor); - - min_d=2.0; + min_d=FLT_MAX; intersect=0; for (i=0,mface=dm->getTessFaceDataArray(dm,CD_MFACE); i<tot; i++,mface++) { @@ -547,20 +545,20 @@ static void distribute_from_volume_exec(ParticleTask *thread, ParticleData *pa, v2=mvert[mface->v2].co; v3=mvert[mface->v3].co; - if (isect_line_tri_v3(co1, co2, v2, v3, v1, &cur_d, 0)) { + if (isect_ray_tri_v3(co, nor, v2, v3, v1, &cur_d, 0)) { if (cur_d<min_d) { min_d=cur_d; - pa->foffset=cur_d*50.0f; /* to the middle of volume */ + pa->foffset=cur_d*0.5f; /* to the middle of volume */ intersect=1; } } if (mface->v4) { v4=mvert[mface->v4].co; - if (isect_line_tri_v3(co1, co2, v4, v1, v3, &cur_d, 0)) { + if (isect_ray_tri_v3(co, nor, v4, v1, v3, &cur_d, 0)) { if (cur_d<min_d) { min_d=cur_d; - pa->foffset=cur_d*50.0f; /* to the middle of volume */ + pa->foffset=cur_d*0.5f; /* to the middle of volume */ intersect=1; } } @@ -668,6 +666,8 @@ static void exec_distribute_parent(TaskPool *UNUSED(pool), void *taskdata, int U ParticleSystem *psys= task->ctx->sim.psys; ParticleData *pa; int p; + + BLI_rng_skip(task->rng, PSYS_RND_DIST_SKIP * task->begin); pa= psys->particles + task->begin; switch (psys->part->from) { diff --git a/source/blender/blenkernel/intern/particle_system.c b/source/blender/blenkernel/intern/particle_system.c index 5a263e24fc4..3a19ca7304c 100644 --- a/source/blender/blenkernel/intern/particle_system.c +++ b/source/blender/blenkernel/intern/particle_system.c @@ -90,6 +90,7 @@ #include "BKE_modifier.h" #include "BKE_scene.h" #include "BKE_bvhutils.h" +#include "BKE_depsgraph.h" #include "PIL_time.h" @@ -297,7 +298,7 @@ int psys_get_child_number(Scene *scene, ParticleSystem *psys) else nbr= psys->part->child_nbr; - return get_render_child_particle_number(&scene->r, nbr); + return get_render_child_particle_number(&scene->r, nbr, psys->renderdata != NULL); } int psys_get_tot_child(Scene *scene, ParticleSystem *psys) @@ -559,17 +560,24 @@ static void initialize_all_particles(ParticleSimulationData *sim) ParticleSystem *psys = sim->psys; PARTICLE_P; + LOOP_PARTICLES { + initialize_particle(sim, pa); + } +} + +static void free_unexisting_particles(ParticleSimulationData *sim) +{ + ParticleSystem *psys = sim->psys; + PARTICLE_P; + psys->totunexist = 0; LOOP_PARTICLES { - if ((pa->flag & PARS_UNEXIST)==0) - initialize_particle(sim, pa); - - if (pa->flag & PARS_UNEXIST) + if (pa->flag & PARS_UNEXIST) { psys->totunexist++; + } } - /* Free unexisting particles. */ if (psys->totpart && psys->totunexist == psys->totpart) { if (psys->particles->boid) MEM_freeN(psys->particles->boid); @@ -3790,6 +3798,7 @@ static void system_step(ParticleSimulationData *sim, float cfra) initialize_all_particles(sim); /* reset only just created particles (on startframe all particles are recreated) */ reset_all_particles(sim, 0.0, cfra, oldtotpart); + free_unexisting_particles(sim); if (psys->fluid_springs) { MEM_freeN(psys->fluid_springs); @@ -4136,6 +4145,7 @@ void particle_system_update(Scene *scene, Object *ob, ParticleSystem *psys) { PARTICLE_P; float disp = psys_get_current_display_percentage(psys); + bool free_unexisting = false; /* Particles without dynamics haven't been reset yet because they don't use pointcache */ if (psys->recalc & PSYS_RECALC_RESET) @@ -4145,6 +4155,7 @@ void particle_system_update(Scene *scene, Object *ob, ParticleSystem *psys) free_keyed_keys(psys); distribute_particles(&sim, part->from); initialize_all_particles(&sim); + free_unexisting = true; /* flag for possible explode modifiers after this system */ sim.psmd->flag |= eParticleSystemFlag_Pars; @@ -4163,6 +4174,10 @@ void particle_system_update(Scene *scene, Object *ob, ParticleSystem *psys) pa->flag &= ~PARS_NO_DISP; } + /* free unexisting after reseting particles */ + if (free_unexisting) + free_unexisting_particles(&sim); + if (part->phystype == PART_PHYS_KEYED) { psys_count_keyed_targets(&sim); set_keyed_keys(&sim); @@ -4195,3 +4210,13 @@ void particle_system_update(Scene *scene, Object *ob, ParticleSystem *psys) invert_m4_m4(psys->imat, ob->obmat); } +/* **** Depsgraph evaluation **** */ + +void BKE_particle_system_eval(EvaluationContext *UNUSED(eval_ctx), + Object *ob, + ParticleSystem *psys) +{ + if (G.debug & G_DEBUG_DEPSGRAPH) { + printf("%s on %s:%s\n", __func__, ob->id.name, psys->name); + } +} diff --git a/source/blender/blenkernel/intern/pbvh.c b/source/blender/blenkernel/intern/pbvh.c index fdda72e4f7d..95d8e37d1c7 100644 --- a/source/blender/blenkernel/intern/pbvh.c +++ b/source/blender/blenkernel/intern/pbvh.c @@ -570,7 +570,7 @@ void BKE_pbvh_build_mesh(PBVH *bvh, MFace *faces, MVert *verts, int totface, int } /* Do a full rebuild with on Grids data structure */ -void BKE_pbvh_build_grids(PBVH *bvh, CCGElem **grids, DMGridAdjacency *gridadj, +void BKE_pbvh_build_grids(PBVH *bvh, CCGElem **grids, int totgrid, CCGKey *key, void **gridfaces, DMFlagMat *flagmats, BLI_bitmap **grid_hidden) { BBC *prim_bbc = NULL; @@ -580,7 +580,6 @@ void BKE_pbvh_build_grids(PBVH *bvh, CCGElem **grids, DMGridAdjacency *gridadj, bvh->type = PBVH_GRIDS; bvh->grids = grids; - bvh->gridadj = gridadj; bvh->gridfaces = gridfaces; bvh->grid_flag_mats = flagmats; bvh->totgrid = totgrid; @@ -1383,7 +1382,7 @@ void BKE_pbvh_node_num_verts(PBVH *bvh, PBVHNode *node, int *uniquevert, int *to } } -void BKE_pbvh_node_get_grids(PBVH *bvh, PBVHNode *node, int **grid_indices, int *totgrid, int *maxgrid, int *gridsize, CCGElem ***griddata, DMGridAdjacency **gridadj) +void BKE_pbvh_node_get_grids(PBVH *bvh, PBVHNode *node, int **grid_indices, int *totgrid, int *maxgrid, int *gridsize, CCGElem ***griddata) { switch (bvh->type) { case PBVH_GRIDS: @@ -1392,7 +1391,6 @@ void BKE_pbvh_node_get_grids(PBVH *bvh, PBVHNode *node, int **grid_indices, int if (maxgrid) *maxgrid = bvh->totgrid; if (gridsize) *gridsize = bvh->gridkey.grid_size; if (griddata) *griddata = bvh->grids; - if (gridadj) *gridadj = bvh->gridadj; break; case PBVH_FACES: case PBVH_BMESH: @@ -1401,7 +1399,6 @@ void BKE_pbvh_node_get_grids(PBVH *bvh, PBVHNode *node, int **grid_indices, int if (maxgrid) *maxgrid = 0; if (gridsize) *gridsize = 0; if (griddata) *griddata = NULL; - if (gridadj) *gridadj = NULL; break; } } @@ -1612,7 +1609,9 @@ bool BKE_pbvh_node_raycast( return hit; } -void BKE_pbvh_raycast_project_ray_root (PBVH *bvh, bool original, float ray_start[3], float ray_end[3], float ray_normal[3]) +void BKE_pbvh_raycast_project_ray_root( + PBVH *bvh, bool original, + float ray_start[3], float ray_end[3], float ray_normal[3]) { if (bvh->nodes) { float rootmin_start, rootmin_end; @@ -1785,13 +1784,12 @@ void BKE_pbvh_draw(PBVH *bvh, float (*planes)[4], float (*face_nors)[3], pbvh_draw_BB(bvh); } -void BKE_pbvh_grids_update(PBVH *bvh, CCGElem **grids, DMGridAdjacency *gridadj, void **gridfaces, +void BKE_pbvh_grids_update(PBVH *bvh, CCGElem **grids, void **gridfaces, DMFlagMat *flagmats, BLI_bitmap **grid_hidden) { int a; bvh->grids = grids; - bvh->gridadj = gridadj; bvh->gridfaces = gridfaces; if (flagmats != bvh->grid_flag_mats || bvh->grid_hidden != grid_hidden) { @@ -1970,7 +1968,7 @@ void pbvh_vertex_iter_init(PBVH *bvh, PBVHNode *node, vi->fno = NULL; vi->mvert = NULL; - BKE_pbvh_node_get_grids(bvh, node, &grid_indices, &totgrid, NULL, &gridsize, &grids, NULL); + BKE_pbvh_node_get_grids(bvh, node, &grid_indices, &totgrid, NULL, &gridsize, &grids); BKE_pbvh_node_num_verts(bvh, node, &uniq_verts, &totvert); BKE_pbvh_node_get_verts(bvh, node, &vert_indices, &verts); vi->key = &bvh->gridkey; diff --git a/source/blender/blenkernel/intern/pbvh_bmesh.c b/source/blender/blenkernel/intern/pbvh_bmesh.c index 5977243a21c..9f092bd651f 100644 --- a/source/blender/blenkernel/intern/pbvh_bmesh.c +++ b/source/blender/blenkernel/intern/pbvh_bmesh.c @@ -29,6 +29,7 @@ #include "BLI_ghash.h" #include "BLI_heap.h" #include "BLI_math.h" +#include "BLI_memarena.h" #include "BKE_ccg.h" #include "BKE_DerivedMesh.h" @@ -47,6 +48,9 @@ # include "BKE_global.h" #endif +/* Support for only operating on front-faces */ +#define USE_EDGEQUEUE_FRONTFACE + /* don't add edges into the queue multiple times */ #define USE_EDGEQUEUE_TAG /** @@ -597,6 +601,12 @@ typedef struct { #ifdef USE_EDGEQUEUE_EVEN_SUBDIV float limit_len; #endif + +#ifdef USE_EDGEQUEUE_FRONTFACE + const float *view_normal; + unsigned int use_view_normal : 1; +#endif + } EdgeQueue; typedef struct { @@ -667,8 +677,9 @@ static bool check_mask(EdgeQueueContext *eq_ctx, BMVert *v) return (BM_ELEM_CD_GET_FLOAT(v, eq_ctx->cd_vert_mask_offset) < 1.0f); } -static void edge_queue_insert(EdgeQueueContext *eq_ctx, BMEdge *e, - float priority) +static void edge_queue_insert( + EdgeQueueContext *eq_ctx, BMEdge *e, + float priority) { BMVert **pair; @@ -694,8 +705,9 @@ static void edge_queue_insert(EdgeQueueContext *eq_ctx, BMEdge *e, } } -static void long_edge_queue_edge_add(EdgeQueueContext *eq_ctx, - BMEdge *e) +static void long_edge_queue_edge_add( + EdgeQueueContext *eq_ctx, + BMEdge *e) { #ifdef USE_EDGEQUEUE_TAG if (EDGE_QUEUE_TEST(e) == false) @@ -716,6 +728,14 @@ static void long_edge_queue_edge_add_recursive( { BLI_assert(len_sq > SQUARE(limit_len)); +#ifdef USE_EDGEQUEUE_FRONTFACE + if (eq_ctx->q->use_view_normal) { + if (dot_v3v3(l_edge->f->no, eq_ctx->q->view_normal) < 0.0f) { + return; + } + } +#endif + #ifdef USE_EDGEQUEUE_TAG if (EDGE_QUEUE_TEST(l_edge->e) == false) #endif @@ -765,8 +785,9 @@ static void long_edge_queue_edge_add_recursive( } #endif /* USE_EDGEQUEUE_EVEN_SUBDIV */ -static void short_edge_queue_edge_add(EdgeQueueContext *eq_ctx, - BMEdge *e) +static void short_edge_queue_edge_add( + EdgeQueueContext *eq_ctx, + BMEdge *e) { #ifdef USE_EDGEQUEUE_TAG if (EDGE_QUEUE_TEST(e) == false) @@ -779,9 +800,18 @@ static void short_edge_queue_edge_add(EdgeQueueContext *eq_ctx, } } -static void long_edge_queue_face_add(EdgeQueueContext *eq_ctx, - BMFace *f) +static void long_edge_queue_face_add( + EdgeQueueContext *eq_ctx, + BMFace *f) { +#ifdef USE_EDGEQUEUE_FRONTFACE + if (eq_ctx->q->use_view_normal) { + if (dot_v3v3(f->no, eq_ctx->q->view_normal) < 0.0f) { + return; + } + } +#endif + if (edge_queue_tri_in_sphere(eq_ctx->q, f)) { BMLoop *l_iter; BMLoop *l_first; @@ -795,7 +825,7 @@ static void long_edge_queue_face_add(EdgeQueueContext *eq_ctx, if (len_sq > eq_ctx->q->limit_len_squared) { long_edge_queue_edge_add_recursive( eq_ctx, l_iter->radial_next, l_iter, - len_sq, eq_ctx->q->limit_len_squared); + len_sq, eq_ctx->q->limit_len); } #else long_edge_queue_edge_add(eq_ctx, l_iter->e); @@ -805,9 +835,18 @@ static void long_edge_queue_face_add(EdgeQueueContext *eq_ctx, } } -static void short_edge_queue_face_add(EdgeQueueContext *eq_ctx, - BMFace *f) +static void short_edge_queue_face_add( + EdgeQueueContext *eq_ctx, + BMFace *f) { +#ifdef USE_EDGEQUEUE_FRONTFACE + if (eq_ctx->q->use_view_normal) { + if (dot_v3v3(f->no, eq_ctx->q->view_normal) < 0.0f) { + return; + } + } +#endif + if (edge_queue_tri_in_sphere(eq_ctx->q, f)) { BMLoop *l_iter; BMLoop *l_first; @@ -829,9 +868,10 @@ static void short_edge_queue_face_add(EdgeQueueContext *eq_ctx, * * The highest priority (lowest number) is given to the longest edge. */ -static void long_edge_queue_create(EdgeQueueContext *eq_ctx, - PBVH *bvh, const float center[3], - float radius) +static void long_edge_queue_create( + EdgeQueueContext *eq_ctx, + PBVH *bvh, const float center[3], const float view_normal[3], + float radius) { int n; @@ -843,6 +883,13 @@ static void long_edge_queue_create(EdgeQueueContext *eq_ctx, eq_ctx->q->limit_len = bvh->bm_max_edge_len; #endif +#ifdef USE_EDGEQUEUE_FRONTFACE + eq_ctx->q->view_normal = view_normal; + eq_ctx->q->use_view_normal = (view_normal != NULL); +#else + UNUSED_VARS(view_normal); +#endif + #ifdef USE_EDGEQUEUE_TAG_VERIFY pbvh_bmesh_edge_tag_verify(bvh); #endif @@ -877,9 +924,10 @@ static void long_edge_queue_create(EdgeQueueContext *eq_ctx, * * The highest priority (lowest number) is given to the shortest edge. */ -static void short_edge_queue_create(EdgeQueueContext *eq_ctx, - PBVH *bvh, const float center[3], - float radius) +static void short_edge_queue_create( + EdgeQueueContext *eq_ctx, + PBVH *bvh, const float center[3], const float view_normal[3], + float radius) { int n; @@ -891,6 +939,13 @@ static void short_edge_queue_create(EdgeQueueContext *eq_ctx, eq_ctx->q->limit_len = bvh->bm_min_edge_len; #endif +#ifdef USE_EDGEQUEUE_FRONTFACE + eq_ctx->q->view_normal = view_normal; + eq_ctx->q->use_view_normal = (view_normal != NULL); +#else + UNUSED_VARS(view_normal); +#endif + for (n = 0; n < bvh->totnode; n++) { PBVHNode *node = &bvh->nodes[n]; @@ -920,8 +975,9 @@ static void bm_edges_from_tri(BMesh *bm, BMVert *v_tri[3], BMEdge *e_tri[3]) e_tri[2] = BM_edge_create(bm, v_tri[2], v_tri[0], NULL, BM_CREATE_NO_DOUBLE); } -static void pbvh_bmesh_split_edge(EdgeQueueContext *eq_ctx, PBVH *bvh, - BMEdge *e, BLI_Buffer *edge_loops) +static void pbvh_bmesh_split_edge( + EdgeQueueContext *eq_ctx, PBVH *bvh, + BMEdge *e, BLI_Buffer *edge_loops) { BMVert *v_new; float co_mid[3], no_mid[3]; @@ -1037,16 +1093,12 @@ static void pbvh_bmesh_split_edge(EdgeQueueContext *eq_ctx, PBVH *bvh, BM_edge_kill(bvh->bm, e); } -static bool pbvh_bmesh_subdivide_long_edges(EdgeQueueContext *eq_ctx, PBVH *bvh, - BLI_Buffer *edge_loops) +static bool pbvh_bmesh_subdivide_long_edges( + EdgeQueueContext *eq_ctx, PBVH *bvh, + BLI_Buffer *edge_loops) { bool any_subdivided = false; -#ifdef USE_EDGEQUEUE_TAG_VERIFY - pbvh_bmesh_edge_tag_verify(bvh); -#endif - - while (!BLI_heap_is_empty(eq_ctx->q->heap)) { BMVert **pair = BLI_heap_popmin(eq_ctx->q->heap); BMVert *v1 = pair[0], *v2 = pair[1]; @@ -1295,9 +1347,10 @@ static bool pbvh_bmesh_collapse_short_edges( /************************* Called from pbvh.c *************************/ -bool pbvh_bmesh_node_raycast(PBVHNode *node, const float ray_start[3], - const float ray_normal[3], float *dist, - bool use_original) +bool pbvh_bmesh_node_raycast( + PBVHNode *node, const float ray_start[3], + const float ray_normal[3], float *dist, + bool use_original) { bool hit = false; @@ -1410,36 +1463,225 @@ void pbvh_bmesh_normals_update(PBVHNode **nodes, int totnode) } } -/***************************** Public API *****************************/ +typedef struct FastNodeBuildInfo { + int totface; /* number of faces */ + int start; /* start of faces in array */ + struct FastNodeBuildInfo *child1; + struct FastNodeBuildInfo *child2; +} FastNodeBuildInfo; -static void pbvh_bmesh_node_layers_reset(PBVH *bvh) +/* Recursively split the node if it exceeds the leaf_limit. This function is multithreadabe since each invocation applies + * to a sub part of the arrays */ +static void pbvh_bmesh_node_limit_ensure_fast(PBVH *bvh, BMFace **nodeinfo, BBC *bbc_array, FastNodeBuildInfo *node, MemArena *arena) { BMFace *f; - BMVert *v; - BMIter iter; - BMesh *bm = bvh->bm; - int cd_vert_node_offset = bvh->cd_vert_node_offset; - int cd_face_node_offset = bvh->cd_face_node_offset; + BB cb; + BBC *bbc; + float mid; + int axis, i; + int end; + FastNodeBuildInfo *child1, *child2; + int num_child1, num_child2; + BMFace *tmp; - /* clear the elements of the node information */ - BM_ITER_MESH(v, &iter, bm, BM_VERTS_OF_MESH) { - BM_ELEM_CD_SET_INT(v, cd_vert_node_offset, DYNTOPO_NODE_NONE); + if (node->totface <= bvh->leaf_limit) { + return; } - BM_ITER_MESH(f, &iter, bm, BM_FACES_OF_MESH) { - BM_ELEM_CD_SET_INT(f, cd_face_node_offset, DYNTOPO_NODE_NONE); + /* Calculate bounding box around primitive centroids */ + BB_reset(&cb); + for (i = 0; i < node->totface; i++) { + f = nodeinfo[i + node->start]; + bbc = &bbc_array[BM_elem_index_get(f)]; + + BB_expand(&cb, bbc->bcentroid); + } + + /* initialize the children */ + + /* Find widest axis and its midpoint */ + axis = BB_widest_axis(&cb); + mid = (cb.bmax[axis] + cb.bmin[axis]) * 0.5f; + + num_child1 = 0, num_child2 = 0; + + /* split vertices along the middle line */ + end = node->start + node->totface; + for (i = node->start; i < end - num_child2; i++) { + f = nodeinfo[i]; + bbc = &bbc_array[BM_elem_index_get(f)]; + + if (bbc->bcentroid[axis] > mid) { + int i_iter = end - num_child2 - 1; + int candidate = -1; + /* found a face that should be part of another node, look for a face to substitute with */ + + for (;i_iter > i; i_iter--) { + BMFace *f_iter = nodeinfo[i_iter]; + const BBC *bbc_iter = &bbc_array[BM_elem_index_get(f_iter)]; + if (bbc_iter->bcentroid[axis] <= mid) { + candidate = i_iter; + break; + } + else { + num_child2++; + } + } + + if (candidate != -1) { + tmp = nodeinfo[i]; + nodeinfo[i] = nodeinfo[candidate]; + nodeinfo[candidate] = tmp; + /* increase both counts */ + num_child1++; + num_child2++; + } + else { + /* not finding candidate means second half of array part is full of + * second node parts, just increase the number of child nodes for it */ + num_child2++; + } + } + else { + num_child1++; + } + } + + /* ensure at least one child in each node */ + if (num_child2 == 0) { + num_child2++; + num_child1--; + } + else if (num_child1 == 0) { + num_child1++; + num_child2--; + } + + /* at this point, faces should have been split along the array range sequentially, + * each sequential part belonging to one node only */ + BLI_assert((num_child1 + num_child2) == node->totface); + + node->child1 = child1 = BLI_memarena_alloc(arena, sizeof(FastNodeBuildInfo)); + node->child2 = child2 = BLI_memarena_alloc(arena, sizeof(FastNodeBuildInfo)); + + child1->totface = num_child1; + child1->start = node->start; + child2->totface = num_child2; + child2->start = node->start + num_child1; + child1->child1 = child1->child2 = child2->child1 = child2->child2 = NULL; + + pbvh_bmesh_node_limit_ensure_fast(bvh, nodeinfo, bbc_array, child1, arena); + pbvh_bmesh_node_limit_ensure_fast(bvh, nodeinfo, bbc_array, child2, arena); + + return; +} + +static void pbvh_bmesh_create_nodes_fast_recursive(PBVH *bvh, BMFace **nodeinfo, BBC *bbc_array, FastNodeBuildInfo *node, int node_index) +{ + PBVHNode *n = bvh->nodes + node_index; + /* two cases, node does not have children or does have children */ + if (node->child1) { + int children_offset = bvh->totnode; + + n->children_offset = children_offset; + pbvh_grow_nodes(bvh, bvh->totnode + 2); + pbvh_bmesh_create_nodes_fast_recursive(bvh, nodeinfo, bbc_array, node->child1, children_offset); + pbvh_bmesh_create_nodes_fast_recursive(bvh, nodeinfo, bbc_array, node->child2, children_offset + 1); + + n = &bvh->nodes[node_index]; + + /* Update bounding box */ + BB_reset(&n->vb); + BB_expand_with_bb(&n->vb, &bvh->nodes[n->children_offset].vb); + BB_expand_with_bb(&n->vb, &bvh->nodes[n->children_offset + 1].vb); + n->orig_vb = n->vb; + } + else { + /* node does not have children so it's a leaf node, populate with faces and tag accordingly + * this is an expensive part but it's not so easily threadable due to vertex node indices */ + const int cd_vert_node_offset = bvh->cd_vert_node_offset; + const int cd_face_node_offset = bvh->cd_face_node_offset; + + bool has_visible = false; + int i, end; + BMFace *f; + BMLoop *l_iter; + BMLoop *l_first; + BMVert *v; + BBC *bbc; + + n->flag = PBVH_Leaf; + n->bm_faces = BLI_gset_ptr_new_ex("bm_faces", node->totface); + + /* Create vert hash sets */ + n->bm_unique_verts = BLI_gset_ptr_new("bm_unique_verts"); + n->bm_other_verts = BLI_gset_ptr_new("bm_other_verts"); + + BB_reset(&n->vb); + + end = node->start + node->totface; + + for (i = node->start; i < end; i++) { + f = nodeinfo[i]; + bbc = &bbc_array[BM_elem_index_get(f)]; + + /* Update ownership of faces */ + BLI_gset_insert(n->bm_faces, f); + BM_ELEM_CD_SET_INT(f, cd_face_node_offset, node_index); + + /* Update vertices */ + l_iter = l_first = BM_FACE_FIRST_LOOP(f); + do { + v = l_iter->v; + if (!BLI_gset_haskey(n->bm_unique_verts, v)) { + if (BM_ELEM_CD_GET_INT(v, cd_vert_node_offset) != DYNTOPO_NODE_NONE) { + BLI_gset_add(n->bm_other_verts, v); + } + else { + BLI_gset_insert(n->bm_unique_verts, v); + BM_ELEM_CD_SET_INT(v, cd_vert_node_offset, node_index); + } + } + /* Update node bounding box */ + } while ((l_iter = l_iter->next) != l_first); + + if (!BM_elem_flag_test(f, BM_ELEM_HIDDEN)) + has_visible = true; + + BB_expand_with_bb(&n->vb, (BB *)bbc); + } + + BLI_assert(n->vb.bmin[0] <= n->vb.bmax[0] && + n->vb.bmin[1] <= n->vb.bmax[1] && + n->vb.bmin[2] <= n->vb.bmax[2]); + + n->orig_vb = n->vb; + + /* Build GPU buffers for new node and update vertex normals */ + BKE_pbvh_node_mark_rebuild_draw(n); + + BKE_pbvh_node_fully_hidden_set(n, !has_visible); + n->flag |= PBVH_UpdateNormals; } } +/***************************** Public API *****************************/ + /* Build a PBVH from a BMesh */ -void BKE_pbvh_build_bmesh(PBVH *bvh, BMesh *bm, bool smooth_shading, BMLog *log, - const int cd_vert_node_offset, const int cd_face_node_offset) +void BKE_pbvh_build_bmesh( + PBVH *bvh, BMesh *bm, bool smooth_shading, BMLog *log, + const int cd_vert_node_offset, const int cd_face_node_offset) { BMIter iter; BMFace *f; - PBVHNode *n; - int node_index = 0; + BMVert *v; + int i; + /* bounding box array of all faces, no need to recalculate every time */ + BBC *bbc_array; + BMFace **nodeinfo; + FastNodeBuildInfo rootnode = {0}; + MemArena *arena; bvh->cd_vert_node_offset = cd_vert_node_offset; bvh->cd_face_node_offset = cd_face_node_offset; @@ -1456,26 +1698,61 @@ void BKE_pbvh_build_bmesh(PBVH *bvh, BMesh *bm, bool smooth_shading, BMLog *log, if (smooth_shading) bvh->flags |= PBVH_DYNTOPO_SMOOTH_SHADING; - pbvh_bmesh_node_layers_reset(bvh); + /* calculate all bounding boxes once for all faces */ + bbc_array = MEM_mallocN(sizeof(BBC) * bm->totface, "BBC"); + nodeinfo = MEM_mallocN(sizeof(*nodeinfo) * bm->totface, "nodeinfo"); + arena = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, "fast PBVH node storage"); + + BM_ITER_MESH_INDEX(f, &iter, bm, BM_FACES_OF_MESH, i) { + BBC *bbc = &bbc_array[i]; + BMLoop *l_iter; + BMLoop *l_first; + + BB_reset((BB *)bbc); + l_iter = l_first = BM_FACE_FIRST_LOOP(f); + do { + BB_expand((BB *)bbc, l_iter->v->co); + } while ((l_iter = l_iter->next) != l_first); + BBC_update_centroid(bbc); + + /* so we can do direct lookups on 'bbc_array' */ + BM_elem_index_set(f, i); /* set_dirty! */ + nodeinfo[i] = f; + BM_ELEM_CD_SET_INT(f, cd_face_node_offset, DYNTOPO_NODE_NONE); + } + + BM_ITER_MESH(v, &iter, bm, BM_VERTS_OF_MESH) { + BM_ELEM_CD_SET_INT(v, cd_vert_node_offset, DYNTOPO_NODE_NONE); + } + + /* likely this is already dirty */ + bm->elem_index_dirty |= BM_FACE; + + /* setup root node */ + rootnode.totface = bm->totface; + + /* start recursion, assign faces to nodes accordingly */ + pbvh_bmesh_node_limit_ensure_fast(bvh, nodeinfo, bbc_array, &rootnode, arena); + + /* we now have all faces assigned to a node, next we need to assign those to the gsets of the nodes */ /* Start with all faces in the root node */ - n = bvh->nodes = MEM_callocN(sizeof(PBVHNode), "PBVHNode"); + bvh->nodes = MEM_callocN(sizeof(PBVHNode), "PBVHNode"); bvh->totnode = 1; - n->flag = PBVH_Leaf; - n->bm_faces = BLI_gset_ptr_new_ex("bm_faces", bvh->bm->totface); - BM_ITER_MESH (f, &iter, bvh->bm, BM_FACES_OF_MESH) { - BLI_gset_insert(n->bm_faces, f); - } - /* Recursively split the node until it is under the limit; if no - * splitting occurs then finalize the existing leaf node */ - if (!pbvh_bmesh_node_limit_ensure(bvh, node_index)) - pbvh_bmesh_node_finalize(bvh, 0, cd_vert_node_offset, cd_face_node_offset); + /* take root node and visit and populate children recursively */ + pbvh_bmesh_create_nodes_fast_recursive(bvh, nodeinfo, bbc_array, &rootnode, 0); + + BLI_memarena_free(arena); + MEM_freeN(bbc_array); + MEM_freeN(nodeinfo); } /* Collapse short edges, subdivide long edges */ -bool BKE_pbvh_bmesh_update_topology(PBVH *bvh, PBVHTopologyUpdateMode mode, - const float center[3], float radius) +bool BKE_pbvh_bmesh_update_topology( + PBVH *bvh, PBVHTopologyUpdateMode mode, + const float center[3], const float view_normal[3], + float radius) { /* 2 is enough for edge faces - manifold edge */ BLI_buffer_declare_static(BMLoop *, edge_loops, BLI_BUFFER_NOP, 2); @@ -1487,12 +1764,16 @@ bool BKE_pbvh_bmesh_update_topology(PBVH *bvh, PBVHTopologyUpdateMode mode, bool modified = false; int n; + if (view_normal) { + BLI_assert(len_squared_v3(view_normal) != 0.0f); + } + if (mode & PBVH_Collapse) { EdgeQueue q; BLI_mempool *queue_pool = BLI_mempool_create(sizeof(BMVert *[2]), 0, 128, BLI_MEMPOOL_NOP); EdgeQueueContext eq_ctx = {&q, queue_pool, bvh->bm, cd_vert_mask_offset, cd_vert_node_offset, cd_face_node_offset}; - short_edge_queue_create(&eq_ctx, bvh, center, radius); + short_edge_queue_create(&eq_ctx, bvh, center, view_normal, radius); modified |= !BLI_heap_is_empty(q.heap); pbvh_bmesh_collapse_short_edges(&eq_ctx, bvh, &deleted_faces); @@ -1505,7 +1786,7 @@ bool BKE_pbvh_bmesh_update_topology(PBVH *bvh, PBVHTopologyUpdateMode mode, BLI_mempool *queue_pool = BLI_mempool_create(sizeof(BMVert *[2]), 0, 128, BLI_MEMPOOL_NOP); EdgeQueueContext eq_ctx = {&q, queue_pool, bvh->bm, cd_vert_mask_offset, cd_vert_node_offset, cd_face_node_offset}; - long_edge_queue_create(&eq_ctx, bvh, center, radius); + long_edge_queue_create(&eq_ctx, bvh, center, view_normal, radius); modified |= !BLI_heap_is_empty(q.heap); pbvh_bmesh_subdivide_long_edges(&eq_ctx, bvh, &edge_loops); BLI_heap_free(q.heap, NULL); diff --git a/source/blender/blenkernel/intern/pbvh_intern.h b/source/blender/blenkernel/intern/pbvh_intern.h index 6b3ef8eb5da..7daccb47c92 100644 --- a/source/blender/blenkernel/intern/pbvh_intern.h +++ b/source/blender/blenkernel/intern/pbvh_intern.h @@ -139,7 +139,6 @@ struct PBVH { /* Grid Data */ CCGKey gridkey; CCGElem **grids; - DMGridAdjacency *gridadj; void **gridfaces; const DMFlagMat *grid_flag_mats; int totgrid; @@ -175,9 +174,10 @@ void BB_expand_with_bb(BB *bb, BB *bb2); void BBC_update_centroid(BBC *bbc); int BB_widest_axis(const BB *bb); void pbvh_grow_nodes(PBVH *bvh, int totnode); -bool ray_face_intersection(const float ray_start[3], const float ray_normal[3], - const float *t0, const float *t1, const float *t2, - const float *t3, float *fdist); +bool ray_face_intersection( + const float ray_start[3], const float ray_normal[3], + const float *t0, const float *t1, const float *t2, + const float *t3, float *fdist); void pbvh_update_BB_redraw(PBVH *bvh, PBVHNode **nodes, int totnode, int flag); /* pbvh_bmesh.c */ diff --git a/source/blender/blenkernel/intern/pointcache.c b/source/blender/blenkernel/intern/pointcache.c index c477aabbb71..2f4a45828ea 100644 --- a/source/blender/blenkernel/intern/pointcache.c +++ b/source/blender/blenkernel/intern/pointcache.c @@ -3093,7 +3093,7 @@ static PointCache *ptcache_copy(PointCache *cache, bool copy_data) } /* returns first point cache */ -PointCache *BKE_ptcache_copy_list(ListBase *ptcaches_new, ListBase *ptcaches_old, bool copy_data) +PointCache *BKE_ptcache_copy_list(ListBase *ptcaches_new, const ListBase *ptcaches_old, bool copy_data) { PointCache *cache = ptcaches_old->first; @@ -3354,7 +3354,7 @@ void BKE_ptcache_bake(PTCacheBaker *baker) } } - BLI_end_threads(&threads); + BLI_end_threads(&threads); } /* clear baking flag */ if (pid) { diff --git a/source/blender/blenkernel/intern/rigidbody.c b/source/blender/blenkernel/intern/rigidbody.c index aaf54b82f32..ff9e1a2b831 100644 --- a/source/blender/blenkernel/intern/rigidbody.c +++ b/source/blender/blenkernel/intern/rigidbody.c @@ -54,6 +54,7 @@ #include "DNA_scene_types.h" #include "BKE_cdderivedmesh.h" +#include "BKE_depsgraph.h" #include "BKE_effect.h" #include "BKE_global.h" #include "BKE_library.h" @@ -61,6 +62,7 @@ #include "BKE_object.h" #include "BKE_pointcache.h" #include "BKE_rigidbody.h" +#include "BKE_scene.h" #ifdef WITH_BULLET @@ -1610,3 +1612,51 @@ void BKE_rigidbody_do_simulation(Scene *scene, float ctime) {} #endif #endif /* WITH_BULLET */ + +/* -------------------- */ +/* Depsgraph evaluation */ + +void BKE_rigidbody_rebuild_sim(EvaluationContext *UNUSED(eval_ctx), + Scene *scene) +{ + float ctime = BKE_scene_frame_get(scene); + + if (G.debug & G_DEBUG_DEPSGRAPH) { + printf("%s at %f\n", __func__, ctime); + } + + /* rebuild sim data (i.e. after resetting to start of timeline) */ + if (BKE_scene_check_rigidbody_active(scene)) { + BKE_rigidbody_rebuild_world(scene, ctime); + } +} + +void BKE_rigidbody_eval_simulation(EvaluationContext *UNUSED(eval_ctx), + Scene *scene) +{ + float ctime = BKE_scene_frame_get(scene); + + if (G.debug & G_DEBUG_DEPSGRAPH) { + printf("%s at %f\n", __func__, ctime); + } + + /* evaluate rigidbody sim */ + if (BKE_scene_check_rigidbody_active(scene)) { + BKE_rigidbody_do_simulation(scene, ctime); + } +} + +void BKE_rigidbody_object_sync_transforms(EvaluationContext *UNUSED(eval_ctx), + Scene *scene, + Object *ob) +{ + RigidBodyWorld *rbw = scene->rigidbody_world; + float ctime = BKE_scene_frame_get(scene); + + if (G.debug & G_DEBUG_DEPSGRAPH) { + printf("%s on %s\n", __func__, ob->id.name); + } + + /* read values pushed into RBO from sim/cache... */ + BKE_rigidbody_sync_transforms(rbw, ob, ctime); +} diff --git a/source/blender/blenkernel/intern/scene.c b/source/blender/blenkernel/intern/scene.c index 07e2a186444..bd03706c5b8 100644 --- a/source/blender/blenkernel/intern/scene.c +++ b/source/blender/blenkernel/intern/scene.c @@ -75,6 +75,7 @@ #include "BKE_idprop.h" #include "BKE_image.h" #include "BKE_library.h" +#include "BKE_linestyle.h" #include "BKE_main.h" #include "BKE_mask.h" #include "BKE_node.h" @@ -82,11 +83,14 @@ #include "BKE_paint.h" #include "BKE_rigidbody.h" #include "BKE_scene.h" +#include "BKE_screen.h" #include "BKE_sequencer.h" #include "BKE_sound.h" #include "BKE_unit.h" #include "BKE_world.h" +#include "DEG_depsgraph.h" + #include "RE_engine.h" #include "PIL_time.h" @@ -154,6 +158,7 @@ Scene *BKE_scene_copy(Scene *sce, int type) { Scene *scen; SceneRenderLayer *srl, *new_srl; + FreestyleLineSet *lineset; ToolSettings *ts; Base *base, *obase; @@ -190,6 +195,7 @@ Scene *BKE_scene_copy(Scene *sce, int type) scen->ed = NULL; scen->theDag = NULL; + scen->depsgraph = NULL; scen->obedit = NULL; scen->stats = NULL; scen->fps_info = NULL; @@ -237,6 +243,14 @@ Scene *BKE_scene_copy(Scene *sce, int type) new_srl = scen->r.layers.first; for (srl = sce->r.layers.first; srl; srl = srl->next) { BKE_freestyle_config_copy(&new_srl->freestyleConfig, &srl->freestyleConfig); + if (type == SCE_COPY_FULL) { + for (lineset = new_srl->freestyleConfig.linesets.first; lineset; lineset = lineset->next) { + if (lineset->linestyle) { + id_us_plus((ID *)lineset->linestyle); + lineset->linestyle = BKE_linestyle_copy(G.main, lineset->linestyle); + } + } + } new_srl = new_srl->next; } } @@ -420,6 +434,8 @@ void BKE_scene_free(Scene *sce) } DAG_scene_free(sce); + if (sce->depsgraph) + DEG_graph_free(sce->depsgraph); if (sce->nodetree) { ntreeFreeTree(sce->nodetree); @@ -680,7 +696,7 @@ Scene *BKE_scene_add(Main *bmain, const char *name) sce->gm.recastData.cellsize = 0.3f; sce->gm.recastData.cellheight = 0.2f; - sce->gm.recastData.agentmaxslope = M_PI / 2; + sce->gm.recastData.agentmaxslope = M_PI_4; sce->gm.recastData.agentmaxclimb = 0.9f; sce->gm.recastData.agentheight = 2.0f; sce->gm.recastData.agentradius = 0.6f; @@ -798,33 +814,6 @@ Scene *BKE_scene_set_name(Main *bmain, const char *name) return NULL; } -static void scene_unlink_space_node(SpaceNode *snode, Scene *sce) -{ - if (snode->id == &sce->id) { - /* nasty DNA logic for SpaceNode: - * ideally should be handled by editor code, but would be bad level call - */ - bNodeTreePath *path, *path_next; - for (path = snode->treepath.first; path; path = path_next) { - path_next = path->next; - MEM_freeN(path); - } - BLI_listbase_clear(&snode->treepath); - - snode->id = NULL; - snode->from = NULL; - snode->nodetree = NULL; - snode->edittree = NULL; - } -} - -static void scene_unlink_space_buts(SpaceButs *sbuts, Scene *sce) -{ - if (sbuts->pinid == &sce->id) { - sbuts->pinid = NULL; - } -} - void BKE_scene_unlink(Main *bmain, Scene *sce, Scene *newsce) { Scene *sce1; @@ -849,24 +838,11 @@ void BKE_scene_unlink(Main *bmain, Scene *sce, Scene *newsce) /* all screens */ for (screen = bmain->screen.first; screen; screen = screen->id.next) { - ScrArea *area; - - if (screen->scene == sce) + if (screen->scene == sce) { screen->scene = newsce; - - for (area = screen->areabase.first; area; area = area->next) { - SpaceLink *space_link; - for (space_link = area->spacedata.first; space_link; space_link = space_link->next) { - switch (space_link->spacetype) { - case SPACE_NODE: - scene_unlink_space_node((SpaceNode *)space_link, sce); - break; - case SPACE_BUTS: - scene_unlink_space_buts((SpaceButs *)space_link, sce); - break; - } - } } + + /* editors are handled by WM_main_remove_editor_id_reference */ } BKE_libblock_free(bmain, sce); @@ -1196,6 +1172,7 @@ void BKE_scene_frame_set(struct Scene *scene, double cfra) scene->r.cfra = (int)intpart; } +#ifdef WITH_LEGACY_DEPSGRAPH /* drivers support/hacks * - this method is called from scene_update_tagged_recursive(), so gets included in viewport + render * - these are always run since the depsgraph can't handle non-object data @@ -1296,6 +1273,7 @@ static void scene_depsgraph_hack(EvaluationContext *eval_ctx, Scene *scene, Scen } } } +#endif /* WITH_LEGACY_DEPSGRAPH */ /* That's like really a bummer, because currently animation data for armatures * might want to use pose, and pose might be missing on the object. @@ -1325,6 +1303,7 @@ static void scene_armature_depsgraph_workaround(Main *bmain) } #endif +#ifdef WITH_LEGACY_DEPSGRAPH static void scene_rebuild_rbw_recursive(Scene *scene, float ctime) { if (scene->set) @@ -1342,12 +1321,18 @@ static void scene_do_rb_simulation_recursive(Scene *scene, float ctime) if (BKE_scene_check_rigidbody_active(scene)) BKE_rigidbody_do_simulation(scene, ctime); } +#endif /* Used to visualize CPU threads activity during threaded object update, * would pollute STDERR with whole bunch of timing information which then * could be parsed and nicely visualized. */ -#undef DETAILED_ANALYSIS_OUTPUT +#ifdef WITH_LEGACY_DEPSGRAPH +# undef DETAILED_ANALYSIS_OUTPUT +#else +/* ALWAYS KEEY DISABLED! */ +# undef DETAILED_ANALYSIS_OUTPUT +#endif /* Mballs evaluation uses BKE_scene_base_iter_next which calls * duplilist for all objects in the scene. This leads to conflict @@ -1359,6 +1344,7 @@ static void scene_do_rb_simulation_recursive(Scene *scene, float ctime) */ #define MBALL_SINGLETHREAD_HACK +#ifdef WITH_LEGACY_DEPSGRAPH typedef struct StatisicsEntry { struct StatisicsEntry *next, *prev; Object *object; @@ -1595,6 +1581,9 @@ static void scene_update_objects(EvaluationContext *eval_ctx, Main *bmain, Scene #endif task_pool = BLI_task_pool_create(task_scheduler, &state); + if (G.debug & G_DEBUG_DEPSGRAPH_NO_THREADS) { + BLI_pool_set_num_threads(task_pool, 1); + } DAG_threaded_update_begin(scene, scene_update_object_add_task, task_pool); BLI_task_pool_work_and_wait(task_pool); @@ -1648,6 +1637,7 @@ static void scene_update_tagged_recursive(EvaluationContext *eval_ctx, Main *bma BKE_mask_update_scene(bmain, scene); } +#endif /* WITH_LEGACY_DEPSGRAPH */ static bool check_rendered_viewport_visible(Main *bmain) { @@ -1699,13 +1689,26 @@ static void prepare_mesh_for_viewport_render(Main *bmain, Scene *scene) void BKE_scene_update_tagged(EvaluationContext *eval_ctx, Main *bmain, Scene *scene) { Scene *sce_iter; - +#ifdef WITH_LEGACY_DEPSGRAPH + bool use_new_eval = !DEG_depsgraph_use_legacy(); +#endif + /* keep this first */ BLI_callback_exec(bmain, &scene->id, BLI_CB_EVT_SCENE_UPDATE_PRE); /* (re-)build dependency graph if needed */ - for (sce_iter = scene; sce_iter; sce_iter = sce_iter->set) + for (sce_iter = scene; sce_iter; sce_iter = sce_iter->set) { DAG_scene_relations_update(bmain, sce_iter); + /* Uncomment this to check if graph was properly tagged for update. */ +#if 0 +#ifdef WITH_LEGACY_DEPSGRAPH + if (use_new_eval) +#endif + { + DAG_scene_relations_validate(bmain, sce_iter); + } +#endif + } /* flush editing data if needed */ prepare_mesh_for_viewport_render(bmain, scene); @@ -1726,7 +1729,17 @@ void BKE_scene_update_tagged(EvaluationContext *eval_ctx, Main *bmain, Scene *sc * * in the future this should handle updates for all datablocks, not * only objects and scenes. - brecht */ - scene_update_tagged_recursive(eval_ctx, bmain, scene, scene); +#ifdef WITH_LEGACY_DEPSGRAPH + if (use_new_eval) { + DEG_evaluate_on_refresh(eval_ctx, scene->depsgraph, scene); + } + else { + scene_update_tagged_recursive(eval_ctx, bmain, scene, scene); + } +#else + DEG_evaluate_on_refresh(eval_ctx, scene->depsgraph, scene); +#endif + /* update sound system animation (TODO, move to depsgraph) */ BKE_sound_update_scene(bmain, scene); @@ -1744,7 +1757,8 @@ void BKE_scene_update_tagged(EvaluationContext *eval_ctx, Main *bmain, Scene *sc * Need to do this so changing material settings from the graph/dopesheet * will update stuff in the viewport. */ - if (DAG_id_type_tagged(bmain, ID_MA)) { +#ifdef WITH_LEGACY_DEPSGRAPH + if (!use_new_eval && DAG_id_type_tagged(bmain, ID_MA)) { Material *material; float ctime = BKE_scene_frame_get(scene); @@ -1759,7 +1773,7 @@ void BKE_scene_update_tagged(EvaluationContext *eval_ctx, Main *bmain, Scene *sc } /* Also do the same for node trees. */ - if (DAG_id_type_tagged(bmain, ID_NT)) { + if (!use_new_eval && DAG_id_type_tagged(bmain, ID_NT)) { float ctime = BKE_scene_frame_get(scene); FOREACH_NODETREE(bmain, ntree, id) @@ -1770,9 +1784,12 @@ void BKE_scene_update_tagged(EvaluationContext *eval_ctx, Main *bmain, Scene *sc } FOREACH_NODETREE_END } +#endif /* notify editors and python about recalc */ BLI_callback_exec(bmain, &scene->id, BLI_CB_EVT_SCENE_UPDATE_POST); + + /* Inform editors about possible changes. */ DAG_ids_check_recalc(bmain, scene, false); /* clear recalc flags */ @@ -1792,6 +1809,12 @@ void BKE_scene_update_for_newframe_ex(EvaluationContext *eval_ctx, Main *bmain, #ifdef DETAILED_ANALYSIS_OUTPUT double start_time = PIL_check_seconds_timer(); #endif +#ifdef WITH_LEGACY_DEPSGRAPH + bool use_new_eval = !DEG_depsgraph_use_legacy(); +#else + /* TODO(sergey): Pass to evaluation routines instead of storing layer in the graph? */ + (void) do_invisible_flush; +#endif /* keep this first */ BLI_callback_exec(bmain, &sce->id, BLI_CB_EVT_FRAME_CHANGE_PRE); @@ -1801,12 +1824,16 @@ void BKE_scene_update_for_newframe_ex(EvaluationContext *eval_ctx, Main *bmain, * call this at the start so modifiers with textures don't lag 1 frame */ BKE_image_update_frame(bmain, sce->r.cfra); +#ifdef WITH_LEGACY_DEPSGRAPH /* rebuild rigid body worlds before doing the actual frame update * this needs to be done on start frame but animation playback usually starts one frame later * we need to do it here to avoid rebuilding the world on every simulation change, which can be very expensive */ - scene_rebuild_rbw_recursive(sce, ctime); - + if (!use_new_eval) { + scene_rebuild_rbw_recursive(sce, ctime); + } +#endif + BKE_sound_set_cfra(sce->r.cfra); /* clear animation overrides */ @@ -1815,14 +1842,18 @@ void BKE_scene_update_for_newframe_ex(EvaluationContext *eval_ctx, Main *bmain, for (sce_iter = sce; sce_iter; sce_iter = sce_iter->set) DAG_scene_relations_update(bmain, sce_iter); - /* flush recalc flags to dependencies, if we were only changing a frame - * this would not be necessary, but if a user or a script has modified - * some datablock before BKE_scene_update_tagged was called, we need the flush */ - DAG_ids_flush_tagged(bmain); +#ifdef WITH_LEGACY_DEPSGRAPH + if (!use_new_eval) { + /* flush recalc flags to dependencies, if we were only changing a frame + * this would not be necessary, but if a user or a script has modified + * some datablock before BKE_scene_update_tagged was called, we need the flush */ + DAG_ids_flush_tagged(bmain); - /* Following 2 functions are recursive - * so don't call within 'scene_update_tagged_recursive' */ - DAG_scene_update_flags(bmain, sce, lay, true, do_invisible_flush); // only stuff that moves or needs display still + /* Following 2 functions are recursive + * so don't call within 'scene_update_tagged_recursive' */ + DAG_scene_update_flags(bmain, sce, lay, true, do_invisible_flush); // only stuff that moves or needs display still + } +#endif BKE_mask_evaluate_all_masks(bmain, ctime, true); @@ -1836,8 +1867,12 @@ void BKE_scene_update_for_newframe_ex(EvaluationContext *eval_ctx, Main *bmain, * can be overridden by settings from Scene, which owns the Texture through a hierarchy * such as Scene->World->MTex/Texture) can still get correctly overridden. */ - BKE_animsys_evaluate_all_animation(bmain, sce, ctime); - /*...done with recursive funcs */ +#ifdef WITH_LEGACY_DEPSGRAPH + if (!use_new_eval) { + BKE_animsys_evaluate_all_animation(bmain, sce, ctime); + /*...done with recursive funcs */ + } +#endif /* clear "LIB_DOIT" flag from all materials, to prevent infinite recursion problems later * when trying to find materials with drivers that need evaluating [#32017] @@ -1847,19 +1882,38 @@ void BKE_scene_update_for_newframe_ex(EvaluationContext *eval_ctx, Main *bmain, /* run rigidbody sim */ /* NOTE: current position is so that rigidbody sim affects other objects, might change in the future */ - scene_do_rb_simulation_recursive(sce, ctime); - +#ifdef WITH_LEGACY_DEPSGRAPH + if (!use_new_eval) { + scene_do_rb_simulation_recursive(sce, ctime); + } +#endif + /* BKE_object_handle_update() on all objects, groups and sets */ - scene_update_tagged_recursive(eval_ctx, bmain, sce, sce); +#ifdef WITH_LEGACY_DEPSGRAPH + if (use_new_eval) { + DEG_evaluate_on_framechange(eval_ctx, bmain, sce->depsgraph, ctime, lay); + } + else { + scene_update_tagged_recursive(eval_ctx, bmain, sce, sce); + } +#else + DEG_evaluate_on_framechange(eval_ctx, bmain, sce->depsgraph, ctime, lay); +#endif + /* update sound system animation (TODO, move to depsgraph) */ BKE_sound_update_scene(bmain, sce); - scene_depsgraph_hack(eval_ctx, sce, sce); +#ifdef WITH_LEGACY_DEPSGRAPH + if (!use_new_eval) { + scene_depsgraph_hack(eval_ctx, sce, sce); + } +#endif /* notify editors and python about recalc */ BLI_callback_exec(bmain, &sce->id, BLI_CB_EVT_SCENE_UPDATE_POST); BLI_callback_exec(bmain, &sce->id, BLI_CB_EVT_FRAME_CHANGE_POST); + /* Inform editors about possible changes. */ DAG_ids_check_recalc(bmain, sce, true); /* clear recalc flags */ @@ -1968,20 +2022,30 @@ bool BKE_scene_remove_render_view(Scene *scene, SceneRenderView *srv) /* render simplification */ -int get_render_subsurf_level(const RenderData *r, int lvl) +int get_render_subsurf_level(const RenderData *r, int lvl, bool for_render) { - if (r->mode & R_SIMPLIFY) - return min_ii(r->simplify_subsurf, lvl); - else + if (r->mode & R_SIMPLIFY) { + if (for_render) + return min_ii(r->simplify_subsurf_render, lvl); + else + return min_ii(r->simplify_subsurf, lvl); + } + else { return lvl; + } } -int get_render_child_particle_number(const RenderData *r, int num) +int get_render_child_particle_number(const RenderData *r, int num, bool for_render) { - if (r->mode & R_SIMPLIFY) - return (int)(r->simplify_particles * num); - else + if (r->mode & R_SIMPLIFY) { + if (for_render) + return (int)(r->simplify_particles_render * num); + else + return (int)(r->simplify_particles * num); + } + else { return num; + } } int get_render_shadow_samples(const RenderData *r, int samples) @@ -2030,6 +2094,12 @@ bool BKE_scene_use_new_shading_nodes(const Scene *scene) return (type && type->flag & RE_USE_SHADING_NODES); } +bool BKE_scene_use_shading_nodes_custom(Scene *scene) +{ + RenderEngineType *type = RE_engines_find(scene->r.engine); + return (type && type->flag & RE_USE_SHADING_NODES_CUSTOM); +} + bool BKE_scene_uses_blender_internal(const Scene *scene) { return STREQ(scene->r.engine, RE_engine_id_BLENDER_RENDER); @@ -2148,11 +2218,13 @@ size_t BKE_scene_multiview_num_views_get(const RenderData *rd) return 1; if (rd->views_format == SCE_VIEWS_FORMAT_STEREO_3D) { - if (BLI_findstring(&rd->views, STEREO_LEFT_NAME, offsetof(SceneRenderView, name))) { + srv = BLI_findstring(&rd->views, STEREO_LEFT_NAME, offsetof(SceneRenderView, name)); + if ((srv && srv->viewflag & SCE_VIEW_DISABLE) == 0) { totviews++; } - if (BLI_findstring(&rd->views, STEREO_RIGHT_NAME, offsetof(SceneRenderView, name))) { + srv = BLI_findstring(&rd->views, STEREO_RIGHT_NAME, offsetof(SceneRenderView, name)); + if ((srv && srv->viewflag & SCE_VIEW_DISABLE) == 0) { totviews++; } } diff --git a/source/blender/blenkernel/intern/screen.c b/source/blender/blenkernel/intern/screen.c index 3c43bfa2920..4125a35cb33 100644 --- a/source/blender/blenkernel/intern/screen.c +++ b/source/blender/blenkernel/intern/screen.c @@ -272,6 +272,19 @@ void BKE_spacedata_draw_locks(int set) } } +static void (*spacedata_id_unref_cb)(struct SpaceLink *sl, const struct ID *id) = NULL; + +void BKE_spacedata_callback_id_unref_set(void (*func)(struct SpaceLink *sl, const struct ID *)) +{ + spacedata_id_unref_cb = func; +} + +void BKE_spacedata_id_unref(struct SpaceLink *sl, const struct ID *id) +{ + if (spacedata_id_unref_cb) { + spacedata_id_unref_cb(sl, id); + } +} /* not region itself */ void BKE_area_region_free(SpaceType *st, ARegion *ar) @@ -405,6 +418,23 @@ ARegion *BKE_area_find_region_active_win(ScrArea *sa) return NULL; } +ARegion *BKE_area_find_region_xy(ScrArea *sa, const int regiontype, int x, int y) +{ + ARegion *ar_found = NULL; + if (sa) { + ARegion *ar; + for (ar = sa->regionbase.first; ar; ar = ar->next) { + if ((regiontype == RGN_TYPE_ANY) || (ar->regiontype == regiontype)) { + if (BLI_rcti_isect_pt(&ar->winrct, x, y)) { + ar_found = ar; + break; + } + } + } + } + return ar_found; +} + /** * \note, ideally we can get the area from the context, * there are a few places however where this isn't practical. @@ -488,6 +518,23 @@ unsigned int BKE_screen_view3d_layer_active(const struct View3D *v3d, const stru return BKE_screen_view3d_layer_active_ex(v3d, scene, true); } +/** + * Accumulate all visible layers on this screen. + */ +unsigned int BKE_screen_view3d_layer_all(const bScreen *sc) +{ + const ScrArea *sa; + unsigned int lay = 0; + for (sa = sc->areabase.first; sa; sa = sa->next) { + if (sa->spacetype == SPACE_VIEW3D) { + View3D *v3d = sa->spacedata.first; + lay |= v3d->lay; + } + } + + return lay; +} + void BKE_screen_view3d_sync(View3D *v3d, struct Scene *scene) { int bit; diff --git a/source/blender/blenkernel/intern/sequencer.c b/source/blender/blenkernel/intern/sequencer.c index 535dcd6ba4d..d4d64af6c94 100644 --- a/source/blender/blenkernel/intern/sequencer.c +++ b/source/blender/blenkernel/intern/sequencer.c @@ -254,15 +254,15 @@ void BKE_sequence_free_anim(Sequence *seq) { while (seq->anims.last) { StripAnim *sanim = seq->anims.last; - BLI_remlink(&seq->anims, sanim); if (sanim->anim) { IMB_free_anim(sanim->anim); sanim->anim = NULL; } - MEM_freeN(sanim); + BLI_freelinkN(&seq->anims, sanim); } + BLI_listbase_clear(&seq->anims); } /* cache must be freed before calling this function @@ -1737,6 +1737,7 @@ static void seq_proxy_build_frame(const SeqRenderData *context, Sequence *seq, i if (ibuf_tmp->x != rectx || ibuf_tmp->y != recty) { ibuf = IMB_dupImBuf(ibuf_tmp); + IMB_metadata_copy(ibuf, ibuf_tmp); IMB_freeImBuf(ibuf_tmp); IMB_scalefastImBuf(ibuf, (short)rectx, (short)recty); } @@ -2423,6 +2424,7 @@ static ImBuf *input_preprocess(const SeqRenderData *context, Sequence *seq, floa IMB_rectcpy(i, ibuf, t.xofs, t.yofs, c.left, c.bottom, sx, sy); sequencer_imbuf_assign_spaces(scene, i); + IMB_metadata_copy(i, ibuf); IMB_freeImBuf(ibuf); ibuf = i; @@ -2474,6 +2476,7 @@ static ImBuf *input_preprocess(const SeqRenderData *context, Sequence *seq, floa ImBuf *ibuf_new = BKE_sequence_modifier_apply_stack(context, seq, ibuf, cfra); if (ibuf_new != ibuf) { + IMB_metadata_copy(ibuf_new, ibuf); IMB_freeImBuf(ibuf); ibuf = ibuf_new; } @@ -2496,6 +2499,7 @@ static ImBuf *copy_from_ibuf_still(const SeqRenderData *context, Sequence *seq, if (ibuf) { rval = IMB_dupImBuf(ibuf); + IMB_metadata_copy(rval, ibuf); IMB_freeImBuf(ibuf); } @@ -2509,9 +2513,11 @@ static void copy_to_ibuf_still(const SeqRenderData *context, Sequence *seq, floa /* we have to store a copy, since the passed ibuf * could be preprocessed afterwards (thereby silently * changing the cached image... */ - ibuf = IMB_dupImBuf(ibuf); + ImBuf *oibuf = ibuf; + ibuf = IMB_dupImBuf(oibuf); if (ibuf) { + IMB_metadata_copy(ibuf, oibuf); sequencer_imbuf_assign_spaces(context->scene, ibuf); } @@ -2721,7 +2727,7 @@ static ImBuf *seq_render_image_strip(const SeqRenderData *context, Sequence *seq BLI_path_abs(name, G.main->name); } - flag = IB_rect; + flag = IB_rect | IB_metadata; if (seq->alpha_mode == SEQ_ALPHA_PREMUL) flag |= IB_alphamode_premul; @@ -3583,6 +3589,8 @@ static ImBuf *seq_render_strip_stack(const SeqRenderData *context, ListBase *seq out = seq_render_strip_stack_apply_effect(context, seq, cfra, ibuf1, ibuf2); + IMB_metadata_copy(out, ibuf2); + IMB_freeImBuf(ibuf1); IMB_freeImBuf(ibuf2); } @@ -4640,7 +4648,7 @@ static size_t sequencer_rna_path_prefix(char str[SEQ_RNAPATH_MAXSTR], const char char name_esc[SEQ_NAME_MAXSTR * 2]; BLI_strescape(name_esc, name, sizeof(name_esc)); - return BLI_snprintf(str, SEQ_RNAPATH_MAXSTR, "sequence_editor.sequences_all[\"%s\"]", name_esc); + return BLI_snprintf_rlen(str, SEQ_RNAPATH_MAXSTR, "sequence_editor.sequences_all[\"%s\"]", name_esc); } /* XXX - hackish function needed for transforming strips! TODO - have some better solution */ @@ -4974,7 +4982,7 @@ Sequence *BKE_sequencer_add_sound_strip(bContext *C, ListBase *seqbasep, SeqLoad sound = BKE_sound_new_file(bmain, seq_load->path); /* handles relative paths */ - if (sound == NULL || sound->playback_handle == NULL) { + if (sound->playback_handle == NULL) { #if 0 if (op) BKE_report(op->reports, RPT_ERROR, "Unsupported audio format"); diff --git a/source/blender/blenkernel/intern/smoke.c b/source/blender/blenkernel/intern/smoke.c index 069f9136a1f..fdff858eeb0 100644 --- a/source/blender/blenkernel/intern/smoke.c +++ b/source/blender/blenkernel/intern/smoke.c @@ -269,7 +269,7 @@ static void smoke_set_domain_from_derivedmesh(SmokeDomainSettings *sds, Object * } /* apply object scale */ for (i = 0; i < 3; i++) { - size[i] = fabs(size[i] * ob->size[i]); + size[i] = fabsf(size[i] * ob->size[i]); } copy_v3_v3(sds->global_size, size); copy_v3_v3(sds->dp0, min); diff --git a/source/blender/blenkernel/intern/softbody.c b/source/blender/blenkernel/intern/softbody.c index 3cc2337d4f1..607f89699a4 100644 --- a/source/blender/blenkernel/intern/softbody.c +++ b/source/blender/blenkernel/intern/softbody.c @@ -1035,6 +1035,7 @@ static int sb_detect_aabb_collisionCached(float UNUSED(force[3]), unsigned int U ccd_Mesh *ccdm = BLI_ghashIterator_getValue (ihash); ob = BLI_ghashIterator_getKey (ihash); + { /* only with deflecting set */ if (ob->pd && ob->pd->deflect) { #if 0 /* UNUSED */ @@ -1076,6 +1077,7 @@ static int sb_detect_aabb_collisionCached(float UNUSED(force[3]), unsigned int U } } /* if (ob->pd && ob->pd->deflect) */ BLI_ghashIterator_step(ihash); + } } /* while () */ BLI_ghashIterator_free(ihash); return deflected; @@ -1114,6 +1116,7 @@ static int sb_detect_face_pointCached(float face_v1[3], float face_v2[3], float ccd_Mesh *ccdm = BLI_ghashIterator_getValue (ihash); ob = BLI_ghashIterator_getKey (ihash); + { /* only with deflecting set */ if (ob->pd && ob->pd->deflect) { MVert *mvert= NULL; @@ -1177,6 +1180,7 @@ static int sb_detect_face_pointCached(float face_v1[3], float face_v2[3], float } /* if (mvert) */ } /* if (ob->pd && ob->pd->deflect) */ BLI_ghashIterator_step(ihash); + } } /* while () */ BLI_ghashIterator_free(ihash); return deflected; @@ -1206,6 +1210,7 @@ static int sb_detect_face_collisionCached(float face_v1[3], float face_v2[3], fl ccd_Mesh *ccdm = BLI_ghashIterator_getValue (ihash); ob = BLI_ghashIterator_getKey (ihash); + { /* only with deflecting set */ if (ob->pd && ob->pd->deflect) { MFace *mface= NULL; @@ -1315,6 +1320,7 @@ static int sb_detect_face_collisionCached(float face_v1[3], float face_v2[3], fl }/* while a */ } /* if (ob->pd && ob->pd->deflect) */ BLI_ghashIterator_step(ihash); + } } /* while () */ BLI_ghashIterator_free(ihash); return deflected; @@ -1434,6 +1440,7 @@ static int sb_detect_edge_collisionCached(float edge_v1[3], float edge_v2[3], fl ccd_Mesh *ccdm = BLI_ghashIterator_getValue (ihash); ob = BLI_ghashIterator_getKey (ihash); + { /* only with deflecting set */ if (ob->pd && ob->pd->deflect) { MFace *mface= NULL; @@ -1555,6 +1562,7 @@ static int sb_detect_edge_collisionCached(float edge_v1[3], float edge_v2[3], fl }/* while a */ } /* if (ob->pd && ob->pd->deflect) */ BLI_ghashIterator_step(ihash); + } } /* while () */ BLI_ghashIterator_free(ihash); return deflected; @@ -1762,6 +1770,7 @@ static int sb_detect_vertex_collisionCached(float opco[3], float facenormal[3], ccd_Mesh *ccdm = BLI_ghashIterator_getValue (ihash); ob = BLI_ghashIterator_getKey (ihash); + { /* only with deflecting set */ if (ob->pd && ob->pd->deflect) { MFace *mface= NULL; @@ -1799,7 +1808,7 @@ static int sb_detect_vertex_collisionCached(float opco[3], float facenormal[3], else { /*aye that should be cached*/ printf("missing cache error\n"); - BLI_ghashIterator_step(ihash); + BLI_ghashIterator_step(ihash); continue; } @@ -1917,16 +1926,16 @@ static int sb_detect_vertex_collisionCached(float opco[3], float facenormal[3], if (facedist > outerfacethickness*ff) force_mag_norm =(float)force_mag_norm*fa*(facedist - outerfacethickness)*(facedist - outerfacethickness); *damp=ob->pd->pdef_sbdamp; - if (facedist > 0.0f) { - *damp *= (1.0f - facedist/outerfacethickness); - Vec3PlusStVec(outerforceaccu, force_mag_norm, d_nvect); - deflected = 3; + if (facedist > 0.0f) { + *damp *= (1.0f - facedist/outerfacethickness); + Vec3PlusStVec(outerforceaccu, force_mag_norm, d_nvect); + deflected = 3; - } - else { - Vec3PlusStVec(innerforceaccu, force_mag_norm, d_nvect); - if (deflected < 2) deflected = 2; - } + } + else { + Vec3PlusStVec(innerforceaccu, force_mag_norm, d_nvect); + if (deflected < 2) deflected = 2; + } if ((mprevvert) && (*damp > 0.0f)) { choose_winner(ve, opco, nv1, nv3, nv4, vv1, vv3, vv4); @@ -1997,6 +2006,7 @@ static int sb_detect_vertex_collisionCached(float opco[3], float facenormal[3], }/* while a */ } /* if (ob->pd && ob->pd->deflect) */ BLI_ghashIterator_step(ihash); + } } /* while () */ if (deflected == 1) { // no face but 'outer' edge cylinder sees vert @@ -2335,14 +2345,14 @@ static int _softbody_calc_forces_slice_in_a_thread(Scene *scene, Object *ob, flo float kd = 1.0f; if (sb_deflect_face(ob, bp->pos, facenormal, defforce, &cf, timenow, vel, &intrusion)) { - if (intrusion < 0.0f) { - sb->scratch->flag |= SBF_DOFUZZY; - bp->loc_flag |= SBF_DOFUZZY; - bp->choke = sb->choke*0.01f; - } + if (intrusion < 0.0f) { + sb->scratch->flag |= SBF_DOFUZZY; + bp->loc_flag |= SBF_DOFUZZY; + bp->choke = sb->choke*0.01f; + } - sub_v3_v3v3(cfforce, bp->vec, vel); - Vec3PlusStVec(bp->force, -cf*50.0f, cfforce); + sub_v3_v3v3(cfforce, bp->vec, vel); + Vec3PlusStVec(bp->force, -cf*50.0f, cfforce); Vec3PlusStVec(bp->force, kd, defforce); } @@ -3484,7 +3494,7 @@ static void makelatticesprings(Lattice *lt, BodySpring *bs, int dostiff, Object bs->v1 = bpc; bs->v2 = bpc+dw+dv-1; bs->springtype=SB_BEND; - bs->len= globallen((bp+dw+dv-1)->vec, bp->vec, ob); + bs->len= globallen((bp+dw+dv-1)->vec, bp->vec, ob); bs++; } } diff --git a/source/blender/blenkernel/intern/sound.c b/source/blender/blenkernel/intern/sound.c index 6a831d23aea..46a50917427 100644 --- a/source/blender/blenkernel/intern/sound.c +++ b/source/blender/blenkernel/intern/sound.c @@ -66,7 +66,7 @@ static int sound_cfra; bSound *BKE_sound_new_file(struct Main *bmain, const char *filename) { - bSound *sound = NULL; + bSound *sound; char str[FILE_MAX]; const char *path; @@ -89,11 +89,6 @@ bSound *BKE_sound_new_file(struct Main *bmain, const char *filename) BKE_sound_load(bmain, sound); - if (!sound->playback_handle) { - BKE_libblock_free(bmain, sound); - sound = NULL; - } - return sound; } @@ -144,8 +139,8 @@ static void sound_sync_callback(void *data, int mode, float time) BKE_sound_play_scene(scene); else BKE_sound_stop_scene(scene); - if (scene->sound_scene_handle) - AUD_seek(scene->sound_scene_handle, time); + if (scene->playback_handle) + AUD_seek(scene->playback_handle, time); } scene = scene->id.next; } @@ -246,12 +241,6 @@ bSound *BKE_sound_new_buffer(struct Main *bmain, bSound *source) sound_load(bmain, sound); - if (!sound->playback_handle) - { - BKE_libblock_free(bmain, sound); - sound = NULL; - } - return sound; } @@ -272,12 +261,6 @@ bSound *BKE_sound_new_limiter(struct Main *bmain, bSound *source, float start, f sound_load(bmain, sound); - if (!sound->playback_handle) - { - BKE_libblock_free(bmain, sound); - sound = NULL; - } - return sound; } #endif @@ -400,15 +383,15 @@ void BKE_sound_create_scene(struct Scene *scene) scene->sound_scene = AUD_createSequencer(FPS, scene->audio.flag & AUDIO_MUTE); AUD_updateSequencerData(scene->sound_scene, scene->audio.speed_of_sound, scene->audio.doppler_factor, scene->audio.distance_model); - scene->sound_scene_handle = NULL; + scene->playback_handle = NULL; scene->sound_scrub_handle = NULL; scene->speaker_handles = NULL; } void BKE_sound_destroy_scene(struct Scene *scene) { - if (scene->sound_scene_handle) - AUD_stop(scene->sound_scene_handle); + if (scene->playback_handle) + AUD_stop(scene->playback_handle); if (scene->sound_scrub_handle) AUD_stop(scene->sound_scrub_handle); if (scene->sound_scene) @@ -541,13 +524,13 @@ void BKE_sound_update_sequencer(struct Main *main, bSound *sound) static void sound_start_play_scene(struct Scene *scene) { - if (scene->sound_scene_handle) - AUD_stop(scene->sound_scene_handle); + if (scene->playback_handle) + AUD_stop(scene->playback_handle); AUD_setSequencerDeviceSpecs(scene->sound_scene); - if ((scene->sound_scene_handle = AUD_play(scene->sound_scene, 1))) - AUD_setLoop(scene->sound_scene_handle, -1); + if ((scene->playback_handle = AUD_play(scene->sound_scene, 1))) + AUD_setLoop(scene->playback_handle, -1); } void BKE_sound_play_scene(struct Scene *scene) @@ -557,20 +540,20 @@ void BKE_sound_play_scene(struct Scene *scene) AUD_lock(); - status = scene->sound_scene_handle ? AUD_getStatus(scene->sound_scene_handle) : AUD_STATUS_INVALID; + status = scene->playback_handle ? AUD_getStatus(scene->playback_handle) : AUD_STATUS_INVALID; if (status == AUD_STATUS_INVALID) { sound_start_play_scene(scene); - if (!scene->sound_scene_handle) { + if (!scene->playback_handle) { AUD_unlock(); return; } } if (status != AUD_STATUS_PLAYING) { - AUD_seek(scene->sound_scene_handle, cur_time); - AUD_resume(scene->sound_scene_handle); + AUD_seek(scene->playback_handle, cur_time); + AUD_resume(scene->playback_handle); } if (scene->audio.flag & AUDIO_SYNC) @@ -581,8 +564,8 @@ void BKE_sound_play_scene(struct Scene *scene) void BKE_sound_stop_scene(struct Scene *scene) { - if (scene->sound_scene_handle) { - AUD_pause(scene->sound_scene_handle); + if (scene->playback_handle) { + AUD_pause(scene->playback_handle); if (scene->audio.flag & AUDIO_SYNC) AUD_stopPlayback(); @@ -600,17 +583,17 @@ void BKE_sound_seek_scene(struct Main *bmain, struct Scene *scene) AUD_lock(); - status = scene->sound_scene_handle ? AUD_getStatus(scene->sound_scene_handle) : AUD_STATUS_INVALID; + status = scene->playback_handle ? AUD_getStatus(scene->playback_handle) : AUD_STATUS_INVALID; if (status == AUD_STATUS_INVALID) { sound_start_play_scene(scene); - if (!scene->sound_scene_handle) { + if (!scene->playback_handle) { AUD_unlock(); return; } - AUD_pause(scene->sound_scene_handle); + AUD_pause(scene->playback_handle); } animation_playing = 0; @@ -623,13 +606,13 @@ void BKE_sound_seek_scene(struct Main *bmain, struct Scene *scene) if (scene->audio.flag & AUDIO_SCRUB && !animation_playing) { if (scene->audio.flag & AUDIO_SYNC) { - AUD_seek(scene->sound_scene_handle, cur_time); - AUD_seekSequencer(scene->sound_scene_handle, cur_time); + AUD_seek(scene->playback_handle, cur_time); + AUD_seekSequencer(scene->playback_handle, cur_time); } else { - AUD_seek(scene->sound_scene_handle, cur_time); + AUD_seek(scene->playback_handle, cur_time); } - AUD_resume(scene->sound_scene_handle); + AUD_resume(scene->playback_handle); if (scene->sound_scrub_handle && AUD_getStatus(scene->sound_scrub_handle) != AUD_STATUS_INVALID) { AUD_seek(scene->sound_scrub_handle, 0); } @@ -637,16 +620,16 @@ void BKE_sound_seek_scene(struct Main *bmain, struct Scene *scene) if (scene->sound_scrub_handle) { AUD_stop(scene->sound_scrub_handle); } - scene->sound_scrub_handle = AUD_pauseAfter(scene->sound_scene_handle, one_frame); + scene->sound_scrub_handle = AUD_pauseAfter(scene->playback_handle, one_frame); } } else { if (scene->audio.flag & AUDIO_SYNC) { - AUD_seekSequencer(scene->sound_scene_handle, cur_time); + AUD_seekSequencer(scene->playback_handle, cur_time); } else { if (status == AUD_STATUS_PLAYING) { - AUD_seek(scene->sound_scene_handle, cur_time); + AUD_seek(scene->playback_handle, cur_time); } } } @@ -656,11 +639,11 @@ void BKE_sound_seek_scene(struct Main *bmain, struct Scene *scene) float BKE_sound_sync_scene(struct Scene *scene) { - if (scene->sound_scene_handle) { + if (scene->playback_handle) { if (scene->audio.flag & AUDIO_SYNC) - return AUD_getSequencerPosition(scene->sound_scene_handle); + return AUD_getSequencerPosition(scene->playback_handle); else - return AUD_getPosition(scene->sound_scene_handle); + return AUD_getPosition(scene->playback_handle); } return NAN_FLT; } diff --git a/source/blender/blenkernel/intern/subsurf_ccg.c b/source/blender/blenkernel/intern/subsurf_ccg.c index a4e0eaaa324..e8bca50c3d7 100644 --- a/source/blender/blenkernel/intern/subsurf_ccg.c +++ b/source/blender/blenkernel/intern/subsurf_ccg.c @@ -300,7 +300,11 @@ static int ss_sync_from_uv(CCGSubSurf *ss, CCGSubSurf *origss, DerivedMesh *dm, float uv[3] = {0.0f, 0.0f, 0.0f}; /* only first 2 values are written into */ limit[0] = limit[1] = STD_UV_CONNECT_LIMIT; - vmap = BKE_mesh_uv_vert_map_create(mpoly, mloop, mloopuv, totface, totvert, 0, limit); + /* previous behavior here is without accounting for winding, however this causes stretching in + * UV map in really simple cases with mirror + subsurf, see second part of T44530. Also, initially + * intention is to treat merged vertices from mirror modifier as seams, see code below with ME_VERT_MERGED + * This fixes a very old regression (2.49 was correct here) */ + vmap = BKE_mesh_uv_vert_map_create(mpoly, mloop, mloopuv, totface, totvert, limit, false, true); if (!vmap) return 0; @@ -2796,7 +2800,6 @@ static void ccgDM_release(DerivedMesh *dm) if (ccgdm->reverseFaceMap) MEM_freeN(ccgdm->reverseFaceMap); if (ccgdm->gridFaces) MEM_freeN(ccgdm->gridFaces); if (ccgdm->gridData) MEM_freeN(ccgdm->gridData); - if (ccgdm->gridAdjacency) MEM_freeN(ccgdm->gridAdjacency); if (ccgdm->gridOffset) MEM_freeN(ccgdm->gridOffset); if (ccgdm->gridFlagMats) MEM_freeN(ccgdm->gridFlagMats); if (ccgdm->gridHidden) { @@ -3107,46 +3110,11 @@ static int ccgDM_getGridSize(DerivedMesh *dm) return ccgSubSurf_getGridSize(ccgdm->ss); } -static int ccgdm_adjacent_grid(int *gridOffset, CCGFace *f, int S, int offset) -{ - CCGFace *adjf; - CCGEdge *e; - int i, j = 0, numFaces, fIndex, numEdges = 0; - - e = ccgSubSurf_getFaceEdge(f, S); - numFaces = ccgSubSurf_getEdgeNumFaces(e); - - if (numFaces != 2) - return -1; - - for (i = 0; i < numFaces; i++) { - adjf = ccgSubSurf_getEdgeFace(e, i); - - if (adjf != f) { - numEdges = ccgSubSurf_getFaceNumVerts(adjf); - for (j = 0; j < numEdges; j++) - if (ccgSubSurf_getFaceEdge(adjf, j) == e) - break; - - if (j != numEdges) - break; - } - } - - if (numEdges == 0) - return -1; - - fIndex = GET_INT_FROM_POINTER(ccgSubSurf_getFaceFaceHandle(adjf)); - - return gridOffset[fIndex] + (j + offset) % numEdges; -} - static void ccgdm_create_grids(DerivedMesh *dm) { CCGDerivedMesh *ccgdm = (CCGDerivedMesh *)dm; CCGSubSurf *ss = ccgdm->ss; CCGElem **gridData; - DMGridAdjacency *gridAdjacency, *adj; DMFlagMat *gridFlagMats; CCGFace **gridFaces; int *gridOffset; @@ -3172,7 +3140,6 @@ static void ccgdm_create_grids(DerivedMesh *dm) /* compute grid data */ gridData = MEM_mallocN(sizeof(CCGElem *) * numGrids, "ccgdm.gridData"); - gridAdjacency = MEM_mallocN(sizeof(DMGridAdjacency) * numGrids, "ccgdm.gridAdjacency"); gridFaces = MEM_mallocN(sizeof(CCGFace *) * numGrids, "ccgdm.gridFaces"); gridFlagMats = MEM_mallocN(sizeof(DMFlagMat) * numGrids, "ccgdm.gridFlagMats"); @@ -3183,29 +3150,14 @@ static void ccgdm_create_grids(DerivedMesh *dm) int numVerts = ccgSubSurf_getFaceNumVerts(f); for (S = 0; S < numVerts; S++, gIndex++) { - int prevS = (S - 1 + numVerts) % numVerts; - int nextS = (S + 1 + numVerts) % numVerts; - gridData[gIndex] = ccgSubSurf_getFaceGridDataArray(ss, f, S); gridFaces[gIndex] = f; gridFlagMats[gIndex] = ccgdm->faceFlags[index]; - - adj = &gridAdjacency[gIndex]; - - adj->index[0] = gIndex - S + nextS; - adj->rotation[0] = 3; - adj->index[1] = ccgdm_adjacent_grid(gridOffset, f, prevS, 0); - adj->rotation[1] = 1; - adj->index[2] = ccgdm_adjacent_grid(gridOffset, f, S, 1); - adj->rotation[2] = 3; - adj->index[3] = gIndex - S + prevS; - adj->rotation[3] = 1; } } ccgdm->gridData = gridData; ccgdm->gridFaces = gridFaces; - ccgdm->gridAdjacency = gridAdjacency; ccgdm->gridOffset = gridOffset; ccgdm->gridFlagMats = gridFlagMats; } @@ -3218,14 +3170,6 @@ static CCGElem **ccgDM_getGridData(DerivedMesh *dm) return ccgdm->gridData; } -static DMGridAdjacency *ccgDM_getGridAdjacency(DerivedMesh *dm) -{ - CCGDerivedMesh *ccgdm = (CCGDerivedMesh *)dm; - - ccgdm_create_grids(dm); - return ccgdm->gridAdjacency; -} - static int *ccgDM_getGridOffset(DerivedMesh *dm) { CCGDerivedMesh *ccgdm = (CCGDerivedMesh *)dm; @@ -3308,7 +3252,7 @@ static struct PBVH *ccgDM_getPBVH(Object *ob, DerivedMesh *dm) * when the ccgdm gets remade, the assumption is that the topology * does not change. */ ccgdm_create_grids(dm); - BKE_pbvh_grids_update(ob->sculpt->pbvh, ccgdm->gridData, ccgdm->gridAdjacency, (void **)ccgdm->gridFaces, + BKE_pbvh_grids_update(ob->sculpt->pbvh, ccgdm->gridData, (void **)ccgdm->gridFaces, ccgdm->gridFlagMats, ccgdm->gridHidden); } @@ -3327,7 +3271,7 @@ static struct PBVH *ccgDM_getPBVH(Object *ob, DerivedMesh *dm) numGrids = ccgDM_getNumGrids(dm); ob->sculpt->pbvh = ccgdm->pbvh = BKE_pbvh_new(); - BKE_pbvh_build_grids(ccgdm->pbvh, ccgdm->gridData, ccgdm->gridAdjacency, + BKE_pbvh_build_grids(ccgdm->pbvh, ccgdm->gridData, numGrids, &key, (void **) ccgdm->gridFaces, ccgdm->gridFlagMats, ccgdm->gridHidden); } else if (ob->type == OB_MESH) { @@ -3455,7 +3399,6 @@ static CCGDerivedMesh *getCCGDerivedMesh(CCGSubSurf *ss, ccgdm->dm.getNumGrids = ccgDM_getNumGrids; ccgdm->dm.getGridSize = ccgDM_getGridSize; ccgdm->dm.getGridData = ccgDM_getGridData; - ccgdm->dm.getGridAdjacency = ccgDM_getGridAdjacency; ccgdm->dm.getGridOffset = ccgDM_getGridOffset; ccgdm->dm.getGridKey = ccgDM_getGridKey; ccgdm->dm.getGridFlagMats = ccgDM_getGridFlagMats; @@ -3820,7 +3763,7 @@ struct DerivedMesh *subsurf_make_derived_from_derived( SubsurfFlags flags) { int useSimple = (smd->subdivType == ME_SIMPLE_SUBSURF) ? CCG_SIMPLE_SUBDIV : 0; - CCGFlags useAging = smd->flags & eSubsurfModifierFlag_DebugIncr ? CCG_USE_AGING : 0; + CCGFlags useAging = (smd->flags & eSubsurfModifierFlag_DebugIncr) ? CCG_USE_AGING : 0; int useSubsurfUv = smd->flags & eSubsurfModifierFlag_SubsurfUv; int drawInteriorEdges = !(smd->flags & eSubsurfModifierFlag_ControlEdges); CCGDerivedMesh *result; @@ -3828,7 +3771,7 @@ struct DerivedMesh *subsurf_make_derived_from_derived( /* note: editmode calculation can only run once per * modifier stack evaluation (uses freed cache) [#36299] */ if (flags & SUBSURF_FOR_EDIT_MODE) { - int levels = (smd->modifier.scene) ? get_render_subsurf_level(&smd->modifier.scene->r, smd->levels) : smd->levels; + int levels = (smd->modifier.scene) ? get_render_subsurf_level(&smd->modifier.scene->r, smd->levels, false) : smd->levels; smd->emCache = _getSubSurf(smd->emCache, levels, 3, useSimple | useAging | CCG_CALC_NORMALS); ss_sync_from_derivedmesh(smd->emCache, dm, vertCos, useSimple); @@ -3840,7 +3783,7 @@ struct DerivedMesh *subsurf_make_derived_from_derived( else if (flags & SUBSURF_USE_RENDER_PARAMS) { /* Do not use cache in render mode. */ CCGSubSurf *ss; - int levels = (smd->modifier.scene) ? get_render_subsurf_level(&smd->modifier.scene->r, smd->renderLevels) : smd->renderLevels; + int levels = (smd->modifier.scene) ? get_render_subsurf_level(&smd->modifier.scene->r, smd->renderLevels, true) : smd->renderLevels; if (levels == 0) return dm; @@ -3856,7 +3799,7 @@ struct DerivedMesh *subsurf_make_derived_from_derived( } else { int useIncremental = (smd->flags & eSubsurfModifierFlag_Incremental); - int levels = (smd->modifier.scene) ? get_render_subsurf_level(&smd->modifier.scene->r, smd->levels) : smd->levels; + int levels = (smd->modifier.scene) ? get_render_subsurf_level(&smd->modifier.scene->r, smd->levels, false) : smd->levels; CCGSubSurf *ss; /* It is quite possible there is a much better place to do this. It diff --git a/source/blender/blenkernel/intern/text.c b/source/blender/blenkernel/intern/text.c index 9f441b45db9..89456763b95 100644 --- a/source/blender/blenkernel/intern/text.c +++ b/source/blender/blenkernel/intern/text.c @@ -330,7 +330,7 @@ static void text_from_buf(Text *text, const unsigned char *buffer, const int len text->curc = text->selc = 0; } -int BKE_text_reload(Text *text) +bool BKE_text_reload(Text *text) { FILE *fp; int len; @@ -339,13 +339,24 @@ int BKE_text_reload(Text *text) char str[FILE_MAX]; BLI_stat_t st; - if (!text->name) return 0; - + if (!text->name) { + return false; + } + BLI_strncpy(str, text->name, FILE_MAX); BLI_path_abs(str, G.main->name); fp = BLI_fopen(str, "r"); - if (fp == NULL) return 0; + if (fp == NULL) { + return false; + } + fseek(fp, 0L, SEEK_END); + len = ftell(fp); + fseek(fp, 0L, SEEK_SET); + if (UNLIKELY(len == -1)) { + fclose(fp); + return false; + } /* free memory: */ @@ -363,11 +374,6 @@ int BKE_text_reload(Text *text) MEM_freeN(text->undo_buf); init_undo_text(text); - fseek(fp, 0L, SEEK_END); - len = ftell(fp); - fseek(fp, 0L, SEEK_SET); - - buffer = MEM_mallocN(len, "text_buffer"); /* under windows fread can return less than len bytes because * of CR stripping */ @@ -385,7 +391,7 @@ int BKE_text_reload(Text *text) text_from_buf(text, buffer, len); MEM_freeN(buffer); - return 1; + return true; } Text *BKE_text_load_ex(Main *bmain, const char *file, const char *relpath, const bool is_internal) @@ -402,8 +408,18 @@ Text *BKE_text_load_ex(Main *bmain, const char *file, const char *relpath, const BLI_path_abs(str, relpath); fp = BLI_fopen(str, "r"); - if (fp == NULL) return NULL; - + if (fp == NULL) { + return NULL; + } + + fseek(fp, 0L, SEEK_END); + len = ftell(fp); + fseek(fp, 0L, SEEK_SET); + if (UNLIKELY(len == -1)) { + fclose(fp); + return NULL; + } + ta = BKE_libblock_alloc(bmain, ID_TXT, BLI_path_basename(str)); ta->id.us = 1; @@ -423,10 +439,6 @@ Text *BKE_text_load_ex(Main *bmain, const char *file, const char *relpath, const /* clear undo buffer */ init_undo_text(ta); - - fseek(fp, 0L, SEEK_END); - len = ftell(fp); - fseek(fp, 0L, SEEK_SET); buffer = MEM_mallocN(len, "text_buffer"); /* under windows fread can return less than len bytes because @@ -473,6 +485,7 @@ Text *BKE_text_copy(Main *bmain, Text *ta) BLI_listbase_clear(&tan->lines); tan->curl = tan->sell = NULL; + tan->compiled = NULL; tan->nlines = ta->nlines; @@ -651,7 +664,7 @@ void BKE_text_unlink(Main *bmain, Text *text) } } - /* Freestyle (while looping oer the scene) */ + /* Freestyle (while looping over the scene) */ for (srl = sce->r.layers.first; srl; srl = srl->next) { for (module = srl->freestyleConfig.modules.first; module; module = module->next) { if (module->script == text) @@ -1895,6 +1908,47 @@ static void txt_undo_add_charop(Text *text, int op_start, unsigned int c) text->undo_buf[text->undo_pos + 1] = 0; } +/* extends Link */ +struct LinkInt { + struct LinkInt *next, *prev; + int value; +}; + +/* unindentLines points to a ListBase composed of LinkInt elements, listing the numbers + * of the lines that should not be indented back. */ +static void txt_undo_add_unindent_op(Text *text, const ListBase *line_index_mask, const int line_index_mask_len) +{ + struct LinkInt *idata; + + BLI_assert(BLI_listbase_count(line_index_mask) == line_index_mask_len); + + /* OP byte + UInt32 count + counted UInt32 line numbers + UInt32 count + 12-bytes selection + OP byte */ + if (!max_undo_test(text, 1 + 4 + (line_index_mask_len * 4) + 4 + 12 + 1)) { + return; + } + + /* Opening buffer sequence with OP */ + text->undo_pos++; + text->undo_buf[text->undo_pos] = UNDO_UNINDENT; + text->undo_pos++; + /* Adding number of line numbers to read */ + txt_undo_store_uint32(text->undo_buf, &text->undo_pos, line_index_mask_len); + + /* Adding linenumbers of lines that shall not be indented if undoing */ + for (idata = line_index_mask->first; idata; idata = idata->next) { + txt_undo_store_uint32(text->undo_buf, &text->undo_pos, idata->value); + } + + /* Adding number of line numbers to read again */ + txt_undo_store_uint32(text->undo_buf, &text->undo_pos, line_index_mask_len); + /* Adding current selection */ + txt_undo_store_cursors(text); + /* Closing with OP (same as above) */ + text->undo_buf[text->undo_pos] = UNDO_UNINDENT; + /* Marking as last undo operation */ + text->undo_buf[text->undo_pos + 1] = 0; +} + static unsigned short txt_undo_read_uint16(const char *undo_buf, int *undo_pos) { unsigned short val; @@ -2189,7 +2243,6 @@ void txt_do_undo(Text *text) text->undo_pos--; break; case UNDO_INDENT: - case UNDO_UNINDENT: case UNDO_COMMENT: case UNDO_UNCOMMENT: case UNDO_DUPLICATE: @@ -2203,9 +2256,6 @@ void txt_do_undo(Text *text) if (op == UNDO_INDENT) { txt_unindent(text); } - else if (op == UNDO_UNINDENT) { - txt_indent(text); - } else if (op == UNDO_COMMENT) { txt_uncomment(text); } @@ -2224,6 +2274,37 @@ void txt_do_undo(Text *text) text->undo_pos--; break; + case UNDO_UNINDENT: + { + int count; + int i; + /* Get and restore the cursors */ + txt_undo_read_cursors(text->undo_buf, &text->undo_pos, &curln, &curc, &selln, &selc); + txt_move_to(text, curln, curc, 0); + txt_move_to(text, selln, selc, 1); + + /* Un-unindent */ + txt_indent(text); + + /* Get the count */ + count = txt_undo_read_uint32(text->undo_buf, &text->undo_pos); + /* Iterate! */ + txt_pop_sel(text); + + for (i = 0; i < count; i++) { + txt_move_to(text, txt_undo_read_uint32(text->undo_buf, &text->undo_pos), 0, 0); + /* Un-un-unindent */ + txt_unindent(text); + } + /* Restore selection */ + txt_move_to(text, curln, curc, 0); + txt_move_to(text, selln, selc, 1); + /* Jumo over count */ + txt_undo_read_uint32(text->undo_buf, &text->undo_pos); + /* Jump over closing OP byte */ + text->undo_pos--; + break; + } default: //XXX error("Undo buffer error - resetting"); text->undo_pos = -1; @@ -2353,7 +2434,6 @@ void txt_do_redo(Text *text) break; case UNDO_INDENT: - case UNDO_UNINDENT: case UNDO_COMMENT: case UNDO_UNCOMMENT: case UNDO_DUPLICATE: @@ -2369,9 +2449,6 @@ void txt_do_redo(Text *text) if (op == UNDO_INDENT) { txt_indent(text); } - else if (op == UNDO_UNINDENT) { - txt_unindent(text); - } else if (op == UNDO_COMMENT) { txt_comment(text); } @@ -2401,6 +2478,26 @@ void txt_do_redo(Text *text) txt_move_to(text, selln, selc, 1); break; + case UNDO_UNINDENT: + { + int count; + int i; + + text->undo_pos++; + /* Scan all the stuff described in txt_undo_add_unindent_op */ + count = txt_redo_read_uint32(text->undo_buf, &text->undo_pos); + for (i = 0; i < count; i++) { + txt_redo_read_uint32(text->undo_buf, &text->undo_pos); + } + /* Count again */ + txt_redo_read_uint32(text->undo_buf, &text->undo_pos); + /* Get the selection and re-unindent */ + txt_redo_read_cursors(text->undo_buf, &text->undo_pos, &curln, &curc, &selln, &selc); + txt_move_to(text, curln, curc, 0); + txt_move_to(text, selln, selc, 1); + txt_unindent(text); + break; + } default: //XXX error("Undo buffer error - resetting"); text->undo_pos = -1; @@ -2801,6 +2898,12 @@ void txt_unindent(Text *text) int indentlen = 1; bool unindented_first = false; + /* List of lines that are already at indent level 0, to store them later into the undo buffer */ + ListBase line_index_mask = {NULL, NULL}; + int line_index_mask_len = 0; + int curl_span_init = 0; + + /* hardcoded: TXT_TABSIZE = 4 spaces: */ int spaceslen = TXT_TABSIZE; @@ -2814,6 +2917,10 @@ void txt_unindent(Text *text) indentlen = spaceslen; } + if (!undoing) { + curl_span_init = txt_get_span(text->lines.first, text->curl); + } + while (true) { bool changed = false; if (STREQLEN(text->curl->line, remove, indentlen)) { @@ -2823,6 +2930,16 @@ void txt_unindent(Text *text) memmove(text->curl->line, text->curl->line + indentlen, text->curl->len + 1); changed = true; } + else { + if (!undoing) { + /* Create list element for 0 indent line */ + struct LinkInt *idata = MEM_mallocN(sizeof(struct LinkInt), __func__); + idata->value = curl_span_init + num; + BLI_assert(idata->value == txt_get_span(text->lines.first, text->curl)); + BLI_addtail(&line_index_mask, idata); + line_index_mask_len += 1; + } + } txt_make_dirty(text); txt_clean_text(text); @@ -2835,6 +2952,7 @@ void txt_unindent(Text *text) else { text->curl = text->curl->next; num++; + } } @@ -2848,8 +2966,10 @@ void txt_unindent(Text *text) } if (!undoing) { - txt_undo_add_op(text, UNDO_UNINDENT); + txt_undo_add_unindent_op(text, &line_index_mask, line_index_mask_len); } + + BLI_freelistN(&line_index_mask); } void txt_comment(Text *text) diff --git a/source/blender/blenkernel/intern/texture.c b/source/blender/blenkernel/intern/texture.c index 8e4fcc5d1cc..2ea903247b2 100644 --- a/source/blender/blenkernel/intern/texture.c +++ b/source/blender/blenkernel/intern/texture.c @@ -567,7 +567,7 @@ void BKE_texture_free(Tex *tex) BKE_animdata_free((struct ID *)tex); BKE_previewimg_free(&tex->preview); - BKE_icon_delete((struct ID *)tex); + BKE_icon_id_delete((struct ID *)tex); tex->id.icon_id = 0; if (tex->nodetree) { @@ -629,7 +629,7 @@ void BKE_texture_default(Tex *tex) tex->env->stype = ENV_ANIM; tex->env->clipsta = 0.1; tex->env->clipend = 100; - tex->env->cuberes = 600; + tex->env->cuberes = 512; tex->env->depth = 0; } @@ -1423,7 +1423,7 @@ EnvMap *BKE_texture_envmap_add(void) env->stype = ENV_ANIM; env->clipsta = 0.1; env->clipend = 100.0; - env->cuberes = 600; + env->cuberes = 512; env->viewscale = 0.5; return env; diff --git a/source/blender/blenkernel/intern/tracking.c b/source/blender/blenkernel/intern/tracking.c index 83db0639468..f9ae987db70 100644 --- a/source/blender/blenkernel/intern/tracking.c +++ b/source/blender/blenkernel/intern/tracking.c @@ -730,7 +730,7 @@ MovieTrackingTrack *BKE_tracking_track_get_named(MovieTracking *tracking, MovieT return NULL; } -MovieTrackingTrack *BKE_tracking_track_get_indexed(MovieTracking *tracking, int tracknr, ListBase **tracksbase_r) +MovieTrackingTrack *BKE_tracking_track_get_indexed(MovieTracking *tracking, int tracknr, ListBase **r_tracksbase) { MovieTrackingObject *object; int cur = 1; @@ -743,7 +743,7 @@ MovieTrackingTrack *BKE_tracking_track_get_indexed(MovieTracking *tracking, int while (track) { if (track->flag & TRACK_HAS_BUNDLE) { if (cur == tracknr) { - *tracksbase_r = tracksbase; + *r_tracksbase = tracksbase; return track; } @@ -756,7 +756,7 @@ MovieTrackingTrack *BKE_tracking_track_get_indexed(MovieTracking *tracking, int object = object->next; } - *tracksbase_r = NULL; + *r_tracksbase = NULL; return NULL; } @@ -1302,6 +1302,95 @@ void BKE_tracking_plane_tracks_deselect_all(ListBase *plane_tracks_base) } } +bool BKE_tracking_plane_track_has_point_track(MovieTrackingPlaneTrack *plane_track, + MovieTrackingTrack *track) +{ + int i; + for (i = 0; i < plane_track->point_tracksnr; i++) { + if (plane_track->point_tracks[i] == track) { + return true; + } + } + return false; +} + +bool BKE_tracking_plane_track_remove_point_track(MovieTrackingPlaneTrack *plane_track, + MovieTrackingTrack *track) +{ + int i, track_index; + MovieTrackingTrack **new_point_tracks; + + if (plane_track->point_tracksnr <= 4) { + return false; + } + + new_point_tracks = MEM_mallocN(sizeof(*new_point_tracks) * (plane_track->point_tracksnr - 1), + "new point tracks array"); + + for (i = 0, track_index = 0; i < plane_track->point_tracksnr; i++) { + if (plane_track->point_tracks[i] != track) { + new_point_tracks[track_index++] = plane_track->point_tracks[i]; + } + } + + MEM_freeN(plane_track->point_tracks); + plane_track->point_tracks = new_point_tracks; + plane_track->point_tracksnr--; + + return true; +} + +void BKE_tracking_plane_tracks_remove_point_track(MovieTracking *tracking, + MovieTrackingTrack *track) +{ + MovieTrackingPlaneTrack *plane_track, *next_plane_track; + ListBase *plane_tracks_base = BKE_tracking_get_active_plane_tracks(tracking); + for (plane_track = plane_tracks_base->first; + plane_track; + plane_track = next_plane_track) + { + next_plane_track = plane_track->next; + if (BKE_tracking_plane_track_has_point_track(plane_track, track)) { + if (!BKE_tracking_plane_track_remove_point_track(plane_track, track)) { + /* Delete planes with less than 3 point tracks in it. */ + BKE_tracking_plane_track_free(plane_track); + BLI_freelinkN(plane_tracks_base, plane_track); + } + } + } +} + +void BKE_tracking_plane_track_replace_point_track(MovieTrackingPlaneTrack *plane_track, + MovieTrackingTrack *old_track, + MovieTrackingTrack *new_track) +{ + int i; + for (i = 0; i < plane_track->point_tracksnr; i++) { + if (plane_track->point_tracks[i] == old_track) { + plane_track->point_tracks[i] = new_track; + break; + } + } +} + +void BKE_tracking_plane_tracks_replace_point_track(MovieTracking *tracking, + MovieTrackingTrack *old_track, + MovieTrackingTrack *new_track) +{ + MovieTrackingPlaneTrack *plane_track; + ListBase *plane_tracks_base = BKE_tracking_get_active_plane_tracks(tracking); + for (plane_track = plane_tracks_base->first; + plane_track; + plane_track = plane_track->next) + { + if (BKE_tracking_plane_track_has_point_track(plane_track, old_track)) { + BKE_tracking_plane_track_replace_point_track(plane_track, + old_track, + new_track); + } + } +} + /*********************** Plane Marker *************************/ MovieTrackingPlaneMarker *BKE_tracking_plane_marker_insert(MovieTrackingPlaneTrack *plane_track, diff --git a/source/blender/blenkernel/intern/tracking_auto.c b/source/blender/blenkernel/intern/tracking_auto.c index 4cb3f2ca493..76261bddfbc 100644 --- a/source/blender/blenkernel/intern/tracking_auto.c +++ b/source/blender/blenkernel/intern/tracking_auto.c @@ -534,19 +534,9 @@ void BKE_autotrack_context_finish(AutoTrackContext *context) if ((plane_track->flag & PLANE_TRACK_AUTOKEY) == 0) { int track; for (track = 0; track < context->num_tracks; ++track) { - MovieTrackingTrack *old_track; - bool do_update = false; - int j; - - old_track = context->options[track].track; - for (j = 0; j < plane_track->point_tracksnr; j++) { - if (plane_track->point_tracks[j] == old_track) { - do_update = true; - break; - } - } - - if (do_update) { + if (BKE_tracking_plane_track_has_point_track(plane_track, + context->options[track].track)) + { BKE_tracking_track_plane_from_existing_motion( plane_track, context->first_frame); diff --git a/source/blender/blenkernel/intern/unit.c b/source/blender/blenkernel/intern/unit.c index 5a2c77b5619..0d83695d2f1 100644 --- a/source/blender/blenkernel/intern/unit.c +++ b/source/blender/blenkernel/intern/unit.c @@ -370,12 +370,7 @@ static size_t unit_as_string(char *str, int len_max, double value, int prec, bUn value_conv = value / unit->scalar; /* Convert to a string */ - { - len = BLI_snprintf(str, len_max, "%.*f", prec, value_conv); - - if (len >= len_max) - len = len_max; - } + len = BLI_snprintf_rlen(str, len_max, "%.*f", prec, value_conv); /* Add unit prefix and strip zeros */ diff --git a/source/blender/blenkernel/intern/world.c b/source/blender/blenkernel/intern/world.c index f26cbf7880a..e4736b1f54c 100644 --- a/source/blender/blenkernel/intern/world.c +++ b/source/blender/blenkernel/intern/world.c @@ -74,7 +74,7 @@ void BKE_world_free_ex(World *wrld, bool do_id_user) if (wrld->gpumaterial.first) GPU_material_free(&wrld->gpumaterial); - BKE_icon_delete((struct ID *)wrld); + BKE_icon_id_delete((struct ID *)wrld); wrld->id.icon_id = 0; } |