diff options
Diffstat (limited to 'source/blender/blenkernel/intern')
89 files changed, 3720 insertions, 2278 deletions
diff --git a/source/blender/blenkernel/intern/DerivedMesh.c b/source/blender/blenkernel/intern/DerivedMesh.c index cfeca50a751..916e11dbd46 100644 --- a/source/blender/blenkernel/intern/DerivedMesh.c +++ b/source/blender/blenkernel/intern/DerivedMesh.c @@ -350,7 +350,7 @@ void DM_init( dm->numPolyData = numPolys; DM_init_funcs(dm); - + dm->needsFree = 1; dm->auto_bump_scale = -1.0f; dm->dirty = 0; @@ -410,7 +410,6 @@ int DM_release(DerivedMesh *dm) if (dm->needsFree) { bvhcache_free(&dm->bvhCache); GPU_drawobject_free(dm); - CustomData_free(&dm->vertData, dm->numVertData); CustomData_free(&dm->edgeData, dm->numEdgeData); CustomData_free(&dm->faceData, dm->numTessFaceData); @@ -1660,7 +1659,7 @@ static void shapekey_layers_to_keyblocks(DerivedMesh *dm, Mesh *me, int actshape cos = CustomData_get_layer_n(&dm->vertData, CD_SHAPEKEY, i); kb->totelem = dm->numVertData; - kb->data = kbcos = MEM_malloc_arrayN(kb->totelem, sizeof(float), "kbcos DerivedMesh.c"); + kb->data = kbcos = MEM_malloc_arrayN(kb->totelem, 3 * sizeof(float), "kbcos DerivedMesh.c"); if (kb->uid == actshape_uid) { MVert *mvert = dm->getVertArray(dm); @@ -3483,17 +3482,25 @@ void DM_draw_attrib_vertex_uniforms(const DMVertexAttribs *attribs) { int i; if (attribs->totorco) { - glUniform1i(attribs->orco.gl_info_index, 0); + if (attribs->orco.gl_info_index != -1) { + glUniform1i(attribs->orco.gl_info_index, 0); + } } for (i = 0; i < attribs->tottface; i++) { - glUniform1i(attribs->tface[i].gl_info_index, 0); + if (attribs->tface[i].gl_info_index != -1) { + glUniform1i(attribs->tface[i].gl_info_index, 0); + } } for (i = 0; i < attribs->totmcol; i++) { - glUniform1i(attribs->mcol[i].gl_info_index, GPU_ATTR_INFO_SRGB); + if (attribs->mcol[i].gl_info_index != -1) { + glUniform1i(attribs->mcol[i].gl_info_index, GPU_ATTR_INFO_SRGB); + } } for (i = 0; i < attribs->tottang; i++) { - glUniform1i(attribs->tang[i].gl_info_index, 0); + if (attribs->tang[i].gl_info_index != -1) { + glUniform1i(attribs->tang[i].gl_info_index, 0); + } } } @@ -3719,7 +3726,7 @@ void DM_init_origspace(DerivedMesh *dm) BKE_mesh_calc_poly_normal(mp, l, mv, p_nor); axis_dominant_v3_to_m3(mat, p_nor); - BLI_array_empty(vcos_2d); + BLI_array_clear(vcos_2d); BLI_array_reserve(vcos_2d, mp->totloop); for (j = 0; j < mp->totloop; j++, l++) { mul_v3_m3v3(co, mat, mv[l->v].co); diff --git a/source/blender/blenkernel/intern/addon.c b/source/blender/blenkernel/intern/addon.c index 0ef12397fe7..689e0fb5ee6 100644 --- a/source/blender/blenkernel/intern/addon.c +++ b/source/blender/blenkernel/intern/addon.c @@ -27,13 +27,58 @@ #include <stddef.h> #include <stdlib.h> +#include "RNA_types.h" + #include "BLI_utildefines.h" #include "BLI_ghash.h" +#include "BLI_string.h" +#include "BLI_listbase.h" #include "BKE_addon.h" /* own include */ +#include "BKE_idprop.h" + +#include "DNA_listBase.h" +#include "DNA_userdef_types.h" + #include "MEM_guardedalloc.h" +/* -------------------------------------------------------------------- */ +/** \name Add-on New/Free + * \{ */ + +bAddon *BKE_addon_new(void) +{ + bAddon *addon = MEM_callocN(sizeof(bAddon), "bAddon"); + return addon; +} + +bAddon *BKE_addon_ensure(ListBase *addon_list, const char *module) +{ + bAddon *addon = BLI_findstring(addon_list, module, offsetof(bAddon, module)); + if (addon == NULL) { + addon = BKE_addon_new(); + BLI_strncpy(addon->module, module, sizeof(addon->module)); + BLI_addtail(addon_list, addon); + } + return addon; +} + +void BKE_addon_free(bAddon *addon) +{ + if (addon->prop) { + IDP_FreeProperty(addon->prop); + MEM_freeN(addon->prop); + } + MEM_freeN(addon); +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Add-on Preference API + * \{ */ + static GHash *global_addonpreftype_hash = NULL; @@ -81,3 +126,5 @@ void BKE_addon_pref_type_free(void) BLI_ghash_free(global_addonpreftype_hash, NULL, MEM_freeN); global_addonpreftype_hash = NULL; } + +/** \} */ diff --git a/source/blender/blenkernel/intern/anim.c b/source/blender/blenkernel/intern/anim.c index 62df97c6afa..0b964145c7f 100644 --- a/source/blender/blenkernel/intern/anim.c +++ b/source/blender/blenkernel/intern/anim.c @@ -278,8 +278,6 @@ void animviz_get_object_motionpaths(Object *ob, ListBase *targets) /* update scene for current frame */ static void motionpaths_calc_update_scene(Main *bmain, - Scene *scene, - ViewLayer *view_layer, struct Depsgraph *depsgraph) { /* Do all updates @@ -292,7 +290,7 @@ static void motionpaths_calc_update_scene(Main *bmain, * * TODO(sergey): Use evaluation context dedicated to motion paths. */ - BKE_scene_graph_update_for_newframe(bmain->eval_ctx, depsgraph, bmain, scene, view_layer); + BKE_scene_graph_update_for_newframe(depsgraph, bmain); } /* ........ */ @@ -369,7 +367,7 @@ static void motionpaths_calc_bake_targets(Scene *scene, ListBase *targets) /* calculate path over requested range */ for (CFRA = sfra; CFRA <= efra; CFRA++) { /* update relevant data for new frame */ - motionpaths_calc_update_scene(bmain, scene, eval_ctx->view_layer, eval_ctx->depsgraph); + motionpaths_calc_update_scene(bmain, eval_ctx->depsgraph); /* perform baking for targets */ motionpaths_calc_bake_targets(scene, targets); @@ -377,7 +375,7 @@ static void motionpaths_calc_bake_targets(Scene *scene, ListBase *targets) /* reset original environment */ CFRA = cfra; - motionpaths_calc_update_scene(bmain, scene, eval_ctx->view_layer, eval_ctx->depsgraph); + motionpaths_calc_update_scene(bmain, eval_ctx->depsgraph); /* clear recalc flags from targets */ for (mpt = targets->first; mpt; mpt = mpt->next) { diff --git a/source/blender/blenkernel/intern/anim_sys.c b/source/blender/blenkernel/intern/anim_sys.c index 58b476d3da5..ecdb180d2ed 100644 --- a/source/blender/blenkernel/intern/anim_sys.c +++ b/source/blender/blenkernel/intern/anim_sys.c @@ -77,6 +77,8 @@ #include "atomic_ops.h" +#include "DEG_depsgraph.h" + /* ***************************************** */ /* AnimData API */ @@ -245,7 +247,7 @@ void BKE_animdata_free(ID *id, const bool do_id_user) } /* free nla data */ - free_nladata(&adt->nla_tracks); + BKE_nla_tracks_free(&adt->nla_tracks); /* free drivers - stored as a list of F-Curves */ free_fcurves(&adt->drivers); @@ -284,7 +286,7 @@ AnimData *BKE_animdata_copy(Main *bmain, AnimData *adt, const bool do_action) } /* duplicate NLA data */ - copy_nladata(&dadt->nla_tracks, &adt->nla_tracks); + BKE_nla_tracks_copy(&dadt->nla_tracks, &adt->nla_tracks); /* duplicate drivers (F-Curves) */ copy_fcurves(&dadt->drivers, &adt->drivers); @@ -366,7 +368,7 @@ void BKE_animdata_merge_copy(ID *dst_id, ID *src_id, eAnimData_MergeCopy_Modes a if (src->nla_tracks.first) { ListBase tracks = {NULL, NULL}; - copy_nladata(&tracks, &src->nla_tracks); + BKE_nla_tracks_copy(&tracks, &src->nla_tracks); BLI_movelisttolist(&dst->nla_tracks, &tracks); } @@ -820,7 +822,7 @@ char *BKE_animsys_fix_rna_path_rename(ID *owner_id, char *old_path, const char * /* if no action, no need to proceed */ if (ELEM(NULL, owner_id, old_path)) { - printf("early abort\n"); + if (G.debug & G_DEBUG) printf("%s: early abort\n", __func__); return old_path; } @@ -843,9 +845,9 @@ char *BKE_animsys_fix_rna_path_rename(ID *owner_id, char *old_path, const char * } /* fix given path */ - printf("%s | %s | oldpath = %p ", oldN, newN, old_path); + if (G.debug & G_DEBUG) printf("%s | %s | oldpath = %p ", oldN, newN, old_path); result = rna_path_rename_fix(owner_id, prefix, oldN, newN, old_path, verify_paths); - printf("result = %p\n", result); + if (G.debug & G_DEBUG) printf("path rename result = %p\n", result); /* free the temp names */ MEM_freeN(oldN); @@ -2879,18 +2881,34 @@ 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(const 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 dependency graph instead... */ - DEBUG_PRINT("%s on %s, time=%f\n\n", __func__, id->name, (double)eval_ctx->ctime); + DEG_debug_print_eval_time(__func__, id->name, id, eval_ctx->ctime); BKE_animsys_evaluate_animdata(scene, id, adt, eval_ctx->ctime, ADT_RECALC_ANIM); } +/* TODO(sergey): This is slow lookup of driver from CoW datablock. + * Keep this for until we've got something smarter for depsgraph + * building.\ + */ +static FCurve *find_driver_from_evaluated_id(ID *id, FCurve *fcu) +{ + /* We've got non-CoW datablock, can use f-curve as-is. */ + if (id->orig_id == NULL) { + return fcu; + } + /*const*/ ID *id_orig = id->orig_id; + const AnimData *adt_orig = BKE_animdata_from_id(id_orig); + const AnimData *adt_cow = BKE_animdata_from_id(id); + const int fcu_index = BLI_findindex(&adt_orig->drivers, fcu); + BLI_assert(fcu_index != -1); + return BLI_findlink(&adt_cow->drivers, fcu_index); +} + void BKE_animsys_eval_driver(const EvaluationContext *eval_ctx, ID *id, FCurve *fcu) @@ -2900,11 +2918,10 @@ void BKE_animsys_eval_driver(const EvaluationContext *eval_ctx, PointerRNA id_ptr; bool ok = false; - DEBUG_PRINT("%s on %s (%s[%d])\n", - __func__, - id->name, - fcu->rna_path, - fcu->array_index); + fcu = find_driver_from_evaluated_id(id, fcu); + + DEG_debug_print_eval_subdata_index( + __func__, id->name, id, "fcu", fcu->rna_path, fcu, fcu->array_index); RNA_id_pointer_create(id, &id_ptr); @@ -2937,5 +2954,3 @@ void BKE_animsys_eval_driver(const EvaluationContext *eval_ctx, } } } - -#undef DEBUG_PRINT diff --git a/source/blender/blenkernel/intern/armature.c b/source/blender/blenkernel/intern/armature.c index 953fef067b4..0a8c97ff175 100644 --- a/source/blender/blenkernel/intern/armature.c +++ b/source/blender/blenkernel/intern/armature.c @@ -63,7 +63,6 @@ #include "BKE_DerivedMesh.h" #include "BKE_deform.h" #include "BKE_displist.h" -#include "BKE_global.h" #include "BKE_idprop.h" #include "BKE_library.h" #include "BKE_library_query.h" diff --git a/source/blender/blenkernel/intern/armature_update.c b/source/blender/blenkernel/intern/armature_update.c index 1b8bf3feb10..29baaff32ba 100644 --- a/source/blender/blenkernel/intern/armature_update.c +++ b/source/blender/blenkernel/intern/armature_update.c @@ -47,10 +47,9 @@ #include "BIK_api.h" -#include "BKE_global.h" #include "BKE_main.h" -#define DEBUG_PRINT if (G.debug & G_DEBUG_DEPSGRAPH) printf +#include "DEG_depsgraph.h" /* ********************** SPLINE IK SOLVER ******************* */ @@ -559,14 +558,23 @@ void BKE_splineik_execute_tree( /* *************** Depsgraph evaluation callbacks ************ */ +BLI_INLINE bPoseChannel *pose_pchan_get_indexed(Object *ob, int pchan_index) +{ + bPose *pose = ob->pose; + BLI_assert(pose != NULL); + BLI_assert(pchan_index >= 0); + BLI_assert(pchan_index < MEM_allocN_len(pose->chan_array) / sizeof(bPoseChannel *)); + return pose->chan_array[pchan_index]; +} + void BKE_pose_eval_init(const struct EvaluationContext *UNUSED(eval_ctx), Scene *UNUSED(scene), - Object *ob, - bPose *pose) + Object *ob) { - bPoseChannel *pchan; + bPose *pose = ob->pose; + BLI_assert(pose != NULL); - DEBUG_PRINT("%s on %s\n", __func__, ob->id.name); + DEG_debug_print_eval(__func__, ob->id.name, ob); BLI_assert(ob->type == OB_ARMATURE); @@ -577,27 +585,34 @@ void BKE_pose_eval_init(const struct EvaluationContext *UNUSED(eval_ctx), /* 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) { + const int num_channels = BLI_listbase_count(&pose->chanbase); + pose->chan_array = MEM_malloc_arrayN( + num_channels, sizeof(bPoseChannel *), "pose->chan_array"); + + /* clear flags */ + int pchan_index = 0; + for (bPoseChannel *pchan = pose->chanbase.first; pchan != NULL; pchan = pchan->next) { pchan->flag &= ~(POSE_DONE | POSE_CHAIN | POSE_IKTREE | POSE_IKSPLINE); + pose->chan_array[pchan_index++] = pchan; } } void BKE_pose_eval_init_ik(const struct EvaluationContext *eval_ctx, Scene *scene, - Object *ob, - bPose *UNUSED(pose)) + Object *ob) { - float ctime = BKE_scene_frame_get(scene); /* not accurate... */ - - DEBUG_PRINT("%s on %s\n", __func__, ob->id.name); - - /* 2a. construct the IK tree (standard IK) */ + DEG_debug_print_eval(__func__, ob->id.name, ob); + BLI_assert(ob->type == OB_ARMATURE); + const float ctime = BKE_scene_frame_get(scene); /* not accurate... */ + bArmature *arm = (bArmature *)ob->data; + if (arm->flag & ARM_RESTPOS) { + return; + } + /* construct the IK tree (standard IK) */ BIK_initialize_tree(eval_ctx, scene, ob, ctime); - - /* 2b. construct the Spline IK trees + /* 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 + * to function in conjunction with standard IK */ BKE_pose_splineik_init_tree(scene, ob, ctime); } @@ -605,11 +620,13 @@ void BKE_pose_eval_init_ik(const struct EvaluationContext *eval_ctx, void BKE_pose_eval_bone(const struct EvaluationContext *eval_ctx, Scene *scene, Object *ob, - bPoseChannel *pchan) + int pchan_index) { - bArmature *arm = (bArmature *)ob->data; - DEBUG_PRINT("%s on %s pchan %s\n", __func__, ob->id.name, pchan->name); + bPoseChannel *pchan = pose_pchan_get_indexed(ob, pchan_index); + DEG_debug_print_eval_subdata( + __func__, ob->id.name, ob, "pchan", pchan->name, pchan); BLI_assert(ob->type == OB_ARMATURE); + bArmature *arm = (bArmature *)ob->data; if (arm->edbo || (arm->flag & ARM_RESTPOS)) { Bone *bone = pchan->bone; if (bone) { @@ -640,9 +657,11 @@ void BKE_pose_eval_bone(const struct EvaluationContext *eval_ctx, void BKE_pose_constraints_evaluate(const struct EvaluationContext *eval_ctx, Scene *scene, Object *ob, - bPoseChannel *pchan) + int pchan_index) { - DEBUG_PRINT("%s on %s pchan %s\n", __func__, ob->id.name, pchan->name); + bPoseChannel *pchan = pose_pchan_get_indexed(ob, pchan_index); + DEG_debug_print_eval_subdata( + __func__, ob->id.name, ob, "pchan", pchan->name, pchan); bArmature *arm = (bArmature *)ob->data; if (arm->flag & ARM_RESTPOS) { return; @@ -659,10 +678,12 @@ void BKE_pose_constraints_evaluate(const struct EvaluationContext *eval_ctx, } void BKE_pose_bone_done(const struct EvaluationContext *UNUSED(eval_ctx), - bPoseChannel *pchan) + struct Object *ob, + int pchan_index) { + bPoseChannel *pchan = pose_pchan_get_indexed(ob, pchan_index); float imat[4][4]; - DEBUG_PRINT("%s on pchan %s\n", __func__, pchan->name); + DEG_debug_print_eval(__func__, pchan->name, pchan); if (pchan->bone) { invert_m4_m4(imat, pchan->bone->arm_mat); mul_m4_m4m4(pchan->chan_mat, pchan->pose_mat, imat); @@ -672,40 +693,61 @@ void BKE_pose_bone_done(const struct EvaluationContext *UNUSED(eval_ctx), void BKE_pose_iktree_evaluate(const struct EvaluationContext *eval_ctx, Scene *scene, Object *ob, - bPoseChannel *rootchan) + int rootchan_index) { - float ctime = BKE_scene_frame_get(scene); /* not accurate... */ - DEBUG_PRINT("%s on %s pchan %s\n", __func__, ob->id.name, rootchan->name); + bPoseChannel *rootchan = pose_pchan_get_indexed(ob, rootchan_index); + DEG_debug_print_eval_subdata( + __func__, ob->id.name, ob, "rootchan", rootchan->name, rootchan); + BLI_assert(ob->type == OB_ARMATURE); + const float ctime = BKE_scene_frame_get(scene); /* not accurate... */ + bArmature *arm = (bArmature *)ob->data; + if (arm->flag & ARM_RESTPOS) { + return; + } BIK_execute_tree(eval_ctx, scene, ob, rootchan, ctime); } void BKE_pose_splineik_evaluate(const struct EvaluationContext *eval_ctx, Scene *scene, Object *ob, - bPoseChannel *rootchan) + int rootchan_index) + { - float ctime = BKE_scene_frame_get(scene); /* not accurate... */ - DEBUG_PRINT("%s on %s pchan %s\n", __func__, ob->id.name, rootchan->name); + bPoseChannel *rootchan = pose_pchan_get_indexed(ob, rootchan_index); + DEG_debug_print_eval_subdata( + __func__, ob->id.name, ob, "rootchan", rootchan->name, rootchan); + BLI_assert(ob->type == OB_ARMATURE); + const float ctime = BKE_scene_frame_get(scene); /* not accurate... */ + bArmature *arm = (bArmature *)ob->data; + if (arm->flag & ARM_RESTPOS) { + return; + } BKE_splineik_execute_tree(eval_ctx, scene, ob, rootchan, ctime); } void BKE_pose_eval_flush(const struct EvaluationContext *UNUSED(eval_ctx), Scene *scene, - Object *ob, - bPose *UNUSED(pose)) + Object *ob) { + bPose *pose = ob->pose; + BLI_assert(pose != NULL); + float ctime = BKE_scene_frame_get(scene); /* not accurate... */ - DEBUG_PRINT("%s on %s\n", __func__, ob->id.name); + DEG_debug_print_eval(__func__, ob->id.name, ob); BLI_assert(ob->type == OB_ARMATURE); - /* 6. release the IK tree */ + /* release the IK tree */ BIK_release_tree(scene, ob, ctime); + + BLI_assert(pose->chan_array != NULL); + MEM_freeN(pose->chan_array); + pose->chan_array = NULL; } void BKE_pose_eval_proxy_copy(const struct EvaluationContext *UNUSED(eval_ctx), Object *ob) { BLI_assert(ID_IS_LINKED(ob) && ob->proxy_from != NULL); - DEBUG_PRINT("%s on %s\n", __func__, ob->id.name); + DEG_debug_print_eval(__func__, ob->id.name, ob); 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 182b88c1c57..236b965ec34 100644 --- a/source/blender/blenkernel/intern/blender.c +++ b/source/blender/blenkernel/intern/blender.c @@ -45,6 +45,7 @@ #include "IMB_imbuf.h" #include "IMB_moviecache.h" +#include "BKE_addon.h" #include "BKE_blender.h" /* own include */ #include "BKE_blender_version.h" /* own include */ #include "BKE_blendfile.h" @@ -84,6 +85,10 @@ void BKE_blender_free(void) BKE_main_free(G.main); G.main = NULL; + if (G.log.file != NULL) { + fclose(G.log.file); + } + BKE_spacetypes_free(); /* after free main, it uses space callbacks */ IMB_exit(); @@ -133,6 +138,8 @@ void BKE_blender_globals_init(void) #else G.f &= ~G_SCRIPT_AUTOEXEC; #endif + + G.log.level = 1; } void BKE_blender_globals_clear(void) @@ -202,11 +209,7 @@ static void userdef_free_addons(UserDef *userdef) { for (bAddon *addon = userdef->addons.first, *addon_next; addon; addon = addon_next) { addon_next = addon->next; - if (addon->prop) { - IDP_FreeProperty(addon->prop); - MEM_freeN(addon->prop); - } - MEM_freeN(addon); + BKE_addon_free(addon); } BLI_listbase_clear(&userdef->addons); } diff --git a/source/blender/blenkernel/intern/blender_undo.c b/source/blender/blenkernel/intern/blender_undo.c index b8f46756445..98482bcc8b1 100644 --- a/source/blender/blenkernel/intern/blender_undo.c +++ b/source/blender/blenkernel/intern/blender_undo.c @@ -42,27 +42,18 @@ #include "DNA_scene_types.h" -#include "BLI_fileops.h" -#include "BLI_listbase.h" #include "BLI_path_util.h" #include "BLI_string.h" #include "BLI_utildefines.h" -#include "IMB_imbuf.h" -#include "IMB_moviecache.h" - #include "BKE_blender_undo.h" /* own include */ #include "BKE_blendfile.h" #include "BKE_appdir.h" -#include "BKE_brush.h" #include "BKE_context.h" #include "BKE_global.h" -#include "BKE_image.h" #include "BKE_main.h" -#include "RE_pipeline.h" #include "BLO_undofile.h" -#include "BLO_readfile.h" #include "BLO_writefile.h" #include "DEG_depsgraph.h" @@ -74,44 +65,22 @@ #define UNDO_DISK 0 -typedef struct UndoElem { - struct UndoElem *next, *prev; - char str[FILE_MAX]; - char name[BKE_UNDO_STR_MAX]; - MemFile memfile; - uintptr_t undosize; -} UndoElem; - -static ListBase undobase = {NULL, NULL}; -static UndoElem *curundo = NULL; - -/** - * Avoid bad-level call to #WM_jobs_kill_all_except() - */ -static void (*undo_wm_job_kill_callback)(struct bContext *C) = NULL; - -void BKE_undo_callback_wm_kill_jobs_set(void (*callback)(struct bContext *C)) -{ - undo_wm_job_kill_callback = callback; -} - -static int read_undosave(bContext *C, UndoElem *uel) +bool BKE_memfile_undo_decode(MemFileUndoData *mfu, bContext *C) { char mainstr[sizeof(G.main->name)]; int success = 0, fileflags; - /* This is needed so undoing/redoing doesn't crash with threaded previews going */ - undo_wm_job_kill_callback(C); - BLI_strncpy(mainstr, G.main->name, sizeof(mainstr)); /* temporal store */ fileflags = G.fileflags; G.fileflags |= G_FILE_NO_UI; - if (UNDO_DISK) - success = (BKE_blendfile_read(C, uel->str, NULL, 0) != BKE_BLENDFILE_READ_FAIL); - else - success = BKE_blendfile_read_from_memfile(C, &uel->memfile, NULL, 0); + if (UNDO_DISK) { + success = (BKE_blendfile_read(C, mfu->filename, NULL, 0) != BKE_BLENDFILE_READ_FAIL); + } + else { + success = BKE_blendfile_read_from_memfile(C, &mfu->memfile, NULL, 0); + } /* restore */ BLI_strncpy(G.main->name, mainstr, sizeof(G.main->name)); /* restore */ @@ -125,283 +94,43 @@ static int read_undosave(bContext *C, UndoElem *uel) return success; } -/* name can be a dynamic string */ -void BKE_undo_write(bContext *C, const char *name) +MemFileUndoData *BKE_memfile_undo_encode(Main *bmain, MemFileUndoData *mfu_prev) { - uintptr_t maxmem, totmem, memused; - int nr /*, success */ /* UNUSED */; - UndoElem *uel; - - if ((U.uiflag & USER_GLOBALUNDO) == 0) { - return; - } - - if (U.undosteps == 0) { - return; - } - - /* remove all undos after (also when curundo == NULL) */ - while (undobase.last != curundo) { - uel = undobase.last; - BLI_remlink(&undobase, uel); - BLO_memfile_free(&uel->memfile); - MEM_freeN(uel); - } - - /* make new */ - curundo = uel = MEM_callocN(sizeof(UndoElem), "undo file"); - BLI_strncpy(uel->name, name, sizeof(uel->name)); - BLI_addtail(&undobase, uel); - - /* and limit amount to the maximum */ - nr = 0; - uel = undobase.last; - while (uel) { - nr++; - if (nr == U.undosteps) break; - uel = uel->prev; - } - if (uel) { - while (undobase.first != uel) { - UndoElem *first = undobase.first; - BLI_remlink(&undobase, first); - /* the merge is because of compression */ - BLO_memfile_merge(&first->memfile, &first->next->memfile); - MEM_freeN(first); - } - } - + MemFileUndoData *mfu = MEM_callocN(sizeof(MemFileUndoData), __func__); /* disk save version */ if (UNDO_DISK) { static int counter = 0; - char filepath[FILE_MAX]; + char filename[FILE_MAX]; char numstr[32]; int fileflags = G.fileflags & ~(G_FILE_HISTORY); /* don't do file history on undo */ - /* calculate current filepath */ + /* Calculate current filename. */ counter++; counter = counter % U.undosteps; BLI_snprintf(numstr, sizeof(numstr), "%d.blend", counter); - BLI_make_file_string("/", filepath, BKE_tempdir_session(), numstr); - - /* success = */ /* UNUSED */ BLO_write_file(CTX_data_main(C), filepath, fileflags, NULL, NULL); - - BLI_strncpy(curundo->str, filepath, sizeof(curundo->str)); - } - else { - MemFile *prevfile = NULL; - - if (curundo->prev) prevfile = &(curundo->prev->memfile); - - memused = MEM_get_memory_in_use(); - /* success = */ /* UNUSED */ BLO_write_file_mem(CTX_data_main(C), prevfile, &curundo->memfile, G.fileflags); - curundo->undosize = MEM_get_memory_in_use() - memused; - } - - if (U.undomemory != 0) { - /* limit to maximum memory (afterwards, we can't know in advance) */ - totmem = 0; - maxmem = ((uintptr_t)U.undomemory) * 1024 * 1024; - - /* keep at least two (original + other) */ - uel = undobase.last; - while (uel && uel->prev) { - totmem += uel->undosize; - if (totmem > maxmem) break; - uel = uel->prev; - } - - if (uel) { - if (uel->prev && uel->prev->prev) - uel = uel->prev; + BLI_make_file_string("/", filename, BKE_tempdir_session(), numstr); - while (undobase.first != uel) { - UndoElem *first = undobase.first; - BLI_remlink(&undobase, first); - /* the merge is because of compression */ - BLO_memfile_merge(&first->memfile, &first->next->memfile); - MEM_freeN(first); - } - } - } -} - -/* 1 = an undo, -1 is a redo. we have to make sure 'curundo' remains at current situation */ -void BKE_undo_step(bContext *C, int step) -{ + /* success = */ /* UNUSED */ BLO_write_file(bmain, filename, fileflags, NULL, NULL); - if (step == 0) { - read_undosave(C, curundo); - } - else if (step == 1) { - /* curundo should never be NULL, after restart or load file it should call undo_save */ - if (curundo == NULL || curundo->prev == NULL) { - // XXX error("No undo available"); - } - else { - if (G.debug & G_DEBUG) printf("undo %s\n", curundo->name); - curundo = curundo->prev; - read_undosave(C, curundo); - } + BLI_strncpy(mfu->filename, filename, sizeof(mfu->filename)); } else { - /* curundo has to remain current situation! */ - - if (curundo == NULL || curundo->next == NULL) { - // XXX error("No redo available"); - } - else { - read_undosave(C, curundo->next); - curundo = curundo->next; - if (G.debug & G_DEBUG) printf("redo %s\n", curundo->name); - } - } -} - -void BKE_undo_reset(void) -{ - UndoElem *uel; - - uel = undobase.first; - while (uel) { - BLO_memfile_free(&uel->memfile); - uel = uel->next; + MemFile *prevfile = (mfu_prev) ? &(mfu_prev->memfile) : NULL; + /* success = */ /* UNUSED */ BLO_write_file_mem(bmain, prevfile, &mfu->memfile, G.fileflags); + mfu->undo_size = mfu->memfile.size; } - BLI_freelistN(&undobase); - curundo = NULL; -} - -/* based on index nr it does a restore */ -void BKE_undo_number(bContext *C, int nr) -{ - curundo = BLI_findlink(&undobase, nr); - BKE_undo_step(C, 0); -} - -/* go back to the last occurance of name in stack */ -void BKE_undo_name(bContext *C, const char *name) -{ - UndoElem *uel = BLI_rfindstring(&undobase, name, offsetof(UndoElem, name)); - - if (uel && uel->prev) { - curundo = uel->prev; - BKE_undo_step(C, 0); - } -} - -/* name optional */ -bool BKE_undo_is_valid(const char *name) -{ - if (name) { - UndoElem *uel = BLI_rfindstring(&undobase, name, offsetof(UndoElem, name)); - return uel && uel->prev; - } + bmain->is_memfile_undo_written = true; - return undobase.last != undobase.first; + return mfu; } -/* get name of undo item, return null if no item with this index */ -/* if active pointer, set it to 1 if true */ -const char *BKE_undo_get_name(int nr, bool *r_active) -{ - UndoElem *uel = BLI_findlink(&undobase, nr); - - if (r_active) *r_active = false; - - if (uel) { - if (r_active && (uel == curundo)) { - *r_active = true; - } - return uel->name; - } - return NULL; -} - -/* return the name of the last item */ -const char *BKE_undo_get_name_last(void) -{ - UndoElem *uel = undobase.last; - return (uel ? uel->name : NULL); -} - -/** - * Saves .blend using undo buffer. - * - * \return success. - */ -bool BKE_undo_save_file(const char *filename) +void BKE_memfile_undo_free(MemFileUndoData *mfu) { - UndoElem *uel; - MemFileChunk *chunk; - int file, oflags; - - if ((U.uiflag & USER_GLOBALUNDO) == 0) { - return false; - } - - uel = curundo; - if (uel == NULL) { - fprintf(stderr, "No undo buffer to save recovery file\n"); - return false; - } - - /* note: This is currently used for autosave and 'quit.blend', where _not_ following symlinks is OK, - * however if this is ever executed explicitly by the user, we may want to allow writing to symlinks. - */ - - oflags = O_BINARY | O_WRONLY | O_CREAT | O_TRUNC; -#ifdef O_NOFOLLOW - /* use O_NOFOLLOW to avoid writing to a symlink - use 'O_EXCL' (CVE-2008-1103) */ - oflags |= O_NOFOLLOW; -#else - /* TODO(sergey): How to deal with symlinks on windows? */ -# ifndef _MSC_VER -# warning "Symbolic links will be followed on undo save, possibly causing CVE-2008-1103" -# endif -#endif - file = BLI_open(filename, oflags, 0666); - - if (file == -1) { - fprintf(stderr, "Unable to save '%s': %s\n", - filename, errno ? strerror(errno) : "Unknown error opening file"); - return false; - } - - for (chunk = uel->memfile.chunks.first; chunk; chunk = chunk->next) { - if (write(file, chunk->buf, chunk->size) != chunk->size) { - break; - } - } - - close(file); - - if (chunk) { - fprintf(stderr, "Unable to save '%s': %s\n", - filename, errno ? strerror(errno) : "Unknown error writing file"); - return false; - } - return true; -} - -/* sets curscene */ -Main *BKE_undo_get_main(Scene **r_scene) -{ - Main *mainp = NULL; - BlendFileData *bfd = BLO_read_from_memfile(G.main, G.main->name, &curundo->memfile, NULL, BLO_READ_SKIP_NONE); - - if (bfd) { - mainp = bfd->main; - if (r_scene) { - *r_scene = bfd->curscene; - } - - MEM_freeN(bfd); - } - - return mainp; + BLO_memfile_free(&mfu->memfile); + MEM_freeN(mfu); } /** \} */ diff --git a/source/blender/blenkernel/intern/boids.c b/source/blender/blenkernel/intern/boids.c index 8c78787c259..f440ce711ff 100644 --- a/source/blender/blenkernel/intern/boids.c +++ b/source/blender/blenkernel/intern/boids.c @@ -35,7 +35,7 @@ #include "MEM_guardedalloc.h" -#include "DNA_object_force.h" +#include "DNA_object_force_types.h" #include "DNA_scene_types.h" #include "BLI_rand.h" diff --git a/source/blender/blenkernel/intern/bpath.c b/source/blender/blenkernel/intern/bpath.c index 158c6c31432..e9a8de4469d 100644 --- a/source/blender/blenkernel/intern/bpath.c +++ b/source/blender/blenkernel/intern/bpath.c @@ -53,8 +53,8 @@ #include "DNA_mesh_types.h" #include "DNA_modifier_types.h" #include "DNA_movieclip_types.h" -#include "DNA_object_fluidsim.h" -#include "DNA_object_force.h" +#include "DNA_object_fluidsim_types.h" +#include "DNA_object_force_types.h" #include "DNA_object_types.h" #include "DNA_particle_types.h" #include "DNA_sequence_types.h" diff --git a/source/blender/blenkernel/intern/brush.c b/source/blender/blenkernel/intern/brush.c index 8d63c1cfb44..d82c1ca56fe 100644 --- a/source/blender/blenkernel/intern/brush.c +++ b/source/blender/blenkernel/intern/brush.c @@ -151,7 +151,7 @@ void BKE_brush_init(Brush *brush) /** * \note Resulting brush will have two users: one as a fake user, another is assumed to be used by the caller. */ -Brush *BKE_brush_add(Main *bmain, const char *name, short ob_mode) +Brush *BKE_brush_add(Main *bmain, const char *name, const eObjectMode ob_mode) { Brush *brush; @@ -164,7 +164,7 @@ Brush *BKE_brush_add(Main *bmain, const char *name, short ob_mode) return brush; } -struct Brush *BKE_brush_first_search(struct Main *bmain, short ob_mode) +struct Brush *BKE_brush_first_search(struct Main *bmain, const eObjectMode ob_mode) { Brush *brush; diff --git a/source/blender/blenkernel/intern/bullet.c b/source/blender/blenkernel/intern/bullet.c index 088031e16a7..c16c0f7af31 100644 --- a/source/blender/blenkernel/intern/bullet.c +++ b/source/blender/blenkernel/intern/bullet.c @@ -33,7 +33,7 @@ #include "MEM_guardedalloc.h" /* types */ -#include "DNA_object_force.h" /* here is the softbody struct */ +#include "DNA_object_force_types.h" /* here is the softbody struct */ #include "BKE_bullet.h" diff --git a/source/blender/blenkernel/intern/bvhutils.c b/source/blender/blenkernel/intern/bvhutils.c index 775499304d4..cd2c7194237 100644 --- a/source/blender/blenkernel/intern/bvhutils.c +++ b/source/blender/blenkernel/intern/bvhutils.c @@ -411,7 +411,7 @@ static BVHTree *bvhtree_from_editmesh_verts_create_tree( BMVert *eve = BM_vert_at_index(em->bm, i); BLI_bvhtree_insert(tree, i, eve->co, 1); } - BLI_assert(BLI_bvhtree_get_size(tree) == verts_num_active); + BLI_assert(BLI_bvhtree_get_len(tree) == verts_num_active); BLI_bvhtree_balance(tree); } @@ -440,7 +440,7 @@ static BVHTree *bvhtree_from_mesh_verts_create_tree( } BLI_bvhtree_insert(tree, i, vert[i].co, 1); } - BLI_assert(BLI_bvhtree_get_size(tree) == verts_num_active); + BLI_assert(BLI_bvhtree_get_len(tree) == verts_num_active); BLI_bvhtree_balance(tree); } @@ -612,7 +612,7 @@ static BVHTree *bvhtree_from_editmesh_edges_create_tree( BLI_bvhtree_insert(tree, i, co[0], 2); } - BLI_assert(BLI_bvhtree_get_size(tree) == edges_num_active); + BLI_assert(BLI_bvhtree_get_len(tree) == edges_num_active); BLI_bvhtree_balance(tree); } @@ -829,7 +829,7 @@ static BVHTree *bvhtree_from_mesh_faces_create_tree( BLI_bvhtree_insert(tree, i, co[0], face[i].v4 ? 4 : 3); } } - BLI_assert(BLI_bvhtree_get_size(tree) == faces_num_active); + BLI_assert(BLI_bvhtree_get_len(tree) == faces_num_active); BLI_bvhtree_balance(tree); } } @@ -990,7 +990,7 @@ static BVHTree *bvhtree_from_editmesh_looptri_create_tree( } } } - BLI_assert(BLI_bvhtree_get_size(tree) == looptri_num_active); + BLI_assert(BLI_bvhtree_get_len(tree) == looptri_num_active); BLI_bvhtree_balance(tree); } } @@ -1032,7 +1032,7 @@ static BVHTree *bvhtree_from_mesh_looptri_create_tree( BLI_bvhtree_insert(tree, i, co[0], 3); } } - BLI_assert(BLI_bvhtree_get_size(tree) == looptri_num_active); + BLI_assert(BLI_bvhtree_get_len(tree) == looptri_num_active); BLI_bvhtree_balance(tree); } } diff --git a/source/blender/blenkernel/intern/cachefile.c b/source/blender/blenkernel/intern/cachefile.c index f8215668034..8f156e8f267 100644 --- a/source/blender/blenkernel/intern/cachefile.c +++ b/source/blender/blenkernel/intern/cachefile.c @@ -42,7 +42,6 @@ #include "BKE_animsys.h" #include "BKE_cachefile.h" -#include "BKE_global.h" #include "BKE_library.h" #include "BKE_main.h" #include "BKE_modifier.h" @@ -181,7 +180,6 @@ void BKE_cachefile_update_frame(Main *bmain, Scene *scene, const float ctime, co ABC_free_handle(cache_file->handle); cache_file->handle = ABC_create_handle(filename, NULL); #endif - break; } } } diff --git a/source/blender/blenkernel/intern/camera.c b/source/blender/blenkernel/intern/camera.c index 869e312614e..8c4bced1563 100644 --- a/source/blender/blenkernel/intern/camera.c +++ b/source/blender/blenkernel/intern/camera.c @@ -48,7 +48,6 @@ #include "BKE_animsys.h" #include "BKE_camera.h" #include "BKE_object.h" -#include "BKE_global.h" #include "BKE_layer.h" #include "BKE_library.h" #include "BKE_library_query.h" @@ -61,8 +60,6 @@ #include "MEM_guardedalloc.h" -#include "GPU_compositing.h" - /****************************** Camera Datablock *****************************/ void BKE_camera_init(Camera *cam) @@ -79,8 +76,6 @@ void BKE_camera_init(Camera *cam) cam->flag |= CAM_SHOWPASSEPARTOUT; cam->passepartalpha = 0.5f; - GPU_fx_compositor_init_dof_settings(&cam->gpu_dof); - /* stereoscopy 3d */ cam->stereo.interocular_distance = 0.065f; cam->stereo.convergence_distance = 30.f * 0.065f; diff --git a/source/blender/blenkernel/intern/cdderivedmesh.c b/source/blender/blenkernel/intern/cdderivedmesh.c index ea54548ab09..a6c6d360769 100644 --- a/source/blender/blenkernel/intern/cdderivedmesh.c +++ b/source/blender/blenkernel/intern/cdderivedmesh.c @@ -3307,7 +3307,7 @@ void CDDM_calc_edges_tessface(DerivedMesh *dm) } } - numEdges = BLI_edgeset_size(eh); + numEdges = BLI_edgeset_len(eh); /* write new edges into a temporary CustomData */ CustomData_reset(&edgeData); @@ -3376,7 +3376,7 @@ void CDDM_calc_edges(DerivedMesh *dm) } } - numEdges = BLI_edgehash_size(eh); + numEdges = BLI_edgehash_len(eh); /* write new edges into a temporary CustomData */ CustomData_reset(&edgeData); diff --git a/source/blender/blenkernel/intern/cloth.c b/source/blender/blenkernel/intern/cloth.c index 09b793629f7..339dcc4a62e 100644 --- a/source/blender/blenkernel/intern/cloth.c +++ b/source/blender/blenkernel/intern/cloth.c @@ -40,6 +40,8 @@ #include "BLI_edgehash.h" #include "BLI_linklist.h" +#include "DEG_depsgraph.h" + #include "BKE_cdderivedmesh.h" #include "BKE_cloth.h" #include "BKE_effect.h" @@ -478,8 +480,6 @@ void clothModifier_do(ClothModifierData *clmd, const struct EvaluationContext *e return; } - return; - /* if on second frame, write cache for first frame */ if (cache->simframe == startframe && (cache->flag & PTCACHE_OUTDATED || cache->last_exact==0)) BKE_ptcache_write(&pid, startframe); @@ -639,7 +639,7 @@ void cloth_free_modifier_extern(ClothModifierData *clmd ) **/ static void cloth_to_object (Object *ob, ClothModifierData *clmd, float (*vertexCos)[3]) { - unsigned int i = 0; + unsigned int i = 0; Cloth *cloth = clmd->clothObject; if (clmd->clothObject) { diff --git a/source/blender/blenkernel/intern/collection.c b/source/blender/blenkernel/intern/collection.c index ca77969ccaa..15fda8a9786 100644 --- a/source/blender/blenkernel/intern/collection.c +++ b/source/blender/blenkernel/intern/collection.c @@ -68,44 +68,67 @@ static SceneCollection *collection_master_from_id(const ID *owner_id) } /** - * Add a collection to a collection ListBase and syncronize all render layers - * The ListBase is NULL when the collection is to be added to the master collection + * The automatic/fallback name of a new collection. */ -SceneCollection *BKE_collection_add(ID *owner_id, SceneCollection *sc_parent, const int type, const char *name_custom) +void BKE_collection_new_name_get(ID *owner_id, SceneCollection *sc_parent, char *rname) +{ + SceneCollection *sc_master = collection_master_from_id(owner_id); + char *name; + + if (sc_parent == sc_master) { + name = BLI_sprintfN("Collection %d", BLI_listbase_count(&sc_master->scene_collections) + 1); + } + else { + const int number = BLI_listbase_count(&sc_parent->scene_collections) + 1; + const int digits = integer_digits_i(number); + const int max_len = sizeof(sc_parent->name) - 1 /* NULL terminator */ - (1 + digits) /* " %d" */; + name = BLI_sprintfN("%.*s %d", max_len, sc_parent->name, number); + } + + BLI_strncpy(rname, name, MAX_NAME); + MEM_freeN(name); +} + +/** + * Add a new collection, but don't handle syncing with layer collections + */ +static SceneCollection *collection_add(ID *owner_id, SceneCollection *sc_parent, const int type, const char *name_custom) { SceneCollection *sc_master = collection_master_from_id(owner_id); SceneCollection *sc = MEM_callocN(sizeof(SceneCollection), "New Collection"); sc->type = type; - const char *name = name_custom; + char name[MAX_NAME]; if (!sc_parent) { sc_parent = sc_master; } - if (!name) { - if (sc_parent == sc_master) { - name = BLI_sprintfN("Collection %d", BLI_listbase_count(&sc_master->scene_collections) + 1); - } - else { - const int number = BLI_listbase_count(&sc_parent->scene_collections) + 1; - const int digits = integer_digits_i(number); - const int max_len = sizeof(sc_parent->name) - - 1 /* NULL terminator */ - - (1 + digits) /* " %d" */; - name = BLI_sprintfN("%.*s %d", max_len, sc_parent->name, number); - } + if (name_custom != NULL) { + BLI_strncpy(name, name_custom, MAX_NAME); + } + else { + BKE_collection_new_name_get(owner_id, sc_parent, name); } BLI_addtail(&sc_parent->scene_collections, sc); - BKE_collection_rename((Scene *)owner_id, sc, name); + BKE_collection_rename(owner_id, sc, name); - BKE_layer_sync_new_scene_collection(owner_id, sc_parent, sc); + return sc; +} - if (name != name_custom) { - MEM_freeN((char *)name); +/** + * Add a collection to a collection ListBase and syncronize all render layers + * The ListBase is NULL when the collection is to be added to the master collection + */ +SceneCollection *BKE_collection_add(ID *owner_id, SceneCollection *sc_parent, const int type, const char *name_custom) +{ + if (sc_parent == NULL) { + sc_parent = BKE_collection_master(owner_id); } - return sc; + SceneCollection *scene_collection = collection_add(owner_id, sc_parent, type, name_custom); + BKE_layer_sync_new_scene_collection(owner_id, sc_parent, scene_collection); + return scene_collection; } /** @@ -208,7 +231,7 @@ bool BKE_collection_remove(ID *owner_id, SceneCollection *sc) ListBase collection_objects; BLI_duplicatelist(&collection_objects, &sc->objects); - FOREACH_SCENE_COLLECTION(owner_id, scene_collection_iter) + FOREACH_SCENE_COLLECTION_BEGIN(owner_id, scene_collection_iter) { if (scene_collection_iter == sc) { continue; @@ -226,7 +249,7 @@ bool BKE_collection_remove(ID *owner_id, SceneCollection *sc) link = link_next; } } - FOREACH_SCENE_COLLECTION_END + FOREACH_SCENE_COLLECTION_END; for (LinkData *link = collection_objects.first; link; link = link->next) { BKE_collection_object_add(owner_id, sc_master, link->data); @@ -270,6 +293,43 @@ void BKE_collection_copy_data(SceneCollection *sc_dst, SceneCollection *sc_src, } } +/** + * Makes a shallow copy of a SceneCollection + * + * Add a new collection in the same level as the old one, copy any nested collections + * but link the objects to the new collection (as oppose to copy them). + */ +SceneCollection *BKE_collection_duplicate(ID *owner_id, SceneCollection *scene_collection) +{ + SceneCollection *scene_collection_master = BKE_collection_master(owner_id); + SceneCollection *scene_collection_parent = find_collection_parent(scene_collection, scene_collection_master); + + /* It's not allowed to copy the master collection. */ + if (scene_collection_master == scene_collection) { + return NULL; + } + + SceneCollection *scene_collection_new = collection_add( + owner_id, + scene_collection_parent, + scene_collection->type, + scene_collection->name); + + if (scene_collection_new != scene_collection->next) { + BLI_remlink(&scene_collection_parent->scene_collections, scene_collection_new); + BLI_insertlinkafter(&scene_collection_parent->scene_collections, scene_collection, scene_collection_new); + } + + BKE_collection_copy_data(scene_collection_new, scene_collection, 0); + BKE_layer_sync_new_scene_collection(owner_id, scene_collection_parent, scene_collection_new); + + /* Make sure every linked instance of the new collection has the same values (flags, overrides, ...) as the + * corresponding original collection. */ + BKE_layer_collection_sync_flags(owner_id, scene_collection_new, scene_collection); + + return scene_collection_new; +} + static SceneCollection *master_collection_from_id(const ID *owner_id) { switch (GS(owner_id->name)) { @@ -298,9 +358,9 @@ static void collection_rename(const ID *owner_id, SceneCollection *sc, const cha BLI_uniquename(&sc_parent->scene_collections, sc, DATA_("Collection"), '.', offsetof(SceneCollection, name), sizeof(sc->name)); } -void BKE_collection_rename(const Scene *scene, SceneCollection *sc, const char *name) +void BKE_collection_rename(const ID *owner_id, SceneCollection *sc, const char *name) { - collection_rename(&scene->id, sc, name); + collection_rename(owner_id, sc, name); } /** @@ -343,7 +403,7 @@ static void collection_object_add(const ID *owner_id, SceneCollection *sc, Objec */ bool BKE_collection_object_add(const ID *owner_id, SceneCollection *sc, Object *ob) { - if (BLI_findptr(&sc->objects, ob, offsetof(LinkData, data))) { + if (BKE_collection_object_exists(sc, ob)) { /* don't add the same object twice */ return false; } @@ -358,13 +418,13 @@ bool BKE_collection_object_add(const ID *owner_id, SceneCollection *sc, Object * */ void BKE_collection_object_add_from(Scene *scene, Object *ob_src, Object *ob_dst) { - FOREACH_SCENE_COLLECTION(scene, sc) + FOREACH_SCENE_COLLECTION_BEGIN(scene, sc) { if (BLI_findptr(&sc->objects, ob_src, offsetof(LinkData, data))) { collection_object_add(&scene->id, sc, ob_dst); } } - FOREACH_SCENE_COLLECTION_END + FOREACH_SCENE_COLLECTION_END; for (ViewLayer *view_layer = scene->view_layers.first; view_layer; view_layer = view_layer->next) { Base *base_src = BKE_view_layer_base_find(view_layer, ob_src); @@ -411,13 +471,28 @@ bool BKE_collection_object_remove(Main *bmain, ID *owner_id, SceneCollection *sc } /** - * Move object from a collection into another + * Remove object from all collections of scene + * \param scene_collection_skip: Don't remove base from this collection. */ -void BKE_collection_object_move(ID *owner_id, SceneCollection *sc_dst, SceneCollection *sc_src, Object *ob) +static bool collections_object_remove_ex(Main *bmain, ID *owner_id, Object *ob, const bool free_us, + SceneCollection *scene_collection_skip) { - if (BKE_collection_object_add(owner_id, sc_dst, ob)) { - BKE_collection_object_remove(NULL, owner_id, sc_src, ob, false); + bool removed = false; + if (GS(owner_id->name) == ID_SCE) { + BKE_scene_remove_rigidbody_object((Scene *)owner_id, ob); } + else { + BLI_assert(GS(owner_id->name) == ID_GR); + } + + FOREACH_SCENE_COLLECTION_BEGIN(owner_id, sc) + { + if (sc != scene_collection_skip) { + removed |= BKE_collection_object_remove(bmain, owner_id, sc, ob, free_us); + } + } + FOREACH_SCENE_COLLECTION_END; + return removed; } /** @@ -425,20 +500,72 @@ void BKE_collection_object_move(ID *owner_id, SceneCollection *sc_dst, SceneColl */ bool BKE_collections_object_remove(Main *bmain, ID *owner_id, Object *ob, const bool free_us) { - bool removed = false; - if (GS(owner_id->name) == ID_SCE) { - BKE_scene_remove_rigidbody_object((Scene *)owner_id, ob); + return collections_object_remove_ex(bmain, owner_id, ob, free_us, NULL); +} + +/** + * Move object from a collection into another + * + * If source collection is NULL move it from all the existing collections. + */ +void BKE_collection_object_move(ID *owner_id, SceneCollection *sc_dst, SceneCollection *sc_src, Object *ob) +{ + /* In both cases we first add the object, then remove it from the other collections. + * Otherwise we lose the original base and whether it was active and selected. */ + if (sc_src != NULL) { + if (BKE_collection_object_add(owner_id, sc_dst, ob)) { + BKE_collection_object_remove(NULL, owner_id, sc_src, ob, false); + } } else { - BLI_assert(GS(owner_id->name) == ID_GR); + /* Adding will fail if object is already in collection. + * However we still need to remove it from the other collections. */ + BKE_collection_object_add(owner_id, sc_dst, ob); + collections_object_remove_ex(NULL, owner_id, ob, false, sc_dst); + } +} + +/** + * Whether the object is directly inside the collection. + */ +bool BKE_collection_object_exists(struct SceneCollection *scene_collection, struct Object *ob) +{ + if (BLI_findptr(&scene_collection->objects, ob, offsetof(LinkData, data))) { + return true; } + return false; +} - FOREACH_SCENE_COLLECTION(owner_id, sc) +static SceneCollection *scene_collection_from_index_recursive(SceneCollection *scene_collection, const int index, int *index_current) +{ + if (index == (*index_current)) { + return scene_collection; + } + + (*index_current)++; + + for (SceneCollection *scene_collection_iter = scene_collection->scene_collections.first; + scene_collection_iter != NULL; + scene_collection_iter = scene_collection_iter->next) { - removed |= BKE_collection_object_remove(bmain, owner_id, sc, ob, free_us); + SceneCollection *nested = scene_collection_from_index_recursive(scene_collection_iter, index, index_current); + if (nested != NULL) { + return nested; + } } - FOREACH_SCENE_COLLECTION_END - return removed; + return NULL; +} + +/** + * Return Scene Collection for a given index. + * + * The index is calculated from top to bottom counting the children before the siblings. + */ +SceneCollection *BKE_collection_from_index(Scene *scene, const int index) +{ + int index_current = 0; + SceneCollection *master_collection = BKE_collection_master(&scene->id); + return scene_collection_from_index_recursive(master_collection, index, &index_current); } static void layer_collection_sync(LayerCollection *lc_dst, LayerCollection *lc_src) @@ -460,6 +587,33 @@ static void layer_collection_sync(LayerCollection *lc_dst, LayerCollection *lc_s } /** + * Select all the objects in this SceneCollection (and its nested collections) for this ViewLayer. + * Return true if any object was selected. + */ +bool BKE_collection_objects_select(ViewLayer *view_layer, SceneCollection *scene_collection) +{ + LayerCollection *layer_collection = BKE_layer_collection_first_from_scene_collection(view_layer, scene_collection); + if (layer_collection != NULL) { + BKE_layer_collection_objects_select(layer_collection); + return true; + } + else { + /* Slower approach, we need to iterate over all the objects and for each one we see if there is a base. */ + bool changed = false; + for (LinkData *link = scene_collection->objects.first; link; link = link->next) { + Base *base = BKE_view_layer_base_find(view_layer, link->data); + if (base != NULL) { + if (((base->flag & BASE_SELECTED) == 0) && ((base->flag & BASE_SELECTABLED) != 0)) { + base->flag |= BASE_SELECTED; + changed = true; + } + } + } + return changed; + } +} + +/** * Leave only the master collection in, remove everything else. * @param group */ @@ -505,11 +659,11 @@ Group *BKE_collection_group_create(Main *bmain, Scene *scene, LayerCollection *l sc_dst = BKE_collection_add(&group->id, NULL, COLLECTION_TYPE_GROUP_INTERNAL, sc_src->name); BKE_collection_copy_data(sc_dst, sc_src, 0); - FOREACH_SCENE_COLLECTION(&group->id, sc_group) + FOREACH_SCENE_COLLECTION_BEGIN(&group->id, sc_group) { sc_group->type = COLLECTION_TYPE_GROUP_INTERNAL; } - FOREACH_SCENE_COLLECTION_END + FOREACH_SCENE_COLLECTION_END; lc_dst = BKE_collection_link(group->view_layer, sc_dst); layer_collection_sync(lc_dst, lc_src); diff --git a/source/blender/blenkernel/intern/collision.c b/source/blender/blenkernel/intern/collision.c index 2f80fbbec46..ee3c38b9282 100644 --- a/source/blender/blenkernel/intern/collision.c +++ b/source/blender/blenkernel/intern/collision.c @@ -36,7 +36,7 @@ #include "DNA_effect_types.h" #include "DNA_group_types.h" #include "DNA_object_types.h" -#include "DNA_object_force.h" +#include "DNA_object_force_types.h" #include "DNA_scene_types.h" #include "DNA_meshdata_types.h" @@ -180,8 +180,8 @@ static void collision_compute_barycentric ( float pv[3], float p1[3], float p2[3 /* dot_v3v3 */ #define INPR(v1, v2) ( (v1)[0] * (v2)[0] + (v1)[1] * (v2)[1] + (v1)[2] * (v2)[2]) - double tempV1[3], tempV2[3], tempV4[3]; - double a, b, c, d, e, f; + double tempV1[3], tempV2[3], tempV4[3]; + double a, b, c, d, e, f; VECSUB ( tempV1, p1, p3 ); VECSUB ( tempV2, p2, p3 ); @@ -506,11 +506,11 @@ static void add_collision_object(Object ***objs, unsigned int *numobj, unsigned Group *group= ob->dup_group; /* add objects */ - FOREACH_GROUP_OBJECT(group, object) + FOREACH_GROUP_OBJECT_BEGIN(group, object) { add_collision_object(objs, numobj, maxobj, object, self, level+1, modifier_type); } - FOREACH_GROUP_OBJECT_END + FOREACH_GROUP_OBJECT_END; } } @@ -527,11 +527,11 @@ Object **get_collisionobjects_ext(Scene *scene, Object *self, Group *group, unsi /* gather all collision objects */ if (group) { /* use specified group */ - FOREACH_GROUP_OBJECT(group, object) + FOREACH_GROUP_OBJECT_BEGIN(group, object) { add_collision_object(&objs, &numobj, &maxobj, object, self, level, modifier_type); } - FOREACH_GROUP_OBJECT_END + FOREACH_GROUP_OBJECT_END; } else { Scene *sce_iter; @@ -584,11 +584,11 @@ static void add_collider_cache_object(ListBase **objs, Object *ob, Object *self, Group *group= ob->dup_group; /* add objects */ - FOREACH_GROUP_OBJECT(group, object) + FOREACH_GROUP_OBJECT_BEGIN(group, object) { add_collider_cache_object(objs, object, self, level+1); } - FOREACH_GROUP_OBJECT_END + FOREACH_GROUP_OBJECT_END; } } @@ -598,11 +598,11 @@ ListBase *get_collider_cache(Scene *scene, Object *self, Group *group) /* add object in same layer in scene */ if (group) { - FOREACH_GROUP_OBJECT(group, object) + FOREACH_GROUP_OBJECT_BEGIN(group, object) { add_collider_cache_object(&objs, object, self, 0); } - FOREACH_GROUP_OBJECT_END + FOREACH_GROUP_OBJECT_END; } else { Scene *sce_iter; diff --git a/source/blender/blenkernel/intern/colorband.c b/source/blender/blenkernel/intern/colorband.c index d35e797ddac..f72d4df725a 100644 --- a/source/blender/blenkernel/intern/colorband.c +++ b/source/blender/blenkernel/intern/colorband.c @@ -210,7 +210,7 @@ static void colorband_init_from_table_rgba_resample( while ((carr_len > 1 && !BLI_heap_is_empty(heap)) && ((carr_len >= MAXCOLORBAND) || (BLI_heap_node_value(BLI_heap_top(heap)) <= eps_2x))) { - c = BLI_heap_popmin(heap); + c = BLI_heap_pop_min(heap); struct ColorResampleElem *c_next = c->next, *c_prev = c->prev; c_prev->next = c_next; c_next->prev = c_prev; diff --git a/source/blender/blenkernel/intern/constraint.c b/source/blender/blenkernel/intern/constraint.c index b8dc7944a75..b070ccdd4eb 100644 --- a/source/blender/blenkernel/intern/constraint.c +++ b/source/blender/blenkernel/intern/constraint.c @@ -1917,14 +1917,15 @@ static void samevolume_evaluate(bConstraint *con, bConstraintOb *cob, ListBase * bSameVolumeConstraint *data = con->data; float volume = data->volume; - float fac = 1.0f; + float fac = 1.0f, total_scale; float obsize[3]; mat4_to_size(obsize, cob->matrix); /* calculate normalizing scale factor for non-essential values */ - if (obsize[data->flag] != 0) - fac = sqrtf(volume / obsize[data->flag]); + total_scale = obsize[0] * obsize[1] * obsize[2]; + if (total_scale != 0) + fac = sqrtf(volume / total_scale); /* apply scaling factor to the channels not being kept */ switch (data->flag) { diff --git a/source/blender/blenkernel/intern/context.c b/source/blender/blenkernel/intern/context.c index 09823a8b463..809db09eb86 100644 --- a/source/blender/blenkernel/intern/context.c +++ b/source/blender/blenkernel/intern/context.c @@ -997,7 +997,7 @@ SceneCollection *CTX_data_scene_collection(const bContext *C) return BKE_collection_master(&scene->id); } -int CTX_data_mode_enum_ex(const Object *obedit, const Object *ob) +int CTX_data_mode_enum_ex(const Object *obedit, const Object *ob, const eObjectMode object_mode) { // Object *obedit = CTX_data_edit_object(C); if (obedit) { @@ -1023,12 +1023,12 @@ int CTX_data_mode_enum_ex(const Object *obedit, const Object *ob) else { // Object *ob = CTX_data_active_object(C); if (ob) { - if (ob->mode & OB_MODE_POSE) return CTX_MODE_POSE; - else if (ob->mode & OB_MODE_SCULPT) return CTX_MODE_SCULPT; - else if (ob->mode & OB_MODE_WEIGHT_PAINT) return CTX_MODE_PAINT_WEIGHT; - else if (ob->mode & OB_MODE_VERTEX_PAINT) return CTX_MODE_PAINT_VERTEX; - else if (ob->mode & OB_MODE_TEXTURE_PAINT) return CTX_MODE_PAINT_TEXTURE; - else if (ob->mode & OB_MODE_PARTICLE_EDIT) return CTX_MODE_PARTICLE; + if (object_mode & OB_MODE_POSE) return CTX_MODE_POSE; + else if (object_mode & OB_MODE_SCULPT) return CTX_MODE_SCULPT; + else if (object_mode & OB_MODE_WEIGHT_PAINT) return CTX_MODE_PAINT_WEIGHT; + else if (object_mode & OB_MODE_VERTEX_PAINT) return CTX_MODE_PAINT_VERTEX; + else if (object_mode & OB_MODE_TEXTURE_PAINT) return CTX_MODE_PAINT_TEXTURE; + else if (object_mode & OB_MODE_PARTICLE_EDIT) return CTX_MODE_PARTICLE; } } @@ -1039,7 +1039,7 @@ int CTX_data_mode_enum(const bContext *C) { Object *obedit = CTX_data_edit_object(C); Object *obact = obedit ? NULL : CTX_data_active_object(C); - return CTX_data_mode_enum_ex(obedit, obact); + return CTX_data_mode_enum_ex(obedit, obact, obact ? obact->mode : OB_MODE_OBJECT); } /* would prefer if we can use the enum version below over this one - Campbell */ @@ -1276,8 +1276,8 @@ void CTX_data_eval_ctx(const bContext *C, EvaluationContext *eval_ctx) Scene *scene = CTX_data_scene(C); ViewLayer *view_layer = CTX_data_view_layer(C); - RenderEngineType *engine_type = CTX_data_engine_type(C); - DEG_evaluation_context_init_from_scene(eval_ctx, - scene, view_layer, engine_type, - DAG_EVAL_VIEWPORT); + DEG_evaluation_context_init_from_scene( + eval_ctx, + scene, view_layer, + DAG_EVAL_VIEWPORT); } diff --git a/source/blender/blenkernel/intern/curve.c b/source/blender/blenkernel/intern/curve.c index 2a27bad0fb5..0c4dbdf7763 100644 --- a/source/blender/blenkernel/intern/curve.c +++ b/source/blender/blenkernel/intern/curve.c @@ -5258,9 +5258,7 @@ void BKE_curve_rect_from_textbox(const struct Curve *cu, const struct TextBox *t void BKE_curve_eval_geometry(const EvaluationContext *UNUSED(eval_ctx), Curve *curve) { - if (G.debug & G_DEBUG_DEPSGRAPH) { - printf("%s on %s\n", __func__, curve->id.name); - } + DEG_debug_print_eval(__func__, curve->id.name, curve); if (curve->bb == NULL || (curve->bb->flag & BOUNDBOX_DIRTY)) { BKE_curve_texspace_calc(curve); } diff --git a/source/blender/blenkernel/intern/curve_decimate.c b/source/blender/blenkernel/intern/curve_decimate.c index 7983c63c99d..1a6c4714afd 100644 --- a/source/blender/blenkernel/intern/curve_decimate.c +++ b/source/blender/blenkernel/intern/curve_decimate.c @@ -159,7 +159,7 @@ static void curve_decimate( struct Knot *k; { - struct Removal *r = BLI_heap_popmin(heap); + struct Removal *r = BLI_heap_pop_min(heap); k = &knots[r->knot_index]; k->heap_node = NULL; k->prev->handles[1] = r->handles[0]; diff --git a/source/blender/blenkernel/intern/displist.c b/source/blender/blenkernel/intern/displist.c index 15a520fe8ce..ffa4e652056 100644 --- a/source/blender/blenkernel/intern/displist.c +++ b/source/blender/blenkernel/intern/displist.c @@ -299,7 +299,10 @@ bool BKE_displist_surfindex_get(DispList *dl, int a, int *b, int *p1, int *p2, i } /* ****************** make displists ********************* */ - +#ifdef __INTEL_COMPILER +/* ICC with the optimization -02 causes crashes. */ +# pragma intel optimization_level 1 +#endif static void curve_to_displist(Curve *cu, ListBase *nubase, ListBase *dispbase, const bool for_render, const bool use_render_resolution) { diff --git a/source/blender/blenkernel/intern/dynamicpaint.c b/source/blender/blenkernel/intern/dynamicpaint.c index 2591c3c3c47..ee678dd4c41 100644 --- a/source/blender/blenkernel/intern/dynamicpaint.c +++ b/source/blender/blenkernel/intern/dynamicpaint.c @@ -54,7 +54,7 @@ #include "BKE_animsys.h" #include "BKE_armature.h" -#include "BKE_bvhutils.h" /* bvh tree */ +#include "BKE_bvhutils.h" /* bvh tree */ #include "BKE_colorband.h" #include "BKE_cdderivedmesh.h" #include "BKE_constraint.h" @@ -3348,7 +3348,7 @@ typedef struct BrushMaterials { /* Initialize materials for brush object: * Calculates inverse matrices for linked objects, updates * volume caches etc. */ -static void dynamicPaint_updateBrushMaterials(Object *brushOb, Material *ui_mat, Scene *scene, BrushMaterials *bMats) +static void dynamicPaint_updateBrushMaterials(const EvaluationContext *eval_ctx, Object *brushOb, Material *ui_mat, Scene *scene, BrushMaterials *bMats) { /* Calculate inverse transformation matrix * for this object */ @@ -3363,13 +3363,13 @@ static void dynamicPaint_updateBrushMaterials(Object *brushOb, Material *ui_mat, if (tot) { bMats->ob_mats = MEM_callocN(sizeof(Material *) * (tot), "BrushMaterials"); for (i = 0; i < tot; i++) { - bMats->ob_mats[i] = RE_sample_material_init(give_current_material(brushOb, (i + 1)), scene); + bMats->ob_mats[i] = RE_sample_material_init(eval_ctx, give_current_material(brushOb, (i + 1)), scene); } } bMats->tot = tot; } else { - bMats->mat = RE_sample_material_init(ui_mat, scene); + bMats->mat = RE_sample_material_init(eval_ctx, ui_mat, scene); } } @@ -4516,7 +4516,7 @@ static int dynamicPaint_paintParticles(DynamicPaintSurface *surface, */ tree = BLI_kdtree_new(psys->totpart); - /* loop through particles and insert valid ones to the tree */ + /* loop through particles and insert valid ones to the tree */ p = 0; for (ParticleData *pa = psys->particles; p < psys->totpart; p++, pa++) { /* Proceed only if particle is active */ @@ -4555,7 +4555,7 @@ static int dynamicPaint_paintParticles(DynamicPaintSurface *surface, } /* begin thread safe malloc */ - BLI_begin_threaded_malloc(); + BLI_threaded_malloc_begin(); /* only continue if particle bb is close enough to canvas bb */ if (boundsIntersectDist(&grid->grid_bounds, &part_bb, range)) { @@ -4590,7 +4590,7 @@ static int dynamicPaint_paintParticles(DynamicPaintSurface *surface, &settings); } } - BLI_end_threaded_malloc(); + BLI_threaded_malloc_end(); BLI_kdtree_free(tree); return 1; @@ -6087,7 +6087,7 @@ static int dynamicPaint_doStep(const struct EvaluationContext *eval_ctx, Scene * } /* Prepare materials if required */ if (brush_usesMaterial(brush, scene)) - dynamicPaint_updateBrushMaterials(brushObj, brush->mat, scene, &bMats); + dynamicPaint_updateBrushMaterials(eval_ctx, brushObj, brush->mat, scene, &bMats); /* Apply brush on the surface depending on it's collision type */ if (brush->psys && brush->psys->part && diff --git a/source/blender/blenkernel/intern/editderivedmesh.c b/source/blender/blenkernel/intern/editderivedmesh.c index 0491cbd21f0..2018962eb62 100644 --- a/source/blender/blenkernel/intern/editderivedmesh.c +++ b/source/blender/blenkernel/intern/editderivedmesh.c @@ -44,7 +44,7 @@ #include "atomic_ops.h" #include "BLI_math.h" -#include "BLI_jitter.h" +#include "BLI_jitter_2d.h" #include "BLI_bitmap.h" #include "BLI_task.h" diff --git a/source/blender/blenkernel/intern/editlattice.c b/source/blender/blenkernel/intern/editlattice.c new file mode 100644 index 00000000000..cef3c970c7a --- /dev/null +++ b/source/blender/blenkernel/intern/editlattice.c @@ -0,0 +1,147 @@ +/* + * ***** 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. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/blenkernel/intern/editlattice.c + * \ingroup bke + */ + +#include "MEM_guardedalloc.h" + +#include "DNA_listBase.h" +#include "DNA_object_types.h" +#include "DNA_key_types.h" +#include "DNA_lattice_types.h" +#include "DNA_meshdata_types.h" +#include "DNA_curve_types.h" + +#include "BLI_math_vector.h" +#include "BLI_listbase.h" + +#include "BKE_deform.h" +#include "BKE_key.h" + +#include "BKE_editlattice.h" /* own include */ + +void BKE_editlattice_free(Object *ob) +{ + Lattice *lt = ob->data; + + if (lt->editlatt) { + Lattice *editlt = lt->editlatt->latt; + + if (editlt->def) { + MEM_freeN(editlt->def); + } + if (editlt->dvert) { + BKE_defvert_array_free(editlt->dvert, editlt->pntsu * editlt->pntsv * editlt->pntsw); + } + MEM_freeN(editlt); + MEM_freeN(lt->editlatt); + + lt->editlatt = NULL; + } +} + +void BKE_editlattice_make(Object *obedit) +{ + Lattice *lt = obedit->data; + KeyBlock *actkey; + + BKE_editlattice_free(obedit); + + actkey = BKE_keyblock_from_object(obedit); + if (actkey) { + BKE_keyblock_convert_to_lattice(actkey, lt); + } + lt->editlatt = MEM_callocN(sizeof(EditLatt), "editlatt"); + lt->editlatt->latt = MEM_dupallocN(lt); + lt->editlatt->latt->def = MEM_dupallocN(lt->def); + + if (lt->dvert) { + int tot = lt->pntsu * lt->pntsv * lt->pntsw; + lt->editlatt->latt->dvert = MEM_mallocN(sizeof(MDeformVert) * tot, "Lattice MDeformVert"); + BKE_defvert_array_copy(lt->editlatt->latt->dvert, lt->dvert, tot); + } + + if (lt->key) { + lt->editlatt->shapenr = obedit->shapenr; + } +} + +void BKE_editlattice_load(Object *obedit) +{ + Lattice *lt, *editlt; + KeyBlock *actkey; + BPoint *bp; + float *fp; + int tot; + + lt = obedit->data; + editlt = lt->editlatt->latt; + + if (lt->editlatt->shapenr) { + actkey = BLI_findlink(<->key->block, lt->editlatt->shapenr - 1); + + /* active key: vertices */ + tot = editlt->pntsu * editlt->pntsv * editlt->pntsw; + + if (actkey->data) { + MEM_freeN(actkey->data); + } + + fp = actkey->data = MEM_callocN(lt->key->elemsize * tot, "actkey->data"); + actkey->totelem = tot; + + bp = editlt->def; + while (tot--) { + copy_v3_v3(fp, bp->vec); + fp += 3; + bp++; + } + } + else { + MEM_freeN(lt->def); + + lt->def = MEM_dupallocN(editlt->def); + + lt->flag = editlt->flag; + + lt->pntsu = editlt->pntsu; + lt->pntsv = editlt->pntsv; + lt->pntsw = editlt->pntsw; + + lt->typeu = editlt->typeu; + lt->typev = editlt->typev; + lt->typew = editlt->typew; + lt->actbp = editlt->actbp; + } + + if (lt->dvert) { + BKE_defvert_array_free(lt->dvert, lt->pntsu * lt->pntsv * lt->pntsw); + lt->dvert = NULL; + } + + if (editlt->dvert) { + tot = lt->pntsu * lt->pntsv * lt->pntsw; + + lt->dvert = MEM_mallocN(sizeof(MDeformVert) * tot, "Lattice MDeformVert"); + BKE_defvert_array_copy(lt->dvert, editlt->dvert, tot); + } +} diff --git a/source/blender/blenkernel/intern/effect.c b/source/blender/blenkernel/intern/effect.c index 16124fb4777..b54093555f5 100644 --- a/source/blender/blenkernel/intern/effect.c +++ b/source/blender/blenkernel/intern/effect.c @@ -42,7 +42,7 @@ #include "DNA_listBase.h" #include "DNA_meshdata_types.h" #include "DNA_object_types.h" -#include "DNA_object_force.h" +#include "DNA_object_force_types.h" #include "DNA_particle_types.h" #include "DNA_texture_types.h" #include "DNA_scene_types.h" @@ -221,7 +221,8 @@ ListBase *pdInitEffectors( if (weights->group) { view_layer = weights->group->view_layer; } - else if (eval_ctx) { + /* TODO(mai): the check for view_layer shouldnt be needed, remove when render engine api is updated for this */ + else if (eval_ctx && eval_ctx->view_layer) { view_layer = eval_ctx->view_layer; } else { diff --git a/source/blender/blenkernel/intern/fcurve.c b/source/blender/blenkernel/intern/fcurve.c index 9c85a26b58a..905f103250a 100644 --- a/source/blender/blenkernel/intern/fcurve.c +++ b/source/blender/blenkernel/intern/fcurve.c @@ -804,7 +804,7 @@ void bezt_add_to_cfra_elem(ListBase *lb, BezTriple *bezt) for (ce = lb->first; ce; ce = ce->next) { /* double key? */ - if (ce->cfra == bezt->vec[1][0]) { + if (IS_EQT(ce->cfra, bezt->vec[1][0], BEZT_BINARYSEARCH_THRESH)) { if (bezt->f2 & SELECT) ce->sel = bezt->f2; return; } @@ -1590,11 +1590,9 @@ static float dvar_eval_transChan(ChannelDriver *driver, DriverVar *dvar) return 0.0f; } else if (dtar->transChan >= DTAR_TRANSCHAN_SCALEX) { - /* extract scale, and choose the right axis */ - float scale[3]; - - mat4_to_size(scale, mat); - return scale[dtar->transChan - DTAR_TRANSCHAN_SCALEX]; + /* Extract scale, and choose the right axis, + * inline 'mat4_to_size'. */ + return len_v3(mat[dtar->transChan - DTAR_TRANSCHAN_SCALEX]); } else if (dtar->transChan >= DTAR_TRANSCHAN_ROTX) { /* extract rotation as eulers (if needed) diff --git a/source/blender/blenkernel/intern/fluidsim.c b/source/blender/blenkernel/intern/fluidsim.c index 12b9abc6d03..d0d3317b477 100644 --- a/source/blender/blenkernel/intern/fluidsim.c +++ b/source/blender/blenkernel/intern/fluidsim.c @@ -40,8 +40,8 @@ #include "DNA_mesh_types.h" #include "DNA_meshdata_types.h" -#include "DNA_object_fluidsim.h" -#include "DNA_object_force.h" // for pointcache +#include "DNA_object_fluidsim_types.h" +#include "DNA_object_force_types.h" // for pointcache #include "DNA_object_types.h" #include "DNA_particle_types.h" #include "DNA_scene_types.h" @@ -54,7 +54,6 @@ #include "BKE_customdata.h" #include "BKE_DerivedMesh.h" #include "BKE_fluidsim.h" -#include "BKE_global.h" #include "BKE_modifier.h" #include "BKE_mesh.h" diff --git a/source/blender/blenkernel/intern/font.c b/source/blender/blenkernel/intern/font.c index a314cc0a131..5545eba8764 100644 --- a/source/blender/blenkernel/intern/font.c +++ b/source/blender/blenkernel/intern/font.c @@ -1080,8 +1080,13 @@ makebreak: float distfac, imat[4][4], imat3[3][3], cmat[3][3]; float minx, maxx, miny, maxy; float timeofs, sizefac; - - invert_m4_m4(imat, ob->obmat); + + if (ob != NULL) { + invert_m4_m4(imat, ob->obmat); + } + else { + unit_m4(imat); + } copy_m3_m4(imat3, imat); copy_m3_m4(cmat, cu->textoncurve->obmat); diff --git a/source/blender/blenkernel/intern/group.c b/source/blender/blenkernel/intern/group.c index ca6d92efa80..7566d370c45 100644 --- a/source/blender/blenkernel/intern/group.c +++ b/source/blender/blenkernel/intern/group.c @@ -55,7 +55,7 @@ #include "BKE_object.h" #include "BKE_scene.h" -#define DEBUG_PRINT if (G.debug & G_DEBUG_DEPSGRAPH) printf +#include "DEG_depsgraph.h" /** Free (or release) any data used by this group (does not free the group itself). */ void BKE_group_free(Group *group) @@ -213,13 +213,13 @@ static bool group_object_cyclic_check_internal(Object *object, Group *group) if (dup_group == group) return true; else { - FOREACH_GROUP_OBJECT(dup_group, group_object) + FOREACH_GROUP_OBJECT_BEGIN(dup_group, group_object) { if (group_object_cyclic_check_internal(group_object, dup_group)) { return true; } } - FOREACH_GROUP_OBJECT_END + FOREACH_GROUP_OBJECT_END; } /* un-flag the object, it's allowed to have the same group multiple times in parallel */ @@ -278,13 +278,13 @@ Group *BKE_group_object_find(Group *group, Object *ob) bool BKE_group_is_animated(Group *group, Object *UNUSED(parent)) { - FOREACH_GROUP_OBJECT(group, object) + FOREACH_GROUP_OBJECT_BEGIN(group, object) { if (object->proxy) { return true; } } - FOREACH_GROUP_OBJECT_END + FOREACH_GROUP_OBJECT_END; return false; } @@ -369,45 +369,21 @@ void BKE_group_handle_recalc_and_update(const struct EvaluationContext *eval_ctx #endif { /* only do existing tags, as set by regular depsgraph */ - FOREACH_GROUP_OBJECT(group, object) + FOREACH_GROUP_OBJECT_BEGIN(group, object) { if (object->id.recalc & ID_RECALC_ALL) { BKE_object_handle_update(eval_ctx, scene, object); } } - FOREACH_GROUP_OBJECT_END + FOREACH_GROUP_OBJECT_END; } } /* ******** Dependency graph evaluation ******** */ -static void group_eval_layer_collections( - const struct EvaluationContext *eval_ctx, - Group *group, - ListBase *layer_collections, - LayerCollection *parent_layer_collection) -{ - BLI_LISTBASE_FOREACH (LayerCollection *, layer_collection, layer_collections) { - /* Evaluate layer collection itself. */ - BKE_layer_eval_layer_collection(eval_ctx, - layer_collection, - parent_layer_collection); - /* Evaluate nested collections. */ - group_eval_layer_collections(eval_ctx, - group, - &layer_collection->layer_collections, - layer_collection); - } -} - void BKE_group_eval_view_layers(const struct EvaluationContext *eval_ctx, Group *group) { - DEBUG_PRINT("%s on %s (%p)\n", __func__, group->id.name, group); - BKE_layer_eval_layer_collection_pre(eval_ctx, &group->id, group->view_layer); - group_eval_layer_collections(eval_ctx, - group, - &group->view_layer->layer_collections, - NULL); - BKE_layer_eval_layer_collection_post(eval_ctx, group->view_layer); + DEG_debug_print_eval(__func__, group->id.name, group); + BKE_layer_eval_view_layer(eval_ctx, &group->id, group->view_layer); } diff --git a/source/blender/blenkernel/intern/icons.c b/source/blender/blenkernel/intern/icons.c index a407fd0bae8..f3ff2c4425a 100644 --- a/source/blender/blenkernel/intern/icons.c +++ b/source/blender/blenkernel/intern/icons.c @@ -433,23 +433,28 @@ void BKE_previewimg_ensure(PreviewImage *prv, const int size) } } -void BKE_icon_changed(int id) +void BKE_icon_changed(const int icon_id) { Icon *icon = NULL; - if (!id || G.background) return; + if (!icon_id || G.background) return; - icon = BLI_ghash_lookup(gIcons, SET_INT_IN_POINTER(id)); + icon = BLI_ghash_lookup(gIcons, SET_INT_IN_POINTER(icon_id)); if (icon) { - PreviewImage *prv = BKE_previewimg_id_ensure((ID *)icon->obj); + /* We *only* expect ID-tied icons here, not non-ID icon/preview! */ + BLI_assert(icon->type != 0); + + /* Do not enforce creation of previews for valid ID types using BKE_previewimg_id_ensure() here , + * we only want to ensure *existing* preview images are properly tagged as changed/invalid, that's all. */ + PreviewImage **p_prv = BKE_previewimg_id_get_p((ID *)icon->obj); - /* all previews changed */ - if (prv) { + /* If we have previews, they all are now invalid changed. */ + if (p_prv && *p_prv) { int i; for (i = 0; i < NUM_ICON_SIZES; ++i) { - prv->flag[i] |= PRV_CHANGED; - prv->changed_timestamp[i]++; + (*p_prv)->flag[i] |= PRV_CHANGED; + (*p_prv)->changed_timestamp[i]++; } } } @@ -549,7 +554,7 @@ int BKE_icon_preview_ensure(ID *id, PreviewImage *preview) return preview->icon_id; } -Icon *BKE_icon_get(int icon_id) +Icon *BKE_icon_get(const int icon_id) { Icon *icon = NULL; @@ -563,7 +568,7 @@ Icon *BKE_icon_get(int icon_id) return icon; } -void BKE_icon_set(int icon_id, struct Icon *icon) +void BKE_icon_set(const int icon_id, struct Icon *icon) { void **val_p; @@ -586,7 +591,7 @@ void BKE_icon_id_delete(struct ID *id) /** * Remove icon and free data. */ -void BKE_icon_delete(int icon_id) +void BKE_icon_delete(const int icon_id) { Icon *icon; diff --git a/source/blender/blenkernel/intern/idprop.c b/source/blender/blenkernel/intern/idprop.c index 33a665ba06e..87e5ed8cc1e 100644 --- a/source/blender/blenkernel/intern/idprop.c +++ b/source/blender/blenkernel/intern/idprop.c @@ -905,9 +905,10 @@ bool IDP_EqualsProperties_ex(IDProperty *prop1, IDProperty *prop2, const bool is if (prop1->len != prop2->len) return false; - for (i = 0; i < prop1->len; i++) - if (!IDP_EqualsProperties(&array1[i], &array2[i])) + for (i = 0; i < prop1->len; i++) { + if (!IDP_EqualsProperties_ex(&array1[i], &array2[i], is_strict)) return false; + } return true; } case IDP_ID: diff --git a/source/blender/blenkernel/intern/image.c b/source/blender/blenkernel/intern/image.c index d720dc41abf..28245f9a4d8 100644 --- a/source/blender/blenkernel/intern/image.c +++ b/source/blender/blenkernel/intern/image.c @@ -46,6 +46,7 @@ #include "IMB_imbuf_types.h" #include "IMB_imbuf.h" #include "IMB_moviecache.h" +#include "IMB_metadata.h" #ifdef WITH_OPENEXR # include "intern/openexr/openexr_multi.h" @@ -152,7 +153,7 @@ static void imagecache_put(Image *image, int index, ImBuf *ibuf) if (image->cache == NULL) { // char cache_name[64]; - // BLI_snprintf(cache_name, sizeof(cache_name), "Image Datablock %s", image->id.name); + // SNPRINTF(cache_name, "Image Datablock %s", image->id.name); image->cache = IMB_moviecache_create("Image Datablock Cache", sizeof(ImageCacheKey), imagecache_hashhash, imagecache_hashcmp); @@ -437,7 +438,7 @@ static void copy_image_packedfiles(ListBase *lb_dst, const ListBase *lb_src) BLI_listbase_clear(lb_dst); for (imapf_src = lb_src->first; imapf_src; imapf_src = imapf_src->next) { ImagePackedFile *imapf_dst = MEM_mallocN(sizeof(ImagePackedFile), "Image Packed Files (copy)"); - BLI_strncpy(imapf_dst->filepath, imapf_src->filepath, sizeof(imapf_dst->filepath)); + STRNCPY(imapf_dst->filepath, imapf_src->filepath); if (imapf_src->packedfile) imapf_dst->packedfile = dupPackedFile(imapf_src->packedfile); @@ -593,7 +594,7 @@ Image *BKE_image_load(Main *bmain, const char *filepath) int file; char str[FILE_MAX]; - BLI_strncpy(str, filepath, sizeof(str)); + STRNCPY(str, filepath); BLI_path_abs(str, bmain->name); /* exists? */ @@ -603,7 +604,7 @@ Image *BKE_image_load(Main *bmain, const char *filepath) close(file); ima = image_alloc(bmain, BLI_path_basename(filepath), IMA_SRC_FILE, IMA_TYPE_IMAGE); - BLI_strncpy(ima->name, filepath, sizeof(ima->name)); + STRNCPY(ima->name, filepath); if (BLI_testextensie_array(filepath, imb_ext_movie)) ima->source = IMA_SRC_MOVIE; @@ -622,13 +623,13 @@ Image *BKE_image_load_exists_ex(const char *filepath, bool *r_exists) Image *ima; char str[FILE_MAX], strtest[FILE_MAX]; - BLI_strncpy(str, filepath, sizeof(str)); + STRNCPY(str, filepath); BLI_path_abs(str, G.main->name); /* first search an identical filepath */ for (ima = G.main->image.first; ima; ima = ima->id.next) { if (ima->source != IMA_SRC_VIEWER && ima->source != IMA_SRC_GENERATED) { - BLI_strncpy(strtest, ima->name, sizeof(ima->name)); + STRNCPY(strtest, ima->name); BLI_path_abs(strtest, ID_BLEND_PATH(G.main, &ima->id)); if (BLI_path_cmp(strtest, str) == 0) { @@ -669,7 +670,7 @@ static ImBuf *add_ibuf_size(unsigned int width, unsigned int height, const char if (colorspace_settings->name[0] == '\0') { const char *colorspace = IMB_colormanagement_role_colorspace_name_get(COLOR_ROLE_DEFAULT_FLOAT); - BLI_strncpy(colorspace_settings->name, colorspace, sizeof(colorspace_settings->name)); + STRNCPY(colorspace_settings->name, colorspace); } if (ibuf != NULL) { @@ -683,7 +684,7 @@ static ImBuf *add_ibuf_size(unsigned int width, unsigned int height, const char if (colorspace_settings->name[0] == '\0') { const char *colorspace = IMB_colormanagement_role_colorspace_name_get(COLOR_ROLE_DEFAULT_BYTE); - BLI_strncpy(colorspace_settings->name, colorspace, sizeof(colorspace_settings->name)); + STRNCPY(colorspace_settings->name, colorspace); } if (ibuf != NULL) { @@ -696,7 +697,7 @@ static ImBuf *add_ibuf_size(unsigned int width, unsigned int height, const char return NULL; } - BLI_strncpy(ibuf->name, name, sizeof(ibuf->name)); + STRNCPY(ibuf->name, name); ibuf->userflags |= IB_BITMAPDIRTY; switch (gen_type) { @@ -726,7 +727,7 @@ Image *BKE_image_add_generated( int view_id; const char *names[2] = {STEREO_LEFT_NAME, STEREO_RIGHT_NAME}; - /* BLI_strncpy(ima->name, name, FILE_MAX); */ /* don't do this, this writes in ain invalid filepath! */ + /* STRNCPY(ima->name, name); */ /* don't do this, this writes in ain invalid filepath! */ ima->gen_x = width; ima->gen_y = height; ima->gen_type = gen_type; @@ -767,7 +768,7 @@ Image *BKE_image_add_from_imbuf(ImBuf *ibuf, const char *name) ima = image_alloc(G.main, name, IMA_SRC_FILE, IMA_TYPE_IMAGE); if (ima) { - BLI_strncpy(ima->name, ibuf->name, FILE_MAX); + STRNCPY(ima->name, ibuf->name); image_assign_ibuf(ima, ibuf, IMA_NO_INDEX, 0); ima->ok = IMA_OK_LOADED; } @@ -813,7 +814,7 @@ static void image_memorypack_multiview(Image *ima) pf->size = ibuf->encodedsize; imapf = MEM_mallocN(sizeof(ImagePackedFile), "Image PackedFile"); - BLI_strncpy(imapf->filepath, iv->filepath, sizeof(imapf->filepath)); + STRNCPY(imapf->filepath, iv->filepath); imapf->packedfile = pf; BLI_addtail(&ima->packedfiles, imapf); @@ -863,7 +864,7 @@ void BKE_image_memorypack(Image *ima) pf->size = ibuf->encodedsize; imapf = MEM_mallocN(sizeof(ImagePackedFile), "Image PackedFile"); - BLI_strncpy(imapf->filepath, ima->name, sizeof(imapf->filepath)); + STRNCPY(imapf->filepath, ima->name); imapf->packedfile = pf; BLI_addtail(&ima->packedfiles, imapf); @@ -889,7 +890,7 @@ void BKE_image_packfiles(ReportList *reports, Image *ima, const char *basepath) BLI_addtail(&ima->packedfiles, imapf); imapf->packedfile = newPackedFile(reports, ima->name, basepath); if (imapf->packedfile) { - BLI_strncpy(imapf->filepath, ima->name, sizeof(imapf->filepath)); + STRNCPY(imapf->filepath, ima->name); } else { BLI_freelinkN(&ima->packedfiles, imapf); @@ -903,7 +904,7 @@ void BKE_image_packfiles(ReportList *reports, Image *ima, const char *basepath) imapf->packedfile = newPackedFile(reports, iv->filepath, basepath); if (imapf->packedfile) { - BLI_strncpy(imapf->filepath, iv->filepath, sizeof(imapf->filepath)); + STRNCPY(imapf->filepath, iv->filepath); } else { BLI_freelinkN(&ima->packedfiles, imapf); @@ -923,7 +924,7 @@ void BKE_image_packfiles_from_mem(ReportList *reports, Image *ima, char *data, c 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)); + STRNCPY(imapf->filepath, ima->name); } } @@ -1623,6 +1624,7 @@ typedef struct StampData { char marker[512]; char time[512]; char frame[512]; + char frame_range[512]; char camera[STAMP_NAME_SIZE]; char cameralens[STAMP_NAME_SIZE]; char scene[STAMP_NAME_SIZE]; @@ -1639,14 +1641,19 @@ typedef struct StampData { } StampData; #undef STAMP_NAME_SIZE -static void stampdata(Scene *scene, Object *camera, StampData *stamp_data, int do_prefix) +/** + * \param do_prefix: Include a label like "File ", "Date ", etc. in the stamp data strings. + * \param use_dynamic: Also include data that can change on a per-frame basis. + */ +static void stampdata(Scene *scene, Object *camera, StampData *stamp_data, int do_prefix, + bool use_dynamic) { char text[256]; struct tm *tl; time_t t; if (scene->r.stamp & R_STAMP_FILENAME) { - BLI_snprintf(stamp_data->file, sizeof(stamp_data->file), do_prefix ? "File %s" : "%s", G.relbase_valid ? G.main->name : "<untitled>"); + SNPRINTF(stamp_data->file, do_prefix ? "File %s" : "%s", G.relbase_valid ? G.main->name : "<untitled>"); } else { stamp_data->file[0] = '\0'; @@ -1654,7 +1661,7 @@ static void stampdata(Scene *scene, Object *camera, StampData *stamp_data, int d if (scene->r.stamp & R_STAMP_NOTE) { /* Never do prefix for Note */ - BLI_snprintf(stamp_data->note, sizeof(stamp_data->note), "%s", scene->r.stamp_udata); + SNPRINTF(stamp_data->note, "%s", scene->r.stamp_udata); } else { stamp_data->note[0] = '\0'; @@ -1663,83 +1670,93 @@ static void stampdata(Scene *scene, Object *camera, StampData *stamp_data, int d if (scene->r.stamp & R_STAMP_DATE) { t = time(NULL); tl = localtime(&t); - BLI_snprintf(text, sizeof(text), "%04d/%02d/%02d %02d:%02d:%02d", tl->tm_year + 1900, tl->tm_mon + 1, tl->tm_mday, tl->tm_hour, tl->tm_min, tl->tm_sec); - BLI_snprintf(stamp_data->date, sizeof(stamp_data->date), do_prefix ? "Date %s" : "%s", text); + SNPRINTF(text, "%04d/%02d/%02d %02d:%02d:%02d", + tl->tm_year + 1900, tl->tm_mon + 1, tl->tm_mday, tl->tm_hour, tl->tm_min, tl->tm_sec); + SNPRINTF(stamp_data->date, do_prefix ? "Date %s" : "%s", text); } else { stamp_data->date[0] = '\0'; } - if (scene->r.stamp & R_STAMP_MARKER) { + if (use_dynamic && scene->r.stamp & R_STAMP_MARKER) { const char *name = BKE_scene_find_last_marker_name(scene, CFRA); - if (name) BLI_strncpy(text, name, sizeof(text)); - else BLI_strncpy(text, "<none>", sizeof(text)); + if (name) STRNCPY(text, name); + else STRNCPY(text, "<none>"); - BLI_snprintf(stamp_data->marker, sizeof(stamp_data->marker), do_prefix ? "Marker %s" : "%s", text); + SNPRINTF(stamp_data->marker, do_prefix ? "Marker %s" : "%s", text); } else { stamp_data->marker[0] = '\0'; } - if (scene->r.stamp & R_STAMP_TIME) { + if (use_dynamic && scene->r.stamp & R_STAMP_TIME) { const short timecode_style = USER_TIMECODE_SMPTE_FULL; BLI_timecode_string_from_time(text, sizeof(text), 0, FRA2TIME(scene->r.cfra), FPS, timecode_style); - BLI_snprintf(stamp_data->time, sizeof(stamp_data->time), do_prefix ? "Timecode %s" : "%s", text); + SNPRINTF(stamp_data->time, do_prefix ? "Timecode %s" : "%s", text); } else { stamp_data->time[0] = '\0'; } - if (scene->r.stamp & R_STAMP_FRAME) { + if (use_dynamic && scene->r.stamp & R_STAMP_FRAME) { char fmtstr[32]; int digits = 1; if (scene->r.efra > 9) digits = integer_digits_i(scene->r.efra); - BLI_snprintf(fmtstr, sizeof(fmtstr), do_prefix ? "Frame %%0%di" : "%%0%di", digits); - BLI_snprintf(stamp_data->frame, sizeof(stamp_data->frame), fmtstr, scene->r.cfra); + SNPRINTF(fmtstr, do_prefix ? "Frame %%0%di" : "%%0%di", digits); + SNPRINTF(stamp_data->frame, fmtstr, scene->r.cfra); } else { stamp_data->frame[0] = '\0'; } - if (scene->r.stamp & R_STAMP_CAMERA) { - BLI_snprintf(stamp_data->camera, sizeof(stamp_data->camera), do_prefix ? "Camera %s" : "%s", camera ? camera->id.name + 2 : "<none>"); + if (scene->r.stamp & R_STAMP_FRAME_RANGE) { + SNPRINTF(stamp_data->frame_range, + do_prefix ? "Frame Range %d:%d" : "%d:%d", + scene->r.sfra, scene->r.efra); + } + else { + stamp_data->frame_range[0] = '\0'; + } + + if (use_dynamic && scene->r.stamp & R_STAMP_CAMERA) { + SNPRINTF(stamp_data->camera, do_prefix ? "Camera %s" : "%s", camera ? camera->id.name + 2 : "<none>"); } else { stamp_data->camera[0] = '\0'; } - if (scene->r.stamp & R_STAMP_CAMERALENS) { + if (use_dynamic && scene->r.stamp & R_STAMP_CAMERALENS) { if (camera && camera->type == OB_CAMERA) { - BLI_snprintf(text, sizeof(text), "%.2f", ((Camera *)camera->data)->lens); + SNPRINTF(text, "%.2f", ((Camera *)camera->data)->lens); } else { - BLI_strncpy(text, "<none>", sizeof(text)); + STRNCPY(text, "<none>"); } - BLI_snprintf(stamp_data->cameralens, sizeof(stamp_data->cameralens), do_prefix ? "Lens %s" : "%s", text); + SNPRINTF(stamp_data->cameralens, do_prefix ? "Lens %s" : "%s", text); } else { stamp_data->cameralens[0] = '\0'; } if (scene->r.stamp & R_STAMP_SCENE) { - BLI_snprintf(stamp_data->scene, sizeof(stamp_data->scene), do_prefix ? "Scene %s" : "%s", scene->id.name + 2); + SNPRINTF(stamp_data->scene, do_prefix ? "Scene %s" : "%s", scene->id.name + 2); } else { stamp_data->scene[0] = '\0'; } - if (scene->r.stamp & R_STAMP_SEQSTRIP) { + if (use_dynamic && scene->r.stamp & R_STAMP_SEQSTRIP) { Sequence *seq = BKE_sequencer_foreground_frame_get(scene, scene->r.cfra); - if (seq) BLI_strncpy(text, seq->name + 2, sizeof(text)); - else BLI_strncpy(text, "<none>", sizeof(text)); + if (seq) STRNCPY(text, seq->name + 2); + else STRNCPY(text, "<none>"); - BLI_snprintf(stamp_data->strip, sizeof(stamp_data->strip), do_prefix ? "Strip %s" : "%s", text); + SNPRINTF(stamp_data->strip, do_prefix ? "Strip %s" : "%s", text); } else { stamp_data->strip[0] = '\0'; @@ -1749,22 +1766,29 @@ static void stampdata(Scene *scene, Object *camera, StampData *stamp_data, int d Render *re = RE_GetSceneRender(scene); RenderStats *stats = re ? RE_GetStats(re) : NULL; - if (stats && (scene->r.stamp & R_STAMP_RENDERTIME)) { + if (use_dynamic && stats && (scene->r.stamp & R_STAMP_RENDERTIME)) { BLI_timecode_string_from_time_simple(text, sizeof(text), stats->lastframetime); - BLI_snprintf(stamp_data->rendertime, sizeof(stamp_data->rendertime), do_prefix ? "RenderTime %s" : "%s", text); + SNPRINTF(stamp_data->rendertime, do_prefix ? "RenderTime %s" : "%s", text); } else { stamp_data->rendertime[0] = '\0'; } - if (stats && (scene->r.stamp & R_STAMP_MEMORY)) { - BLI_snprintf(stamp_data->memory, sizeof(stamp_data->memory), do_prefix ? "Peak Memory %.2fM" : "%.2fM", stats->mem_peak); + if (use_dynamic && stats && (scene->r.stamp & R_STAMP_MEMORY)) { + SNPRINTF(stamp_data->memory, do_prefix ? "Peak Memory %.2fM" : "%.2fM", stats->mem_peak); } else { stamp_data->memory[0] = '\0'; } } + if (scene->r.stamp & R_STAMP_FRAME_RANGE) { + SNPRINTF(stamp_data->frame_range, + do_prefix ? "Frame Range %d:%d" : "%d:%d", scene->r.sfra, scene->r.efra); + } + else { + stamp_data->frame_range[0] = '\0'; + } } /* Will always add prefix. */ @@ -1773,73 +1797,73 @@ static void stampdata_from_template(StampData *stamp_data, const StampData *stamp_data_template) { if (scene->r.stamp & R_STAMP_FILENAME) { - BLI_snprintf(stamp_data->file, sizeof(stamp_data->file), "File %s", stamp_data_template->file); + SNPRINTF(stamp_data->file, "File %s", stamp_data_template->file); } else { stamp_data->file[0] = '\0'; } if (scene->r.stamp & R_STAMP_NOTE) { - BLI_snprintf(stamp_data->note, sizeof(stamp_data->note), "%s", stamp_data_template->note); + SNPRINTF(stamp_data->note, "%s", stamp_data_template->note); } else { stamp_data->note[0] = '\0'; } if (scene->r.stamp & R_STAMP_DATE) { - BLI_snprintf(stamp_data->date, sizeof(stamp_data->date), "Date %s", stamp_data_template->date); + SNPRINTF(stamp_data->date, "Date %s", stamp_data_template->date); } else { stamp_data->date[0] = '\0'; } if (scene->r.stamp & R_STAMP_MARKER) { - BLI_snprintf(stamp_data->marker, sizeof(stamp_data->marker), "Marker %s", stamp_data_template->marker); + SNPRINTF(stamp_data->marker, "Marker %s", stamp_data_template->marker); } else { stamp_data->marker[0] = '\0'; } if (scene->r.stamp & R_STAMP_TIME) { - BLI_snprintf(stamp_data->time, sizeof(stamp_data->time), "Timecode %s", stamp_data_template->time); + SNPRINTF(stamp_data->time, "Timecode %s", stamp_data_template->time); } else { stamp_data->time[0] = '\0'; } if (scene->r.stamp & R_STAMP_FRAME) { - BLI_snprintf(stamp_data->frame, sizeof(stamp_data->frame), "Frame %s", stamp_data_template->frame); + SNPRINTF(stamp_data->frame, "Frame %s", stamp_data_template->frame); } else { stamp_data->frame[0] = '\0'; } if (scene->r.stamp & R_STAMP_CAMERA) { - BLI_snprintf(stamp_data->camera, sizeof(stamp_data->camera), "Camera %s", stamp_data_template->camera); + SNPRINTF(stamp_data->camera, "Camera %s", stamp_data_template->camera); } else { stamp_data->camera[0] = '\0'; } if (scene->r.stamp & R_STAMP_CAMERALENS) { - BLI_snprintf(stamp_data->cameralens, sizeof(stamp_data->cameralens), "Lens %s", stamp_data_template->cameralens); + SNPRINTF(stamp_data->cameralens, "Lens %s", stamp_data_template->cameralens); } else { stamp_data->cameralens[0] = '\0'; } if (scene->r.stamp & R_STAMP_SCENE) { - BLI_snprintf(stamp_data->scene, sizeof(stamp_data->scene), "Scene %s", stamp_data_template->scene); + SNPRINTF(stamp_data->scene, "Scene %s", stamp_data_template->scene); } else { stamp_data->scene[0] = '\0'; } if (scene->r.stamp & R_STAMP_SEQSTRIP) { - BLI_snprintf(stamp_data->strip, sizeof(stamp_data->strip), "Strip %s", stamp_data_template->strip); + SNPRINTF(stamp_data->strip, "Strip %s", stamp_data_template->strip); } else { stamp_data->strip[0] = '\0'; } if (scene->r.stamp & R_STAMP_RENDERTIME) { - BLI_snprintf(stamp_data->rendertime, sizeof(stamp_data->rendertime), "RenderTime %s", stamp_data_template->rendertime); + SNPRINTF(stamp_data->rendertime, "RenderTime %s", stamp_data_template->rendertime); } else { stamp_data->rendertime[0] = '\0'; } if (scene->r.stamp & R_STAMP_MEMORY) { - BLI_snprintf(stamp_data->memory, sizeof(stamp_data->memory), "Peak Memory %s", stamp_data_template->memory); + SNPRINTF(stamp_data->memory, "Peak Memory %s", stamp_data_template->memory); } else { stamp_data->memory[0] = '\0'; @@ -1885,7 +1909,7 @@ void BKE_image_stamp_buf( display = IMB_colormanagement_display_get_named(display_device); if (stamp_data_template == NULL) { - stampdata(scene, camera, &stamp_data, (scene->r.stamp & R_STAMP_HIDE_LABELS) == 0); + stampdata(scene, camera, &stamp_data, (scene->r.stamp & R_STAMP_HIDE_LABELS) == 0, true); } else { stampdata_from_template(&stamp_data, scene, stamp_data_template); @@ -2106,13 +2130,28 @@ void BKE_render_result_stamp_info(Scene *scene, Object *camera, struct RenderRes } if (!allocate_only) - stampdata(scene, camera, stamp_data, 0); + stampdata(scene, camera, stamp_data, 0, true); if (!rr->stamp_data) { rr->stamp_data = stamp_data; } } +struct StampData *BKE_stamp_info_from_scene_static(Scene *scene) +{ + struct StampData *stamp_data; + + if (!(scene && (scene->r.stamp & R_STAMP_ALL))) + return NULL; + + /* Memory is allocated here (instead of by the caller) so that the caller + * doesn't have to know the size of the StampData struct. */ + stamp_data = MEM_callocN(sizeof(StampData), __func__); + stampdata(scene, NULL, stamp_data, 0, false); + + return stamp_data; +} + void BKE_stamp_info_callback(void *data, struct StampData *stamp_data, StampCallback callback, bool noskip) { if ((callback == NULL) || (stamp_data == NULL)) { @@ -2130,6 +2169,7 @@ void BKE_stamp_info_callback(void *data, struct StampData *stamp_data, StampCall CALL(marker, "Marker"); CALL(time, "Time"); CALL(frame, "Frame"); + CALL(frame_range, "FrameRange"); CALL(camera, "Camera"); CALL(cameralens, "Lens"); CALL(scene, "Scene"); @@ -2158,8 +2198,8 @@ void BKE_render_result_stamp_data(RenderResult *rr, const char *key, const char stamp_data = rr->stamp_data; StampDataCustomField *field = MEM_mallocN(sizeof(StampDataCustomField), "StampData Custom Field"); - BLI_strncpy(field->key, key, sizeof(field->key)); - BLI_strncpy(field->value, value, sizeof(field->value)); + STRNCPY(field->key, key); + STRNCPY(field->value, value); BLI_addtail(&stamp_data->custom_fields, field); } @@ -2173,27 +2213,31 @@ void BKE_stamp_data_free(struct StampData *stamp_data) } /* wrap for callback only */ -static void metadata_change_field(void *data, const char *propname, char *propvalue, int UNUSED(len)) +static void metadata_set_field(void *data, const char *propname, char *propvalue, int UNUSED(len)) { - IMB_metadata_change_field(data, propname, propvalue); + /* We know it is an ImBuf* because that's what we pass to BKE_stamp_info_callback. */ + struct ImBuf *imbuf = data; + IMB_metadata_set_field(imbuf->metadata, propname, propvalue); } static void metadata_get_field(void *data, const char *propname, char *propvalue, int len) { - IMB_metadata_get_field(data, propname, propvalue, len); + /* We know it is an ImBuf* because that's what we pass to BKE_stamp_info_callback. */ + struct ImBuf *imbuf = data; + IMB_metadata_get_field(imbuf->metadata, propname, propvalue, len); } void BKE_imbuf_stamp_info(RenderResult *rr, struct ImBuf *ibuf) { struct StampData *stamp_data = rr->stamp_data; - - BKE_stamp_info_callback(ibuf, stamp_data, metadata_change_field, false); + IMB_metadata_ensure(&ibuf->metadata); + BKE_stamp_info_callback(ibuf, stamp_data, metadata_set_field, false); } void BKE_stamp_info_from_imbuf(RenderResult *rr, struct ImBuf *ibuf) { struct StampData *stamp_data = rr->stamp_data; - + IMB_metadata_ensure(&ibuf->metadata); BKE_stamp_info_callback(ibuf, stamp_data, metadata_get_field, true); } @@ -2548,7 +2592,7 @@ void BKE_image_verify_viewer_views(const RenderData *rd, Image *ima, ImageUser * bool do_reset; const bool is_multiview = (rd->scemode & R_MULTIVIEW) != 0; - BLI_lock_thread(LOCK_DRAW_IMAGE); + BLI_thread_lock(LOCK_DRAW_IMAGE); if (!BKE_scene_multiview_is_stereo3d(rd)) iuser->flag &= ~IMA_SHOW_STEREO; @@ -2582,7 +2626,7 @@ void BKE_image_verify_viewer_views(const RenderData *rd, Image *ima, ImageUser * BLI_spin_unlock(&image_spin); } - BLI_unlock_thread(LOCK_DRAW_IMAGE); + BLI_thread_unlock(LOCK_DRAW_IMAGE); } void BKE_image_walk_all_users(const Main *mainp, void *customdata, @@ -2740,7 +2784,7 @@ void BKE_image_signal(Image *ima, ImageUser *iuser, int signal) if (BKE_image_has_packedfile(ima)) { const int totfiles = image_num_files(ima); - if (totfiles != BLI_listbase_count_ex(&ima->packedfiles, totfiles + 1)) { + if (totfiles != BLI_listbase_count_at_most(&ima->packedfiles, totfiles + 1)) { /* in case there are new available files to be loaded */ image_free_packedfiles(ima); BKE_image_packfiles(NULL, ima, ID_BLEND_PATH(G.main, &ima->id)); @@ -2895,7 +2939,7 @@ void BKE_image_multiview_index(Image *ima, ImageUser *iuser) iuser->multi_index = iuser->multiview_eye; } else { - if ((iuser->view < 0) || (iuser->view >= BLI_listbase_count_ex(&ima->views, iuser->view + 1))) { + if ((iuser->view < 0) || (iuser->view >= BLI_listbase_count_at_most(&ima->views, iuser->view + 1))) { iuser->multi_index = iuser->view = 0; } else { @@ -2958,7 +3002,7 @@ static void image_init_multilayer_multiview(Image *ima, RenderResult *rr) if (rr) { for (RenderView *rv = rr->views.first; rv; rv = rv->next) { ImageView *iv = MEM_callocN(sizeof(ImageView), "Viewer Image View"); - BLI_strncpy(iv->name, rv->name, sizeof(iv->name)); + STRNCPY(iv->name, rv->name); BLI_addtail(&ima->views, iv); } } @@ -3039,8 +3083,8 @@ static void image_add_view(Image *ima, const char *viewname, const char *filepat ImageView *iv; iv = MEM_mallocN(sizeof(ImageView), "Viewer Image View"); - BLI_strncpy(iv->name, viewname, sizeof(iv->name)); - BLI_strncpy(iv->filepath, filepath, sizeof(iv->filepath)); + STRNCPY(iv->name, viewname); + STRNCPY(iv->filepath, filepath); /* For stereo drawing we need to ensure: * STEREO_LEFT_NAME == STEREO_LEFT_ID and @@ -3362,7 +3406,7 @@ static ImBuf *image_load_movie_file(Image *ima, ImageUser *iuser, int frame) const int totfiles = image_num_files(ima); int i; - if (totfiles != BLI_listbase_count_ex(&ima->anims, totfiles + 1)) { + if (totfiles != BLI_listbase_count_at_most(&ima->anims, totfiles + 1)) { image_free_anims(ima); for (i = 0; i < totfiles; i++) { @@ -3490,7 +3534,7 @@ static ImBuf *load_image_single( ImagePackedFile *imapf = MEM_mallocN(sizeof(ImagePackedFile), "Image Packefile"); BLI_addtail(&ima->packedfiles, imapf); - BLI_strncpy(imapf->filepath, filepath, sizeof(imapf->filepath)); + STRNCPY(imapf->filepath, filepath); imapf->packedfile = newPackedFile(NULL, filepath, ID_BLEND_PATH(G.main, &ima->id)); } } @@ -3518,7 +3562,7 @@ static ImBuf *image_load_image_file(Image *ima, ImageUser *iuser, int cfra) /* this should never happen, but just playing safe */ if (has_packed) { - if (totfiles != BLI_listbase_count_ex(&ima->packedfiles, totfiles + 1)) { + if (totfiles != BLI_listbase_count_at_most(&ima->packedfiles, totfiles + 1)) { image_free_packedfiles(ima); has_packed = false; } @@ -3663,7 +3707,7 @@ static ImBuf *image_get_render_result(Image *ima, ImageUser *iuser, void **r_loc /* release is done in BKE_image_release_ibuf using r_lock */ if (from_render) { - BLI_lock_thread(LOCK_VIEWER); + BLI_thread_lock(LOCK_VIEWER); *r_lock = re; rv = NULL; } @@ -3756,7 +3800,7 @@ static ImBuf *image_get_render_result(Image *ima, ImageUser *iuser, void **r_loc } /* invalidate color managed buffers if render result changed */ - BLI_lock_thread(LOCK_COLORMANAGE); + BLI_thread_lock(LOCK_COLORMANAGE); if (ibuf->x != rres.rectx || ibuf->y != rres.recty || ibuf->rect_float != rectf) { ibuf->userflags |= IB_DISPLAY_BUFFER_INVALID; } @@ -3797,7 +3841,7 @@ static ImBuf *image_get_render_result(Image *ima, ImageUser *iuser, void **r_loc ibuf->flags &= ~IB_zbuffloat; } - BLI_unlock_thread(LOCK_COLORMANAGE); + BLI_thread_unlock(LOCK_COLORMANAGE); ibuf->dither = dither; @@ -3999,7 +4043,7 @@ static ImBuf *image_acquire_ibuf(Image *ima, ImageUser *iuser, void **r_lock) /* requires lock/unlock, otherwise don't return image */ if (r_lock) { /* unlock in BKE_image_release_ibuf */ - BLI_lock_thread(LOCK_VIEWER); + BLI_thread_lock(LOCK_VIEWER); *r_lock = ima; /* XXX anim play for viewer nodes not yet supported */ @@ -4052,11 +4096,11 @@ void BKE_image_release_ibuf(Image *ima, ImBuf *ibuf, void *lock) if (lock) { /* for getting image during threaded render / compositing, need to release */ if (lock == ima) { - BLI_unlock_thread(LOCK_VIEWER); /* viewer image */ + BLI_thread_unlock(LOCK_VIEWER); /* viewer image */ } else if (lock) { RE_ReleaseResultImage(lock); /* render result */ - BLI_unlock_thread(LOCK_VIEWER); /* view image imbuf */ + BLI_thread_unlock(LOCK_VIEWER); /* view image imbuf */ } } @@ -4645,7 +4689,7 @@ static void image_update_views_format(Image *ima, ImageUser *iuser) for (srv = scene->r.views.first; srv; srv = srv->next) { if (BKE_scene_multiview_is_render_view_active(&scene->r, srv)) { char filepath[FILE_MAX]; - BLI_snprintf(filepath, sizeof(filepath), "%s%s%s", prefix, srv->suffix, ext); + SNPRINTF(filepath, "%s%s%s", prefix, srv->suffix, ext); image_add_view(ima, srv->name, filepath); } } @@ -4656,7 +4700,7 @@ static void image_update_views_format(Image *ima, ImageUser *iuser) int file; char str[FILE_MAX]; - BLI_strncpy(str, iv->filepath, sizeof(str)); + STRNCPY(str, iv->filepath); BLI_path_abs(str, G.main->name); /* exists? */ diff --git a/source/blender/blenkernel/intern/ipo.c b/source/blender/blenkernel/intern/ipo.c index 00cf40f06cd..fcbc25ebad5 100644 --- a/source/blender/blenkernel/intern/ipo.c +++ b/source/blender/blenkernel/intern/ipo.c @@ -1663,7 +1663,7 @@ static void nlastrips_to_animdata(ID *id, ListBase *strips) /* trying to add to the current failed (no space), * so add a new track to the stack, and add to that... */ - nlt = add_nlatrack(adt, NULL); + nlt = BKE_nlatrack_add(adt, NULL); BKE_nlatrack_add_strip(nlt, strip); } diff --git a/source/blender/blenkernel/intern/lamp.c b/source/blender/blenkernel/intern/lamp.c index 931fc09d235..bf36c437d60 100644 --- a/source/blender/blenkernel/intern/lamp.c +++ b/source/blender/blenkernel/intern/lamp.c @@ -47,7 +47,6 @@ #include "BKE_animsys.h" #include "BKE_colortools.h" #include "BKE_icons.h" -#include "BKE_global.h" #include "BKE_lamp.h" #include "BKE_library.h" #include "BKE_library_query.h" diff --git a/source/blender/blenkernel/intern/lattice.c b/source/blender/blenkernel/intern/lattice.c index d92d0d9edbf..c41ad78977e 100644 --- a/source/blender/blenkernel/intern/lattice.c +++ b/source/blender/blenkernel/intern/lattice.c @@ -54,7 +54,6 @@ #include "BKE_cdderivedmesh.h" #include "BKE_curve.h" #include "BKE_displist.h" -#include "BKE_global.h" #include "BKE_key.h" #include "BKE_lattice.h" #include "BKE_library.h" diff --git a/source/blender/blenkernel/intern/layer.c b/source/blender/blenkernel/intern/layer.c index c6515d0c47a..50c7dc0c02f 100644 --- a/source/blender/blenkernel/intern/layer.c +++ b/source/blender/blenkernel/intern/layer.c @@ -57,10 +57,9 @@ #include "MEM_guardedalloc.h" -#define DEBUG_PRINT if (G.debug & G_DEBUG_DEPSGRAPH) printf - /* prototype */ struct EngineSettingsCB_Type; +static void layer_collections_sync_flags(ListBase *layer_collections_dst, const ListBase *layer_collections_src); static void layer_collection_free(ViewLayer *view_layer, LayerCollection *lc); static void layer_collection_objects_populate(ViewLayer *view_layer, LayerCollection *lc, ListBase *objects); static LayerCollection *layer_collection_add(ViewLayer *view_layer, LayerCollection *parent, SceneCollection *sc); @@ -217,6 +216,8 @@ void BKE_view_layer_free_ex(ViewLayer *view_layer, const bool do_id_user) MEM_freeN(view_layer->id_properties); } + MEM_SAFE_FREE(view_layer->object_bases_array); + MEM_freeN(view_layer); } @@ -353,27 +354,95 @@ static SceneCollection *scene_collection_from_new_tree( return NULL; } +static void layer_collection_sync_flags( + LayerCollection *layer_collection_dst, + const LayerCollection *layer_collection_src) +{ + layer_collection_dst->flag = layer_collection_src->flag; + + if (layer_collection_dst->properties != NULL) { + IDP_FreeProperty(layer_collection_dst->properties); + MEM_SAFE_FREE(layer_collection_dst->properties); + } + + if (layer_collection_src->properties != NULL) { + layer_collection_dst->properties = IDP_CopyProperty(layer_collection_src->properties); + } + + layer_collections_sync_flags(&layer_collection_dst->layer_collections, + &layer_collection_src->layer_collections); +} + static void layer_collections_sync_flags(ListBase *layer_collections_dst, const ListBase *layer_collections_src) { + BLI_assert(BLI_listbase_count(layer_collections_dst) == BLI_listbase_count(layer_collections_src)); LayerCollection *layer_collection_dst = (LayerCollection *)layer_collections_dst->first; const LayerCollection *layer_collection_src = (const LayerCollection *)layer_collections_src->first; while (layer_collection_dst != NULL) { - layer_collection_dst->flag = layer_collection_src->flag; + layer_collection_sync_flags(layer_collection_dst, layer_collection_src); + layer_collection_dst = layer_collection_dst->next; + layer_collection_src = layer_collection_src->next; + } +} - if (layer_collection_dst->properties != NULL) { - IDP_FreeProperty(layer_collection_dst->properties); - MEM_SAFE_FREE(layer_collection_dst->properties); +static bool layer_collection_sync_if_match( + ListBase *lb, + const SceneCollection *scene_collection_dst, + const SceneCollection *scene_collection_src) +{ + for (LayerCollection *layer_collection = lb->first; + layer_collection; + layer_collection = layer_collection->next) + { + if (layer_collection->scene_collection == scene_collection_src) { + LayerCollection *layer_collection_dst = + BLI_findptr( + lb, + scene_collection_dst, + offsetof(LayerCollection, scene_collection)); + + if (layer_collection_dst != NULL) { + layer_collection_sync_flags(layer_collection_dst, layer_collection); + } + return true; } - - if (layer_collection_src->properties != NULL) { - layer_collection_dst->properties = IDP_CopyProperty(layer_collection_src->properties); + else { + if (layer_collection_sync_if_match( + &layer_collection->layer_collections, + scene_collection_dst, + scene_collection_src)) + { + return true; + } } + } + return false; +} - layer_collections_sync_flags(&layer_collection_dst->layer_collections, - &layer_collection_src->layer_collections); - - layer_collection_dst = layer_collection_dst->next; - layer_collection_src = layer_collection_src->next; +/** + * Sync sibling collections across all view layers + * + * Make sure every linked instance of \a scene_collection_dst has the same values + * (flags, overrides, ...) as the corresponding scene_collection_src. + * + * \note expect scene_collection_dst to be scene_collection_src->next, and it also + * expects both collections to have the same ammount of sub-collections. + */ +void BKE_layer_collection_sync_flags( + ID *owner_id, + SceneCollection *scene_collection_dst, + SceneCollection *scene_collection_src) +{ + for (ViewLayer *view_layer = BKE_view_layer_first_from_id(owner_id); view_layer; view_layer = view_layer->next) { + for (LayerCollection *layer_collection = view_layer->layer_collections.first; + layer_collection; + layer_collection = layer_collection->next) + { + layer_collection_sync_if_match( + &layer_collection->layer_collections, + scene_collection_dst, + scene_collection_src); + } } } @@ -436,6 +505,80 @@ void BKE_view_layer_copy_data( view_layer_dst->basact = base_dst; } } + + view_layer_dst->object_bases_array = NULL; +} + +/** + * Find and return the ListBase of LayerCollection that has \a lc_child as one of its directly + * nested LayerCollection. + * + * \param lb_parent Initial ListBase of LayerCollection to look into recursively + * usually the view layer's collection list + */ +static ListBase *find_layer_collection_parent_list_base(ListBase *lb_parent, const LayerCollection *lc_child) +{ + for (LayerCollection *lc_nested = lb_parent->first; lc_nested; lc_nested = lc_nested->next) { + if (lc_nested == lc_child) { + return lb_parent; + } + + ListBase *found = find_layer_collection_parent_list_base(&lc_nested->layer_collections, lc_child); + if (found != NULL) { + return found; + } + } + + return NULL; +} + +/** + * Makes a shallow copy of a LayerCollection + * + * Add a new collection in the same level as the old one (linking if necessary), + * and copy all the collection data across them. + */ +struct LayerCollection *BKE_layer_collection_duplicate(struct ID *owner_id, struct LayerCollection *layer_collection) +{ + SceneCollection *scene_collection, *scene_collection_new; + + scene_collection = layer_collection->scene_collection; + scene_collection_new = BKE_collection_duplicate(owner_id, scene_collection); + + LayerCollection *layer_collection_new = NULL; + + /* If the original layer_collection was directly linked to the view layer + we need to link the new scene collection here as well. */ + for (ViewLayer *view_layer = BKE_view_layer_first_from_id(owner_id); view_layer; view_layer = view_layer->next) { + if (BLI_findindex(&view_layer->layer_collections, layer_collection) != -1) { + layer_collection_new = BKE_collection_link(view_layer, scene_collection_new); + layer_collection_sync_flags(layer_collection_new, layer_collection); + + if (layer_collection_new != layer_collection->next) { + BLI_remlink(&view_layer->layer_collections, layer_collection_new); + BLI_insertlinkafter(&view_layer->layer_collections, layer_collection, layer_collection_new); + } + break; + } + } + + /* Otherwise just try to find the corresponding layer collection to return it back. */ + if (layer_collection_new == NULL) { + for (ViewLayer *view_layer = BKE_view_layer_first_from_id(owner_id); view_layer; view_layer = view_layer->next) { + ListBase *layer_collections_parent; + layer_collections_parent = find_layer_collection_parent_list_base( + &view_layer->layer_collections, + layer_collection); + if (layer_collections_parent != NULL) { + layer_collection_new = BLI_findptr( + layer_collections_parent, + scene_collection_new, + offsetof(LayerCollection, scene_collection)); + break; + } + } + } + return layer_collection_new; } static void view_layer_object_base_unref(ViewLayer *view_layer, Base *base) @@ -988,6 +1131,34 @@ void BKE_layer_collection_resync(const ID *owner_id, const SceneCollection *sc) /* ---------------------------------------------------------------------- */ /** + * Select all the objects of this layer collection + * + * It also select the objects that are in nested collections. + * \note Recursive + */ +void BKE_layer_collection_objects_select(struct LayerCollection *layer_collection) +{ + if ((layer_collection->flag & COLLECTION_DISABLED) || + ((layer_collection->flag & COLLECTION_SELECTABLE) == 0)) + { + return; + } + + for (LinkData *link = layer_collection->object_bases.first; link; link = link->next) { + Base *base = link->data; + if (base->flag & BASE_SELECTABLED) { + base->flag |= BASE_SELECTED; + } + } + + for (LayerCollection *iter = layer_collection->layer_collections.first; iter; iter = iter->next) { + BKE_layer_collection_objects_select(iter); + } +} + +/* ---------------------------------------------------------------------- */ + +/** * Link a collection to a renderlayer * The collection needs to be created separately */ @@ -1115,16 +1286,29 @@ static LayerCollection *layer_collection_add(ViewLayer *view_layer, LayerCollect /* ---------------------------------------------------------------------- */ /** - * See if render layer has the scene collection linked directly, or indirectly (nested) + * Return the first matching LayerCollection in the ViewLayer for the SceneCollection. */ -bool BKE_view_layer_has_collection(ViewLayer *view_layer, const SceneCollection *sc) +LayerCollection *BKE_layer_collection_first_from_scene_collection(ViewLayer *view_layer, const SceneCollection *scene_collection) { - for (LayerCollection *lc = view_layer->layer_collections.first; lc; lc = lc->next) { - if (find_layer_collection_by_scene_collection(lc, sc) != NULL) { - return true; + for (LayerCollection *layer_collection = view_layer->layer_collections.first; + layer_collection != NULL; + layer_collection = layer_collection->next) + { + LayerCollection *found = find_layer_collection_by_scene_collection(layer_collection, scene_collection); + + if (found != NULL) { + return found; } } - return false; + return NULL; +} + +/** + * See if view layer has the scene collection linked directly, or indirectly (nested) + */ +bool BKE_view_layer_has_collection(ViewLayer *view_layer, const SceneCollection *scene_collection) +{ + return BKE_layer_collection_first_from_scene_collection(view_layer, scene_collection) != NULL; } /** @@ -1968,12 +2152,13 @@ void BKE_visible_bases_iterator_end(BLI_Iterator *UNUSED(iter)) void BKE_renderable_objects_iterator_begin(BLI_Iterator *iter, void *data_in) { - ObjectsRenderableIteratorData *data = data_in; + struct ObjectsRenderableIteratorData *data = data_in; + /* Tag objects to prevent going over the same object twice. */ for (Scene *scene = data->scene; scene; scene = scene->set) { for (ViewLayer *view_layer = scene->view_layers.first; view_layer; view_layer = view_layer->next) { for (Base *base = view_layer->object_bases.first; base; base = base->next) { - base->object->id.flag |= LIB_TAG_DOIT; + base->object->id.flag |= LIB_TAG_DOIT; } } } @@ -1981,8 +2166,8 @@ void BKE_renderable_objects_iterator_begin(BLI_Iterator *iter, void *data_in) ViewLayer *view_layer = data->scene->view_layers.first; data->iter.view_layer = view_layer; - Base base = {(Base *)view_layer->object_bases.first, NULL}; - data->iter.base = &base; + data->base_temp.next = view_layer->object_bases.first; + data->iter.base = &data->base_temp; data->iter.set = NULL; @@ -1992,18 +2177,27 @@ void BKE_renderable_objects_iterator_begin(BLI_Iterator *iter, void *data_in) void BKE_renderable_objects_iterator_next(BLI_Iterator *iter) { - ObjectsRenderableIteratorData *data = iter->data; + /* Set it early in case we need to exit and we are running from within a loop. */ + iter->skip = true; + + struct ObjectsRenderableIteratorData *data = iter->data; Base *base = data->iter.base->next; /* There is still a base in the current scene layer. */ if (base != NULL) { Object *ob = base->object; - iter->current = ob; + /* We need to set the iter.base even if the rest fail otherwise + * we keep checking the exactly same base over and over again. */ data->iter.base = base; - if ((base->flag & BASE_VISIBLED) == 0) { - BKE_renderable_objects_iterator_next(iter); + if (ob->id.flag & LIB_TAG_DOIT) { + ob->id.flag &= ~LIB_TAG_DOIT; + + if ((base->flag & BASE_VISIBLED) != 0) { + iter->skip = false; + iter->current = ob; + } } return; } @@ -2013,30 +2207,23 @@ void BKE_renderable_objects_iterator_next(BLI_Iterator *iter) while ((data->iter.view_layer = data->iter.view_layer->next)) { ViewLayer *view_layer = data->iter.view_layer; if (view_layer->flag & VIEW_LAYER_RENDER) { - - Base base_iter = {(Base *)view_layer->object_bases.first, NULL}; - data->iter.base = &base_iter; - - BKE_renderable_objects_iterator_next(iter); + data->base_temp.next = view_layer->object_bases.first; + data->iter.base = &data->base_temp; return; } } /* Setup the "set" for the next iteration. */ - Scene scene = {.set = data->scene}; - data->iter.set = &scene; - BKE_renderable_objects_iterator_next(iter); + data->scene_temp.set = data->scene; + data->iter.set = &data->scene_temp; return; } /* Look for an object in the next set. */ while ((data->iter.set = data->iter.set->set)) { ViewLayer *view_layer = BKE_view_layer_from_scene_get(data->iter.set); - - Base base_iter = {(Base *)view_layer->object_bases.first, NULL}; - data->iter.base = &base_iter; - - BKE_renderable_objects_iterator_next(iter); + data->base_temp.next = view_layer->object_bases.first; + data->iter.base = &data->base_temp; return; } @@ -2070,10 +2257,9 @@ static void idproperty_reset(IDProperty **props, IDProperty *props_ref) } } -void BKE_layer_eval_layer_collection_pre(const struct EvaluationContext *UNUSED(eval_ctx), - ID *owner_id, ViewLayer *view_layer) +static void layer_eval_layer_collection_pre(ID *owner_id, ViewLayer *view_layer) { - DEBUG_PRINT("%s on %s (%p)\n", __func__, view_layer->name, view_layer); + DEG_debug_print_eval(__func__, view_layer->name, view_layer); Scene *scene = (GS(owner_id->name) == ID_SCE) ? (Scene *)owner_id : NULL; for (Base *base = view_layer->object_bases.first; base != NULL; base = base->next) { @@ -2113,18 +2299,21 @@ static bool layer_collection_visible_get(const EvaluationContext *eval_ctx, Laye } } -void BKE_layer_eval_layer_collection(const EvaluationContext *eval_ctx, - LayerCollection *layer_collection, - LayerCollection *parent_layer_collection) +static void layer_eval_layer_collection(const EvaluationContext *eval_ctx, + LayerCollection *layer_collection, + LayerCollection *parent_layer_collection) { - DEBUG_PRINT("%s on %s (%p) [%s], parent %s (%p) [%s]\n", - __func__, - layer_collection->scene_collection->name, - layer_collection->scene_collection, - collection_type_lookup[layer_collection->scene_collection->type], - (parent_layer_collection != NULL) ? parent_layer_collection->scene_collection->name : "NONE", - (parent_layer_collection != NULL) ? parent_layer_collection->scene_collection : NULL, - (parent_layer_collection != NULL) ? collection_type_lookup[parent_layer_collection->scene_collection->type] : ""); + if (G.debug & G_DEBUG_DEPSGRAPH_EVAL) { + /* TODO)sergey): Try to make it more generic and handled by depsgraph messaging. */ + printf("%s on %s (%p) [%s], parent %s (%p) [%s]\n", + __func__, + layer_collection->scene_collection->name, + layer_collection->scene_collection, + collection_type_lookup[layer_collection->scene_collection->type], + (parent_layer_collection != NULL) ? parent_layer_collection->scene_collection->name : "NONE", + (parent_layer_collection != NULL) ? parent_layer_collection->scene_collection : NULL, + (parent_layer_collection != NULL) ? collection_type_lookup[parent_layer_collection->scene_collection->type] : ""); + } BLI_assert(layer_collection != parent_layer_collection); /* visibility */ @@ -2170,18 +2359,65 @@ void BKE_layer_eval_layer_collection(const EvaluationContext *eval_ctx, } } -void BKE_layer_eval_layer_collection_post(const struct EvaluationContext *UNUSED(eval_ctx), - ViewLayer *view_layer) +static void layer_eval_layer_collection_post(ViewLayer *view_layer) { - DEBUG_PRINT("%s on %s (%p)\n", __func__, view_layer->name, view_layer); - /* if base is not selectabled, clear select */ + DEG_debug_print_eval(__func__, view_layer->name, view_layer); + /* Create array of bases, for fast index-based lookup. */ + const int num_object_bases = BLI_listbase_count(&view_layer->object_bases); + MEM_SAFE_FREE(view_layer->object_bases_array); + view_layer->object_bases_array = MEM_malloc_arrayN( + num_object_bases, sizeof(Base *), "view_layer->object_bases_array"); + int base_index = 0; for (Base *base = view_layer->object_bases.first; base; base = base->next) { + /* if base is not selectabled, clear select. */ if ((base->flag & BASE_SELECTABLED) == 0) { base->flag &= ~BASE_SELECTED; } + /* Store base in the array. */ + view_layer->object_bases_array[base_index++] = base; + } +} + +static void layer_eval_collections_recurse(const EvaluationContext *eval_ctx, + ListBase *layer_collections, + LayerCollection *parent_layer_collection) +{ + for (LayerCollection *layer_collection = layer_collections->first; + layer_collection != NULL; + layer_collection = layer_collection->next) + { + layer_eval_layer_collection(eval_ctx, + layer_collection, + parent_layer_collection); + layer_eval_collections_recurse(eval_ctx, + &layer_collection->layer_collections, + layer_collection); } } +void BKE_layer_eval_view_layer(const struct EvaluationContext *eval_ctx, + struct ID *owner_id, + ViewLayer *view_layer) +{ + layer_eval_layer_collection_pre(owner_id, view_layer); + layer_eval_collections_recurse(eval_ctx, + &view_layer->layer_collections, + NULL); + layer_eval_layer_collection_post(view_layer); +} + +void BKE_layer_eval_view_layer_indexed(const struct EvaluationContext *eval_ctx, + struct ID *owner_id, + int view_layer_index) +{ + BLI_assert(GS(owner_id->name) == ID_SCE); + BLI_assert(view_layer_index >= 0); + Scene *scene = (Scene *)owner_id; + ViewLayer *view_layer = BLI_findlink(&scene->view_layers, view_layer_index); + BLI_assert(view_layer != NULL); + BKE_layer_eval_view_layer(eval_ctx, owner_id, view_layer); +} + /** * Free any static allocated memory. */ diff --git a/source/blender/blenkernel/intern/library.c b/source/blender/blenkernel/intern/library.c index 75a288092d8..f7f0991238f 100644 --- a/source/blender/blenkernel/intern/library.c +++ b/source/blender/blenkernel/intern/library.c @@ -849,6 +849,7 @@ void BKE_libblock_management_main_add(Main *bmain, void *idv) new_id(lb, id, NULL); /* alphabetic insertion: is in new_id */ id->tag &= ~(LIB_TAG_NO_MAIN | LIB_TAG_NO_USER_REFCOUNT); + bmain->is_memfile_undo_written = false; BKE_main_unlock(bmain); } @@ -868,6 +869,7 @@ void BKE_libblock_management_main_remove(Main *bmain, void *idv) BKE_main_lock(bmain); BLI_remlink(lb, id); id->tag |= LIB_TAG_NO_MAIN; + bmain->is_memfile_undo_written = false; BKE_main_unlock(bmain); } @@ -1244,6 +1246,7 @@ void *BKE_libblock_alloc(Main *bmain, short type, const char *name, const int fl BKE_main_lock(bmain); BLI_addtail(lb, id); new_id(lb, id, name); + bmain->is_memfile_undo_written = false; /* alphabetic insertion: is in new_id */ BKE_main_unlock(bmain); @@ -2144,7 +2147,7 @@ void BKE_library_make_local( GSet *loop_tags = BLI_gset_ptr_new(__func__); for (LinkNode *it = todo_ids; it; it = it->next) { library_make_local_copying_check(it->link, loop_tags, bmain->relations, done_ids); - BLI_assert(BLI_gset_size(loop_tags) == 0); + BLI_assert(BLI_gset_len(loop_tags) == 0); } BLI_gset_free(loop_tags, NULL); BLI_gset_free(done_ids, NULL); diff --git a/source/blender/blenkernel/intern/library_query.c b/source/blender/blenkernel/intern/library_query.c index da765ca45af..953db6f3cb0 100644 --- a/source/blender/blenkernel/intern/library_query.c +++ b/source/blender/blenkernel/intern/library_query.c @@ -52,7 +52,7 @@ #include "DNA_movieclip_types.h" #include "DNA_mask_types.h" #include "DNA_node_types.h" -#include "DNA_object_force.h" +#include "DNA_object_force_types.h" #include "DNA_lightprobe_types.h" #include "DNA_rigidbody_types.h" #include "DNA_scene_types.h" @@ -422,10 +422,6 @@ void BKE_library_foreach_ID_link(Main *bmain, ID *id, LibraryIDLinkCallback call /* nodetree **are owned by IDs**, treat them as mere sub-data and not real ID! */ library_foreach_ID_as_subdata_link((ID **)&scene->nodetree, callback, user_data, flag, &data); } - /* DO NOT handle scene->basact here, it's doubling with the loop over whole scene->base later, - * since basact is just a pointer to one of those items. */ - CALLBACK_INVOKE(scene->obedit, IDWALK_CB_NOP); - if (scene->ed) { Sequence *seq; SEQP_BEGIN(scene->ed, seq) @@ -445,13 +441,13 @@ void BKE_library_foreach_ID_link(Main *bmain, ID *id, LibraryIDLinkCallback call CALLBACK_INVOKE(scene->gpd, IDWALK_CB_USER); - FOREACH_SCENE_COLLECTION(scene, sc) + FOREACH_SCENE_COLLECTION_BEGIN(scene, sc) { for (LinkData *link = sc->objects.first; link; link = link->next) { CALLBACK_INVOKE_ID(link->data, IDWALK_CB_USER); } } - FOREACH_SCENE_COLLECTION_END + FOREACH_SCENE_COLLECTION_END; ViewLayer *view_layer; for (view_layer = scene->view_layers.first; view_layer; view_layer = view_layer->next) { @@ -685,6 +681,9 @@ void BKE_library_foreach_ID_link(Main *bmain, ID *id, LibraryIDLinkCallback call } CALLBACK_INVOKE(material->group, IDWALK_CB_USER); CALLBACK_INVOKE(material->edit_image, IDWALK_CB_USER); + if (material->texpaintslot != NULL) { + CALLBACK_INVOKE(material->texpaintslot->ima, IDWALK_CB_NOP); + } break; } @@ -777,7 +776,7 @@ void BKE_library_foreach_ID_link(Main *bmain, ID *id, LibraryIDLinkCallback call case ID_GR: { Group *group = (Group *) id; - FOREACH_GROUP_BASE(group, base) + FOREACH_GROUP_BASE_BEGIN(group, base) { CALLBACK_INVOKE(base->object, IDWALK_CB_USER_ONE); } diff --git a/source/blender/blenkernel/intern/library_remap.c b/source/blender/blenkernel/intern/library_remap.c index 87e45990a6c..2c6df24f762 100644 --- a/source/blender/blenkernel/intern/library_remap.c +++ b/source/blender/blenkernel/intern/library_remap.c @@ -281,6 +281,26 @@ static void libblock_remap_data_preprocess_scene_object_unlink( } } +static void libblock_remap_data_preprocess_group_unlink( + IDRemap *r_id_remap_data, Object *ob, const bool skip_indirect, const bool is_indirect) +{ + Main *bmain = r_id_remap_data->bmain; + for (Group *group = bmain->group.first; group; group = group->id.next) { + if (BKE_group_object_exists(group, ob)) { + if (skip_indirect && is_indirect) { + r_id_remap_data->skipped_indirect++; + r_id_remap_data->skipped_refcounted++; + } + else { + BKE_collections_object_remove(bmain, &group->id, ob, false); + if (!is_indirect) { + r_id_remap_data->status |= ID_REMAP_IS_LINKED_DIRECT; + } + } + } + } +} + static void libblock_remap_data_preprocess(IDRemap *r_id_remap_data) { switch (GS(r_id_remap_data->id->name)) { @@ -295,19 +315,24 @@ static void libblock_remap_data_preprocess(IDRemap *r_id_remap_data) /* In case we are unlinking... */ if (!r_id_remap_data->old_id) { /* ... everything from scene. */ - FOREACH_SCENE_OBJECT(sce, ob_iter) + FOREACH_SCENE_OBJECT_BEGIN(sce, ob_iter) { libblock_remap_data_preprocess_scene_object_unlink( r_id_remap_data, sce, ob_iter, skip_indirect, is_indirect); + libblock_remap_data_preprocess_group_unlink( + r_id_remap_data, ob_iter, skip_indirect, is_indirect); } - FOREACH_SCENE_OBJECT_END + FOREACH_SCENE_OBJECT_END; } else if (GS(r_id_remap_data->old_id->name) == ID_OB) { /* ... a specific object from scene. */ Object *old_ob = (Object *)r_id_remap_data->old_id; libblock_remap_data_preprocess_scene_object_unlink( r_id_remap_data, sce, old_ob, skip_indirect, is_indirect); + libblock_remap_data_preprocess_group_unlink( + r_id_remap_data, old_ob, skip_indirect, is_indirect); } + } break; } @@ -368,7 +393,7 @@ static void libblock_remap_data_postprocess_group_scene_unlink(Main *UNUSED(bmai { /* Note that here we assume no object has no base (i.e. all objects are assumed instanced * in one scene...). */ - FOREACH_SCENE_OBJECT(sce, ob) + FOREACH_SCENE_OBJECT_BEGIN(sce, ob) { if (ob->flag & OB_FROMGROUP) { Group *grp = BKE_group_object_find(NULL, ob); @@ -382,7 +407,7 @@ static void libblock_remap_data_postprocess_group_scene_unlink(Main *UNUSED(bmai } } } - FOREACH_SCENE_OBJECT_END + FOREACH_SCENE_OBJECT_END; } static void libblock_remap_data_postprocess_obdata_relink(Main *UNUSED(bmain), Object *ob, ID *new_id) diff --git a/source/blender/blenkernel/intern/linestyle.c b/source/blender/blenkernel/intern/linestyle.c index 2fc4c81cb0b..dd1315fe3fa 100644 --- a/source/blender/blenkernel/intern/linestyle.c +++ b/source/blender/blenkernel/intern/linestyle.c @@ -47,7 +47,6 @@ #include "BKE_colorband.h" #include "BKE_context.h" #include "BKE_freestyle.h" -#include "BKE_global.h" #include "BKE_library.h" #include "BKE_linestyle.h" #include "BKE_node.h" diff --git a/source/blender/blenkernel/intern/mask.c b/source/blender/blenkernel/intern/mask.c index 3256c16e2f6..ba5a6a25048 100644 --- a/source/blender/blenkernel/intern/mask.c +++ b/source/blender/blenkernel/intern/mask.c @@ -51,7 +51,7 @@ #include "BKE_animsys.h" #include "BKE_curve.h" -#include "BKE_global.h" + #include "BKE_library.h" #include "BKE_main.h" #include "BKE_mask.h" diff --git a/source/blender/blenkernel/intern/mask_evaluate.c b/source/blender/blenkernel/intern/mask_evaluate.c index f60d87f2464..61c136d2c4f 100644 --- a/source/blender/blenkernel/intern/mask_evaluate.c +++ b/source/blender/blenkernel/intern/mask_evaluate.c @@ -42,12 +42,10 @@ #include "DNA_mask_types.h" #include "BKE_curve.h" -#include "BKE_global.h" #include "BKE_mask.h" #include "DEG_depsgraph.h" - unsigned int BKE_mask_spline_resolution(MaskSpline *spline, int width, int height) { float max_segment = 0.01f; @@ -898,11 +896,9 @@ void BKE_mask_layer_evaluate_deform(MaskLayer *masklay, const float ctime) } } -#define DEBUG_PRINT if (G.debug & G_DEBUG_DEPSGRAPH) printf - void BKE_mask_eval_animation(struct EvaluationContext *eval_ctx, Mask *mask) { - DEBUG_PRINT("%s on %s (%p)\n", __func__, mask->id.name, mask); + DEG_debug_print_eval(__func__, mask->id.name, mask); for (MaskLayer *mask_layer = mask->masklayers.first; mask_layer != NULL; mask_layer = mask_layer->next) @@ -913,7 +909,7 @@ void BKE_mask_eval_animation(struct EvaluationContext *eval_ctx, Mask *mask) void BKE_mask_eval_update(struct EvaluationContext *eval_ctx, Mask *mask) { - DEBUG_PRINT("%s on %s (%p)\n", __func__, mask->id.name, mask); + DEG_debug_print_eval(__func__, mask->id.name, mask); for (MaskLayer *mask_layer = mask->masklayers.first; mask_layer != NULL; mask_layer = mask_layer->next) diff --git a/source/blender/blenkernel/intern/material.c b/source/blender/blenkernel/intern/material.c index 7235aa0aaf6..2971f56c775 100644 --- a/source/blender/blenkernel/intern/material.c +++ b/source/blender/blenkernel/intern/material.c @@ -72,6 +72,7 @@ #include "BKE_editmesh.h" #include "BKE_font.h" +#include "DEG_depsgraph.h" #include "DEG_depsgraph_build.h" #include "GPU_material.h" @@ -98,6 +99,9 @@ void BKE_material_free(Material *ma) MEM_SAFE_FREE(ma->ramp_col); MEM_SAFE_FREE(ma->ramp_spec); + + /* Free gpu material before the ntree */ + GPU_material_free(&ma->gpumaterial); /* is no lib link block, but material extension */ if (ma->nodetree) { @@ -108,8 +112,6 @@ void BKE_material_free(Material *ma) MEM_SAFE_FREE(ma->texpaintslot); - GPU_material_free(&ma->gpumaterial); - BKE_icon_id_delete((ID *)ma); BKE_previewimg_free(&ma->preview); } @@ -259,6 +261,10 @@ void BKE_material_copy_data(Main *bmain, Material *ma_dst, const Material *ma_sr ma_dst->preview = NULL; } + if (ma_src->texpaintslot != NULL) { + ma_dst->texpaintslot = MEM_dupallocN(ma_src->texpaintslot); + } + BLI_listbase_clear(&ma_dst->gpumaterial); /* TODO Duplicate Engine Settings and set runtime to NULL */ @@ -1709,13 +1715,14 @@ void paste_matcopybuf(Material *ma) MEM_freeN(mtex); } + /* Free gpu material before the ntree */ + GPU_material_free(&ma->gpumaterial); + if (ma->nodetree) { ntreeFreeTree(ma->nodetree); MEM_freeN(ma->nodetree); } - GPU_material_free(&ma->gpumaterial); - id = (ma->id); memcpy(ma, &matcopybuf, sizeof(Material)); (ma->id) = id; @@ -1772,9 +1779,7 @@ bool BKE_object_material_edit_image_set(Object *ob, short mat_nr, Image *image) void BKE_material_eval(const struct EvaluationContext *UNUSED(eval_ctx), Material *material) { - if (G.debug & G_DEBUG_DEPSGRAPH) { - printf("%s on %s (%p)\n", __func__, material->id.name, material); - } + DEG_debug_print_eval(__func__, material->id.name, material); if ((BLI_listbase_is_empty(&material->gpumaterial) == false)) { GPU_material_uniform_buffer_tag_dirty(&material->gpumaterial); } diff --git a/source/blender/blenkernel/intern/mball.c b/source/blender/blenkernel/intern/mball.c index 5a0ac86823f..cc801b2d8c3 100644 --- a/source/blender/blenkernel/intern/mball.c +++ b/source/blender/blenkernel/intern/mball.c @@ -549,9 +549,9 @@ void BKE_mball_eval_geometry(const struct EvaluationContext *UNUSED(eval_ctx), /* Draw Engine */ /* use for draw-manager only. */ -void BKE_mball_element_calc_display_m3x4(float r_scale_xform[3][4], - const float obmat[4][4], - const float local_pos[3]) +void BKE_mball_element_calc_scale_xform(float r_scale_xform[3][4], + const float obmat[4][4], + const float local_pos[3]) { float world_pos[3], scamat[3][3]; mul_v3_m4v3(world_pos, obmat, local_pos); diff --git a/source/blender/blenkernel/intern/mesh.c b/source/blender/blenkernel/intern/mesh.c index 3217c234718..af92422f4c3 100644 --- a/source/blender/blenkernel/intern/mesh.c +++ b/source/blender/blenkernel/intern/mesh.c @@ -66,6 +66,7 @@ #include "BKE_editmesh.h" #include "DEG_depsgraph.h" +#include "DEG_depsgraph_query.h" /* Define for cases when you want extra validation of mesh * after certain modifications. @@ -1044,7 +1045,7 @@ static void make_edges_mdata_extend(MEdge **r_alledge, int *r_totedge, BKE_mesh_poly_edgehash_insert(eh, mp, mloop + mp->loopstart); } - totedge_new = BLI_edgehash_size(eh); + totedge_new = BLI_edgehash_len(eh); #ifdef DEBUG /* ensure that theres no overlap! */ @@ -2205,6 +2206,8 @@ static int split_faces_prepare_new_verts( MLoop *ml = mloop; MLoopNorSpace **lnor_space = lnors_spacearr->lspacearr; + BLI_assert(lnors_spacearr->data_type == MLNOR_SPACEARR_LOOP_INDEX); + for (int loop_idx = 0; loop_idx < num_loops; loop_idx++, ml++, lnor_space++) { if (!BLI_BITMAP_TEST(done_loops, loop_idx)) { const int vert_idx = ml->v; @@ -2214,7 +2217,15 @@ static int split_faces_prepare_new_verts( BLI_assert(*lnor_space); - if ((*lnor_space)->loops) { + if ((*lnor_space)->flags & MLNOR_SPACE_IS_SINGLE) { + /* Single loop in this fan... */ + BLI_assert(GET_INT_FROM_POINTER((*lnor_space)->loops) == loop_idx); + BLI_BITMAP_ENABLE(done_loops, loop_idx); + if (vert_used) { + ml->v = new_vert_idx; + } + } + else { for (LinkNode *lnode = (*lnor_space)->loops; lnode; lnode = lnode->next) { const int ml_fan_idx = GET_INT_FROM_POINTER(lnode->link); BLI_BITMAP_ENABLE(done_loops, ml_fan_idx); @@ -2223,13 +2234,6 @@ static int split_faces_prepare_new_verts( } } } - else { - /* Single loop in this fan... */ - BLI_BITMAP_ENABLE(done_loops, loop_idx); - if (vert_used) { - ml->v = new_vert_idx; - } - } if (!vert_used) { BLI_BITMAP_ENABLE(verts_used, vert_idx); @@ -2425,12 +2429,12 @@ void BKE_mesh_split_faces(Mesh *mesh, bool free_loop_normals) /* settings: 1 - preview, 2 - render */ Mesh *BKE_mesh_new_from_object( const EvaluationContext *eval_ctx, Main *bmain, Scene *sce, Object *ob, - int apply_modifiers, int settings, int calc_tessface, int calc_undeformed) + int apply_modifiers, int calc_tessface, int calc_undeformed) { Mesh *tmpmesh; Curve *tmpcu = NULL, *copycu; int i; - const bool render = (settings == eModifierMode_Render); + const bool render = (DEG_get_mode(eval_ctx->depsgraph) == DAG_EVAL_RENDER); const bool cage = !apply_modifiers; bool do_mat_id_data_us = true; @@ -2466,7 +2470,7 @@ Mesh *BKE_mesh_new_from_object( /* if getting the original caged mesh, delete object modifiers */ if (cage) - BKE_object_free_modifiers(tmpobj); + BKE_object_free_modifiers(tmpobj, 0); /* copies the data */ copycu = tmpobj->data = BKE_curve_copy(bmain, (Curve *) ob->data); @@ -2667,9 +2671,7 @@ Mesh *BKE_mesh_new_from_object( void BKE_mesh_eval_geometry(const EvaluationContext *UNUSED(eval_ctx), Mesh *mesh) { - if (G.debug & G_DEBUG_DEPSGRAPH) { - printf("%s on %s\n", __func__, mesh->id.name); - } + DEG_debug_print_eval(__func__, mesh->id.name, mesh); 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 00d1b29caf8..01cee2a19ff 100644 --- a/source/blender/blenkernel/intern/mesh_evaluate.c +++ b/source/blender/blenkernel/intern/mesh_evaluate.c @@ -43,7 +43,7 @@ #include "BLI_math.h" #include "BLI_edgehash.h" #include "BLI_bitmap.h" -#include "BLI_polyfill2d.h" +#include "BLI_polyfill_2d.h" #include "BLI_linklist.h" #include "BLI_linklist_stack.h" #include "BLI_alloca.h" @@ -253,16 +253,6 @@ static void mesh_calc_normals_poly_prepare_cb( } } -static void mesh_calc_normals_poly_accum_cb( - void *__restrict userdata, - const int lidx, - const ParallelRangeTLS *__restrict UNUSED(tls)) -{ - MeshCalcNormalsData *data = userdata; - - add_v3_v3(data->vnors[data->mloop[lidx].v], data->lnors_weighted[lidx]); -} - static void mesh_calc_normals_poly_finalize_cb( void *__restrict userdata, const int vidx, @@ -327,7 +317,11 @@ void BKE_mesh_calc_normals_poly( BLI_task_parallel_range(0, numPolys, &data, mesh_calc_normals_poly_prepare_cb, &settings); /* Actually accumulate weighted loop normals into vertex ones. */ - BLI_task_parallel_range(0, numLoops, &data, mesh_calc_normals_poly_accum_cb, &settings); + /* Unfortunately, not possible to thread that (not in a reasonable, totally lock- and barrier-free fashion), + * since several loops will point to the same vertex... */ + for (int lidx = 0; lidx < numLoops; lidx++) { + add_v3_v3(vnors[mloop[lidx].v], data.lnors_weighted[lidx]); + } /* Normalize and validate computed vertex normals. */ BLI_task_parallel_range(0, numVerts, &data, mesh_calc_normals_poly_finalize_cb, &settings); @@ -450,7 +444,7 @@ cleanup: MEM_freeN(fnors); } -void BKE_lnor_spacearr_init(MLoopNorSpaceArray *lnors_spacearr, const int numLoops) +void BKE_lnor_spacearr_init(MLoopNorSpaceArray *lnors_spacearr, const int numLoops, const char data_type) { if (!(lnors_spacearr->lspacearr && lnors_spacearr->loops_pool)) { MemArena *mem; @@ -462,6 +456,8 @@ void BKE_lnor_spacearr_init(MLoopNorSpaceArray *lnors_spacearr, const int numLoo lnors_spacearr->lspacearr = BLI_memarena_calloc(mem, sizeof(MLoopNorSpace *) * (size_t)numLoops); lnors_spacearr->loops_pool = BLI_memarena_alloc(mem, sizeof(LinkNode) * (size_t)numLoops); } + BLI_assert(ELEM(data_type, MLNOR_SPACEARR_BMLOOP_PTR, MLNOR_SPACEARR_LOOP_INDEX)); + lnors_spacearr->data_type = data_type; } void BKE_lnor_spacearr_clear(MLoopNorSpaceArray *lnors_spacearr) @@ -555,12 +551,32 @@ void BKE_lnor_space_define(MLoopNorSpace *lnor_space, const float lnor[3], } } -void BKE_lnor_space_add_loop(MLoopNorSpaceArray *lnors_spacearr, MLoopNorSpace *lnor_space, const int ml_index, - const bool do_add_loop) +/** + * Add a new given loop to given lnor_space. + * Depending on \a lnor_space->data_type, we expect \a bm_loop to be a pointer to BMLoop struct (in case of BMLOOP_PTR), + * or NULL (in case of LOOP_INDEX), loop index is then stored in pointer. + * If \a is_single is set, the BMLoop or loop index is directly stored in \a lnor_space->loops pointer (since there + * is only one loop in this fan), else it is added to the linked list of loops in the fan. + */ +void BKE_lnor_space_add_loop( + MLoopNorSpaceArray *lnors_spacearr, MLoopNorSpace *lnor_space, + const int ml_index, void *bm_loop, const bool is_single) { + BLI_assert((lnors_spacearr->data_type == MLNOR_SPACEARR_LOOP_INDEX && bm_loop == NULL) || + (lnors_spacearr->data_type == MLNOR_SPACEARR_BMLOOP_PTR && bm_loop != NULL)); + lnors_spacearr->lspacearr[ml_index] = lnor_space; - if (do_add_loop) { - BLI_linklist_prepend_nlink(&lnor_space->loops, SET_INT_IN_POINTER(ml_index), &lnors_spacearr->loops_pool[ml_index]); + if (bm_loop == NULL) { + bm_loop = SET_INT_IN_POINTER(ml_index); + } + if (is_single) { + BLI_assert(lnor_space->loops == NULL); + lnor_space->flags |= MLNOR_SPACE_IS_SINGLE; + lnor_space->loops = bm_loop; + } + else { + BLI_assert((lnor_space->flags & MLNOR_SPACE_IS_SINGLE) == 0); + BLI_linklist_prepend_nlink(&lnor_space->loops, bm_loop, &lnors_spacearr->loops_pool[ml_index]); } } @@ -686,10 +702,11 @@ typedef struct LoopSplitTaskDataCommon { const MEdge *medges; const MLoop *mloops; const MPoly *mpolys; - const int (*edge_to_loops)[2]; - const int *loop_to_poly; + int (*edge_to_loops)[2]; + int *loop_to_poly; const float (*polynors)[3]; + int numEdges; int numLoops; int numPolys; } LoopSplitTaskDataCommon; @@ -699,7 +716,154 @@ typedef struct LoopSplitTaskDataCommon { /* See comment about edge_to_loops below. */ #define IS_EDGE_SHARP(_e2l) (ELEM((_e2l)[1], INDEX_UNSET, INDEX_INVALID)) -static void loop_manifold_fan_around_vert_next( +static void mesh_edges_sharp_tag( + LoopSplitTaskDataCommon *data, + const bool check_angle, const float split_angle, const bool do_sharp_edges_tag) +{ + const MVert *mverts = data->mverts; + const MEdge *medges = data->medges; + const MLoop *mloops = data->mloops; + + const MPoly *mpolys = data->mpolys; + + const int numEdges = data->numEdges; + const int numPolys = data->numPolys; + + float (*loopnors)[3] = data->loopnors; /* Note: loopnors may be NULL here. */ + const float (*polynors)[3] = data->polynors; + + int (*edge_to_loops)[2] = data->edge_to_loops; + int *loop_to_poly = data->loop_to_poly; + + BLI_bitmap *sharp_edges = do_sharp_edges_tag ? BLI_BITMAP_NEW(numEdges, __func__) : NULL; + + const MPoly *mp; + int mp_index; + + const float split_angle_cos = check_angle ? cosf(split_angle) : -1.0f; + + for (mp = mpolys, mp_index = 0; mp_index < numPolys; mp++, mp_index++) { + const MLoop *ml_curr; + int *e2l; + int ml_curr_index = mp->loopstart; + const int ml_last_index = (ml_curr_index + mp->totloop) - 1; + + ml_curr = &mloops[ml_curr_index]; + + for (; ml_curr_index <= ml_last_index; ml_curr++, ml_curr_index++) { + e2l = edge_to_loops[ml_curr->e]; + + loop_to_poly[ml_curr_index] = mp_index; + + /* Pre-populate all loop normals as if their verts were all-smooth, this way we don't have to compute + * those later! + */ + if (loopnors) { + normal_short_to_float_v3(loopnors[ml_curr_index], mverts[ml_curr->v].no); + } + + /* Check whether current edge might be smooth or sharp */ + if ((e2l[0] | e2l[1]) == 0) { + /* 'Empty' edge until now, set e2l[0] (and e2l[1] to INDEX_UNSET to tag it as unset). */ + e2l[0] = ml_curr_index; + /* We have to check this here too, else we might miss some flat faces!!! */ + e2l[1] = (mp->flag & ME_SMOOTH) ? INDEX_UNSET : INDEX_INVALID; + } + else if (e2l[1] == INDEX_UNSET) { + const bool is_angle_sharp = (check_angle && + dot_v3v3(polynors[loop_to_poly[e2l[0]]], polynors[mp_index]) < split_angle_cos); + + /* Second loop using this edge, time to test its sharpness. + * An edge is sharp if it is tagged as such, or its face is not smooth, + * or both poly have opposed (flipped) normals, i.e. both loops on the same edge share the same vertex, + * or angle between both its polys' normals is above split_angle value. + */ + if (!(mp->flag & ME_SMOOTH) || (medges[ml_curr->e].flag & ME_SHARP) || + ml_curr->v == mloops[e2l[0]].v || + is_angle_sharp) + { + /* Note: we are sure that loop != 0 here ;) */ + e2l[1] = INDEX_INVALID; + + /* We want to avoid tagging edges as sharp when it is already defined as such by + * other causes than angle threshold... */ + if (do_sharp_edges_tag && is_angle_sharp) { + BLI_BITMAP_SET(sharp_edges, ml_curr->e, true); + } + } + else { + e2l[1] = ml_curr_index; + } + } + else if (!IS_EDGE_SHARP(e2l)) { + /* More than two loops using this edge, tag as sharp if not yet done. */ + e2l[1] = INDEX_INVALID; + + /* We want to avoid tagging edges as sharp when it is already defined as such by + * other causes than angle threshold... */ + if (do_sharp_edges_tag) { + BLI_BITMAP_SET(sharp_edges, ml_curr->e, false); + } + } + /* Else, edge is already 'disqualified' (i.e. sharp)! */ + } + } + + /* If requested, do actual tagging of edges as sharp in another loop. */ + if (do_sharp_edges_tag) { + MEdge *me; + int me_index; + for (me = (MEdge *)medges, me_index = 0; me_index < numEdges; me++, me_index++) { + if (BLI_BITMAP_TEST(sharp_edges, me_index)) { + me->flag |= ME_SHARP; + } + } + + MEM_freeN(sharp_edges); + } +} + +/** Define sharp edges as needed to mimic 'autosmooth' from angle threshold. + * + * Used when defining an empty custom loop normals data layer, to keep same shading as with autosmooth! + */ +void BKE_edges_sharp_from_angle_set( + const struct MVert *mverts, const int UNUSED(numVerts), + struct MEdge *medges, const int numEdges, + struct MLoop *mloops, const int numLoops, + struct MPoly *mpolys, const float (*polynors)[3], const int numPolys, + const float split_angle) +{ + if (split_angle >= (float)M_PI) { + /* Nothing to do! */ + return; + } + + /* Mapping edge -> loops. See BKE_mesh_normals_loop_split() for details. */ + int (*edge_to_loops)[2] = MEM_calloc_arrayN((size_t)numEdges, sizeof(*edge_to_loops), __func__); + + /* Simple mapping from a loop to its polygon index. */ + int *loop_to_poly = MEM_malloc_arrayN((size_t)numLoops, sizeof(*loop_to_poly), __func__); + + LoopSplitTaskDataCommon common_data = { + .mverts = mverts, + .medges = medges, + .mloops = mloops, + .mpolys = mpolys, + .edge_to_loops = edge_to_loops, + .loop_to_poly = loop_to_poly, + .polynors = polynors, + .numEdges = numEdges, + .numPolys = numPolys, + }; + + mesh_edges_sharp_tag(&common_data, true, split_angle, true); + + MEM_freeN(edge_to_loops); + MEM_freeN(loop_to_poly); +} + +void BKE_mesh_loop_manifold_fan_around_vert_next( const MLoop *mloops, const MPoly *mpolys, const int *loop_to_poly, const int *e2lfan_curr, const uint mv_pivot_index, const MLoop **r_mlfan_curr, int *r_mlfan_curr_index, int *r_mlfan_vert_index, int *r_mpfan_curr_index) @@ -788,7 +952,7 @@ static void split_loop_nor_single_do(LoopSplitTaskDataCommon *common_data, LoopS BKE_lnor_space_define(lnor_space, *lnor, vec_curr, vec_prev, NULL); /* We know there is only one loop in this space, no need to create a linklist in this case... */ - BKE_lnor_space_add_loop(lnors_spacearr, lnor_space, ml_curr_index, false); + BKE_lnor_space_add_loop(lnors_spacearr, lnor_space, ml_curr_index, NULL, true); if (clnors_data) { BKE_lnor_space_custom_data_to_normal(lnor_space, clnors_data[ml_curr_index], *lnor); @@ -921,7 +1085,7 @@ static void split_loop_nor_fan_do(LoopSplitTaskDataCommon *common_data, LoopSpli if (lnors_spacearr) { /* Assign current lnor space to current 'vertex' loop. */ - BKE_lnor_space_add_loop(lnors_spacearr, lnor_space, mlfan_vert_index, true); + BKE_lnor_space_add_loop(lnors_spacearr, lnor_space, mlfan_vert_index, NULL, false); if (me_curr != me_org) { /* We store here all edges-normalized vectors processed. */ BLI_stack_push(edge_vectors, vec_curr); @@ -939,7 +1103,7 @@ static void split_loop_nor_fan_do(LoopSplitTaskDataCommon *common_data, LoopSpli copy_v3_v3(vec_prev, vec_curr); /* Find next loop of the smooth fan. */ - loop_manifold_fan_around_vert_next( + BKE_mesh_loop_manifold_fan_around_vert_next( mloops, mpolys, loop_to_poly, e2lfan_curr, mv_pivot_index, &mlfan_curr, &mlfan_curr_index, &mlfan_vert_index, &mpfan_curr_index); @@ -1076,7 +1240,7 @@ static bool loop_split_generator_check_cyclic_smooth_fan( while (true) { /* Find next loop of the smooth fan. */ - loop_manifold_fan_around_vert_next( + BKE_mesh_loop_manifold_fan_around_vert_next( mloops, mpolys, loop_to_poly, e2lfan_curr, mv_pivot_index, &mlfan_curr, &mlfan_curr_index, &mlfan_vert_index, &mpfan_curr_index); @@ -1270,7 +1434,7 @@ void BKE_mesh_normals_loop_split( const MVert *mverts, const int UNUSED(numVerts), MEdge *medges, const int numEdges, MLoop *mloops, float (*r_loopnors)[3], const int numLoops, MPoly *mpolys, const float (*polynors)[3], const int numPolys, - const bool use_split_normals, float split_angle, + const bool use_split_normals, const float split_angle, MLoopNorSpaceArray *r_lnors_spacearr, short (*clnors_data)[2], int *r_loop_to_poly) { /* For now this is not supported. If we do not use split normals, we do not generate anything fancy! */ @@ -1319,9 +1483,6 @@ void BKE_mesh_normals_loop_split( /* Simple mapping from a loop to its polygon index. */ int *loop_to_poly = r_loop_to_poly ? r_loop_to_poly : MEM_malloc_arrayN((size_t)numLoops, sizeof(*loop_to_poly), __func__); - MPoly *mp; - int mp_index; - /* When using custom loop normals, disable the angle feature! */ const bool check_angle = (split_angle < (float)M_PI) && (clnors_data == NULL); @@ -1331,67 +1492,12 @@ void BKE_mesh_normals_loop_split( TIMEIT_START_AVERAGED(BKE_mesh_normals_loop_split); #endif - if (check_angle) { - split_angle = cosf(split_angle); - } - if (!r_lnors_spacearr && clnors_data) { /* We need to compute lnor spacearr if some custom lnor data are given to us! */ r_lnors_spacearr = &_lnors_spacearr; } if (r_lnors_spacearr) { - BKE_lnor_spacearr_init(r_lnors_spacearr, numLoops); - } - - /* This first loop check which edges are actually smooth, and compute edge vectors. */ - for (mp = mpolys, mp_index = 0; mp_index < numPolys; mp++, mp_index++) { - MLoop *ml_curr; - int *e2l; - int ml_curr_index = mp->loopstart; - const int ml_last_index = (ml_curr_index + mp->totloop) - 1; - - ml_curr = &mloops[ml_curr_index]; - - for (; ml_curr_index <= ml_last_index; ml_curr++, ml_curr_index++) { - e2l = edge_to_loops[ml_curr->e]; - - loop_to_poly[ml_curr_index] = mp_index; - - /* Pre-populate all loop normals as if their verts were all-smooth, this way we don't have to compute - * those later! - */ - normal_short_to_float_v3(r_loopnors[ml_curr_index], mverts[ml_curr->v].no); - - /* Check whether current edge might be smooth or sharp */ - if ((e2l[0] | e2l[1]) == 0) { - /* 'Empty' edge until now, set e2l[0] (and e2l[1] to INDEX_UNSET to tag it as unset). */ - e2l[0] = ml_curr_index; - /* We have to check this here too, else we might miss some flat faces!!! */ - e2l[1] = (mp->flag & ME_SMOOTH) ? INDEX_UNSET : INDEX_INVALID; - } - else if (e2l[1] == INDEX_UNSET) { - /* Second loop using this edge, time to test its sharpness. - * An edge is sharp if it is tagged as such, or its face is not smooth, - * or both poly have opposed (flipped) normals, i.e. both loops on the same edge share the same vertex, - * or angle between both its polys' normals is above split_angle value. - */ - if (!(mp->flag & ME_SMOOTH) || (medges[ml_curr->e].flag & ME_SHARP) || - ml_curr->v == mloops[e2l[0]].v || - (check_angle && dot_v3v3(polynors[loop_to_poly[e2l[0]]], polynors[mp_index]) < split_angle)) - { - /* Note: we are sure that loop != 0 here ;) */ - e2l[1] = INDEX_INVALID; - } - else { - e2l[1] = ml_curr_index; - } - } - else if (!IS_EDGE_SHARP(e2l)) { - /* More than two loops using this edge, tag as sharp if not yet done. */ - e2l[1] = INDEX_INVALID; - } - /* Else, edge is already 'disqualified' (i.e. sharp)! */ - } + BKE_lnor_spacearr_init(r_lnors_spacearr, numLoops, MLNOR_SPACEARR_LOOP_INDEX); } /* Init data common to all tasks. */ @@ -1403,13 +1509,17 @@ void BKE_mesh_normals_loop_split( .medges = medges, .mloops = mloops, .mpolys = mpolys, - .edge_to_loops = (const int(*)[2])edge_to_loops, + .edge_to_loops = edge_to_loops, .loop_to_poly = loop_to_poly, .polynors = polynors, + .numEdges = numEdges, .numLoops = numLoops, .numPolys = numPolys, }; + /* This first loop check which edges are actually smooth, and compute edge vectors. */ + mesh_edges_sharp_tag(&common_data, check_angle, split_angle, false); + if (numLoops < LOOP_SPLIT_TASK_BLOCK_SIZE * 8) { /* Not enough loops to be worth the whole threading overhead... */ loop_split_generator(NULL, &common_data); @@ -1501,6 +1611,8 @@ static void mesh_normals_loop_custom_set( } } + BLI_assert(lnors_spacearr.data_type == MLNOR_SPACEARR_LOOP_INDEX); + /* Now, check each current smooth fan (one lnor space per smooth fan!), and if all its matching custom lnors * are not (enough) equal, add sharp edges as needed. * This way, next time we run BKE_mesh_normals_loop_split(), we'll get lnor spacearr/smooth fans matching @@ -1524,7 +1636,7 @@ static void mesh_normals_loop_custom_set( if (!BLI_BITMAP_TEST(done_loops, i)) { /* Notes: - * * In case of mono-loop smooth fan, loops is NULL, so everything is fine (we have nothing to do). + * * In case of mono-loop smooth fan, we have nothing to do. * * Loops in this linklist are ordered (in reversed order compared to how they were discovered by * BKE_mesh_normals_loop_split(), but this is not a problem). Which means if we find a * mismatching clnor, we know all remaining loops will have to be in a new, different smooth fan/ @@ -1532,6 +1644,11 @@ static void mesh_normals_loop_custom_set( * * In smooth fan case, we compare each clnor against a ref one, to avoid small differences adding * up into a real big one in the end! */ + if (lnors_spacearr.lspacearr[i]->flags & MLNOR_SPACE_IS_SINGLE) { + BLI_BITMAP_ENABLE(done_loops, i); + continue; + } + LinkNode *loops = lnors_spacearr.lspacearr[i]->loops; MLoop *prev_ml = NULL; const float *org_nor = NULL; @@ -1579,9 +1696,6 @@ static void mesh_normals_loop_custom_set( medges[(prev_ml->e == mlp->e) ? prev_ml->e : ml->e].flag |= ME_SHARP; } } - - /* For single loops, where lnors_spacearr.lspacearr[i]->loops is NULL. */ - BLI_BITMAP_ENABLE(done_loops, i); } } @@ -1611,7 +1725,15 @@ static void mesh_normals_loop_custom_set( * computed 2D factors). */ LinkNode *loops = lnors_spacearr.lspacearr[i]->loops; - if (loops) { + if (lnors_spacearr.lspacearr[i]->flags & MLNOR_SPACE_IS_SINGLE) { + BLI_assert(GET_INT_FROM_POINTER(loops) == i); + const int nidx = use_vertices ? (int)mloops[i].v : i; + float *nor = r_custom_loopnors[nidx]; + + BKE_lnor_space_custom_normal_to_data(lnors_spacearr.lspacearr[i], nor, r_clnors_data[i]); + BLI_BITMAP_DISABLE(done_loops, i); + } + else { int nbr_nors = 0; float avg_nor[3]; short clnor_data_tmp[2], *clnor_data; @@ -1638,13 +1760,6 @@ static void mesh_normals_loop_custom_set( clnor_data[1] = clnor_data_tmp[1]; } } - else { - const int nidx = use_vertices ? (int)mloops[i].v : i; - float *nor = r_custom_loopnors[nidx]; - - BKE_lnor_space_custom_normal_to_data(lnors_spacearr.lspacearr[i], nor, r_clnors_data[i]); - BLI_BITMAP_DISABLE(done_loops, i); - } } } @@ -2272,6 +2387,7 @@ void BKE_mesh_calc_volume( } } +/** \} */ /* -------------------------------------------------------------------- */ @@ -2798,9 +2914,22 @@ void BKE_mesh_recalc_looptri( } else if (mp_totloop == 4) { ML_TO_MLT(0, 1, 2); + MLoopTri *mlt_a = mlt; mlooptri_index++; ML_TO_MLT(0, 2, 3); + MLoopTri *mlt_b = mlt; mlooptri_index++; + + if (UNLIKELY(is_quad_flip_v3_first_third_fast( + mvert[mloop[mlt_a->tri[0]].v].co, + mvert[mloop[mlt_a->tri[1]].v].co, + mvert[mloop[mlt_a->tri[2]].v].co, + mvert[mloop[mlt_b->tri[2]].v].co))) + { + /* flip out of degenerate 0-2 state. */ + mlt_a->tri[2] = mlt_b->tri[2]; + mlt_b->tri[0] = mlt_a->tri[1]; + } } #endif /* USE_TESSFACE_SPEEDUP */ else { diff --git a/source/blender/blenkernel/intern/mesh_remap.c b/source/blender/blenkernel/intern/mesh_remap.c index f321c94bf00..0af4dae4506 100644 --- a/source/blender/blenkernel/intern/mesh_remap.c +++ b/source/blender/blenkernel/intern/mesh_remap.c @@ -36,7 +36,7 @@ #include "BLI_bitmap.h" #include "BLI_math.h" #include "BLI_memarena.h" -#include "BLI_polyfill2d.h" +#include "BLI_polyfill_2d.h" #include "BLI_rand.h" #include "BKE_bvhutils.h" diff --git a/source/blender/blenkernel/intern/mesh_validate.c b/source/blender/blenkernel/intern/mesh_validate.c index 54de843bc64..8301b6a42b1 100644 --- a/source/blender/blenkernel/intern/mesh_validate.c +++ b/source/blender/blenkernel/intern/mesh_validate.c @@ -63,8 +63,8 @@ typedef union { } EdgeUUID; typedef struct SortFace { - EdgeUUID es[4]; - unsigned int index; + EdgeUUID es[4]; + unsigned int index; } SortFace; /* Used to detect polys (faces) using exactly the same vertices. */ @@ -127,28 +127,28 @@ static int search_face_cmp(const void *v1, const void *v2) if (sfa->es[0].edval > sfb->es[0].edval) { return 1; } - else if (sfa->es[0].edval < sfb->es[0].edval) { + else if (sfa->es[0].edval < sfb->es[0].edval) { return -1; } - else if (sfa->es[1].edval > sfb->es[1].edval) { + else if (sfa->es[1].edval > sfb->es[1].edval) { return 1; } - else if (sfa->es[1].edval < sfb->es[1].edval) { + else if (sfa->es[1].edval < sfb->es[1].edval) { return -1; } - else if (sfa->es[2].edval > sfb->es[2].edval) { + else if (sfa->es[2].edval > sfb->es[2].edval) { return 1; } - else if (sfa->es[2].edval < sfb->es[2].edval) { + else if (sfa->es[2].edval < sfb->es[2].edval) { return -1; } - else if (sfa->es[3].edval > sfb->es[3].edval) { + else if (sfa->es[3].edval > sfb->es[3].edval) { return 1; } - else if (sfa->es[3].edval < sfb->es[3].edval) { + else if (sfa->es[3].edval < sfb->es[3].edval) { return -1; } @@ -1412,7 +1412,7 @@ void BKE_mesh_calc_edges(Mesh *mesh, bool update, const bool select) } } - totedge = BLI_edgehash_size(eh); + totedge = BLI_edgehash_len(eh); /* write new edges into a temporary CustomData */ CustomData_reset(&edata); diff --git a/source/blender/blenkernel/intern/modifier.c b/source/blender/blenkernel/intern/modifier.c index 8bfeacd256c..5eb5272f3e5 100644 --- a/source/blender/blenkernel/intern/modifier.c +++ b/source/blender/blenkernel/intern/modifier.c @@ -69,6 +69,8 @@ #include "BKE_main.h" /* end */ +#include "DEG_depsgraph.h" + #include "MOD_modifiertypes.h" static ModifierTypeInfo *modifier_types[NUM_MODIFIER_TYPES] = {NULL}; @@ -136,16 +138,38 @@ ModifierData *modifier_new(int type) return md; } -void modifier_free(ModifierData *md) +static void modifier_free_data_id_us_cb(void *UNUSED(userData), Object *UNUSED(ob), ID **idpoin, int cb_flag) +{ + ID *id = *idpoin; + if (id != NULL && (cb_flag & IDWALK_CB_USER) != 0) { + id_us_min(id); + } +} + +void modifier_free_ex(ModifierData *md, const int flag) { const ModifierTypeInfo *mti = modifierType_getInfo(md->type); + if ((flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0) { + if (mti->foreachIDLink) { + mti->foreachIDLink(md, NULL, modifier_free_data_id_us_cb, NULL); + } + else if (mti->foreachObjectLink) { + mti->foreachObjectLink(md, NULL, (ObjectWalkFunc)modifier_free_data_id_us_cb, NULL); + } + } + if (mti->freeData) mti->freeData(md); if (md->error) MEM_freeN(md->error); MEM_freeN(md); } +void modifier_free(ModifierData *md) +{ + modifier_free_ex(md, 0); +} + bool modifier_unique_name(ListBase *modifiers, ModifierData *md) { if (modifiers && md) { @@ -666,9 +690,9 @@ bool modifiers_isCorrectableDeformed(struct Scene *scene, Object *ob) ModifierData *md = modifiers_getVirtualModifierList(ob, &virtualModifierData); int required_mode = eModifierMode_Realtime; - if (ob->mode == OB_MODE_EDIT) + if (ob->mode == OB_MODE_EDIT) { required_mode |= eModifierMode_Editmode; - + } for (; md; md = md->next) { if (!modifier_isEnabled(scene, md, required_mode)) { /* pass */ diff --git a/source/blender/blenkernel/intern/modifiers_bmesh.c b/source/blender/blenkernel/intern/modifiers_bmesh.c index 0838630a6cb..a1172d3f110 100644 --- a/source/blender/blenkernel/intern/modifiers_bmesh.c +++ b/source/blender/blenkernel/intern/modifiers_bmesh.c @@ -62,7 +62,7 @@ void DM_to_bmesh_ex(DerivedMesh *dm, BMesh *bm, const bool calc_face_normal) { MVert *mv, *mvert; MEdge *me, *medge; - MPoly /* *mpoly, */ /* UNUSED */ *mp; + MPoly *mpoly, *mp; MLoop *mloop; BMVert *v, **vtable; BMEdge *e, **etable; @@ -70,7 +70,6 @@ void DM_to_bmesh_ex(DerivedMesh *dm, BMesh *bm, const bool calc_face_normal) BMFace *f; int i, j, totvert, totedge /* , totface */ /* UNUSED */ ; bool is_init = (bm->totvert == 0) && (bm->totedge == 0) && (bm->totface == 0); - bool is_cddm = (dm->type == DM_TYPE_CDDM); /* duplicate the arrays for non cddm */ char has_orig_htype = 0; int cd_vert_bweight_offset; @@ -106,7 +105,8 @@ void DM_to_bmesh_ex(DerivedMesh *dm, BMesh *bm, const bool calc_face_normal) etable = MEM_mallocN(sizeof(*etable) * totedge, __func__); /*do verts*/ - mv = mvert = is_cddm ? dm->getVertArray(dm) : dm->dupVertArray(dm); + bool vert_allocated; + mv = mvert = DM_get_vert_array(dm, &vert_allocated);; for (i = 0; i < totvert; i++, mv++) { v = BM_vert_create(bm, mv->co, NULL, BM_CREATE_SKIP_CD); normal_short_to_float_v3(v->no, mv->no); @@ -124,11 +124,12 @@ void DM_to_bmesh_ex(DerivedMesh *dm, BMesh *bm, const bool calc_face_normal) *orig_index = ORIGINDEX_NONE; } } - if (!is_cddm) MEM_freeN(mvert); + if (vert_allocated) MEM_freeN(mvert); if (is_init) bm->elem_index_dirty &= ~BM_VERT; /*do edges*/ - me = medge = is_cddm ? dm->getEdgeArray(dm) : dm->dupEdgeArray(dm); + bool edge_allocated; + me = medge = DM_get_edge_array(dm, &edge_allocated); for (i = 0; i < totedge; i++, me++) { //BLI_assert(BM_edge_exists(vtable[me->v1], vtable[me->v2]) == NULL); e = BM_edge_create(bm, vtable[me->v1], vtable[me->v2], NULL, BM_CREATE_SKIP_CD); @@ -147,13 +148,14 @@ void DM_to_bmesh_ex(DerivedMesh *dm, BMesh *bm, const bool calc_face_normal) *orig_index = ORIGINDEX_NONE; } } - if (!is_cddm) MEM_freeN(medge); + if (edge_allocated) MEM_freeN(medge); if (is_init) bm->elem_index_dirty &= ~BM_EDGE; /* do faces */ /* note: i_alt is aligned with bmesh faces which may not always align with mpolys */ - mp = dm->getPolyArray(dm); - mloop = dm->getLoopArray(dm); + bool poly_allocated, loop_allocated; + mpoly = mp = DM_get_poly_array(dm, &poly_allocated); + mloop = DM_get_loop_array(dm, &loop_allocated); face_normals = (dm->dirty & DM_DIRTY_NORMALS) ? NULL : CustomData_get_layer(&dm->polyData, CD_NORMAL); for (i = 0; i < dm->numPolyData; i++, mp++) { BMLoop *l_iter; @@ -194,6 +196,8 @@ void DM_to_bmesh_ex(DerivedMesh *dm, BMesh *bm, const bool calc_face_normal) *orig_index = ORIGINDEX_NONE; } } + if (poly_allocated) MEM_freeN(mpoly); + if (loop_allocated) MEM_freeN(mloop); if (is_init) bm->elem_index_dirty &= ~(BM_FACE | BM_LOOP); MEM_freeN(vtable); diff --git a/source/blender/blenkernel/intern/movieclip.c b/source/blender/blenkernel/intern/movieclip.c index 08df976941b..9ed715d7591 100644 --- a/source/blender/blenkernel/intern/movieclip.c +++ b/source/blender/blenkernel/intern/movieclip.c @@ -73,12 +73,12 @@ #include "IMB_imbuf.h" #include "IMB_moviecache.h" +#include "DEG_depsgraph.h" + #ifdef WITH_OPENEXR # include "intern/openexr/openexr_multi.h" #endif -#define DEBUG_PRINT if (G.debug & G_DEBUG_DEPSGRAPH) printf - /*********************** movieclip buffer loaders *************************/ static int sequence_guess_offset(const char *full_name, int head_len, unsigned short numlen) @@ -926,7 +926,7 @@ static ImBuf *movieclip_get_postprocessed_ibuf(MovieClip *clip, /* cache isn't threadsafe itself and also loading of movies * can't happen from concurrent threads that's why we use lock here */ - BLI_lock_thread(LOCK_MOVIECLIP); + BLI_thread_lock(LOCK_MOVIECLIP); /* try to obtain cached postprocessed frame first */ if (need_postprocessed_frame(user, postprocess_flag)) { @@ -976,7 +976,7 @@ static ImBuf *movieclip_get_postprocessed_ibuf(MovieClip *clip, } } - BLI_unlock_thread(LOCK_MOVIECLIP); + BLI_thread_unlock(LOCK_MOVIECLIP); return ibuf; } @@ -1202,6 +1202,23 @@ int BKE_movieclip_get_duration(MovieClip *clip) return clip->len; } +float BKE_movieclip_get_fps(MovieClip *clip) +{ + if (clip->source != MCLIP_SRC_MOVIE) { + return 0.0f; + } + movieclip_open_anim_file(clip); + if (clip->anim == NULL) { + return 0.0f; + } + short frs_sec; + float frs_sec_base; + if (IMB_anim_get_fps(clip->anim, &frs_sec, &frs_sec_base, true)) { + return (float)frs_sec / frs_sec_base; + } + return 0.0f; +} + void BKE_movieclip_get_aspect(MovieClip *clip, float *aspx, float *aspy) { *aspx = 1.0; @@ -1410,13 +1427,13 @@ static void movieclip_build_proxy_ibuf(MovieClip *clip, ImBuf *ibuf, int cfra, i * could be solved in a way that thread only prepares memory * buffer and write to disk happens separately */ - BLI_lock_thread(LOCK_MOVIECLIP); + BLI_thread_lock(LOCK_MOVIECLIP); BLI_make_existing_file(name); if (IMB_saveiff(scaleibuf, name, IB_rect) == 0) perror(name); - BLI_unlock_thread(LOCK_MOVIECLIP); + BLI_thread_unlock(LOCK_MOVIECLIP); IMB_freeImBuf(scaleibuf); } @@ -1560,9 +1577,9 @@ ImBuf *BKE_movieclip_anim_ibuf_for_frame(MovieClip *clip, MovieClipUser *user) ImBuf *ibuf = NULL; if (clip->source == MCLIP_SRC_MOVIE) { - BLI_lock_thread(LOCK_MOVIECLIP); + BLI_thread_lock(LOCK_MOVIECLIP); ibuf = movieclip_load_movie_file(clip, user, user->framenr, clip->flag); - BLI_unlock_thread(LOCK_MOVIECLIP); + BLI_thread_unlock(LOCK_MOVIECLIP); } return ibuf; @@ -1572,9 +1589,9 @@ bool BKE_movieclip_has_cached_frame(MovieClip *clip, MovieClipUser *user) { bool has_frame = false; - BLI_lock_thread(LOCK_MOVIECLIP); + BLI_thread_lock(LOCK_MOVIECLIP); has_frame = has_imbuf_cache(clip, user, clip->flag); - BLI_unlock_thread(LOCK_MOVIECLIP); + BLI_thread_unlock(LOCK_MOVIECLIP); return has_frame; } @@ -1585,15 +1602,15 @@ bool BKE_movieclip_put_frame_if_possible(MovieClip *clip, { bool result; - BLI_lock_thread(LOCK_MOVIECLIP); + BLI_thread_lock(LOCK_MOVIECLIP); result = put_imbuf_cache(clip, user, ibuf, clip->flag, false); - BLI_unlock_thread(LOCK_MOVIECLIP); + BLI_thread_unlock(LOCK_MOVIECLIP); return result; } void BKE_movieclip_eval_update(struct EvaluationContext *UNUSED(eval_ctx), MovieClip *clip) { - DEBUG_PRINT("%s on %s (%p)\n", __func__, clip->id.name, clip); + DEG_debug_print_eval(__func__, clip->id.name, clip); BKE_tracking_dopesheet_tag_update(&clip->tracking); } diff --git a/source/blender/blenkernel/intern/nla.c b/source/blender/blenkernel/intern/nla.c index cbb7a766dfe..777c2a580fd 100644 --- a/source/blender/blenkernel/intern/nla.c +++ b/source/blender/blenkernel/intern/nla.c @@ -75,7 +75,7 @@ /* Remove the given NLA strip from the NLA track it occupies, free the strip's data, * and the strip itself. */ -void free_nlastrip(ListBase *strips, NlaStrip *strip) +void BKE_nlastrip_free(ListBase *strips, NlaStrip *strip) { NlaStrip *cs, *csn; @@ -86,7 +86,7 @@ void free_nlastrip(ListBase *strips, NlaStrip *strip) /* free child-strips */ for (cs = strip->strips.first; cs; cs = csn) { csn = cs->next; - free_nlastrip(&strip->strips, cs); + BKE_nlastrip_free(&strip->strips, cs); } /* remove reference to action */ @@ -113,7 +113,7 @@ void free_nlastrip(ListBase *strips, NlaStrip *strip) /* Remove the given NLA track from the set of NLA tracks, free the track's data, * and the track itself. */ -void free_nlatrack(ListBase *tracks, NlaTrack *nlt) +void BKE_nlatrack_free(ListBase *tracks, NlaTrack *nlt) { NlaStrip *strip, *stripn; @@ -124,7 +124,7 @@ void free_nlatrack(ListBase *tracks, NlaTrack *nlt) /* free strips */ for (strip = nlt->strips.first; strip; strip = stripn) { stripn = strip->next; - free_nlastrip(&nlt->strips, strip); + BKE_nlastrip_free(&nlt->strips, strip); } /* free NLA track itself now */ @@ -137,7 +137,7 @@ void free_nlatrack(ListBase *tracks, NlaTrack *nlt) /* Free the elements of type NLA Tracks provided in the given list, but do not free * the list itself since that is not free-standing */ -void free_nladata(ListBase *tracks) +void BKE_nla_tracks_free(ListBase *tracks) { NlaTrack *nlt, *nltn; @@ -148,7 +148,7 @@ void free_nladata(ListBase *tracks) /* free tracks one by one */ for (nlt = tracks->first; nlt; nlt = nltn) { nltn = nlt->next; - free_nlatrack(tracks, nlt); + BKE_nlatrack_free(tracks, nlt); } /* clear the list's pointers to be safe */ @@ -162,7 +162,7 @@ void free_nladata(ListBase *tracks) * * \param use_same_action When true, the existing action is used (instead of being duplicated) */ -NlaStrip *copy_nlastrip(NlaStrip *strip, const bool use_same_action) +NlaStrip *BKE_nlastrip_copy(NlaStrip *strip, const bool use_same_action) { NlaStrip *strip_d; NlaStrip *cs, *cs_d; @@ -195,7 +195,7 @@ NlaStrip *copy_nlastrip(NlaStrip *strip, const bool use_same_action) BLI_listbase_clear(&strip_d->strips); for (cs = strip->strips.first; cs; cs = cs->next) { - cs_d = copy_nlastrip(cs, use_same_action); + cs_d = BKE_nlastrip_copy(cs, use_same_action); BLI_addtail(&strip_d->strips, cs_d); } @@ -204,7 +204,7 @@ NlaStrip *copy_nlastrip(NlaStrip *strip, const bool use_same_action) } /* Copy NLA Track */ -NlaTrack *copy_nlatrack(NlaTrack *nlt, const bool use_same_actions) +NlaTrack *BKE_nlatrack_copy(NlaTrack *nlt, const bool use_same_actions) { NlaStrip *strip, *strip_d; NlaTrack *nlt_d; @@ -221,7 +221,7 @@ NlaTrack *copy_nlatrack(NlaTrack *nlt, const bool use_same_actions) BLI_listbase_clear(&nlt_d->strips); for (strip = nlt->strips.first; strip; strip = strip->next) { - strip_d = copy_nlastrip(strip, use_same_actions); + strip_d = BKE_nlastrip_copy(strip, use_same_actions); BLI_addtail(&nlt_d->strips, strip_d); } @@ -230,7 +230,7 @@ NlaTrack *copy_nlatrack(NlaTrack *nlt, const bool use_same_actions) } /* Copy all NLA data */ -void copy_nladata(ListBase *dst, ListBase *src) +void BKE_nla_tracks_copy(ListBase *dst, ListBase *src) { NlaTrack *nlt, *nlt_d; @@ -245,7 +245,7 @@ void copy_nladata(ListBase *dst, ListBase *src) for (nlt = src->first; nlt; nlt = nlt->next) { /* make a copy, and add the copy to the destination list */ // XXX: we need to fix this sometime - nlt_d = copy_nlatrack(nlt, true); + nlt_d = BKE_nlatrack_copy(nlt, true); BLI_addtail(dst, nlt_d); } } @@ -255,7 +255,7 @@ void copy_nladata(ListBase *dst, ListBase *src) /* Add a NLA Track to the given AnimData * - prev: NLA-Track to add the new one after */ -NlaTrack *add_nlatrack(AnimData *adt, NlaTrack *prev) +NlaTrack *BKE_nlatrack_add(AnimData *adt, NlaTrack *prev) { NlaTrack *nlt; @@ -285,8 +285,8 @@ NlaTrack *add_nlatrack(AnimData *adt, NlaTrack *prev) return nlt; } -/* Add a NLA Strip referencing the given Action */ -NlaStrip *add_nlastrip(bAction *act) +/* Create a NLA Strip referencing the given Action */ +NlaStrip *BKE_nlastrip_new(bAction *act) { NlaStrip *strip; @@ -327,7 +327,7 @@ NlaStrip *add_nlastrip(bAction *act) } /* Add new NLA-strip to the top of the NLA stack - i.e. into the last track if space, or a new one otherwise */ -NlaStrip *add_nlastrip_to_stack(AnimData *adt, bAction *act) +NlaStrip *BKE_nlastack_add_strip(AnimData *adt, bAction *act) { NlaStrip *strip; NlaTrack *nlt; @@ -337,7 +337,7 @@ NlaStrip *add_nlastrip_to_stack(AnimData *adt, bAction *act) return NULL; /* create a new NLA strip */ - strip = add_nlastrip(act); + strip = BKE_nlastrip_new(act); if (strip == NULL) return NULL; @@ -346,7 +346,7 @@ NlaStrip *add_nlastrip_to_stack(AnimData *adt, bAction *act) /* trying to add to the last track failed (no track or no space), * so add a new track to the stack, and add to that... */ - nlt = add_nlatrack(adt, NULL); + nlt = BKE_nlatrack_add(adt, NULL); BKE_nlatrack_add_strip(nlt, strip); } @@ -358,7 +358,7 @@ NlaStrip *add_nlastrip_to_stack(AnimData *adt, bAction *act) } /* Add a NLA Strip referencing the given speaker's sound */ -NlaStrip *add_nla_soundstrip(Scene *scene, Speaker *speaker) +NlaStrip *BKE_nla_add_soundstrip(Scene *scene, Speaker *speaker) { NlaStrip *strip = MEM_callocN(sizeof(NlaStrip), "NlaSoundStrip"); @@ -751,7 +751,7 @@ void BKE_nlastrips_clear_metastrip(ListBase *strips, NlaStrip *strip) } /* free the meta-strip now */ - free_nlastrip(strips, strip); + BKE_nlastrip_free(strips, strip); } /* Remove meta-strips (i.e. flatten the list of strips) from the top-level of the list of strips @@ -1392,7 +1392,12 @@ void BKE_nlastrip_validate_fcurves(NlaStrip *strip) /* store path - make copy, and store that */ fcu->rna_path = BLI_strdupn("influence", 9); - /* TODO: insert a few keyframes to ensure default behavior? */ + /* insert keyframe to ensure current value stays on first refresh */ + fcu->bezt = MEM_callocN(sizeof(BezTriple), "nlastrip influence bezt"); + fcu->totvert = 1; + + fcu->bezt->vec[1][0] = strip->start; + fcu->bezt->vec[1][1] = strip->influence; } } @@ -1709,7 +1714,7 @@ bool BKE_nla_action_stash(AnimData *adt) } } - nlt = add_nlatrack(adt, prev_track); + nlt = BKE_nlatrack_add(adt, prev_track); BLI_assert(nlt != NULL); /* we need to ensure that if there wasn't any previous instance, it must go to tbe bottom of the stack */ @@ -1724,7 +1729,7 @@ bool BKE_nla_action_stash(AnimData *adt) /* add the action as a strip in this new track * NOTE: a new user is created here */ - strip = add_nlastrip(adt->action); + strip = BKE_nlastrip_new(adt->action); BLI_assert(strip != NULL); BKE_nlatrack_add_strip(nlt, strip); @@ -1760,7 +1765,8 @@ bool BKE_nla_action_stash(AnimData *adt) void BKE_nla_action_pushdown(AnimData *adt) { NlaStrip *strip; - + const bool is_first = (adt) && (adt->nla_tracks.first == NULL); + /* sanity checks */ /* TODO: need to report the error for this */ if (ELEM(NULL, adt, adt->action)) @@ -1776,7 +1782,7 @@ void BKE_nla_action_pushdown(AnimData *adt) } /* add a new NLA strip to the track, which references the active action */ - strip = add_nlastrip_to_stack(adt, adt->action); + strip = BKE_nlastack_add_strip(adt, adt->action); /* do other necessary work on strip */ if (strip) { @@ -1784,6 +1790,32 @@ void BKE_nla_action_pushdown(AnimData *adt) id_us_min(&adt->action->id); adt->action = NULL; + /* copy current "action blending" settings from adt to the strip, + * as it was keyframed with these settings, so omitting them will + * change the effect [T54233] + * + * NOTE: We only do this when there are no tracks + */ + if (is_first == false) { + strip->blendmode = adt->act_blendmode; + strip->influence = adt->act_influence; + strip->extendmode = adt->act_extendmode; + + if (adt->act_influence < 1.0f) { + /* enable "user-controlled" influence (which will insert a default keyframe) + * so that the influence doesn't get lost on the new update + * + * NOTE: An alternative way would have been to instead hack the influence + * to not get always get reset to full strength if NLASTRIP_FLAG_USR_INFLUENCE + * is disabled but auto-blending isn't being used. However, that approach + * is a bit hacky/hard to discover, and may cause backwards compatability issues, + * so it's better to just do it this way. + */ + strip->flag |= NLASTRIP_FLAG_USR_INFLUENCE; + BKE_nlastrip_validate_fcurves(strip); + } + } + /* if the strip is the first one in the track it lives in, check if there * are strips in any other tracks that may be before this, and set the extend * mode accordingly @@ -1793,7 +1825,8 @@ void BKE_nla_action_pushdown(AnimData *adt) * so that it doesn't override strips in previous tracks */ /* FIXME: this needs to be more automated, since user can rearrange strips */ - strip->extendmode = NLASTRIP_EXTEND_HOLD_FORWARD; + if (strip->extendmode == NLASTRIP_EXTEND_HOLD) + strip->extendmode = NLASTRIP_EXTEND_HOLD_FORWARD; } /* make strip the active one... */ diff --git a/source/blender/blenkernel/intern/node.c b/source/blender/blenkernel/intern/node.c index cac2aab26dd..41b7cd1f48e 100644 --- a/source/blender/blenkernel/intern/node.c +++ b/source/blender/blenkernel/intern/node.c @@ -75,6 +75,8 @@ #include "NOD_shader.h" #include "NOD_texture.h" +#include "DEG_depsgraph.h" + #define NODE_DEFAULT_MAX_WIDTH 700 /* Fallback types for undefined tree, nodes, sockets */ @@ -2787,7 +2789,7 @@ int BKE_node_instance_hash_haskey(bNodeInstanceHash *hash, bNodeInstanceKey key) int BKE_node_instance_hash_size(bNodeInstanceHash *hash) { - return BLI_ghash_size(hash->ghash); + return BLI_ghash_len(hash->ghash); } void BKE_node_instance_hash_clear_tags(bNodeInstanceHash *hash) @@ -3590,6 +3592,7 @@ static void registerShaderNodes(void) register_node_type_sh_attribute(); register_node_type_sh_bevel(); register_node_type_sh_displacement(); + register_node_type_sh_vector_displacement(); register_node_type_sh_geometry(); register_node_type_sh_light_path(); register_node_type_sh_light_falloff(); @@ -3615,6 +3618,7 @@ static void registerShaderNodes(void) register_node_type_sh_holdout(); register_node_type_sh_volume_absorption(); register_node_type_sh_volume_scatter(); + register_node_type_sh_volume_principled(); register_node_type_sh_subsurface_scattering(); register_node_type_sh_mix_shader(); register_node_type_sh_add_shader(); @@ -3819,6 +3823,7 @@ bool BKE_node_tree_iter_step(struct NodeTreeIterStore *ntreeiter, void BKE_nodetree_remove_layer_n(bNodeTree *ntree, Scene *scene, const int layer_index) { + BLI_assert(layer_index != -1); for (bNode *node = ntree->nodes.first; node; node = node->next) { if (node->type == CMP_NODE_R_LAYERS && (Scene *)node->id == scene) { if (node->custom1 == layer_index) { @@ -3868,8 +3873,6 @@ void BKE_nodetree_shading_params_eval(const struct EvaluationContext *UNUSED(eva bNodeTree *ntree_dst, const bNodeTree *ntree_src) { - if (G.debug & G_DEBUG_DEPSGRAPH) { - printf("%s on %s (%p)\n", __func__, ntree_src->id.name, ntree_dst); - } + DEG_debug_print_eval(__func__, ntree_src->id.name, ntree_dst); BKE_nodetree_copy_default_values(ntree_dst, ntree_src); } diff --git a/source/blender/blenkernel/intern/object.c b/source/blender/blenkernel/intern/object.c index 2a4914da101..2cb4356a52a 100644 --- a/source/blender/blenkernel/intern/object.c +++ b/source/blender/blenkernel/intern/object.c @@ -200,12 +200,12 @@ void BKE_object_free_curve_cache(Object *ob) } } -void BKE_object_free_modifiers(Object *ob) +void BKE_object_free_modifiers(Object *ob, const int flag) { ModifierData *md; while ((md = BLI_pophead(&ob->modifiers))) { - modifier_free(md); + modifier_free_ex(md, flag); } /* particle modifiers were freed, so free the particlesystems as well */ @@ -240,7 +240,7 @@ void BKE_object_modifier_hook_reset(Object *ob, HookModifierData *hmd) } } -bool BKE_object_support_modifier_type_check(Object *ob, int modifier_type) +bool BKE_object_support_modifier_type_check(const Object *ob, int modifier_type) { const ModifierTypeInfo *mti; @@ -267,7 +267,7 @@ bool BKE_object_support_modifier_type_check(Object *ob, int modifier_type) void BKE_object_link_modifiers(struct Object *ob_dst, const struct Object *ob_src) { ModifierData *md; - BKE_object_free_modifiers(ob_dst); + BKE_object_free_modifiers(ob_dst, 0); if (!ELEM(ob_dst->type, OB_MESH, OB_CURVE, OB_SURF, OB_FONT, OB_LATTICE)) { /* only objects listed above can have modifiers and linking them to objects @@ -427,7 +427,8 @@ void BKE_object_free(Object *ob) { BKE_animdata_free((ID *)ob, false); - BKE_object_free_modifiers(ob); + /* BKE_<id>_free shall never touch to ID->us. Never ever. */ + BKE_object_free_modifiers(ob, LIB_ID_CREATE_NO_USER_REFCOUNT); MEM_SAFE_FREE(ob->mat); MEM_SAFE_FREE(ob->matbits); @@ -467,11 +468,8 @@ void BKE_object_free(Object *ob) GPU_lamp_free(ob); for (ObjectEngineData *oed = ob->drawdata.first; oed; oed = oed->next) { - if (oed->storage) { - if (oed->free) { - oed->free(oed->storage); - } - MEM_freeN(oed->storage); + if (oed->free != NULL) { + oed->free(oed); } } BLI_freelistN(&ob->drawdata); @@ -498,7 +496,7 @@ void BKE_object_free(Object *ob) } /* actual check for internal data, not context or flags */ -bool BKE_object_is_in_editmode(Object *ob) +bool BKE_object_is_in_editmode(const Object *ob) { if (ob->data == NULL) return false; @@ -546,13 +544,13 @@ bool BKE_object_is_in_editmode(Object *ob) return false; } -bool BKE_object_is_in_editmode_vgroup(Object *ob) +bool BKE_object_is_in_editmode_vgroup(const Object *ob) { return (OB_TYPE_SUPPORT_VGROUP(ob->type) && BKE_object_is_in_editmode(ob)); } -bool BKE_object_is_in_wpaint_select_vert(Object *ob) +bool BKE_object_is_in_wpaint_select_vert(const Object *ob) { if (ob->type == OB_MESH) { Mesh *me = ob->data; @@ -594,7 +592,7 @@ bool BKE_object_is_visible(Object *ob, const eObjectVisibilityCheck mode) } } -bool BKE_object_exists_check(Object *obtest) +bool BKE_object_exists_check(const Object *obtest) { Object *ob; @@ -1056,7 +1054,6 @@ ParticleSystem *BKE_object_copy_particlesystem(ParticleSystem *psys, const int f BLI_listbase_clear(&psysn->pathcachebufs); BLI_listbase_clear(&psysn->childcachebufs); - psysn->renderdata = NULL; /* XXX Never copy caches here? */ psysn->pointcache = BKE_ptcache_copy_list(&psysn->ptcaches, &psys->ptcaches, flag & ~LIB_ID_COPY_CACHES); @@ -1169,7 +1166,7 @@ static void copy_object_lod(Object *obn, const Object *ob, const int UNUSED(flag obn->currentlod = (LodLevel *)obn->lodlevels.first; } -bool BKE_object_pose_context_check(Object *ob) +bool BKE_object_pose_context_check(const Object *ob) { if ((ob) && (ob->type == OB_ARMATURE) && @@ -1193,12 +1190,26 @@ Object *BKE_object_pose_armature_get(Object *ob) ob = modifiers_isDeformedByArmature(ob); + /* Only use selected check when non-active. */ if (BKE_object_pose_context_check(ob)) return ob; return NULL; } +Object *BKE_object_pose_armature_get_visible(Object *ob, ViewLayer *view_layer) +{ + Object *ob_armature = BKE_object_pose_armature_get(ob); + if (ob_armature) { + Base *base = BKE_view_layer_base_find(view_layer, ob_armature); + if (base) { + if (BASE_VISIBLE(base)) { + return ob_armature; + } + } + } + return NULL; +} void BKE_object_transform_copy(Object *ob_tar, const Object *ob_src) { copy_v3_v3(ob_tar->loc, ob_src->loc); @@ -1357,13 +1368,13 @@ void BKE_object_make_local(Main *bmain, Object *ob, const bool lib_local) } /* Returns true if the Object is from an external blend file (libdata) */ -bool BKE_object_is_libdata(Object *ob) +bool BKE_object_is_libdata(const Object *ob) { return (ob && ID_IS_LINKED(ob)); } /* Returns true if the Object data is from an external blend file (libdata) */ -bool BKE_object_obdata_is_libdata(Object *ob) +bool BKE_object_obdata_is_libdata(const Object *ob) { /* Linked objects with local obdata are forbidden! */ BLI_assert(!ob || !ob->data || (ID_IS_LINKED(ob) ? ID_IS_LINKED(ob->data) : true)); @@ -2318,7 +2329,7 @@ void BKE_object_apply_mat4(Object *ob, float mat[4][4], const bool use_compat, c BoundBox *BKE_boundbox_alloc_unit(void) { BoundBox *bb; - const float min[3] = {-1.0f, -1.0f, -1.0f}, max[3] = {-1.0f, -1.0f, -1.0f}; + const float min[3] = {-1.0f, -1.0f, -1.0f}, max[3] = {1.0f, 1.0f, 1.0f}; bb = MEM_callocN(sizeof(BoundBox), "OB-BoundBox"); BKE_boundbox_init_from_minmax(bb, min, max); @@ -2767,7 +2778,7 @@ void BKE_object_handle_update_ex(const EvaluationContext *eval_ctx, * which is only in BKE_object_where_is_calc now */ /* XXX: should this case be OB_RECALC_OB instead? */ if (recalc_object || recalc_data) { - if (G.debug & G_DEBUG_DEPSGRAPH) { + if (G.debug & G_DEBUG_DEPSGRAPH_EVAL) { printf("recalcob %s\n", ob->id.name + 2); } /* Handle proxy copy for target. */ @@ -3143,7 +3154,7 @@ bool BKE_object_flag_test_recursive(const Object *ob, short flag) } } -bool BKE_object_is_child_recursive(Object *ob_parent, Object *ob_child) +bool BKE_object_is_child_recursive(const Object *ob_parent, const Object *ob_child) { for (ob_child = ob_child->parent; ob_child; ob_child = ob_child->parent) { if (ob_child == ob_parent) { diff --git a/source/blender/blenkernel/intern/object_deform.c b/source/blender/blenkernel/intern/object_deform.c index 754434eaef6..fb2e824b299 100644 --- a/source/blender/blenkernel/intern/object_deform.c +++ b/source/blender/blenkernel/intern/object_deform.c @@ -42,7 +42,7 @@ #include "DNA_mesh_types.h" #include "DNA_modifier_types.h" #include "DNA_object_types.h" -#include "DNA_object_force.h" +#include "DNA_object_force_types.h" #include "DNA_particle_types.h" #include "DNA_scene_types.h" @@ -460,6 +460,70 @@ void BKE_object_defgroup_remove_all(struct Object *ob) BKE_object_defgroup_remove_all_ex(ob, false); } +/** + * Compute mapping for vertex groups with matching name, -1 is used for no remapping. + * Returns null if no remapping is required. + * The returned array has to be freed. + */ +int *BKE_object_defgroup_index_map_create(Object *ob_src, Object *ob_dst, int *r_map_len) +{ + /* Build src to merged mapping of vgroup indices. */ + if (BLI_listbase_is_empty(&ob_src->defbase) || BLI_listbase_is_empty(&ob_dst->defbase)) { + *r_map_len = 0; + return NULL; + } + + bDeformGroup *dg_src; + *r_map_len = BLI_listbase_count(&ob_src->defbase); + int *vgroup_index_map = MEM_malloc_arrayN(*r_map_len, sizeof(*vgroup_index_map), "defgroup index map create"); + bool is_vgroup_remap_needed = false; + int i; + + for (dg_src = ob_src->defbase.first, i = 0; dg_src; dg_src = dg_src->next, i++) { + vgroup_index_map[i] = defgroup_name_index(ob_dst, dg_src->name); + is_vgroup_remap_needed = is_vgroup_remap_needed || (vgroup_index_map[i] != i); + } + + if (!is_vgroup_remap_needed) { + MEM_freeN(vgroup_index_map); + vgroup_index_map = NULL; + *r_map_len = 0; + } + + return vgroup_index_map; +} + +void BKE_object_defgroup_index_map_apply(MDeformVert *dvert, int dvert_len, const int *map, int map_len) +{ + if (map == NULL || map_len == 0) { + return; + } + + MDeformVert *dv = dvert; + for (int i = 0; i < dvert_len; i++, dv++) { + int totweight = dv->totweight; + for (int j = 0; j < totweight; j++) { + int def_nr = dv->dw[j].def_nr; + if ((uint)def_nr < (uint)map_len && map[def_nr] != -1) { + dv->dw[j].def_nr = map[def_nr]; + } + else { + totweight--; + dv->dw[j] = dv->dw[totweight]; + j--; + } + } + if (totweight != dv->totweight) { + if (totweight) { + dv->dw = MEM_reallocN(dv->dw, sizeof(*dv->dw) * totweight); + } + else { + MEM_SAFE_FREE(dv->dw); + } + dv->totweight = totweight; + } + } +} /** * Get MDeformVert vgroup data from given object. Should only be used in Object mode. @@ -542,7 +606,7 @@ bool *BKE_object_defgroup_validmap_get(Object *ob, const int defbase_tot) BLI_ghash_insert(gh, dg->name, NULL); } - BLI_assert(BLI_ghash_size(gh) == defbase_tot); + BLI_assert(BLI_ghash_len(gh) == defbase_tot); /* now loop through the armature modifiers and identify deform bones */ for (md = ob->modifiers.first; md; md = !md->next && step1 ? (step1 = 0), modifiers_getVirtualModifierList(ob, &virtualModifierData) : md->next) { @@ -577,7 +641,7 @@ bool *BKE_object_defgroup_validmap_get(Object *ob, const int defbase_tot) defgroup_validmap[i] = (BLI_ghash_lookup(gh, dg->name) != NULL); } - BLI_assert(i == BLI_ghash_size(gh)); + BLI_assert(i == BLI_ghash_len(gh)); BLI_ghash_free(gh, NULL, NULL); diff --git a/source/blender/blenkernel/intern/object_dupli.c b/source/blender/blenkernel/intern/object_dupli.c index 13589866e48..1b976fef166 100644 --- a/source/blender/blenkernel/intern/object_dupli.c +++ b/source/blender/blenkernel/intern/object_dupli.c @@ -74,6 +74,7 @@ typedef struct DupliContext { bool do_update; bool animated; Group *group; /* XXX child objects are selected from this group if set, could be nicer */ + Object *obedit; /* Only to check if the object is in edit-mode. */ Scene *scene; ViewLayer *view_layer; @@ -108,6 +109,7 @@ static void init_context(DupliContext *r_ctx, const EvaluationContext *eval_ctx, r_ctx->group = NULL; r_ctx->object = ob; + r_ctx->obedit = OBEDIT_FROM_OBACT(ob); if (space_mat) copy_m4_m4(r_ctx->space_mat, space_mat); else @@ -241,14 +243,13 @@ static bool is_child(const Object *ob, const Object *parent) static void make_child_duplis(const DupliContext *ctx, void *userdata, MakeChildDuplisFunc make_child_duplis_cb) { Object *parent = ctx->object; - Object *obedit = ctx->scene->obedit; if (ctx->group) { int groupid = 0; - FOREACH_GROUP_BASE(ctx->group, base) + FOREACH_GROUP_BASE_BEGIN(ctx->group, base) { Object *ob = base->object; - if ((base->flag & BASE_VISIBLED) && ob != obedit && is_child(ob, parent)) { + if ((base->flag & BASE_VISIBLED) && ob != ctx->obedit && is_child(ob, parent)) { DupliContext pctx; copy_dupli_context(&pctx, ctx, ctx->object, NULL, groupid, false); @@ -267,7 +268,7 @@ static void make_child_duplis(const DupliContext *ctx, void *userdata, MakeChild ViewLayer *view_layer = ctx->view_layer; for (Base *base = view_layer->object_bases.first; base; base = base->next, baseid++) { Object *ob = base->object; - if ((base->flag & BASE_VISIBLED) && ob != obedit && is_child(ob, parent)) { + if ((ob != ctx->obedit) && is_child(ob, parent)) { DupliContext pctx; copy_dupli_context(&pctx, ctx, ctx->object, NULL, baseid, false); @@ -880,7 +881,7 @@ static void make_duplis_particle_system(const DupliContext *ctx, ParticleSystem BLI_srandom((unsigned int)(31415926 + psys->seed)); - if ((psys->renderdata || part->draw_as == PART_DRAW_REND) && ELEM(part->ren_as, PART_DRAW_OB, PART_DRAW_GR)) { + if ((for_render || part->draw_as == PART_DRAW_REND) && ELEM(part->ren_as, PART_DRAW_OB, PART_DRAW_GR)) { ParticleSimulationData sim = {NULL}; sim.eval_ctx = ctx->eval_ctx; sim.scene = scene; @@ -931,12 +932,12 @@ static void make_duplis_particle_system(const DupliContext *ctx, ParticleSystem totgroup += dw->count; } else { - FOREACH_GROUP_OBJECT(part->dup_group, object) + FOREACH_GROUP_OBJECT_BEGIN(part->dup_group, object) { (void) object; totgroup++; } - FOREACH_GROUP_OBJECT_END + FOREACH_GROUP_OBJECT_END; } /* we also copy the actual objects to restore afterwards, since @@ -956,7 +957,7 @@ static void make_duplis_particle_system(const DupliContext *ctx, ParticleSystem } else { a = 0; - FOREACH_GROUP_OBJECT(part->dup_group, object) + FOREACH_GROUP_OBJECT_BEGIN(part->dup_group, object) { oblist[a] = object; obcopylist[a] = *object; @@ -966,7 +967,7 @@ static void make_duplis_particle_system(const DupliContext *ctx, ParticleSystem continue; } } - FOREACH_GROUP_OBJECT_END + FOREACH_GROUP_OBJECT_END; } } else { @@ -1056,7 +1057,7 @@ static void make_duplis_particle_system(const DupliContext *ctx, ParticleSystem if (part->ren_as == PART_DRAW_GR && psys->part->draw & PART_DRAW_WHOLE_GR) { b = 0; - FOREACH_GROUP_OBJECT(part->dup_group, object) + FOREACH_GROUP_OBJECT_BEGIN(part->dup_group, object) { copy_m4_m4(tmat, oblist[b]->obmat); @@ -1081,7 +1082,7 @@ static void make_duplis_particle_system(const DupliContext *ctx, ParticleSystem b++; } - FOREACH_GROUP_OBJECT_END + FOREACH_GROUP_OBJECT_END; } else { /* to give ipos in object correct offset */ diff --git a/source/blender/blenkernel/intern/object_update.c b/source/blender/blenkernel/intern/object_update.c index 99291b14b88..10ccc9fb672 100644 --- a/source/blender/blenkernel/intern/object_update.c +++ b/source/blender/blenkernel/intern/object_update.c @@ -66,12 +66,11 @@ #include "MEM_guardedalloc.h" #include "DEG_depsgraph.h" -#define DEBUG_PRINT if (G.debug & G_DEBUG_DEPSGRAPH) printf void BKE_object_eval_local_transform(const EvaluationContext *UNUSED(eval_ctx), Object *ob) { - DEBUG_PRINT("%s on %s (%p)\n", __func__, ob->id.name, ob); + DEG_debug_print_eval(__func__, ob->id.name, ob); /* calculate local matrix */ BKE_object_to_mat4(ob, ob->obmat); @@ -89,7 +88,7 @@ void BKE_object_eval_parent(const EvaluationContext *UNUSED(eval_ctx), float tmat[4][4]; float locmat[4][4]; - DEBUG_PRINT("%s on %s (%p)\n", __func__, ob->id.name, ob); + DEG_debug_print_eval(__func__, ob->id.name, ob); /* get local matrix (but don't calculate it, as that was done already!) */ // XXX: redundant? @@ -118,7 +117,7 @@ void BKE_object_eval_constraints(const EvaluationContext *eval_ctx, bConstraintOb *cob; float ctime = BKE_scene_frame_get(scene); - DEBUG_PRINT("%s on %s (%p)\n", __func__, ob->id.name, ob); + DEG_debug_print_eval(__func__, ob->id.name, ob); /* evaluate constraints stack */ /* TODO: split this into: @@ -136,7 +135,7 @@ void BKE_object_eval_constraints(const EvaluationContext *eval_ctx, void BKE_object_eval_done(const EvaluationContext *UNUSED(eval_ctx), Object *ob) { - DEBUG_PRINT("%s on %s (%p)\n", __func__, ob->id.name, ob); + DEG_debug_print_eval(__func__, ob->id.name, ob); /* Set negative scale flag in object. */ if (is_negative_m4(ob->obmat)) ob->transflag |= OB_NEG_SCALE; @@ -153,7 +152,7 @@ void BKE_object_handle_data_update( Key *key; float ctime = BKE_scene_frame_get(scene); - if (G.debug & G_DEBUG_DEPSGRAPH) + if (G.debug & G_DEBUG_DEPSGRAPH_EVAL) printf("recalcdata %s\n", ob->id.name + 2); /* TODO(sergey): Only used by legacy depsgraph. */ @@ -174,7 +173,7 @@ void BKE_object_handle_data_update( switch (ob->type) { case OB_MESH: { - BMEditMesh *em = (ob == scene->obedit) ? BKE_editmesh_from_object(ob) : NULL; + BMEditMesh *em = (ob->mode & OB_MODE_EDIT) ? 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) */ @@ -224,7 +223,7 @@ void BKE_object_handle_data_update( } /* particles */ - if (ob != scene->obedit && ob->particlesystem.first) { + if (!(ob->mode & OB_MODE_EDIT) && ob->particlesystem.first) { ParticleSystem *tpsys, *psys; DerivedMesh *dm; ob->transflag &= ~OB_DUPLIPARTS; @@ -306,7 +305,7 @@ void BKE_object_eval_uber_data(const EvaluationContext *eval_ctx, Scene *scene, Object *ob) { - DEBUG_PRINT("%s on %s (%p)\n", __func__, ob->id.name, ob); + DEG_debug_print_eval(__func__, ob->id.name, ob); BLI_assert(ob->type != OB_ARMATURE); BKE_object_handle_data_update(eval_ctx, scene, ob); @@ -387,7 +386,7 @@ void BKE_object_eval_cloth(const EvaluationContext *UNUSED(eval_ctx), Scene *scene, Object *object) { - DEBUG_PRINT("%s on %s (%p)\n", __func__, object->id.name, object); + DEG_debug_print_eval(__func__, object->id.name, object); BKE_ptcache_object_reset(scene, object, PTCACHE_RESET_DEPSGRAPH); } @@ -410,7 +409,7 @@ void BKE_object_eval_transform_all(const EvaluationContext *eval_ctx, void BKE_object_eval_update_shading(const EvaluationContext *UNUSED(eval_ctx), Object *object) { - DEBUG_PRINT("%s on %s (%p)\n", __func__, object->id.name, object); + DEG_debug_print_eval(__func__, object->id.name, object); if (object->type == OB_MESH) { BKE_mesh_batch_cache_dirty(object->data, BKE_MESH_BATCH_DIRTY_SHADING); } @@ -419,7 +418,7 @@ void BKE_object_eval_update_shading(const EvaluationContext *UNUSED(eval_ctx), void BKE_object_data_select_update(const EvaluationContext *UNUSED(eval_ctx), struct ID *object_data) { - DEBUG_PRINT("%s on %s (%p)\n", __func__, object_data->name, object_data); + DEG_debug_print_eval(__func__, object_data->name, object_data); switch (GS(object_data->name)) { case ID_ME: BKE_mesh_batch_cache_dirty((Mesh *)object_data, @@ -442,10 +441,17 @@ void BKE_object_data_select_update(const EvaluationContext *UNUSED(eval_ctx), } } -void BKE_object_eval_flush_base_flags(const EvaluationContext *UNUSED(eval_ctx), - Object *object, Base *base, bool is_from_set) +void BKE_object_eval_flush_base_flags(const EvaluationContext *eval_ctx, + Object *object, int base_index, bool is_from_set) { - DEBUG_PRINT("%s on %s (%p)\n", __func__, object->id.name, object); + ViewLayer *view_layer = eval_ctx->view_layer; + BLI_assert(view_layer->object_bases_array != NULL); + BLI_assert(base_index >= 0); + BLI_assert(base_index < MEM_allocN_len(view_layer->object_bases_array) / sizeof(Base *)); + Base *base = view_layer->object_bases_array[base_index]; + BLI_assert(base->object == object); + + DEG_debug_print_eval(__func__, object->id.name, object); /* Make sure we have the base collection settings is already populated. * This will fail when BKE_layer_eval_layer_collection_pre hasn't run yet. diff --git a/source/blender/blenkernel/intern/ocean.c b/source/blender/blenkernel/intern/ocean.c index 0b4bc39627e..2d8527f23d6 100644 --- a/source/blender/blenkernel/intern/ocean.c +++ b/source/blender/blenkernel/intern/ocean.c @@ -917,7 +917,7 @@ void BKE_ocean_init(struct Ocean *o, int M, int N, float Lx, float Lz, float V, o->_fft_in = (fftw_complex *)MEM_mallocN(o->_M * (1 + o->_N / 2) * sizeof(fftw_complex), "ocean_fft_in"); o->_htilda = (fftw_complex *)MEM_mallocN(o->_M * (1 + o->_N / 2) * sizeof(fftw_complex), "ocean_htilda"); - BLI_lock_thread(LOCK_FFTW); + BLI_thread_lock(LOCK_FFTW); if (o->_do_disp_y) { o->_disp_y = (double *)MEM_mallocN(o->_M * o->_N * sizeof(double), "ocean_disp_y"); @@ -963,7 +963,7 @@ void BKE_ocean_init(struct Ocean *o, int M, int N, float Lx, float Lz, float V, o->_Jxz_plan = fftw_plan_dft_c2r_2d(o->_M, o->_N, o->_fft_in_jxz, o->_Jxz, FFTW_ESTIMATE); } - BLI_unlock_thread(LOCK_FFTW); + BLI_thread_unlock(LOCK_FFTW); BLI_rw_mutex_unlock(&o->oceanmutex); @@ -978,7 +978,7 @@ void BKE_ocean_free_data(struct Ocean *oc) BLI_rw_mutex_lock(&oc->oceanmutex, THREAD_LOCK_WRITE); - BLI_lock_thread(LOCK_FFTW); + BLI_thread_lock(LOCK_FFTW); if (oc->_do_disp_y) { fftw_destroy_plan(oc->_disp_y_plan); @@ -1016,7 +1016,7 @@ void BKE_ocean_free_data(struct Ocean *oc) MEM_freeN(oc->_Jxz); } - BLI_unlock_thread(LOCK_FFTW); + BLI_thread_unlock(LOCK_FFTW); if (oc->_fft_in) MEM_freeN(oc->_fft_in); diff --git a/source/blender/blenkernel/intern/outliner_treehash.c b/source/blender/blenkernel/intern/outliner_treehash.c index d9a602aa41e..9bbde607b80 100644 --- a/source/blender/blenkernel/intern/outliner_treehash.c +++ b/source/blender/blenkernel/intern/outliner_treehash.c @@ -133,7 +133,7 @@ static void fill_treehash(void *treehash, BLI_mempool *treestore) void *BKE_outliner_treehash_create_from_treestore(BLI_mempool *treestore) { - GHash *treehash = BLI_ghash_new_ex(tse_hash, tse_cmp, "treehash", BLI_mempool_count(treestore)); + GHash *treehash = BLI_ghash_new_ex(tse_hash, tse_cmp, "treehash", BLI_mempool_len(treestore)); fill_treehash(treehash, treestore); return treehash; } @@ -147,7 +147,7 @@ void *BKE_outliner_treehash_rebuild_from_treestore(void *treehash, BLI_mempool * { BLI_assert(treehash); - BLI_ghash_clear_ex(treehash, NULL, free_treehash_group, BLI_mempool_count(treestore)); + BLI_ghash_clear_ex(treehash, NULL, free_treehash_group, BLI_mempool_len(treestore)); fill_treehash(treehash, treestore); return treehash; } diff --git a/source/blender/blenkernel/intern/packedFile.c b/source/blender/blenkernel/intern/packedFile.c index 35e2531675d..f17c10765b8 100644 --- a/source/blender/blenkernel/intern/packedFile.c +++ b/source/blender/blenkernel/intern/packedFile.c @@ -354,16 +354,15 @@ int writePackedFile(ReportList *reports, const char *filename, PackedFile *pf, i return (ret_value); } - -/* + +/** * This function compares a packed file to a 'real' file. * It returns an integer indicating if: * - * PF_EQUAL - the packed file and original file are identical - * PF_DIFFERENT - the packed file and original file differ - * PF_NOFILE - the original file doens't exist + * - PF_EQUAL: the packed file and original file are identical + * - PF_DIFFERENT: the packed file and original file differ + * - PF_NOFILE: the original file doens't exist */ - int checkPackedFile(const char *filename, PackedFile *pf) { BLI_stat_t st; diff --git a/source/blender/blenkernel/intern/paint.c b/source/blender/blenkernel/intern/paint.c index 152a882de97..20375fe6953 100644 --- a/source/blender/blenkernel/intern/paint.c +++ b/source/blender/blenkernel/intern/paint.c @@ -41,6 +41,7 @@ #include "DNA_scene_types.h" #include "DNA_brush_types.h" #include "DNA_space_types.h" +#include "DNA_workspace_types.h" #include "BLI_bitmap.h" #include "BLI_utildefines.h" @@ -176,6 +177,8 @@ Paint *BKE_paint_get_active(Scene *sce, ViewLayer *view_layer) if (ts->use_uv_sculpt) return &ts->uvsculpt->paint; return &ts->imapaint.paint; + default: + break; } } @@ -376,7 +379,7 @@ void BKE_paint_curve_clamp_endpoint_add_index(PaintCurve *pc, const int add_inde /* remove colour from palette. Must be certain color is inside the palette! */ void BKE_palette_color_remove(Palette *palette, PaletteColor *color) { - if (BLI_listbase_count_ex(&palette->colors, palette->active_color) == palette->active_color) { + if (BLI_listbase_count_at_most(&palette->colors, palette->active_color) == palette->active_color) { palette->active_color--; } @@ -499,7 +502,7 @@ void BKE_paint_cavity_curve_preset(Paint *p, int preset) curvemapping_changed(p->cavity_curve, false); } -short BKE_paint_object_mode_from_paint_mode(ePaintMode mode) +eObjectMode BKE_paint_object_mode_from_paint_mode(ePaintMode mode) { switch (mode) { case ePaintSculpt: @@ -529,7 +532,7 @@ void BKE_paint_init(Scene *sce, ePaintMode mode, const char col[3]) /* If there's no brush, create one */ brush = BKE_paint_brush(paint); if (brush == NULL) { - short ob_mode = BKE_paint_object_mode_from_paint_mode(mode); + eObjectMode ob_mode = BKE_paint_object_mode_from_paint_mode(mode); brush = BKE_brush_first_search(G.main, ob_mode); if (!brush) { @@ -902,7 +905,7 @@ void BKE_sculpt_update_mesh_elements( if (!CustomData_has_layer(&me->ldata, CD_GRID_PAINT_MASK)) { #if 1 BKE_sculpt_mask_layers_ensure(ob, mmd); -#else /* if we wanted to support adding mask data while multi-res painting, we would need to do this */ +#else /* if we wanted to support adding mask data while multi-res painting, we would need to do this */ if ((ED_sculpt_mask_layers_ensure(ob, mmd) & ED_SCULPT_MASK_LAYER_CALC_LOOP)) { /* remake the derived mesh */ ob->recalc |= OB_RECALC_DATA; @@ -1064,3 +1067,39 @@ int BKE_sculpt_mask_layers_ensure(Object *ob, MultiresModifierData *mmd) return ret; } + +void BKE_sculpt_toolsettings_data_ensure(struct Scene *scene) +{ + Sculpt *sd = scene->toolsettings->sculpt; + if (sd == NULL) { + sd = scene->toolsettings->sculpt = MEM_callocN(sizeof(Sculpt), __func__); + + /* Turn on X plane mirror symmetry by default */ + sd->paint.symmetry_flags |= PAINT_SYMM_X; + sd->paint.flags |= PAINT_SHOW_BRUSH; + + /* Make sure at least dyntopo subdivision is enabled */ + sd->flags |= SCULPT_DYNTOPO_SUBDIVIDE | SCULPT_DYNTOPO_COLLAPSE; + } + + if (!sd->detail_size) { + sd->detail_size = 12; + } + if (!sd->detail_percent) { + sd->detail_percent = 25; + } + if (sd->constant_detail == 0.0f) { + sd->constant_detail = 3.0f; + } + + /* Set sane default tiling offsets */ + if (!sd->paint.tile_offset[0]) { + sd->paint.tile_offset[0] = 1.0f; + } + if (!sd->paint.tile_offset[1]) { + sd->paint.tile_offset[1] = 1.0f; + } + if (!sd->paint.tile_offset[2]) { + sd->paint.tile_offset[2] = 1.0f; + } +} diff --git a/source/blender/blenkernel/intern/particle.c b/source/blender/blenkernel/intern/particle.c index e23ca3eaa09..713d523cb1e 100644 --- a/source/blender/blenkernel/intern/particle.c +++ b/source/blender/blenkernel/intern/particle.c @@ -87,9 +87,12 @@ #include "DEG_depsgraph.h" #include "DEG_depsgraph_build.h" +#include "DEG_depsgraph_query.h" #include "RE_render_ext.h" +#include "particle_private.h" + unsigned int PSYS_FRAND_SEED_OFFSET[PSYS_FRAND_COUNT]; unsigned int PSYS_FRAND_SEED_MULTIPLIER[PSYS_FRAND_COUNT]; float PSYS_FRAND_BASE[PSYS_FRAND_COUNT]; @@ -109,9 +112,6 @@ static void get_child_modifier_parameters(ParticleSettings *part, ParticleThread ChildParticle *cpa, short cpa_from, int cpa_num, float *cpa_fuv, float *orco, ParticleTexture *ptex); static void get_cpa_texture(DerivedMesh *dm, ParticleSystem *psys, ParticleSettings *part, ParticleData *par, int child_index, int face_index, const float fw[4], float *orco, ParticleTexture *ptex, int event, float cfra); -extern void do_child_modifiers(ParticleThreadContext *ctx, ParticleSimulationData *sim, - ParticleTexture *ptex, const float par_co[3], const float par_vel[3], const float par_rot[4], const float par_orco[3], - ChildParticle *cpa, const float orco[3], float mat[4][4], ParticleKey *state, float t); /* few helpers for countall etc. */ int count_particles(ParticleSystem *psys) @@ -252,7 +252,7 @@ struct LatticeDeformData *psys_create_lattice_deform_data(ParticleSimulationData { struct LatticeDeformData *lattice_deform_data = NULL; - if (psys_in_edit_mode(sim->eval_ctx->view_layer, sim->psys) == 0) { + if (psys_in_edit_mode(sim->eval_ctx->depsgraph, sim->psys) == 0) { Object *lattice = NULL; ModifierData *md = (ModifierData *)psys_get_modifier(sim->ob, sim->psys); int mode = G.is_rendering ? eModifierMode_Render : eModifierMode_Realtime; @@ -289,13 +289,16 @@ void psys_enable_all(Object *ob) psys->flag &= ~PSYS_DISABLED; } -bool psys_in_edit_mode(ViewLayer *view_layer, ParticleSystem *psys) +bool psys_in_edit_mode(Depsgraph *depsgraph, ParticleSystem *psys) { + ViewLayer *view_layer = DEG_get_input_view_layer(depsgraph); + const bool use_render_params = (DEG_get_mode(depsgraph) == DAG_EVAL_RENDER); + return (view_layer->basact && (view_layer->basact->object->mode & OB_MODE_PARTICLE_EDIT) && psys == psys_get_current((view_layer->basact)->object) && (psys->edit || psys->pointcache->edit) && - !psys->renderdata); + !use_render_params); } bool psys_check_enabled(Object *ob, ParticleSystem *psys, const bool use_render_params) @@ -306,7 +309,7 @@ bool psys_check_enabled(Object *ob, ParticleSystem *psys, const bool use_render_ return 0; psmd = psys_get_modifier(ob, psys); - if (psys->renderdata || use_render_params) { + if (use_render_params) { if (!(psmd->modifier.mode & eModifierMode_Render)) return 0; } @@ -351,7 +354,7 @@ void psys_check_group_weights(ParticleSettings *part) } /* then add objects in the group to new list */ - FOREACH_GROUP_OBJECT(part->dup_group, object) + FOREACH_GROUP_OBJECT_BEGIN(part->dup_group, object) { dw = part->dupliweights.first; while (dw && dw->ob != object) { @@ -365,7 +368,7 @@ void psys_check_group_weights(ParticleSettings *part) BLI_addtail(&part->dupliweights, dw); } } - FOREACH_GROUP_OBJECT_END + FOREACH_GROUP_OBJECT_END; dw = part->dupliweights.first; for (; dw; dw = dw->next) { @@ -413,6 +416,8 @@ void BKE_particlesettings_free(ParticleSettings *part) curvemapping_free(part->clumpcurve); if (part->roughcurve) curvemapping_free(part->roughcurve); + if (part->twistcurve) + curvemapping_free(part->twistcurve); free_partdeflect(part->pd); free_partdeflect(part->pd2); @@ -621,204 +626,6 @@ void psys_free(Object *ob, ParticleSystem *psys) } /************************************************/ -/* Rendering */ -/************************************************/ -/* these functions move away particle data and bring it back after - * rendering, to make different render settings possible without - * removing the previous data. this should be solved properly once */ - -void psys_render_set(Object *ob, ParticleSystem *psys, float viewmat[4][4], float winmat[4][4], int winx, int winy, int timeoffset) -{ - ParticleRenderData *data; - ParticleSystemModifierData *psmd = psys_get_modifier(ob, psys); - - if (psys->renderdata) - return; - - data = MEM_callocN(sizeof(ParticleRenderData), "ParticleRenderData"); - - data->child = psys->child; - data->totchild = psys->totchild; - data->pathcache = psys->pathcache; - data->pathcachebufs.first = psys->pathcachebufs.first; - data->pathcachebufs.last = psys->pathcachebufs.last; - data->totcached = psys->totcached; - data->childcache = psys->childcache; - data->childcachebufs.first = psys->childcachebufs.first; - data->childcachebufs.last = psys->childcachebufs.last; - data->totchildcache = psys->totchildcache; - - if (psmd->dm_final) { - data->dm = CDDM_copy_with_tessface(psmd->dm_final); - } - data->totdmvert = psmd->totdmvert; - data->totdmedge = psmd->totdmedge; - data->totdmface = psmd->totdmface; - - psys->child = NULL; - psys->pathcache = NULL; - psys->childcache = NULL; - psys->totchild = psys->totcached = psys->totchildcache = 0; - BLI_listbase_clear(&psys->pathcachebufs); - BLI_listbase_clear(&psys->childcachebufs); - - copy_m4_m4(data->winmat, winmat); - mul_m4_m4m4(data->viewmat, viewmat, ob->obmat); - mul_m4_m4m4(data->mat, winmat, data->viewmat); - data->winx = winx; - data->winy = winy; - - data->timeoffset = timeoffset; - - psys->renderdata = data; - - /* Hair can and has to be recalculated if everything isn't displayed. */ - if (psys->part->disp != 100 && ELEM(psys->part->type, PART_HAIR, PART_FLUID)) { - psys->recalc |= PSYS_RECALC_RESET; - } -} - -void psys_render_restore(Object *ob, ParticleSystem *psys) -{ - ParticleRenderData *data; - ParticleSystemModifierData *psmd = psys_get_modifier(ob, psys); - float render_disp = psys_get_current_display_percentage(psys); - float disp; - - data = psys->renderdata; - if (!data) - return; - - if (data->elems) - MEM_freeN(data->elems); - - if (psmd->dm_final) { - psmd->dm_final->needsFree = 1; - psmd->dm_final->release(psmd->dm_final); - } - if (psmd->dm_deformed) { - psmd->dm_deformed->needsFree = 1; - psmd->dm_deformed->release(psmd->dm_deformed); - psmd->dm_deformed = NULL; - } - - psys_free_path_cache(psys, NULL); - - if (psys->child) { - MEM_freeN(psys->child); - psys->child = 0; - psys->totchild = 0; - } - - psys->child = data->child; - psys->totchild = data->totchild; - psys->pathcache = data->pathcache; - psys->pathcachebufs.first = data->pathcachebufs.first; - psys->pathcachebufs.last = data->pathcachebufs.last; - psys->totcached = data->totcached; - psys->childcache = data->childcache; - psys->childcachebufs.first = data->childcachebufs.first; - psys->childcachebufs.last = data->childcachebufs.last; - psys->totchildcache = data->totchildcache; - - psmd->dm_final = data->dm; - psmd->totdmvert = data->totdmvert; - psmd->totdmedge = data->totdmedge; - psmd->totdmface = data->totdmface; - psmd->flag &= ~eParticleSystemFlag_psys_updated; - - if (psmd->dm_final) { - if (!psmd->dm_final->deformedOnly) { - if (ob->derivedDeform) { - psmd->dm_deformed = CDDM_copy(ob->derivedDeform); - } - else { - psmd->dm_deformed = CDDM_from_mesh((Mesh *)ob->data); - } - DM_ensure_tessface(psmd->dm_deformed); - } - psys_calc_dmcache(ob, psmd->dm_final, psmd->dm_deformed, psys); - } - - MEM_freeN(data); - psys->renderdata = NULL; - - /* restore particle display percentage */ - disp = psys_get_current_display_percentage(psys); - - if (disp != render_disp) { - /* Hair can and has to be recalculated if everything isn't displayed. */ - if (ELEM(psys->part->type, PART_HAIR, PART_FLUID)) { - psys->recalc |= PSYS_RECALC_RESET; - } - else { - PARTICLE_P; - - LOOP_PARTICLES { - if (psys_frand(psys, p) > disp) - pa->flag |= PARS_NO_DISP; - else - pa->flag &= ~PARS_NO_DISP; - } - } - } -} - -bool psys_render_simplify_params(ParticleSystem *psys, ChildParticle *cpa, float *params) -{ - ParticleRenderData *data; - ParticleRenderElem *elem; - float x, w, scale, alpha, lambda, t, scalemin, scalemax; - int b; - - if (!(psys->renderdata && (psys->part->simplify_flag & PART_SIMPLIFY_ENABLE))) - return false; - - data = psys->renderdata; - if (!data->do_simplify) - return false; - b = (data->index_mf_to_mpoly) ? DM_origindex_mface_mpoly(data->index_mf_to_mpoly, data->index_mp_to_orig, cpa->num) : cpa->num; - if (b == ORIGINDEX_NONE) { - return false; - } - - elem = &data->elems[b]; - - lambda = elem->lambda; - t = elem->t; - scalemin = elem->scalemin; - scalemax = elem->scalemax; - - if (!elem->reduce) { - scale = scalemin; - alpha = 1.0f; - } - else { - x = (elem->curchild + 0.5f) / elem->totchild; - if (x < lambda - t) { - scale = scalemax; - alpha = 1.0f; - } - else if (x >= lambda + t) { - scale = scalemin; - alpha = 0.0f; - } - else { - w = (lambda + t - x) / (2.0f * t); - scale = scalemin + (scalemax - scalemin) * w; - alpha = w; - } - } - - params[0] = scale; - params[1] = alpha; - - elem->curchild++; - - return 1; -} - -/************************************************/ /* Interpolation */ /************************************************/ static float interpolate_particle_value(float v1, float v2, float v3, float v4, const float w[4], int four) @@ -1811,11 +1618,6 @@ void psys_particle_on_emitter(ParticleSystemModifierData *psmd, int from, int in /* Path Cache */ /************************************************/ -extern void do_kink(ParticleKey *state, const float par_co[3], const float par_vel[3], const float par_rot[4], float time, float freq, float shape, float amplitude, float flat, - short type, short axis, float obmat[4][4], int smooth_start); -extern float do_clump(ParticleKey *state, const float par_co[3], float time, const float orco_offset[3], float clumpfac, float clumppow, float pa_clump, - bool use_clump_noise, float clump_noise_size, CurveMapping *clumpcurve); - void precalc_guides(ParticleSimulationData *sim, ListBase *effectors) { EffectedPoint point; @@ -2059,7 +1861,7 @@ void psys_find_parents(ParticleSimulationData *sim, const bool use_render_params int from = PART_FROM_FACE; totparent = (int)(totchild * part->parents * 0.3f); - if ((sim->psys->renderdata || use_render_params) && part->child_nbr && part->ren_child_nbr) + if (use_render_params && part->child_nbr && part->ren_child_nbr) totparent *= (float)part->child_nbr / (float)part->ren_child_nbr; /* hard limit, workaround for it being ignored above */ @@ -2103,10 +1905,10 @@ static bool psys_thread_context_init_path( psys_thread_context_init(ctx, sim); /*---start figuring out what is actually wanted---*/ - if (psys_in_edit_mode(sim->eval_ctx->view_layer, psys)) { + if (psys_in_edit_mode(sim->eval_ctx->depsgraph, psys)) { ParticleEditSettings *pset = &scene->toolsettings->particle; - if ((psys->renderdata == 0 && use_render_params == 0) && (psys->edit == NULL || pset->flag & PE_DRAW_PART) == 0) + if ((use_render_params == 0) && (psys->edit == NULL || pset->flag & PE_DRAW_PART) == 0) totchild = 0; segments = 1 << pset->draw_step; @@ -2115,14 +1917,14 @@ static bool psys_thread_context_init_path( if (totchild && part->childtype == PART_CHILD_FACES) { totparent = (int)(totchild * part->parents * 0.3f); - if ((psys->renderdata || use_render_params) && part->child_nbr && part->ren_child_nbr) + if (use_render_params && part->child_nbr && part->ren_child_nbr) totparent *= (float)part->child_nbr / (float)part->ren_child_nbr; /* part->parents could still be 0 so we can't test with totparent */ between = 1; } - if (psys->renderdata || use_render_params) + if (use_render_params) segments = 1 << part->ren_step; else { totchild = (int)((float)totchild * (float)part->disp / 100.0f); @@ -2154,6 +1956,7 @@ static bool psys_thread_context_init_path( ctx->vg_rough1 = psys_cache_vgroup(ctx->dm, psys, PSYS_VG_ROUGH1); ctx->vg_rough2 = psys_cache_vgroup(ctx->dm, psys, PSYS_VG_ROUGH2); ctx->vg_roughe = psys_cache_vgroup(ctx->dm, psys, PSYS_VG_ROUGHE); + ctx->vg_twist = psys_cache_vgroup(ctx->dm, psys, PSYS_VG_TWIST); if (psys->part->flag & PART_CHILD_EFFECT) ctx->vg_effector = psys_cache_vgroup(ctx->dm, psys, PSYS_VG_EFFECTOR); @@ -2172,6 +1975,13 @@ static bool psys_thread_context_init_path( else { ctx->roughcurve = NULL; } + if ((part->child_flag & PART_CHILD_USE_TWIST_CURVE) && part->twistcurve) { + ctx->twistcurve = curvemapping_copy(part->twistcurve); + curvemapping_changed_all(ctx->twistcurve); + } + else { + ctx->twistcurve = NULL; + } return true; } @@ -2192,7 +2002,7 @@ static void psys_thread_create_path(ParticleTask *task, struct ChildParticle *cp ParticleSystem *psys = ctx->sim.psys; ParticleSettings *part = psys->part; ParticleCacheKey **cache = psys->childcache; - ParticleCacheKey **pcache = psys_in_edit_mode(ctx->sim.eval_ctx->view_layer, psys) && psys->edit ? psys->edit->pathcache : psys->pathcache; + ParticleCacheKey **pcache = psys_in_edit_mode(ctx->sim.eval_ctx->depsgraph, psys) && psys->edit ? psys->edit->pathcache : psys->pathcache; ParticleCacheKey *child, *key[4]; ParticleTexture ptex; float *cpa_fuv = 0, *par_rot = 0, rot[4]; @@ -2316,7 +2126,19 @@ static void psys_thread_create_path(ParticleTask *task, struct ChildParticle *cp /* get the original coordinates (orco) for texture usage */ cpa_from = part->from; - cpa_num = pa->num; + + /* + * NOTE: Should in theory be the same as: + cpa_num = psys_particle_dm_face_lookup( + ctx->sim.psmd->dm_final, + ctx->sim.psmd->dm_deformed, + pa->num, pa->fuv, + NULL); + */ + cpa_num = (ELEM(pa->num_dmcache, DMCACHE_ISCHILD, DMCACHE_NOTFOUND)) + ? pa->num + : pa->num_dmcache; + /* XXX hack to avoid messed up particle num and subsequent crash (#40733) */ if (cpa_num > ctx->sim.psmd->dm_final->getNumTessFaces(ctx->sim.psmd->dm_final)) cpa_num = 0; @@ -2569,7 +2391,9 @@ static void cache_key_incremental_rotation(ParticleCacheKey *key0, ParticleCache void psys_cache_paths(ParticleSimulationData *sim, float cfra, const bool use_render_params) { PARTICLE_PSMD; +#if 0 ParticleEditSettings *pset = &sim->scene->toolsettings->particle; +#endif ParticleSystem *psys = sim->psys; ParticleSettings *part = psys->part; ParticleCacheKey *ca, **cache; @@ -2590,7 +2414,7 @@ void psys_cache_paths(ParticleSimulationData *sim, float cfra, const bool use_re float prev_tangent[3] = {0.0f, 0.0f, 0.0f}, hairmat[4][4]; float rotmat[3][3]; int k; - int segments = (int)pow(2.0, (double)((psys->renderdata || use_render_params) ? part->ren_step : part->draw_step)); + int segments = (int)pow(2.0, (double)((use_render_params) ? part->ren_step : part->draw_step)); int totpart = psys->totpart; float length, vec[3]; float *vg_effector = NULL; @@ -2601,9 +2425,11 @@ void psys_cache_paths(ParticleSimulationData *sim, float cfra, const bool use_re if ((psys->flag & PSYS_HAIR_DONE || psys->flag & PSYS_KEYED || psys->pointcache) == 0) return; - if (psys_in_edit_mode(sim->eval_ctx->view_layer, psys)) - if (psys->renderdata == 0 && (psys->edit == NULL || pset->flag & PE_DRAW_PART) == 0) +#if 0 /* TODO(mai): something is very wrong with these conditionals, they dont make sense and the cache isnt updating */ + if (psys_in_edit_mode(sim->eval_ctx->depsgraph, psys)) + if ((psys->edit == NULL || pset->flag & PE_DRAW_PART) == 0) return; +#endif keyed = psys->flag & PSYS_KEYED; baked = psys->pointcache->mem_cache.first && psys->part->type != PART_HAIR; @@ -3164,7 +2990,7 @@ ModifierData *object_add_particle_system(Scene *scene, Object *ob, const char *n psys->part = BKE_particlesettings_add(NULL, DATA_("ParticleSettings")); - if (BLI_listbase_count_ex(&ob->particlesystem, 2) > 1) + if (BLI_listbase_count_at_most(&ob->particlesystem, 2) > 1) BLI_snprintf(psys->name, sizeof(psys->name), DATA_("ParticleSystem %i"), BLI_listbase_count(&ob->particlesystem)); else BLI_strncpy(psys->name, DATA_("ParticleSystem"), sizeof(psys->name)); @@ -3307,11 +3133,6 @@ static void default_particle_settings(ParticleSettings *part) part->color_vec_max = 1.f; part->draw_col = PART_DRAW_COL_MAT; - part->simplify_refsize = 1920; - part->simplify_rate = 1.0f; - part->simplify_transition = 0.1f; - part->simplify_viewport = 0.8; - if (!part->effector_weights) part->effector_weights = BKE_add_effector_weights(NULL); @@ -3359,6 +3180,18 @@ void BKE_particlesettings_rough_curve_init(ParticleSettings *part) part->roughcurve = cumap; } +void BKE_particlesettings_twist_curve_init(ParticleSettings *part) +{ + CurveMapping *cumap = curvemapping_add(1, 0.0f, 0.0f, 1.0f, 1.0f); + + cumap->cm[0].curve[0].x = 0.0f; + cumap->cm[0].curve[0].y = 1.0f; + cumap->cm[0].curve[1].x = 1.0f; + cumap->cm[0].curve[1].y = 1.0f; + + part->twistcurve = cumap; +} + /** * Only copy internal data of ParticleSettings ID from source to already allocated/initialized destination. * You probably nerver want to use that directly, use id_copy or BKE_id_copy_ex for typical needs. @@ -3381,6 +3214,9 @@ void BKE_particlesettings_copy_data( if (part_src->roughcurve) { part_dst->roughcurve = curvemapping_copy(part_src->roughcurve); } + if (part_src->twistcurve) { + part_dst->twistcurve = curvemapping_copy(part_src->twistcurve); + } part_dst->boids = boid_copy_settings(part_src->boids); @@ -3500,6 +3336,7 @@ static void get_cpa_texture(DerivedMesh *dm, ParticleSystem *psys, ParticleSetti ptex->ivel = ptex->life = ptex->exist = ptex->size = ptex->damp = ptex->gravity = ptex->field = ptex->time = ptex->clump = ptex->kink_freq = ptex->kink_amp = ptex->effector = ptex->rough1 = ptex->rough2 = ptex->roughe = 1.0f; + ptex->twist = 1.0f; ptex->length = 1.0f - part->randlength * psys_frand(psys, child_index + 26); ptex->length *= part->clength_thres < psys_frand(psys, child_index + 27) ? part->clength : 1.0f; @@ -3552,6 +3389,7 @@ static void get_cpa_texture(DerivedMesh *dm, ParticleSystem *psys, ParticleSetti SET_PARTICLE_TEXTURE(PAMAP_KINK_AMP, ptex->kink_amp, mtex->kinkampfac); SET_PARTICLE_TEXTURE(PAMAP_KINK_FREQ, ptex->kink_freq, mtex->kinkfac); SET_PARTICLE_TEXTURE(PAMAP_DENS, ptex->exist, mtex->padensfac); + SET_PARTICLE_TEXTURE(PAMAP_TWIST, ptex->twist, mtex->twistfac); } } @@ -3577,6 +3415,7 @@ void psys_get_texture(ParticleSimulationData *sim, ParticleData *pa, ParticleTex ptex->ivel = ptex->life = ptex->exist = ptex->size = ptex->damp = ptex->gravity = ptex->field = ptex->length = ptex->clump = ptex->kink_freq = ptex->kink_amp = ptex->effector = ptex->rough1 = ptex->rough2 = ptex->roughe = 1.0f; + ptex->twist = 1.0f; ptex->time = (float)(pa - sim->psys->particles) / (float)sim->psys->totpart; @@ -3651,6 +3490,7 @@ void psys_get_texture(ParticleSimulationData *sim, ParticleData *pa, ParticleTex SET_PARTICLE_TEXTURE(PAMAP_GRAVITY, ptex->gravity, mtex->gravityfac); SET_PARTICLE_TEXTURE(PAMAP_DAMP, ptex->damp, mtex->dampfac); SET_PARTICLE_TEXTURE(PAMAP_LENGTH, ptex->length, mtex->lengthfac); + SET_PARTICLE_TEXTURE(PAMAP_TWIST, ptex->twist, mtex->twistfac); } } @@ -3742,6 +3582,8 @@ static void get_child_modifier_parameters(ParticleSettings *part, ParticleThread ptex->roughe *= psys_interpolate_value_from_verts(ctx->dm, cpa_from, cpa_num, cpa_fuv, ctx->vg_roughe); if (ctx->vg_effector) ptex->effector *= psys_interpolate_value_from_verts(ctx->dm, cpa_from, cpa_num, cpa_fuv, ctx->vg_effector); + if (ctx->vg_twist) + ptex->twist *= psys_interpolate_value_from_verts(ctx->dm, cpa_from, cpa_num, cpa_fuv, ctx->vg_twist); } /* get's hair (or keyed) particles state at the "path time" specified in state->time */ void psys_get_particle_on_path(ParticleSimulationData *sim, int p, ParticleKey *state, const bool vel) @@ -3794,7 +3636,7 @@ void psys_get_particle_on_path(ParticleSimulationData *sim, int p, ParticleKey * pind.bspline = (psys->part->flag & PART_HAIR_BSPLINE); /* pind.dm disabled in editmode means we don't get effectors taken into * account when subdividing for instance */ - pind.dm = psys_in_edit_mode(sim->eval_ctx->view_layer, psys) ? NULL : psys->hair_out_dm; + pind.dm = psys_in_edit_mode(sim->eval_ctx->depsgraph, psys) ? NULL : psys->hair_out_dm; init_particle_interpolation(sim->ob, psys, pa, &pind); do_particle_interpolation(psys, p, pa, t, &pind, state); @@ -3947,7 +3789,18 @@ void psys_get_particle_on_path(ParticleSimulationData *sim, int p, ParticleKey * copy_particle_key(&tstate, state, 1); /* apply different deformations to the child path */ - do_child_modifiers(NULL, sim, &ptex, par->co, par->vel, par->rot, par_orco, cpa, orco, hairmat, state, t); + ParticleChildModifierContext modifier_ctx = {NULL}; + modifier_ctx.thread_ctx = NULL; + modifier_ctx.sim = sim; + modifier_ctx.ptex = &ptex; + modifier_ctx.cpa = cpa; + modifier_ctx.orco = orco; + modifier_ctx.par_co = par->co; + modifier_ctx.par_vel = par->vel; + modifier_ctx.par_rot = par->rot; + modifier_ctx.par_orco = par_orco; + modifier_ctx.parent_keys = psys->childcache ? psys->childcache[p - totpart] : NULL; + do_child_modifiers(&modifier_ctx, hairmat, state, t); /* try to estimate correct velocity */ if (vel) { @@ -4050,7 +3903,19 @@ int psys_get_particle_state(ParticleSimulationData *sim, int p, ParticleKey *sta CLAMP(t, 0.0f, 1.0f); unit_m4(mat); - do_child_modifiers(NULL, sim, NULL, key1->co, key1->vel, key1->rot, par_orco, cpa, cpa->fuv, mat, state, t); + ParticleChildModifierContext modifier_ctx = {NULL}; + modifier_ctx.thread_ctx = NULL; + modifier_ctx.sim = sim; + modifier_ctx.ptex = NULL; + modifier_ctx.cpa = cpa; + modifier_ctx.orco = cpa->fuv; + modifier_ctx.par_co = key1->co; + modifier_ctx.par_vel = key1->vel; + modifier_ctx.par_rot = key1->rot; + modifier_ctx.par_orco = par_orco; + modifier_ctx.parent_keys = psys->childcache ? psys->childcache[p - totpart] : NULL; + + do_child_modifiers(&modifier_ctx, mat, state, t); if (psys->lattice_deform_data) calc_latt_deform(psys->lattice_deform_data, state->co, psys->lattice_strength); diff --git a/source/blender/blenkernel/intern/particle_child.c b/source/blender/blenkernel/intern/particle_child.c index d2ad05c20b7..c2640e9b9e2 100644 --- a/source/blender/blenkernel/intern/particle_child.c +++ b/source/blender/blenkernel/intern/particle_child.c @@ -37,15 +37,9 @@ #include "BKE_colortools.h" #include "BKE_particle.h" -struct Material; +#include "particle_private.h" -void do_kink(ParticleKey *state, const float par_co[3], const float par_vel[3], const float par_rot[4], float time, float freq, float shape, float amplitude, float flat, - short type, short axis, float obmat[4][4], int smooth_start); -float do_clump(ParticleKey *state, const float par_co[3], float time, const float orco_offset[3], float clumpfac, float clumppow, float pa_clump, - bool use_clump_noise, float clump_noise_size, CurveMapping *clumpcurve); -void do_child_modifiers(ParticleThreadContext *ctx, ParticleSimulationData *sim, - ParticleTexture *ptex, const float par_co[3], const float par_vel[3], const float par_rot[4], const float par_orco[3], - ChildParticle *cpa, const float orco[3], float mat[4][4], ParticleKey *state, float t); +struct Material; static void get_strand_normal(Material *ma, const float surfnor[3], float surfdist, float nor[3]) { @@ -67,7 +61,7 @@ static void get_strand_normal(Material *ma, const float surfnor[3], float surfdi else { copy_v3_v3(vnor, nor); } - + if (ma->strand_surfnor > 0.0f) { if (ma->strand_surfnor > surfdist) { blend = (ma->strand_surfnor - surfdist) / ma->strand_surfnor; @@ -85,7 +79,7 @@ typedef struct ParticlePathIterator { ParticleCacheKey *key; int index; float time; - + ParticleCacheKey *parent_key; float parent_rotation[4]; } ParticlePathIterator; @@ -94,11 +88,11 @@ static void psys_path_iter_get(ParticlePathIterator *iter, ParticleCacheKey *key ParticleCacheKey *parent, int index) { BLI_assert(index >= 0 && index < totkeys); - + iter->key = keys + index; iter->index = index; iter->time = (float)index / (float)(totkeys - 1); - + if (parent) { iter->parent_key = parent + index; if (index > 0) @@ -114,7 +108,7 @@ static void psys_path_iter_get(ParticlePathIterator *iter, ParticleCacheKey *key typedef struct ParticlePathModifier { struct ParticlePathModifier *next, *prev; - + void (*apply)(ParticleCacheKey *keys, int totkeys, ParticleCacheKey *parent_keys); } ParticlePathModifier; @@ -133,7 +127,7 @@ static void do_kink_spiral_deform(ParticleKey *state, const float dir[3], const { /* Creates a logarithmic spiral: * r(theta) = a * exp(b * theta) - * + * * The "density" parameter b is defined by the shape parameter * and goes up to the Golden Spiral for 1.0 * https://en.wikipedia.org/wiki/Golden_spiral @@ -142,33 +136,33 @@ static void do_kink_spiral_deform(ParticleKey *state, const float dir[3], const /* angle of the spiral against the curve (rotated opposite to make a smooth transition) */ const float start_angle = ((b != 0.0f) ? atanf(1.0f / b) : (float)-M_PI_2) + (b > 0.0f ? -(float)M_PI_2 : (float)M_PI_2); - + float spiral_axis[3], rot[3][3]; float vec[3]; - + float theta = freq * time * 2.0f * (float)M_PI; float radius = amplitude * expf(b * theta); - + /* a bit more intuitive than using negative frequency for this */ if (amplitude < 0.0f) theta = -theta; - + cross_v3_v3v3(spiral_axis, dir, kink); normalize_v3(spiral_axis); - + mul_v3_v3fl(vec, kink, -radius); - + axis_angle_normalized_to_mat3(rot, spiral_axis, theta); mul_m3_v3(rot, vec); - + madd_v3_v3fl(vec, kink, amplitude); - + axis_angle_normalized_to_mat3(rot, spiral_axis, -start_angle); mul_m3_v3(rot, vec); - + add_v3_v3v3(result, spiral_start, vec); } - + copy_v3_v3(state->co, result); } @@ -180,7 +174,7 @@ static void do_kink_spiral(ParticleThreadContext *ctx, ParticleTexture *ptex, co const int seed = ctx->sim.psys->child_seed + (int)(cpa - ctx->sim.psys->child); const int totkeys = ctx->segments + 1; const int extrakeys = ctx->extra_segments; - + float kink_amp_random = part->kink_amp_random; float kink_amp = part->kink_amp * (1.0f - kink_amp_random * psys_frand(ctx->sim.psys, 93541 + seed)); float kink_freq = part->kink_freq; @@ -189,11 +183,11 @@ static void do_kink_spiral(ParticleThreadContext *ctx, ParticleTexture *ptex, co float rough1 = part->rough1; float rough2 = part->rough2; float rough_end = part->rough_end; - + ParticlePathIterator iter; ParticleCacheKey *key; int k; - + float dir[3]; float spiral_start[3] = {0.0f, 0.0f, 0.0f}; float spiral_start_time = 0.0f; @@ -204,7 +198,7 @@ static void do_kink_spiral(ParticleThreadContext *ctx, ParticleTexture *ptex, co float cut_time; int start_index = 0, end_index = 0; float kink_base[3]; - + if (ptex) { kink_amp *= ptex->kink_amp; kink_freq *= ptex->kink_freq; @@ -212,44 +206,53 @@ static void do_kink_spiral(ParticleThreadContext *ctx, ParticleTexture *ptex, co rough2 *= ptex->rough2; rough_end *= ptex->roughe; } - + cut_time = (totkeys - 1) * ptex->length; zero_v3(spiral_start); - + for (k = 0, key = keys; k < totkeys-1; k++, key++) { if ((float)(k + 1) >= cut_time) { float fac = cut_time - (float)k; ParticleCacheKey *par = parent_keys + k; - + start_index = k + 1; end_index = start_index + extrakeys; - + spiral_start_time = ((float)k + fac) / (float)(totkeys - 1); interp_v3_v3v3(spiral_start, key->co, (key+1)->co, fac); - + interp_v3_v3v3(spiral_par_co, par->co, (par+1)->co, fac); interp_v3_v3v3(spiral_par_vel, par->vel, (par+1)->vel, fac); interp_qt_qtqt(spiral_par_rot, par->rot, (par+1)->rot, fac); - + break; } } - + zero_v3(dir); - + zero_v3(kink_base); kink_base[part->kink_axis] = 1.0f; mul_mat3_m4_v3(ctx->sim.ob->obmat, kink_base); - + + /* Fill in invariant part of modifier context. */ + ParticleChildModifierContext modifier_ctx = {NULL}; + modifier_ctx.thread_ctx = ctx; + modifier_ctx.sim = &ctx->sim; + modifier_ctx.ptex = ptex; + modifier_ctx.cpa = cpa; + modifier_ctx.orco = orco; + modifier_ctx.parent_keys = parent_keys; + for (k = 0, key = keys; k < end_index; k++, key++) { float par_time; float *par_co, *par_vel, *par_rot; - + psys_path_iter_get(&iter, keys, end_index, NULL, k); if (k < start_index) { sub_v3_v3v3(dir, (key+1)->co, key->co); normalize_v3(dir); - + par_time = (float)k / (float)(totkeys - 1); par_co = parent_keys[k].co; par_vel = parent_keys[k].vel; @@ -258,36 +261,42 @@ static void do_kink_spiral(ParticleThreadContext *ctx, ParticleTexture *ptex, co else { float spiral_time = (float)(k - start_index) / (float)(extrakeys-1); float kink[3], tmp[3]; - + /* use same time value for every point on the spiral */ par_time = spiral_start_time; par_co = spiral_par_co; par_vel = spiral_par_vel; par_rot = spiral_par_rot; - + project_v3_v3v3(tmp, kink_base, dir); sub_v3_v3v3(kink, kink_base, tmp); normalize_v3(kink); - + if (kink_axis_random > 0.0f) { float a = kink_axis_random * (psys_frand(ctx->sim.psys, 7112 + seed) * 2.0f - 1.0f) * (float)M_PI; float rot[3][3]; - + axis_angle_normalized_to_mat3(rot, dir, a); mul_m3_v3(rot, kink); } - + do_kink_spiral_deform((ParticleKey *)key, dir, kink, spiral_time, kink_freq, kink_shape, kink_amp, spiral_start); } - - /* apply different deformations to the child path */ - do_child_modifiers(ctx, &ctx->sim, ptex, par_co, par_vel, par_rot, parent_orco, cpa, orco, hairmat, (ParticleKey *)key, par_time); + + /* Fill in variant part of modifier context. */ + modifier_ctx.par_co = par_co; + modifier_ctx.par_vel = par_vel; + modifier_ctx.par_rot = par_rot; + modifier_ctx.par_orco = parent_orco; + + /* Apply different deformations to the child path/ */ + do_child_modifiers(&modifier_ctx, hairmat, (ParticleKey *)key, par_time); } - + totlen = 0.0f; for (k = 0, key = keys; k < end_index-1; k++, key++) totlen += len_v3v3((key+1)->co, key->co); - + *r_totkeys = end_index; *r_max_length = totlen; } @@ -318,12 +327,12 @@ void psys_apply_child_modifiers(ParticleThreadContext *ctx, struct ListBase *mod struct Material *ma = ctx->ma; const bool draw_col_ma = (part->draw_col == PART_DRAW_COL_MAT); const bool use_length_check = !ELEM(part->kink, PART_KINK_SPIRAL); - + ParticlePathModifier *mod; ParticleCacheKey *key; int totkeys, k; float max_length; - + #if 0 /* TODO for the future: use true particle modifiers that work on the whole curve */ for (mod = modifiers->first; mod; mod = mod->next) { mod->apply(keys, totkeys, parent_keys); @@ -331,25 +340,38 @@ void psys_apply_child_modifiers(ParticleThreadContext *ctx, struct ListBase *mod #else (void)modifiers; (void)mod; - + if (part->kink == PART_KINK_SPIRAL) { do_kink_spiral(ctx, ptex, parent_orco, cpa, orco, hairmat, keys, parent_keys, &totkeys, &max_length); keys->segments = totkeys - 1; } else { - ParticlePathIterator iter; - + /* Fill in invariant part of modifier context. */ + ParticleChildModifierContext modifier_ctx = {NULL}; + modifier_ctx.thread_ctx = ctx; + modifier_ctx.sim = &ctx->sim; + modifier_ctx.ptex = ptex; + modifier_ctx.cpa = cpa; + modifier_ctx.orco = orco; + modifier_ctx.parent_keys = parent_keys; + totkeys = ctx->segments + 1; max_length = ptex->length; - + for (k = 0, key = keys; k < totkeys; k++, key++) { - ParticleKey *par; - + ParticlePathIterator iter; psys_path_iter_get(&iter, keys, totkeys, parent_keys, k); - par = (ParticleKey *)iter.parent_key; - - /* apply different deformations to the child path */ - do_child_modifiers(ctx, &ctx->sim, ptex, par->co, par->vel, iter.parent_rotation, parent_orco, cpa, orco, hairmat, (ParticleKey *)key, iter.time); + + ParticleKey *par = (ParticleKey *)iter.parent_key; + + /* Fill in variant part of modifier context. */ + modifier_ctx.par_co = par->co; + modifier_ctx.par_vel = par->vel; + modifier_ctx.par_rot = iter.parent_rotation; + modifier_ctx.par_orco = parent_orco; + + /* Apply different deformations to the child path. */ + do_child_modifiers(&modifier_ctx, hairmat, (ParticleKey *)key, iter.time); } } @@ -367,12 +389,12 @@ void psys_apply_child_modifiers(ParticleThreadContext *ctx, struct ListBase *mod if (k >= 2) { sub_v3_v3v3((key-1)->vel, key->co, (key-2)->co); mul_v3_fl((key-1)->vel, 0.5); - + if (ma && draw_col_ma) get_strand_normal(ma, ornor, cur_length, (key-1)->vel); } - - if (use_length_check && k > 1) { + + if (use_length_check && k > 0) { float dvec[3]; /* check if path needs to be cut before actual end of data points */ if (!check_path_length(k, keys, key, max_length, step_length, &cur_length, dvec)) { @@ -388,7 +410,7 @@ void psys_apply_child_modifiers(ParticleThreadContext *ctx, struct ListBase *mod /* last key */ sub_v3_v3v3(key->vel, key->co, (key-1)->co); } - + if (ma && draw_col_ma) { copy_v3_v3(key->col, &ma->r); get_strand_normal(ma, ornor, cur_length, key->vel); @@ -419,7 +441,7 @@ void do_kink(ParticleKey *state, const float par_co[3], const float par_vel[3], } t = time * freq * (float)M_PI; - + if (smooth_start) { dt = fabsf(t); /* smooth the beginning of kink */ @@ -434,7 +456,7 @@ void do_kink(ParticleKey *state, const float par_co[3], const float par_vel[3], if (obmat) mul_mat3_m4_v3(obmat, kink); - + mul_qt_v3(par_rot, kink); /* make sure kink is normal to strand */ @@ -450,12 +472,12 @@ void do_kink(ParticleKey *state, const float par_co[3], const float par_vel[3], case PART_KINK_CURL: { float curl_offset[3]; - + /* rotate kink vector around strand tangent */ mul_v3_v3fl(curl_offset, kink, amplitude); axis_angle_to_quat(q1, par_vel, t); mul_qt_v3(q1, curl_offset); - + interp_v3_v3v3(par_vec, state->co, par_co, flat); add_v3_v3v3(result, par_vec, curl_offset); break; @@ -494,7 +516,7 @@ void do_kink(ParticleKey *state, const float par_co[3], const float par_vel[3], float z_vec[3] = {0.f, 0.f, 1.f}; float vec_one[3], state_co[3]; float inp_y, inp_z, length; - + if (par_rot) { mul_qt_v3(par_rot, y_vec); mul_qt_v3(par_rot, z_vec); @@ -563,10 +585,10 @@ static float do_clump_level(float result[3], const float co[3], const float par_ float clumpfac, float clumppow, float pa_clump, CurveMapping *clumpcurve) { float clump = 0.0f; - + if (clumpcurve) { - clump = pa_clump * (1.0f - CLAMPIS(curvemapping_evaluateF(clumpcurve, 0, time), 0.0f, 1.0f)); - + clump = pa_clump * (1.0f - clamp_f(curvemapping_evaluateF(clumpcurve, 0, time), 0.0f, 1.0f)); + interp_v3_v3v3(result, co, par_co, clump); } else if (clumpfac != 0.0f) { @@ -584,7 +606,7 @@ static float do_clump_level(float result[3], const float co[3], const float par_ interp_v3_v3v3(result, co, par_co, clump); } - + return clump; } @@ -592,21 +614,21 @@ float do_clump(ParticleKey *state, const float par_co[3], float time, const floa bool use_clump_noise, float clump_noise_size, CurveMapping *clumpcurve) { float clump; - + if (use_clump_noise && clump_noise_size != 0.0f) { float center[3], noisevec[3]; float da[4], pa[12]; - + mul_v3_v3fl(noisevec, orco_offset, 1.0f / clump_noise_size); voronoi(noisevec[0], noisevec[1], noisevec[2], da, pa, 1.0f, 0); mul_v3_fl(&pa[0], clump_noise_size); add_v3_v3v3(center, par_co, &pa[0]); - + do_clump_level(state->co, state->co, center, time, clumpfac, clumppow, pa_clump, clumpcurve); } - + clump = do_clump_level(state->co, state->co, par_co, time, clumpfac, clumppow, pa_clump, clumpcurve); - + return clump; } @@ -651,27 +673,117 @@ static void do_rough_curve(const float loc[3], float mat[4][4], float time, floa { float rough[3]; float rco[3]; - + if (!roughcurve) return; - - fac *= CLAMPIS(curvemapping_evaluateF(roughcurve, 0, time), 0.0f, 1.0f); - + + fac *= clamp_f(curvemapping_evaluateF(roughcurve, 0, time), 0.0f, 1.0f); + copy_v3_v3(rco, loc); mul_v3_fl(rco, time); rough[0] = -1.0f + 2.0f * BLI_gTurbulence(size, rco[0], rco[1], rco[2], 2, 0, 2); rough[1] = -1.0f + 2.0f * BLI_gTurbulence(size, rco[1], rco[2], rco[0], 2, 0, 2); rough[2] = -1.0f + 2.0f * BLI_gTurbulence(size, rco[2], rco[0], rco[1], 2, 0, 2); - + madd_v3_v3fl(state->co, mat[0], fac * rough[0]); madd_v3_v3fl(state->co, mat[1], fac * rough[1]); madd_v3_v3fl(state->co, mat[2], fac * rough[2]); } -void do_child_modifiers(ParticleThreadContext *ctx, ParticleSimulationData *sim, ParticleTexture *ptex, - const float par_co[3], const float par_vel[3], const float par_rot[4], const float par_orco[3], - ChildParticle *cpa, const float orco[3], float mat[4][4], ParticleKey *state, float t) +static int twist_num_segments(const ParticleChildModifierContext *modifier_ctx) { + ParticleThreadContext *thread_ctx = modifier_ctx->thread_ctx; + return (thread_ctx != NULL) ? thread_ctx->segments + : modifier_ctx->sim->psys->part->draw_step; +} + +static void twist_get_axis(const ParticleChildModifierContext *modifier_ctx, + const float time, float r_axis[3]) +{ + const int num_segments = twist_num_segments(modifier_ctx); + const int index = clamp_i(time * num_segments, 0, num_segments); + if (index > 0) { + sub_v3_v3v3(r_axis, + modifier_ctx->parent_keys[index].co, + modifier_ctx->parent_keys[index - 1].co); + } + else { + sub_v3_v3v3(r_axis, + modifier_ctx->parent_keys[index + 1].co, + modifier_ctx->parent_keys[index].co); + } +} + +static float curvemapping_integrate_clamped(CurveMapping *curve, + float start, float end, float step) +{ + float integral = 0.0f; + float x = start; + while (x < end) { + float y = curvemapping_evaluateF(curve, 0, x); + y = clamp_f(y, 0.0f, 1.0f); + /* TODO(sergey): Clamp last step to end. */ + integral += y * step; + x += step; + } + return integral; +} + +static void do_twist(const ParticleChildModifierContext *modifier_ctx, + ParticleKey *state, const float time) +{ + ParticleThreadContext *thread_ctx = modifier_ctx->thread_ctx; + ParticleSimulationData *sim = modifier_ctx->sim; + ParticleTexture *ptex = modifier_ctx->ptex; + ParticleSettings *part = sim->psys->part; + /* Early output checks. */ + if (part->childtype != PART_CHILD_PARTICLES) { + /* Interpolated children behave weird with twist. */ + return; + } + if (part->twist == 0.0f) { + /* No twist along the strand. */ + return; + } + /* Dependent on whether it's threaded update or not, curve comes + * from different places. + */ + CurveMapping *twist_curve = NULL; + if (part->child_flag & PART_CHILD_USE_TWIST_CURVE) { + twist_curve = (thread_ctx != NULL) ? thread_ctx->twistcurve + : part->twistcurve; + } + /* Axis of rotation. */ + float axis[3]; + twist_get_axis(modifier_ctx, time, axis); + /* Angle of rotation. */ + float angle = part->twist; + if (ptex != NULL) { + angle *= (ptex->twist - 0.5f) * 2.0f; + } + if (twist_curve != NULL) { + const int num_segments = twist_num_segments(modifier_ctx); + angle *= curvemapping_integrate_clamped(twist_curve, + 0.0f, time, + 1.0f / num_segments); + } + else { + angle *= time; + } + /* Perform rotation around parent curve. */ + float vec[3]; + sub_v3_v3v3(vec, state->co, modifier_ctx->par_co); + rotate_v3_v3v3fl(state->co, vec, axis, angle * 2.0f * M_PI); + add_v3_v3(state->co, modifier_ctx->par_co); +} + +void do_child_modifiers(const ParticleChildModifierContext *modifier_ctx, + float mat[4][4], ParticleKey *state, float t) +{ + ParticleThreadContext *ctx = modifier_ctx->thread_ctx; + ParticleSimulationData *sim = modifier_ctx->sim; + ParticleTexture *ptex = modifier_ctx->ptex; + ChildParticle *cpa = modifier_ctx->cpa; ParticleSettings *part = sim->psys->part; CurveMapping *clumpcurve = NULL, *roughcurve = NULL; int i = cpa - sim->psys->child; @@ -700,6 +812,8 @@ void do_child_modifiers(ParticleThreadContext *ctx, ParticleSimulationData *sim, rough_end *= ptex->roughe; } + do_twist(modifier_ctx, state, t); + if (part->flag & PART_CHILD_EFFECT) /* state is safe to cast, since only co and vel are used */ guided = do_guides(sim->eval_ctx, sim->psys->part, sim->psys->effectors, (ParticleKey *)state, cpa->parent, t); @@ -707,33 +821,51 @@ void do_child_modifiers(ParticleThreadContext *ctx, ParticleSimulationData *sim, if (guided == 0) { float orco_offset[3]; float clump; - - sub_v3_v3v3(orco_offset, orco, par_orco); - clump = do_clump(state, par_co, t, orco_offset, part->clumpfac, part->clumppow, ptex ? ptex->clump : 1.f, - part->child_flag & PART_CHILD_USE_CLUMP_NOISE, part->clump_noise_size, clumpcurve); + + sub_v3_v3v3(orco_offset, modifier_ctx->orco, modifier_ctx->par_orco); + clump = do_clump(state, + modifier_ctx->par_co, + t, + orco_offset, + part->clumpfac, + part->clumppow, + ptex ? ptex->clump : 1.0f, + part->child_flag & PART_CHILD_USE_CLUMP_NOISE, + part->clump_noise_size, + clumpcurve); if (kink_freq != 0.f) { kink_amp *= (1.f - kink_amp_clump * clump); - - do_kink(state, par_co, par_vel, par_rot, t, kink_freq, part->kink_shape, - kink_amp, part->kink_flat, part->kink, part->kink_axis, - sim->ob->obmat, smooth_start); + + do_kink(state, + modifier_ctx->par_co, + modifier_ctx->par_vel, + modifier_ctx->par_rot, + t, + kink_freq, + part->kink_shape, + kink_amp, + part->kink_flat, + part->kink, + part->kink_axis, + sim->ob->obmat, + smooth_start); } } if (roughcurve) { - do_rough_curve(orco, mat, t, rough1, part->rough1_size, roughcurve, state); + do_rough_curve(modifier_ctx->orco, mat, t, rough1, part->rough1_size, roughcurve, state); } else { if (rough1 > 0.f) - do_rough(orco, mat, t, rough1, part->rough1_size, 0.0, state); - + do_rough(modifier_ctx->orco, mat, t, rough1, part->rough1_size, 0.0, state); + if (rough2 > 0.f) { float vec[3]; psys_frand_vec(sim->psys, i + 27, vec); do_rough(vec, mat, t, rough2, part->rough2_size, part->rough2_thres, state); } - + if (rough_end > 0.f) { float vec[3]; psys_frand_vec(sim->psys, i + 27, vec); diff --git a/source/blender/blenkernel/intern/particle_distribute.c b/source/blender/blenkernel/intern/particle_distribute.c index ff8a638089f..c261b0dc22c 100644 --- a/source/blender/blenkernel/intern/particle_distribute.c +++ b/source/blender/blenkernel/intern/particle_distribute.c @@ -36,7 +36,7 @@ #include "MEM_guardedalloc.h" #include "BLI_utildefines.h" -#include "BLI_jitter.h" +#include "BLI_jitter_2d.h" #include "BLI_kdtree.h" #include "BLI_math.h" #include "BLI_math_geom.h" @@ -57,7 +57,7 @@ #include "BKE_object.h" #include "BKE_particle.h" -static int psys_render_simplify_distribution(ParticleThreadContext *ctx, int tot); +#include "DEG_depsgraph_query.h" static void alloc_child_particles(ParticleSystem *psys, int tot) { @@ -80,12 +80,12 @@ static void alloc_child_particles(ParticleSystem *psys, int tot) } } -static void distribute_simple_children(Scene *scene, Object *ob, DerivedMesh *finaldm, DerivedMesh *deformdm, ParticleSystem *psys) +static void distribute_simple_children(Scene *scene, Object *ob, DerivedMesh *finaldm, DerivedMesh *deformdm, ParticleSystem *psys, const bool use_render_params) { ChildParticle *cpa = NULL; int i, p; - int child_nbr= psys_get_child_number(scene, psys); - int totpart= psys_get_tot_child(scene, psys); + int child_nbr= psys_get_child_number(scene, psys, use_render_params); + int totpart= psys_get_tot_child(scene, psys, use_render_params); alloc_child_particles(psys, totpart); @@ -738,16 +738,10 @@ static void exec_distribute_child(TaskPool * __restrict UNUSED(pool), void *task /* RNG skipping at the beginning */ cpa = psys->child; for (p = 0; p < task->begin; ++p, ++cpa) { - if (task->ctx->skip) /* simplification skip */ - BLI_rng_skip(task->rng, PSYS_RND_DIST_SKIP * task->ctx->skip[p]); - BLI_rng_skip(task->rng, PSYS_RND_DIST_SKIP); } for (; p < task->end; ++p, ++cpa) { - if (task->ctx->skip) /* simplification skip */ - BLI_rng_skip(task->rng, PSYS_RND_DIST_SKIP * task->ctx->skip[p]); - distribute_children_exec(task, cpa, p); } } @@ -774,11 +768,15 @@ static int distribute_compare_orig_index(const void *p1, const void *p2, void *u return 1; } -static void distribute_invalid(Scene *scene, ParticleSystem *psys, int from) +static void distribute_invalid(ParticleSimulationData *sim, int from) { + Scene *scene = sim->scene; + ParticleSystem *psys = sim->psys; + const bool use_render_params = (DEG_get_mode(sim->eval_ctx->depsgraph) == DAG_EVAL_RENDER); + if (from == PART_FROM_CHILD) { ChildParticle *cpa; - int p, totchild = psys_get_tot_child(scene, psys); + int p, totchild = psys_get_tot_child(scene, psys, use_render_params); if (psys->child && totchild) { for (p=0,cpa=psys->child; p<totchild; p++,cpa++) { @@ -800,7 +798,7 @@ static void distribute_invalid(Scene *scene, ParticleSystem *psys, int from) } } -/* Creates a distribution of coordinates on a DerivedMesh */ +/* Creates a distribution of coordinates on a DerivedMesh */ /* This is to denote functionality that does not yet work with mesh - only derived mesh */ static int psys_thread_context_init_distribute(ParticleThreadContext *ctx, ParticleSimulationData *sim, int from) { @@ -841,13 +839,15 @@ static int psys_thread_context_init_distribute(ParticleThreadContext *ctx, Parti */ psys_thread_context_init(ctx, sim); + + const bool use_render_params = (DEG_get_mode(sim->eval_ctx->depsgraph) == DAG_EVAL_RENDER); /* First handle special cases */ if (from == PART_FROM_CHILD) { /* Simple children */ if (part->childtype != PART_CHILD_FACES) { BLI_srandom(31415926 + psys->seed + psys->child_seed); - distribute_simple_children(scene, ob, finaldm, sim->psmd->dm_deformed, psys); + distribute_simple_children(scene, ob, finaldm, sim->psmd->dm_deformed, psys, use_render_params); return 0; } } @@ -895,7 +895,7 @@ static int psys_thread_context_init_distribute(ParticleThreadContext *ctx, Parti BLI_kdtree_balance(tree); - totpart = psys_get_tot_child(scene, psys); + totpart = psys_get_tot_child(scene, psys, use_render_params); cfrom = from = PART_FROM_FACE; } else { @@ -938,7 +938,7 @@ static int psys_thread_context_init_distribute(ParticleThreadContext *ctx, Parti totelem = (from == PART_FROM_VERT) ? dm->getNumVerts(dm) : dm->getNumTessFaces(dm); if (totelem == 0) { - distribute_invalid(scene, psys, children ? PART_FROM_CHILD : 0); + distribute_invalid(sim, children ? PART_FROM_CHILD : 0); if (G.debug & G_DEBUG) fprintf(stderr,"Particle distribution error: Nothing to emit from!\n"); @@ -950,9 +950,9 @@ static int psys_thread_context_init_distribute(ParticleThreadContext *ctx, Parti return 0; } - element_weight = MEM_callocN(sizeof(float)*totelem, "particle_distribution_weights"); - particle_element= MEM_callocN(sizeof(int)*totpart, "particle_distribution_indexes"); - jitter_offset = MEM_callocN(sizeof(float)*totelem, "particle_distribution_jitoff"); + element_weight = MEM_callocN(sizeof(float) * totelem, "particle_distribution_weights"); + particle_element = MEM_callocN(sizeof(int) * totpart, "particle_distribution_indexes"); + jitter_offset = MEM_callocN(sizeof(float) * totelem, "particle_distribution_jitoff"); /* Calculate weights from face areas */ if ((part->flag&PART_EDISTR || children) && from != PART_FROM_VERT) { @@ -1082,7 +1082,7 @@ static int psys_thread_context_init_distribute(ParticleThreadContext *ctx, Parti totmapped = i_mapped; /* Finally assign elements to particles */ - if ((part->flag & PART_TRAND) || (part->simplify_flag & PART_SIMPLIFY_ENABLE)) { + if (part->flag & PART_TRAND) { for (p = 0; p < totpart; p++) { /* In theory element_sum[totmapped - 1] should be 1.0, * but due to float errors this is not necessarily always true, so scale pos accordingly. */ @@ -1101,7 +1101,7 @@ static int psys_thread_context_init_distribute(ParticleThreadContext *ctx, Parti /* This is to address tricky issues with vertex-emitting when user tries (and expects) exact 1-1 vert/part * distribution (see T47983 and its two example files). It allows us to consider pos as * 'midpoint between v and v+1' (or 'p and p+1', depending whether we have more vertices than particles or not), - * and avoid stumbling over float imprecisions in element_sum. + * and avoid stumbling over float impression in element_sum. * Note: moved face and volume distribution to this as well (instead of starting at zero), * for the same reasons, see T52682. */ pos = (totpart < totmapped) ? 0.5 / (double)totmapped : step * 0.5; /* We choose the smaller step. */ @@ -1176,7 +1176,6 @@ static int psys_thread_context_init_distribute(ParticleThreadContext *ctx, Parti ctx->tpars= tpars; if (children) { - totpart= psys_render_simplify_distribution(ctx, totpart); alloc_child_particles(psys, totpart); } @@ -1235,7 +1234,7 @@ static void distribute_particles_on_dm(ParticleSimulationData *sim, int from) /* ready for future use, to emit particles without geometry */ static void distribute_particles_on_shape(ParticleSimulationData *sim, int UNUSED(from)) { - distribute_invalid(sim->scene, sim->psys, 0); + distribute_invalid(sim, 0); fprintf(stderr,"Shape emission not yet possible!\n"); } @@ -1255,250 +1254,8 @@ void distribute_particles(ParticleSimulationData *sim, int from) distribute_particles_on_shape(sim, from); if (distr_error) { - distribute_invalid(sim->scene, sim->psys, from); + distribute_invalid(sim, from); fprintf(stderr,"Particle distribution error!\n"); } } - -/* ======== Simplify ======== */ - -static float psys_render_viewport_falloff(double rate, float dist, float width) -{ - return pow(rate, dist / width); -} - -static float psys_render_projected_area(ParticleSystem *psys, const float center[3], float area, double vprate, float *viewport) -{ - ParticleRenderData *data = psys->renderdata; - float co[4], view[3], ortho1[3], ortho2[3], w, dx, dy, radius; - - /* transform to view space */ - copy_v3_v3(co, center); - co[3] = 1.0f; - mul_m4_v4(data->viewmat, co); - - /* compute two vectors orthogonal to view vector */ - normalize_v3_v3(view, co); - ortho_basis_v3v3_v3(ortho1, ortho2, view); - - /* compute on screen minification */ - w = co[2] * data->winmat[2][3] + data->winmat[3][3]; - dx = data->winx * ortho2[0] * data->winmat[0][0]; - dy = data->winy * ortho2[1] * data->winmat[1][1]; - w = sqrtf(dx * dx + dy * dy) / w; - - /* w squared because we are working with area */ - area = area * w * w; - - /* viewport of the screen test */ - - /* project point on screen */ - mul_m4_v4(data->winmat, co); - if (co[3] != 0.0f) { - co[0] = 0.5f * data->winx * (1.0f + co[0] / co[3]); - co[1] = 0.5f * data->winy * (1.0f + co[1] / co[3]); - } - - /* screen space radius */ - radius = sqrtf(area / (float)M_PI); - - /* make smaller using fallof once over screen edge */ - *viewport = 1.0f; - - if (co[0] + radius < 0.0f) - *viewport *= psys_render_viewport_falloff(vprate, -(co[0] + radius), data->winx); - else if (co[0] - radius > data->winx) - *viewport *= psys_render_viewport_falloff(vprate, (co[0] - radius) - data->winx, data->winx); - - if (co[1] + radius < 0.0f) - *viewport *= psys_render_viewport_falloff(vprate, -(co[1] + radius), data->winy); - else if (co[1] - radius > data->winy) - *viewport *= psys_render_viewport_falloff(vprate, (co[1] - radius) - data->winy, data->winy); - - return area; -} - -/* BMESH_TODO, for orig face data, we need to use MPoly */ -static int psys_render_simplify_distribution(ParticleThreadContext *ctx, int tot) -{ - DerivedMesh *dm = ctx->dm; - Mesh *me = (Mesh *)(ctx->sim.ob->data); - MFace *mf, *mface; - MVert *mvert; - ParticleRenderData *data; - ParticleRenderElem *elems, *elem; - ParticleSettings *part = ctx->sim.psys->part; - float *facearea, (*facecenter)[3], size[3], fac, powrate, scaleclamp; - float co1[3], co2[3], co3[3], co4[3], lambda, arearatio, t, area, viewport; - double vprate; - int *facetotvert; - int a, b, totorigface, totface, newtot, skipped; - - /* double lookup */ - const int *index_mf_to_mpoly; - const int *index_mp_to_orig; - - if (part->ren_as != PART_DRAW_PATH || !(part->draw & PART_DRAW_REN_STRAND)) - return tot; - if (!ctx->sim.psys->renderdata) - return tot; - - data = ctx->sim.psys->renderdata; - if (data->timeoffset) - return 0; - if (!(part->simplify_flag & PART_SIMPLIFY_ENABLE)) - return tot; - - mvert = dm->getVertArray(dm); - mface = dm->getTessFaceArray(dm); - totface = dm->getNumTessFaces(dm); - totorigface = me->totpoly; - - if (totface == 0 || totorigface == 0) - return tot; - - index_mf_to_mpoly = dm->getTessFaceDataArray(dm, CD_ORIGINDEX); - index_mp_to_orig = dm->getPolyDataArray(dm, CD_ORIGINDEX); - if (index_mf_to_mpoly == NULL) { - index_mp_to_orig = NULL; - } - - facearea = MEM_callocN(sizeof(float) * totorigface, "SimplifyFaceArea"); - facecenter = MEM_callocN(sizeof(float[3]) * totorigface, "SimplifyFaceCenter"); - facetotvert = MEM_callocN(sizeof(int) * totorigface, "SimplifyFaceArea"); - elems = MEM_callocN(sizeof(ParticleRenderElem) * totorigface, "SimplifyFaceElem"); - - if (data->elems) - MEM_freeN(data->elems); - - data->do_simplify = true; - data->elems = elems; - data->index_mf_to_mpoly = index_mf_to_mpoly; - data->index_mp_to_orig = index_mp_to_orig; - - /* compute number of children per original face */ - for (a = 0; a < tot; a++) { - b = (index_mf_to_mpoly) ? DM_origindex_mface_mpoly(index_mf_to_mpoly, index_mp_to_orig, ctx->index[a]) : ctx->index[a]; - if (b != ORIGINDEX_NONE) { - elems[b].totchild++; - } - } - - /* compute areas and centers of original faces */ - for (mf = mface, a = 0; a < totface; a++, mf++) { - b = (index_mf_to_mpoly) ? DM_origindex_mface_mpoly(index_mf_to_mpoly, index_mp_to_orig, a) : a; - - if (b != ORIGINDEX_NONE) { - copy_v3_v3(co1, mvert[mf->v1].co); - copy_v3_v3(co2, mvert[mf->v2].co); - copy_v3_v3(co3, mvert[mf->v3].co); - - add_v3_v3(facecenter[b], co1); - add_v3_v3(facecenter[b], co2); - add_v3_v3(facecenter[b], co3); - - if (mf->v4) { - copy_v3_v3(co4, mvert[mf->v4].co); - add_v3_v3(facecenter[b], co4); - facearea[b] += area_quad_v3(co1, co2, co3, co4); - facetotvert[b] += 4; - } - else { - facearea[b] += area_tri_v3(co1, co2, co3); - facetotvert[b] += 3; - } - } - } - - for (a = 0; a < totorigface; a++) - if (facetotvert[a] > 0) - mul_v3_fl(facecenter[a], 1.0f / facetotvert[a]); - - /* for conversion from BU area / pixel area to reference screen size */ - BKE_mesh_texspace_get(me, 0, 0, size); - fac = ((size[0] + size[1] + size[2]) / 3.0f) / part->simplify_refsize; - fac = fac * fac; - - powrate = log(0.5f) / log(part->simplify_rate * 0.5f); - if (part->simplify_flag & PART_SIMPLIFY_VIEWPORT) - vprate = pow(1.0f - part->simplify_viewport, 5.0); - else - vprate = 1.0; - - /* set simplification parameters per original face */ - for (a = 0, elem = elems; a < totorigface; a++, elem++) { - area = psys_render_projected_area(ctx->sim.psys, facecenter[a], facearea[a], vprate, &viewport); - arearatio = fac * area / facearea[a]; - - if ((arearatio < 1.0f || viewport < 1.0f) && elem->totchild) { - /* lambda is percentage of elements to keep */ - lambda = (arearatio < 1.0f) ? powf(arearatio, powrate) : 1.0f; - lambda *= viewport; - - lambda = MAX2(lambda, 1.0f / elem->totchild); - - /* compute transition region */ - t = part->simplify_transition; - elem->t = (lambda - t < 0.0f) ? lambda : (lambda + t > 1.0f) ? 1.0f - lambda : t; - elem->reduce = 1; - - /* scale at end and beginning of the transition region */ - elem->scalemax = (lambda + t < 1.0f) ? 1.0f / lambda : 1.0f / (1.0f - elem->t * elem->t / t); - elem->scalemin = (lambda + t < 1.0f) ? 0.0f : elem->scalemax * (1.0f - elem->t / t); - - elem->scalemin = sqrtf(elem->scalemin); - elem->scalemax = sqrtf(elem->scalemax); - - /* clamp scaling */ - scaleclamp = (float)min_ii(elem->totchild, 10); - elem->scalemin = MIN2(scaleclamp, elem->scalemin); - elem->scalemax = MIN2(scaleclamp, elem->scalemax); - - /* extend lambda to include transition */ - lambda = lambda + elem->t; - if (lambda > 1.0f) - lambda = 1.0f; - } - else { - lambda = arearatio; - - elem->scalemax = 1.0f; //sqrt(lambda); - elem->scalemin = 1.0f; //sqrt(lambda); - elem->reduce = 0; - } - - elem->lambda = lambda; - elem->scalemin = sqrtf(elem->scalemin); - elem->scalemax = sqrtf(elem->scalemax); - elem->curchild = 0; - } - - MEM_freeN(facearea); - MEM_freeN(facecenter); - MEM_freeN(facetotvert); - - /* move indices and set random number skipping */ - ctx->skip = MEM_callocN(sizeof(int) * tot, "SimplificationSkip"); - - skipped = 0; - for (a = 0, newtot = 0; a < tot; a++) { - b = (index_mf_to_mpoly) ? DM_origindex_mface_mpoly(index_mf_to_mpoly, index_mp_to_orig, ctx->index[a]) : ctx->index[a]; - - if (b != ORIGINDEX_NONE) { - if (elems[b].curchild++ < ceil(elems[b].lambda * elems[b].totchild)) { - ctx->index[newtot] = ctx->index[a]; - ctx->skip[newtot] = skipped; - skipped = 0; - newtot++; - } - else skipped++; - } - else skipped++; - } - - for (a = 0, elem = elems; a < totorigface; a++, elem++) - elem->curchild = 0; - - return newtot; -} diff --git a/source/blender/blenkernel/intern/particle_system.c b/source/blender/blenkernel/intern/particle_system.c index ac10ad44bf1..ffe6617d561 100644 --- a/source/blender/blenkernel/intern/particle_system.c +++ b/source/blender/blenkernel/intern/particle_system.c @@ -48,7 +48,7 @@ #include "DNA_mesh_types.h" #include "DNA_meshdata_types.h" #include "DNA_modifier_types.h" -#include "DNA_object_force.h" +#include "DNA_object_force_types.h" #include "DNA_object_types.h" #include "DNA_curve_types.h" #include "DNA_scene_types.h" @@ -58,7 +58,7 @@ #include "BLI_utildefines.h" #include "BLI_edgehash.h" #include "BLI_rand.h" -#include "BLI_jitter.h" +#include "BLI_jitter_2d.h" #include "BLI_math.h" #include "BLI_blenlib.h" #include "BLI_kdtree.h" @@ -76,7 +76,6 @@ #include "BKE_effect.h" #include "BKE_library_query.h" #include "BKE_particle.h" -#include "BKE_global.h" #include "BKE_collection.h" #include "BKE_DerivedMesh.h" @@ -91,6 +90,7 @@ #include "BKE_bvhutils.h" #include "DEG_depsgraph.h" +#include "DEG_depsgraph_query.h" #include "PIL_time.h" @@ -98,7 +98,7 @@ /* fluid sim particle import */ #ifdef WITH_MOD_FLUID -#include "DNA_object_fluidsim.h" +#include "DNA_object_fluidsim_types.h" #include "LBM_fluidsim.h" #include <zlib.h> #include <string.h> @@ -122,11 +122,11 @@ static int particles_are_dynamic(ParticleSystem *psys) return ELEM(psys->part->phystype, PART_PHYS_NEWTON, PART_PHYS_BOIDS, PART_PHYS_FLUID); } -float psys_get_current_display_percentage(ParticleSystem *psys) +float psys_get_current_display_percentage(ParticleSystem *psys, const bool use_render_params) { ParticleSettings *part=psys->part; - if ((psys->renderdata && !particles_are_dynamic(psys)) || /* non-dynamic particles can be rendered fully */ + if ((use_render_params && !particles_are_dynamic(psys)) || /* non-dynamic particles can be rendered fully */ (part->child_nbr && part->childtype) || /* display percentage applies to children */ (psys->pointcache->flag & PTCACHE_BAKING)) /* baking is always done with full amount */ { @@ -286,24 +286,24 @@ static void realloc_particles(ParticleSimulationData *sim, int new_totpart) } } -int psys_get_child_number(Scene *scene, ParticleSystem *psys) +int psys_get_child_number(Scene *scene, ParticleSystem *psys, const bool use_render_params) { int nbr; if (!psys->part->childtype) return 0; - if (psys->renderdata) + if (use_render_params) nbr= psys->part->ren_child_nbr; else nbr= psys->part->child_nbr; - return get_render_child_particle_number(&scene->r, nbr, psys->renderdata != NULL); + return get_render_child_particle_number(&scene->r, nbr, use_render_params); } -int psys_get_tot_child(Scene *scene, ParticleSystem *psys) +int psys_get_tot_child(Scene *scene, ParticleSystem *psys, const bool use_render_params) { - return psys->totpart*psys_get_child_number(scene, psys); + return psys->totpart*psys_get_child_number(scene, psys, use_render_params); } /************************************************/ @@ -499,6 +499,8 @@ void psys_thread_context_free(ParticleThreadContext *ctx) MEM_freeN(ctx->vg_rough2); if (ctx->vg_roughe) MEM_freeN(ctx->vg_roughe); + if (ctx->vg_twist) + MEM_freeN(ctx->vg_twist); if (ctx->sim.psys->lattice_deform_data) { end_latt_deform(ctx->sim.psys->lattice_deform_data); @@ -510,7 +512,6 @@ void psys_thread_context_free(ParticleThreadContext *ctx) if (ctx->jitoff) MEM_freeN(ctx->jitoff); if (ctx->weight) MEM_freeN(ctx->weight); if (ctx->index) MEM_freeN(ctx->index); - if (ctx->skip) MEM_freeN(ctx->skip); if (ctx->seams) MEM_freeN(ctx->seams); //if (ctx->vertpart) MEM_freeN(ctx->vertpart); BLI_kdtree_free(ctx->tree); @@ -521,6 +522,9 @@ void psys_thread_context_free(ParticleThreadContext *ctx) if (ctx->roughcurve != NULL) { curvemapping_free(ctx->roughcurve); } + if (ctx->twistcurve != NULL) { + curvemapping_free(ctx->twistcurve); + } } static void initialize_particle_texture(ParticleSimulationData *sim, ParticleData *pa, int p) @@ -2898,10 +2902,12 @@ static void psys_update_path_cache(ParticleSimulationData *sim, float cfra, cons { ParticleSystem *psys = sim->psys; ParticleSettings *part = psys->part; +#if 0 ParticleEditSettings *pset = &sim->scene->toolsettings->particle; +#endif int distr=0, alloc=0, skip=0; - if ((psys->part->childtype && psys->totchild != psys_get_tot_child(sim->scene, psys)) || psys->recalc&PSYS_RECALC_RESET) + if ((psys->part->childtype && psys->totchild != psys_get_tot_child(sim->scene, psys, use_render_params)) || psys->recalc&PSYS_RECALC_RESET) alloc=1; if (alloc || psys->recalc&PSYS_RECALC_CHILD || (psys->vgroup[PSYS_VG_DENSITY] && (sim->ob && sim->ob->mode & OB_MODE_WEIGHT_PAINT))) @@ -2911,7 +2917,7 @@ static void psys_update_path_cache(ParticleSimulationData *sim, float cfra, cons if (alloc) realloc_particles(sim, sim->psys->totpart); - if (psys_get_tot_child(sim->scene, psys)) { + if (psys_get_tot_child(sim->scene, psys, use_render_params)) { /* don't generate children while computing the hair keys */ if (!(psys->part->type == PART_HAIR) || (psys->flag & PSYS_HAIR_DONE)) { distribute_particles(sim, PART_FROM_CHILD); @@ -2928,22 +2934,25 @@ static void psys_update_path_cache(ParticleSimulationData *sim, float cfra, cons skip = 1; /* only hair, keyed and baked stuff can have paths */ else if (part->ren_as != PART_DRAW_PATH && !(part->type==PART_HAIR && ELEM(part->ren_as, PART_DRAW_OB, PART_DRAW_GR))) skip = 1; /* particle visualization must be set as path */ - else if (!psys->renderdata) { + else { if (part->draw_as != PART_DRAW_REND) skip = 1; /* draw visualization */ else if (psys->pointcache->flag & PTCACHE_BAKING) skip = 1; /* no need to cache paths while baking dynamics */ - else if (psys_in_edit_mode(sim->eval_ctx->view_layer, psys)) { + +#if 0 /* TODO(mai): something is very wrong with these conditionals, they dont make sense and the cache isnt updating */ + else if (psys_in_edit_mode(sim->eval_ctx->depsgraph, psys)) { if ((pset->flag & PE_DRAW_PART)==0) skip = 1; else if (part->childtype==0 && (psys->flag & PSYS_HAIR_DYNAMICS && psys->pointcache->flag & PTCACHE_BAKED)==0) skip = 1; /* in edit mode paths are needed for child particles and dynamic hair */ } +#endif } /* particle instance modifier with "path" option need cached paths even if particle system doesn't */ - FOREACH_SCENE_OBJECT(sim->scene, ob) + FOREACH_SCENE_OBJECT_BEGIN(sim->scene, ob) { ModifierData *md = modifiers_findByType(ob, eModifierType_ParticleInstance); if (md) { @@ -2954,7 +2963,7 @@ static void psys_update_path_cache(ParticleSimulationData *sim, float cfra, cons } } } - FOREACH_SCENE_OBJECT_END + FOREACH_SCENE_OBJECT_END; if (!skip) { psys_cache_paths(sim, cfra, use_render_params); @@ -3214,7 +3223,7 @@ static void hair_step(ParticleSimulationData *sim, float cfra, const bool use_re ParticleSystem *psys = sim->psys; ParticleSettings *part = psys->part; PARTICLE_P; - float disp = psys_get_current_display_percentage(psys); + float disp = psys_get_current_display_percentage(psys, use_render_params); LOOP_PARTICLES { pa->size = part->size; @@ -3730,13 +3739,13 @@ static void dynamics_step(ParticleSimulationData *sim, float cfra) free_collider_cache(&sim->colliders); BLI_rng_free(rng); } -static void update_children(ParticleSimulationData *sim) +static void update_children(ParticleSimulationData *sim, const bool use_render_params) { if ((sim->psys->part->type == PART_HAIR) && (sim->psys->flag & PSYS_HAIR_DONE)==0) /* don't generate children while growing hair - waste of time */ psys_free_children(sim->psys); else if (sim->psys->part->childtype) { - if (sim->psys->totchild != psys_get_tot_child(sim->scene, sim->psys)) + if (sim->psys->totchild != psys_get_tot_child(sim->scene, sim->psys, use_render_params)) distribute_particles(sim, PART_FROM_CHILD); else { /* Children are up to date, nothing to do. */ @@ -3746,7 +3755,7 @@ static void update_children(ParticleSimulationData *sim) psys_free_children(sim->psys); } /* updates cached particles' alive & other flags etc..*/ -static void cached_step(ParticleSimulationData *sim, float cfra) +static void cached_step(ParticleSimulationData *sim, float cfra, const bool use_render_params) { ParticleSystem *psys = sim->psys; ParticleSettings *part = psys->part; @@ -3756,7 +3765,7 @@ static void cached_step(ParticleSimulationData *sim, float cfra) psys_update_effectors(sim); - disp= psys_get_current_display_percentage(psys); + disp= psys_get_current_display_percentage(psys, use_render_params); LOOP_PARTICLES { psys_get_texture(sim, pa, &ptex, PAMAP_SIZE, cfra); @@ -3978,8 +3987,8 @@ static void system_step(ParticleSimulationData *sim, float cfra, const bool use_ int cache_result = BKE_ptcache_read(pid, cache_cfra, true); if (ELEM(cache_result, PTCACHE_READ_EXACT, PTCACHE_READ_INTERPOLATED)) { - cached_step(sim, cfra); - update_children(sim); + cached_step(sim, cfra, use_render_params); + update_children(sim, use_render_params); psys_update_path_cache(sim, cfra, use_render_params); BKE_ptcache_validate(cache, (int)cache_cfra); @@ -3996,7 +4005,7 @@ static void system_step(ParticleSimulationData *sim, float cfra, const bool use_ } else if (cache_result == PTCACHE_READ_OLD) { psys->cfra = (float)cache->simframe; - cached_step(sim, psys->cfra); + cached_step(sim, psys->cfra, use_render_params); } /* if on second frame, write cache for first frame */ @@ -4008,7 +4017,7 @@ static void system_step(ParticleSimulationData *sim, float cfra, const bool use_ /* 3. do dynamics */ /* set particles to be not calculated TODO: can't work with pointcache */ - disp= psys_get_current_display_percentage(psys); + disp= psys_get_current_display_percentage(psys, use_render_params); LOOP_PARTICLES { if (psys_frand(psys, p) > disp) @@ -4064,7 +4073,7 @@ static void system_step(ParticleSimulationData *sim, float cfra, const bool use_ BKE_ptcache_write(pid, (int)cache_cfra); } - update_children(sim); + update_children(sim, use_render_params); /* cleanup */ if (psys->lattice_deform_data) { @@ -4307,7 +4316,7 @@ void particle_system_update(const struct EvaluationContext *eval_ctx, Scene *sce case PART_PHYS_KEYED: { PARTICLE_P; - float disp = psys_get_current_display_percentage(psys); + float disp = psys_get_current_display_percentage(psys, use_render_params); bool free_unexisting = false; /* Particles without dynamics haven't been reset yet because they don't use pointcache */ @@ -4369,8 +4378,7 @@ void particle_system_update(const struct EvaluationContext *eval_ctx, Scene *sce psys->recalc = 0; /* save matrix for duplicators, at rendertime the actual dupliobject's matrix is used so don't update! */ - if (psys->renderdata==0) - invert_m4_m4(psys->imat, ob->obmat); + invert_m4_m4(psys->imat, ob->obmat); BKE_particle_batch_cache_dirty(psys, BKE_PARTICLE_BATCH_DIRTY_ALL); } @@ -4403,30 +4411,16 @@ void BKE_particlesystem_id_loop(ParticleSystem *psys, ParticleSystemIDFunc func, /* **** Depsgraph evaluation **** */ -void BKE_particle_system_settings_eval(const struct EvaluationContext *UNUSED(eval_ctx), - ParticleSystem *psys) -{ - if (G.debug & G_DEBUG_DEPSGRAPH) { - printf("%s on %s (%p)\n", __func__, psys->name, psys); - } - psys->recalc |= psys->part->recalc; -} - -void BKE_particle_system_settings_recalc_clear(struct EvaluationContext *UNUSED(eval_ctx), - ParticleSettings *particle_settings) -{ - if (G.debug & G_DEBUG_DEPSGRAPH) { - printf("%s on %s (%p)\n", __func__, particle_settings->id.name, particle_settings); - } - particle_settings->recalc = 0; -} - void BKE_particle_system_eval_init(const struct EvaluationContext *UNUSED(eval_ctx), Scene *scene, Object *ob) { - if (G.debug & G_DEBUG_DEPSGRAPH) { - printf("%s on %s (%p)\n", __func__, ob->id.name, ob); + DEG_debug_print_eval(__func__, ob->id.name, ob); + for (ParticleSystem *psys = ob->particlesystem.first; + psys != NULL; + psys = psys->next) + { + psys->recalc |= (psys->part->id.recalc & DEG_TAG_PSYS_ALL); } BKE_ptcache_object_reset(scene, ob, PTCACHE_RESET_DEPSGRAPH); } diff --git a/source/blender/blenkernel/intern/pbvh.c b/source/blender/blenkernel/intern/pbvh.c index 63f2c7e5452..14e0cfa75b5 100644 --- a/source/blender/blenkernel/intern/pbvh.c +++ b/source/blender/blenkernel/intern/pbvh.c @@ -1296,7 +1296,7 @@ void BKE_pbvh_get_grid_updates(PBVH *bvh, bool clear, void ***r_gridfaces, int * pbvh_iter_end(&iter); - const int tot = BLI_gset_size(face_set); + const int tot = BLI_gset_len(face_set); if (tot == 0) { *r_totface = 0; *r_gridfaces = NULL; @@ -1435,8 +1435,8 @@ void BKE_pbvh_node_num_verts( if (r_uniquevert) *r_uniquevert = node->uniq_verts; break; case PBVH_BMESH: - tot = BLI_gset_size(node->bm_unique_verts); - if (r_totvert) *r_totvert = tot + BLI_gset_size(node->bm_other_verts); + tot = BLI_gset_len(node->bm_unique_verts); + if (r_totvert) *r_totvert = tot + BLI_gset_len(node->bm_other_verts); if (r_uniquevert) *r_uniquevert = tot; break; } diff --git a/source/blender/blenkernel/intern/pbvh_bmesh.c b/source/blender/blenkernel/intern/pbvh_bmesh.c index e77edb21798..e32a5d0681e 100644 --- a/source/blender/blenkernel/intern/pbvh_bmesh.c +++ b/source/blender/blenkernel/intern/pbvh_bmesh.c @@ -255,7 +255,7 @@ static void pbvh_bmesh_node_split(PBVH *bvh, const BBC *bbc_array, int node_inde const int cd_face_node_offset = bvh->cd_face_node_offset; PBVHNode *n = &bvh->nodes[node_index]; - if (BLI_gset_size(n->bm_faces) <= bvh->leaf_limit) { + if (BLI_gset_len(n->bm_faces) <= bvh->leaf_limit) { /* Node limit not exceeded */ pbvh_bmesh_node_finalize(bvh, node_index, cd_vert_node_offset, cd_face_node_offset); return; @@ -289,8 +289,8 @@ static void pbvh_bmesh_node_split(PBVH *bvh, const BBC *bbc_array, int node_inde *c2 = &bvh->nodes[children + 1]; c1->flag |= PBVH_Leaf; c2->flag |= PBVH_Leaf; - c1->bm_faces = BLI_gset_ptr_new_ex("bm_faces", BLI_gset_size(n->bm_faces) / 2); - c2->bm_faces = BLI_gset_ptr_new_ex("bm_faces", BLI_gset_size(n->bm_faces) / 2); + c1->bm_faces = BLI_gset_ptr_new_ex("bm_faces", BLI_gset_len(n->bm_faces) / 2); + c2->bm_faces = BLI_gset_ptr_new_ex("bm_faces", BLI_gset_len(n->bm_faces) / 2); /* Partition the parent node's faces between the two children */ GSET_ITER (gs_iter, n->bm_faces) { @@ -305,11 +305,11 @@ static void pbvh_bmesh_node_split(PBVH *bvh, const BBC *bbc_array, int node_inde /* Enforce at least one primitive in each node */ GSet *empty = NULL, *other; - if (BLI_gset_size(c1->bm_faces) == 0) { + if (BLI_gset_len(c1->bm_faces) == 0) { empty = c1->bm_faces; other = c2->bm_faces; } - else if (BLI_gset_size(c2->bm_faces) == 0) { + else if (BLI_gset_len(c2->bm_faces) == 0) { empty = c2->bm_faces; other = c1->bm_faces; } @@ -375,7 +375,7 @@ static void pbvh_bmesh_node_split(PBVH *bvh, const BBC *bbc_array, int node_inde static bool pbvh_bmesh_node_limit_ensure(PBVH *bvh, int node_index) { GSet *bm_faces = bvh->nodes[node_index].bm_faces; - const int bm_faces_size = BLI_gset_size(bm_faces); + const int bm_faces_size = BLI_gset_len(bm_faces); if (bm_faces_size <= bvh->leaf_limit) { /* Node limit not exceeded */ return false; @@ -555,9 +555,9 @@ static int pbvh_bmesh_node_vert_use_count(PBVH *bvh, PBVHNode *node, BMVert *v) #endif #define pbvh_bmesh_node_vert_use_count_is_equal(bvh, node, v, n) \ - (pbvh_bmesh_node_vert_use_count_ex(bvh, node, v, (n) + 1) == n) + (pbvh_bmesh_node_vert_use_count_at_most(bvh, node, v, (n) + 1) == n) -static int pbvh_bmesh_node_vert_use_count_ex(PBVH *bvh, PBVHNode *node, BMVert *v, const int count_max) +static int pbvh_bmesh_node_vert_use_count_at_most(PBVH *bvh, PBVHNode *node, BMVert *v, const int count_max) { int count = 0; BMFace *f; @@ -1238,7 +1238,7 @@ static bool pbvh_bmesh_subdivide_long_edges( bool any_subdivided = false; while (!BLI_heap_is_empty(eq_ctx->q->heap)) { - BMVert **pair = BLI_heap_popmin(eq_ctx->q->heap); + BMVert **pair = BLI_heap_pop_min(eq_ctx->q->heap); BMVert *v1 = pair[0], *v2 = pair[1]; BMEdge *e; @@ -1326,7 +1326,7 @@ static void pbvh_bmesh_collapse_edge( /* Note: this could be done with BM_vert_splice(), but that * requires handling other issues like duplicate edges, so doesn't * really buy anything. */ - BLI_buffer_empty(deleted_faces); + BLI_buffer_clear(deleted_faces); BMLoop *l; @@ -1455,7 +1455,7 @@ static bool pbvh_bmesh_collapse_short_edges( GHash *deleted_verts = BLI_ghash_ptr_new("deleted_verts"); while (!BLI_heap_is_empty(eq_ctx->q->heap)) { - BMVert **pair = BLI_heap_popmin(eq_ctx->q->heap); + BMVert **pair = BLI_heap_pop_min(eq_ctx->q->heap); BMVert *v1 = pair[0], *v2 = pair[1]; BLI_mempool_free(eq_ctx->pool, pair); pair = NULL; @@ -2011,10 +2011,10 @@ void BKE_pbvh_bmesh_node_save_orig(PBVHNode *node) if (node->bm_orco) return; - const int totvert = BLI_gset_size(node->bm_unique_verts) + - BLI_gset_size(node->bm_other_verts); + const int totvert = BLI_gset_len(node->bm_unique_verts) + + BLI_gset_len(node->bm_other_verts); - const int tottri = BLI_gset_size(node->bm_faces); + const int tottri = BLI_gset_len(node->bm_faces); node->bm_orco = MEM_mallocN(sizeof(*node->bm_orco) * totvert, __func__); node->bm_ortri = MEM_mallocN(sizeof(*node->bm_ortri) * tottri, __func__); @@ -2189,12 +2189,12 @@ static void pbvh_bmesh_verify(PBVH *bvh) int totface = 0, totvert = 0; for (int i = 0; i < bvh->totnode; i++) { PBVHNode *n = &bvh->nodes[i]; - totface += n->bm_faces ? BLI_gset_size(n->bm_faces) : 0; - totvert += n->bm_unique_verts ? BLI_gset_size(n->bm_unique_verts) : 0; + totface += n->bm_faces ? BLI_gset_len(n->bm_faces) : 0; + totvert += n->bm_unique_verts ? BLI_gset_len(n->bm_unique_verts) : 0; } - BLI_assert(totface == BLI_gset_size(faces_all)); - BLI_assert(totvert == BLI_gset_size(verts_all)); + BLI_assert(totface == BLI_gset_len(faces_all)); + BLI_assert(totvert == BLI_gset_len(verts_all)); } { diff --git a/source/blender/blenkernel/intern/pointcache.c b/source/blender/blenkernel/intern/pointcache.c index b794fcfd929..50314daa014 100644 --- a/source/blender/blenkernel/intern/pointcache.c +++ b/source/blender/blenkernel/intern/pointcache.c @@ -38,9 +38,10 @@ #include "DNA_ID.h" #include "DNA_dynamicpaint_types.h" +#include "DNA_group_types.h" #include "DNA_modifier_types.h" #include "DNA_object_types.h" -#include "DNA_object_force.h" +#include "DNA_object_force_types.h" #include "DNA_particle_types.h" #include "DNA_rigidbody_types.h" #include "DNA_scene_types.h" @@ -972,20 +973,20 @@ static int ptcache_smoke_openvdb_write(struct OpenVDBWriter *writer, void *smoke smoke_turbulence_export(sds->wt, &dens, &react, &flame, &fuel, &r, &g, &b, &tcu, &tcv, &tcw); - wt_density_grid = OpenVDB_export_grid_fl(writer, "density", dens, sds->res_wt, sds->fluidmat_wt, NULL); + wt_density_grid = OpenVDB_export_grid_fl(writer, "density", dens, sds->res_wt, sds->fluidmat_wt, sds->clipping, NULL); clip_grid = wt_density_grid; if (fluid_fields & SM_ACTIVE_FIRE) { - OpenVDB_export_grid_fl(writer, "flame", flame, sds->res_wt, sds->fluidmat_wt, wt_density_grid); - OpenVDB_export_grid_fl(writer, "fuel", fuel, sds->res_wt, sds->fluidmat_wt, wt_density_grid); - OpenVDB_export_grid_fl(writer, "react", react, sds->res_wt, sds->fluidmat_wt, wt_density_grid); + OpenVDB_export_grid_fl(writer, "flame", flame, sds->res_wt, sds->fluidmat_wt, sds->clipping, wt_density_grid); + OpenVDB_export_grid_fl(writer, "fuel", fuel, sds->res_wt, sds->fluidmat_wt, sds->clipping, wt_density_grid); + OpenVDB_export_grid_fl(writer, "react", react, sds->res_wt, sds->fluidmat_wt, sds->clipping, wt_density_grid); } if (fluid_fields & SM_ACTIVE_COLORS) { - OpenVDB_export_grid_vec(writer, "color", r, g, b, sds->res_wt, sds->fluidmat_wt, VEC_INVARIANT, true, wt_density_grid); + OpenVDB_export_grid_vec(writer, "color", r, g, b, sds->res_wt, sds->fluidmat_wt, VEC_INVARIANT, true, sds->clipping, wt_density_grid); } - OpenVDB_export_grid_vec(writer, "texture coordinates", tcu, tcv, tcw, sds->res, sds->fluidmat, VEC_INVARIANT, false, wt_density_grid); + OpenVDB_export_grid_vec(writer, "texture coordinates", tcu, tcv, tcw, sds->res, sds->fluidmat, VEC_INVARIANT, false, sds->clipping, wt_density_grid); } if (sds->fluid) { @@ -999,33 +1000,33 @@ static int ptcache_smoke_openvdb_write(struct OpenVDBWriter *writer, void *smoke OpenVDBWriter_add_meta_fl(writer, "blender/smoke/dx", dx); OpenVDBWriter_add_meta_fl(writer, "blender/smoke/dt", dt); - const char *name = (!sds->wt) ? "density" : "density low"; - density_grid = OpenVDB_export_grid_fl(writer, name, dens, sds->res, sds->fluidmat, NULL); + const char *name = (!sds->wt) ? "density" : "density_low"; + density_grid = OpenVDB_export_grid_fl(writer, name, dens, sds->res, sds->fluidmat, sds->clipping, NULL); clip_grid = sds->wt ? clip_grid : density_grid; - OpenVDB_export_grid_fl(writer, "shadow", sds->shadow, sds->res, sds->fluidmat, NULL); + OpenVDB_export_grid_fl(writer, "shadow", sds->shadow, sds->res, sds->fluidmat, sds->clipping, NULL); if (fluid_fields & SM_ACTIVE_HEAT) { - OpenVDB_export_grid_fl(writer, "heat", heat, sds->res, sds->fluidmat, clip_grid); - OpenVDB_export_grid_fl(writer, "heat old", heatold, sds->res, sds->fluidmat, clip_grid); + OpenVDB_export_grid_fl(writer, "heat", heat, sds->res, sds->fluidmat, sds->clipping, clip_grid); + OpenVDB_export_grid_fl(writer, "heat_old", heatold, sds->res, sds->fluidmat, sds->clipping, clip_grid); } if (fluid_fields & SM_ACTIVE_FIRE) { - name = (!sds->wt) ? "flame" : "flame low"; - OpenVDB_export_grid_fl(writer, name, flame, sds->res, sds->fluidmat, density_grid); - name = (!sds->wt) ? "fuel" : "fuel low"; - OpenVDB_export_grid_fl(writer, name, fuel, sds->res, sds->fluidmat, density_grid); - name = (!sds->wt) ? "react" : "react low"; - OpenVDB_export_grid_fl(writer, name, react, sds->res, sds->fluidmat, density_grid); + name = (!sds->wt) ? "flame" : "flame_low"; + OpenVDB_export_grid_fl(writer, name, flame, sds->res, sds->fluidmat, sds->clipping, density_grid); + name = (!sds->wt) ? "fuel" : "fuel_low"; + OpenVDB_export_grid_fl(writer, name, fuel, sds->res, sds->fluidmat, sds->clipping, density_grid); + name = (!sds->wt) ? "react" : "react_low"; + OpenVDB_export_grid_fl(writer, name, react, sds->res, sds->fluidmat, sds->clipping, density_grid); } if (fluid_fields & SM_ACTIVE_COLORS) { - name = (!sds->wt) ? "color" : "color low"; - OpenVDB_export_grid_vec(writer, name, r, g, b, sds->res, sds->fluidmat, VEC_INVARIANT, true, density_grid); + name = (!sds->wt) ? "color" : "color_low"; + OpenVDB_export_grid_vec(writer, name, r, g, b, sds->res, sds->fluidmat, VEC_INVARIANT, true, sds->clipping, density_grid); } - OpenVDB_export_grid_vec(writer, "velocity", vx, vy, vz, sds->res, sds->fluidmat, VEC_CONTRAVARIANT_RELATIVE, false, clip_grid); - OpenVDB_export_grid_ch(writer, "obstacles", obstacles, sds->res, sds->fluidmat, NULL); + OpenVDB_export_grid_vec(writer, "velocity", vx, vy, vz, sds->res, sds->fluidmat, VEC_CONTRAVARIANT_RELATIVE, false, sds->clipping, clip_grid); + OpenVDB_export_grid_ch(writer, "obstacles", obstacles, sds->res, sds->fluidmat, sds->clipping, NULL); } return 1; @@ -1104,25 +1105,25 @@ static int ptcache_smoke_openvdb_read(struct OpenVDBReader *reader, void *smoke_ OpenVDB_import_grid_fl(reader, "shadow", &sds->shadow, sds->res); - const char *name = (!sds->wt) ? "density" : "density low"; + const char *name = (!sds->wt) ? "density" : "density_low"; OpenVDB_import_grid_fl(reader, name, &dens, sds->res); if (cache_fields & SM_ACTIVE_HEAT) { OpenVDB_import_grid_fl(reader, "heat", &heat, sds->res); - OpenVDB_import_grid_fl(reader, "heat old", &heatold, sds->res); + OpenVDB_import_grid_fl(reader, "heat_old", &heatold, sds->res); } if (cache_fields & SM_ACTIVE_FIRE) { - name = (!sds->wt) ? "flame" : "flame low"; + name = (!sds->wt) ? "flame" : "flame_low"; OpenVDB_import_grid_fl(reader, name, &flame, sds->res); - name = (!sds->wt) ? "fuel" : "fuel low"; + name = (!sds->wt) ? "fuel" : "fuel_low"; OpenVDB_import_grid_fl(reader, name, &fuel, sds->res); - name = (!sds->wt) ? "react" : "react low"; + name = (!sds->wt) ? "react" : "react_low"; OpenVDB_import_grid_fl(reader, name, &react, sds->res); } if (cache_fields & SM_ACTIVE_COLORS) { - name = (!sds->wt) ? "color" : "color low"; + name = (!sds->wt) ? "color" : "color_low"; OpenVDB_import_grid_vec(reader, name, &r, &g, &b, sds->res); } @@ -1646,6 +1647,25 @@ void BKE_ptcache_id_from_rigidbody(PTCacheID *pid, Object *ob, RigidBodyWorld *r pid->file_type = PTCACHE_FILE_PTCACHE; } +PTCacheID BKE_ptcache_id_find(Object *ob, Scene *scene, PointCache *cache) +{ + PTCacheID result = {0}; + + ListBase pidlist; + BKE_ptcache_ids_from_object(&pidlist, ob, scene, MAX_DUPLI_RECUR); + + for (PTCacheID *pid = pidlist.first; pid; pid = pid->next) { + if (pid->cache == cache) { + result = *pid; + break; + } + } + + BLI_freelistN(&pidlist); + + return result; +} + void BKE_ptcache_ids_from_object(ListBase *lb, Object *ob, Scene *scene, int duplis) { PTCacheID *pid; @@ -1714,22 +1734,19 @@ void BKE_ptcache_ids_from_object(ListBase *lb, Object *ob, Scene *scene, int dup BLI_addtail(lb, pid); } - if (scene && (duplis-- > 0) && (ob->transflag & OB_DUPLI)) { - ListBase *lb_dupli_ob; - /* don't update the dupli groups, we only want their pid's */ - if ((lb_dupli_ob = object_duplilist_ex(G.main->eval_ctx, scene, ob, false))) { - DupliObject *dob; - for (dob= lb_dupli_ob->first; dob; dob= dob->next) { - if (dob->ob != ob) { /* avoids recursive loops with dupliframes: bug 22988 */ - ListBase lb_dupli_pid; - BKE_ptcache_ids_from_object(&lb_dupli_pid, dob->ob, scene, duplis); - BLI_movelisttolist(lb, &lb_dupli_pid); - if (lb_dupli_pid.first) - printf("Adding Dupli\n"); - } - } + /* Consider all object in dupli groups to be part of the same object, + * for baking with linking dupligroups. Once we have better overrides + * this can be revisited so users select the local objects directly. */ + if (scene && (duplis-- > 0) && (ob->dup_group)) { + Group *group = ob->dup_group; + Base *base = group->view_layer->object_bases.first; - free_object_duplilist(lb_dupli_ob); /* does restore */ + for (; base; base = base->next) { + if (base->object != ob) { + ListBase lb_dupli_pid; + BKE_ptcache_ids_from_object(&lb_dupli_pid, base->object, scene, duplis); + BLI_movelisttolist(lb, &lb_dupli_pid); + } } } } @@ -3662,7 +3679,7 @@ void BKE_ptcache_bake(PTCacheBaker *baker) stime = ptime = PIL_check_seconds_timer(); for (int fr = CFRA; fr <= endframe; fr += baker->quick_step, CFRA = fr) { - BKE_scene_graph_update_for_newframe(G.main->eval_ctx, depsgraph, bmain, scene, view_layer); + BKE_scene_graph_update_for_newframe(depsgraph, bmain); if (baker->update_progress) { float progress = ((float)(CFRA - startframe)/(float)(endframe - startframe)); @@ -3748,7 +3765,7 @@ void BKE_ptcache_bake(PTCacheBaker *baker) CFRA = cfrao; if (bake) { /* already on cfra unless baking */ - BKE_scene_graph_update_for_newframe(bmain->eval_ctx, depsgraph, bmain, scene, view_layer); + BKE_scene_graph_update_for_newframe(depsgraph, bmain); } /* TODO: call redraw all windows somehow */ diff --git a/source/blender/blenkernel/intern/rigidbody.c b/source/blender/blenkernel/intern/rigidbody.c index bd4b817c8cd..ff521260993 100644 --- a/source/blender/blenkernel/intern/rigidbody.c +++ b/source/blender/blenkernel/intern/rigidbody.c @@ -50,7 +50,7 @@ #include "DNA_group_types.h" #include "DNA_meshdata_types.h" #include "DNA_object_types.h" -#include "DNA_object_force.h" +#include "DNA_object_force_types.h" #include "DNA_rigidbody_types.h" #include "DNA_scene_types.h" @@ -66,6 +66,8 @@ #include "BKE_rigidbody.h" #include "BKE_scene.h" +#include "DEG_depsgraph.h" + /* ************************************** */ /* Memory Management */ @@ -92,7 +94,7 @@ void BKE_rigidbody_free_world(RigidBodyWorld *rbw) if (rbw->physics_world) { /* free physics references, we assume that all physics objects in will have been added to the world */ if (rbw->constraints) { - FOREACH_GROUP_OBJECT(rbw->constraints, object) + FOREACH_GROUP_OBJECT_BEGIN(rbw->constraints, object) { if (object->rigidbody_constraint) { RigidBodyCon *rbc = object->rigidbody_constraint; @@ -101,11 +103,11 @@ void BKE_rigidbody_free_world(RigidBodyWorld *rbw) } } } - FOREACH_GROUP_OBJECT_END + FOREACH_GROUP_OBJECT_END; } if (rbw->group) { - FOREACH_GROUP_OBJECT(rbw->group, object) + FOREACH_GROUP_OBJECT_BEGIN(rbw->group, object) { if (object->rigidbody_object) { RigidBodyOb *rbo = object->rigidbody_object; @@ -114,7 +116,7 @@ void BKE_rigidbody_free_world(RigidBodyWorld *rbw) } } } - FOREACH_GROUP_OBJECT_END + FOREACH_GROUP_OBJECT_END; } /* free dynamics world */ RB_dworld_delete(rbw->physics_world); @@ -702,6 +704,39 @@ static void rigidbody_validate_sim_object(RigidBodyWorld *rbw, Object *ob, bool /* --------------------- */ +static void rigidbody_constraint_set_limits(RigidBodyCon *rbc, void (*set_limits)(rbConstraint*,int,float,float)) +{ + if (rbc->flag & RBC_FLAG_USE_LIMIT_LIN_X) + set_limits(rbc->physics_constraint, RB_LIMIT_LIN_X, rbc->limit_lin_x_lower, rbc->limit_lin_x_upper); + else + set_limits(rbc->physics_constraint, RB_LIMIT_LIN_X, 0.0f, -1.0f); + + if (rbc->flag & RBC_FLAG_USE_LIMIT_LIN_Y) + set_limits(rbc->physics_constraint, RB_LIMIT_LIN_Y, rbc->limit_lin_y_lower, rbc->limit_lin_y_upper); + else + set_limits(rbc->physics_constraint, RB_LIMIT_LIN_Y, 0.0f, -1.0f); + + if (rbc->flag & RBC_FLAG_USE_LIMIT_LIN_Z) + set_limits(rbc->physics_constraint, RB_LIMIT_LIN_Z, rbc->limit_lin_z_lower, rbc->limit_lin_z_upper); + else + set_limits(rbc->physics_constraint, RB_LIMIT_LIN_Z, 0.0f, -1.0f); + + if (rbc->flag & RBC_FLAG_USE_LIMIT_ANG_X) + set_limits(rbc->physics_constraint, RB_LIMIT_ANG_X, rbc->limit_ang_x_lower, rbc->limit_ang_x_upper); + else + set_limits(rbc->physics_constraint, RB_LIMIT_ANG_X, 0.0f, -1.0f); + + if (rbc->flag & RBC_FLAG_USE_LIMIT_ANG_Y) + set_limits(rbc->physics_constraint, RB_LIMIT_ANG_Y, rbc->limit_ang_y_lower, rbc->limit_ang_y_upper); + else + set_limits(rbc->physics_constraint, RB_LIMIT_ANG_Y, 0.0f, -1.0f); + + if (rbc->flag & RBC_FLAG_USE_LIMIT_ANG_Z) + set_limits(rbc->physics_constraint, RB_LIMIT_ANG_Z, rbc->limit_ang_z_lower, rbc->limit_ang_z_upper); + else + set_limits(rbc->physics_constraint, RB_LIMIT_ANG_Z, 0.0f, -1.0f); +} + /** * Create physics sim representation of constraint given rigid body constraint settings * @@ -820,40 +855,13 @@ static void rigidbody_validate_sim_constraint(RigidBodyWorld *rbw, Object *ob, b RB_constraint_set_damping_6dof_spring(rbc->physics_constraint, RB_LIMIT_ANG_Z, rbc->spring_damping_ang_z); RB_constraint_set_equilibrium_6dof_spring(rbc->physics_constraint); - ATTR_FALLTHROUGH; - case RBC_TYPE_6DOF: - if (rbc->type == RBC_TYPE_6DOF) /* a litte awkward but avoids duplicate code for limits */ - rbc->physics_constraint = RB_constraint_new_6dof(loc, rot, rb1, rb2); - - if (rbc->flag & RBC_FLAG_USE_LIMIT_LIN_X) - RB_constraint_set_limits_6dof(rbc->physics_constraint, RB_LIMIT_LIN_X, rbc->limit_lin_x_lower, rbc->limit_lin_x_upper); - else - RB_constraint_set_limits_6dof(rbc->physics_constraint, RB_LIMIT_LIN_X, 0.0f, -1.0f); - if (rbc->flag & RBC_FLAG_USE_LIMIT_LIN_Y) - RB_constraint_set_limits_6dof(rbc->physics_constraint, RB_LIMIT_LIN_Y, rbc->limit_lin_y_lower, rbc->limit_lin_y_upper); - else - RB_constraint_set_limits_6dof(rbc->physics_constraint, RB_LIMIT_LIN_Y, 0.0f, -1.0f); - - if (rbc->flag & RBC_FLAG_USE_LIMIT_LIN_Z) - RB_constraint_set_limits_6dof(rbc->physics_constraint, RB_LIMIT_LIN_Z, rbc->limit_lin_z_lower, rbc->limit_lin_z_upper); - else - RB_constraint_set_limits_6dof(rbc->physics_constraint, RB_LIMIT_LIN_Z, 0.0f, -1.0f); - - if (rbc->flag & RBC_FLAG_USE_LIMIT_ANG_X) - RB_constraint_set_limits_6dof(rbc->physics_constraint, RB_LIMIT_ANG_X, rbc->limit_ang_x_lower, rbc->limit_ang_x_upper); - else - RB_constraint_set_limits_6dof(rbc->physics_constraint, RB_LIMIT_ANG_X, 0.0f, -1.0f); - - if (rbc->flag & RBC_FLAG_USE_LIMIT_ANG_Y) - RB_constraint_set_limits_6dof(rbc->physics_constraint, RB_LIMIT_ANG_Y, rbc->limit_ang_y_lower, rbc->limit_ang_y_upper); - else - RB_constraint_set_limits_6dof(rbc->physics_constraint, RB_LIMIT_ANG_Y, 0.0f, -1.0f); + rigidbody_constraint_set_limits(rbc, RB_constraint_set_limits_6dof_spring); + break; + case RBC_TYPE_6DOF: + rbc->physics_constraint = RB_constraint_new_6dof(loc, rot, rb1, rb2); - if (rbc->flag & RBC_FLAG_USE_LIMIT_ANG_Z) - RB_constraint_set_limits_6dof(rbc->physics_constraint, RB_LIMIT_ANG_Z, rbc->limit_ang_z_lower, rbc->limit_ang_z_upper); - else - RB_constraint_set_limits_6dof(rbc->physics_constraint, RB_LIMIT_ANG_Z, 0.0f, -1.0f); + rigidbody_constraint_set_limits(rbc, RB_constraint_set_limits_6dof); break; case RBC_TYPE_MOTOR: rbc->physics_constraint = RB_constraint_new_motor(loc, rot, rb1, rb2); @@ -1148,7 +1156,7 @@ void BKE_rigidbody_remove_object(Scene *scene, Object *ob) /* remove object from rigid body constraints */ if (rbw->constraints) { - FOREACH_GROUP_OBJECT(rbw->constraints, obt) + FOREACH_GROUP_OBJECT_BEGIN(rbw->constraints, obt) { if (obt && obt->rigidbody_constraint) { rbc = obt->rigidbody_constraint; @@ -1157,7 +1165,7 @@ void BKE_rigidbody_remove_object(Scene *scene, Object *ob) } } } - FOREACH_GROUP_OBJECT_END + FOREACH_GROUP_OBJECT_END; } } @@ -1201,12 +1209,12 @@ static void rigidbody_update_ob_array(RigidBodyWorld *rbw) } i = 0; - FOREACH_GROUP_OBJECT(rbw->group, object) + FOREACH_GROUP_OBJECT_BEGIN(rbw->group, object) { rbw->objects[i] = object; i++; } - FOREACH_GROUP_OBJECT_END + FOREACH_GROUP_OBJECT_END; } static void rigidbody_update_sim_world(Scene *scene, RigidBodyWorld *rbw) @@ -1332,7 +1340,7 @@ static void rigidbody_update_simulation(const struct EvaluationContext *eval_ctx * Memory management needs redesign here, this is just a dirty workaround. */ if (rebuild && rbw->constraints) { - FOREACH_GROUP_OBJECT(rbw->constraints, ob) + FOREACH_GROUP_OBJECT_BEGIN(rbw->constraints, ob) { RigidBodyCon *rbc = ob->rigidbody_constraint; if (rbc && rbc->physics_constraint) { @@ -1341,11 +1349,11 @@ static void rigidbody_update_simulation(const struct EvaluationContext *eval_ctx rbc->physics_constraint = NULL; } } - FOREACH_GROUP_OBJECT_END + FOREACH_GROUP_OBJECT_END; } /* update objects */ - FOREACH_GROUP_OBJECT(rbw->group, ob) + FOREACH_GROUP_OBJECT_BEGIN(rbw->group, ob) { if (ob->type == OB_MESH) { /* validate that we've got valid object set up here... */ @@ -1388,13 +1396,13 @@ static void rigidbody_update_simulation(const struct EvaluationContext *eval_ctx rigidbody_update_sim_ob(eval_ctx, scene, rbw, ob, rbo); } } - FOREACH_GROUP_OBJECT_END + FOREACH_GROUP_OBJECT_END; /* update constraints */ if (rbw->constraints == NULL) /* no constraints, move on */ return; - FOREACH_GROUP_OBJECT(rbw->constraints, ob) + FOREACH_GROUP_OBJECT_BEGIN(rbw->constraints, ob) { /* validate that we've got valid object set up here... */ RigidBodyCon *rbc = ob->rigidbody_constraint; @@ -1422,12 +1430,12 @@ static void rigidbody_update_simulation(const struct EvaluationContext *eval_ctx rbc->flag &= ~RBC_FLAG_NEEDS_VALIDATE; } } - FOREACH_GROUP_OBJECT_END + FOREACH_GROUP_OBJECT_END; } static void rigidbody_update_simulation_post_step(RigidBodyWorld *rbw) { - FOREACH_GROUP_BASE(rbw->group, base) + FOREACH_GROUP_BASE_BEGIN(rbw->group, base) { Object *ob = base->object; RigidBodyOb *rbo = ob->rigidbody_object; @@ -1688,11 +1696,7 @@ void BKE_rigidbody_rebuild_sim(const struct EvaluationContext *eval_ctx, Scene *scene) { float ctime = BKE_scene_frame_get(scene); - - if (G.debug & G_DEBUG_DEPSGRAPH) { - printf("%s at %f\n", __func__, ctime); - } - + DEG_debug_print_eval_time(__func__, scene->id.name, scene, ctime); /* rebuild sim data (i.e. after resetting to start of timeline) */ if (BKE_scene_check_rigidbody_active(scene)) { BKE_rigidbody_rebuild_world(eval_ctx, scene, ctime); @@ -1703,11 +1707,7 @@ void BKE_rigidbody_eval_simulation(const struct EvaluationContext *eval_ctx, Scene *scene) { float ctime = BKE_scene_frame_get(scene); - - if (G.debug & G_DEBUG_DEPSGRAPH) { - printf("%s at %f\n", __func__, ctime); - } - + DEG_debug_print_eval_time(__func__, scene->id.name, scene, ctime); /* evaluate rigidbody sim */ if (BKE_scene_check_rigidbody_active(scene)) { BKE_rigidbody_do_simulation(eval_ctx, scene, ctime); @@ -1720,11 +1720,7 @@ void BKE_rigidbody_object_sync_transforms(const struct EvaluationContext *UNUSED { 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); - } - + DEG_debug_print_eval_time(__func__, ob->id.name, ob, ctime); /* 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 16e9844241d..9a7c10d31de 100644 --- a/source/blender/blenkernel/intern/scene.c +++ b/source/blender/blenkernel/intern/scene.c @@ -151,6 +151,83 @@ static void remove_sequencer_fcurves(Scene *sce) } } +/* flag -- copying options (see BKE_library.h's LIB_ID_COPY_... flags for more). */ +ToolSettings *BKE_toolsettings_copy(ToolSettings *toolsettings, const int flag) +{ + if (toolsettings == NULL) { + return NULL; + } + ToolSettings *ts = MEM_dupallocN(toolsettings); + if (ts->vpaint) { + ts->vpaint = MEM_dupallocN(ts->vpaint); + BKE_paint_copy(&ts->vpaint->paint, &ts->vpaint->paint, flag); + } + if (ts->wpaint) { + ts->wpaint = MEM_dupallocN(ts->wpaint); + BKE_paint_copy(&ts->wpaint->paint, &ts->wpaint->paint, flag); + } + if (ts->sculpt) { + ts->sculpt = MEM_dupallocN(ts->sculpt); + BKE_paint_copy(&ts->sculpt->paint, &ts->sculpt->paint, flag); + } + if (ts->uvsculpt) { + ts->uvsculpt = MEM_dupallocN(ts->uvsculpt); + BKE_paint_copy(&ts->uvsculpt->paint, &ts->uvsculpt->paint, flag); + } + + BKE_paint_copy(&ts->imapaint.paint, &ts->imapaint.paint, flag); + ts->imapaint.paintcursor = NULL; + ts->particle.paintcursor = NULL; + ts->particle.scene = NULL; + ts->particle.object = NULL; + + /* duplicate Grease Pencil Drawing Brushes */ + BLI_listbase_clear(&ts->gp_brushes); + for (bGPDbrush *brush = toolsettings->gp_brushes.first; brush; brush = brush->next) { + bGPDbrush *newbrush = BKE_gpencil_brush_duplicate(brush); + BLI_addtail(&ts->gp_brushes, newbrush); + } + + /* duplicate Grease Pencil interpolation curve */ + ts->gp_interpolate.custom_ipo = curvemapping_copy(ts->gp_interpolate.custom_ipo); + return ts; +} + +void BKE_toolsettings_free(ToolSettings *toolsettings) +{ + if (toolsettings == NULL) { + return; + } + if (toolsettings->vpaint) { + BKE_paint_free(&toolsettings->vpaint->paint); + MEM_freeN(toolsettings->vpaint); + } + if (toolsettings->wpaint) { + BKE_paint_free(&toolsettings->wpaint->paint); + MEM_freeN(toolsettings->wpaint); + } + if (toolsettings->sculpt) { + BKE_paint_free(&toolsettings->sculpt->paint); + MEM_freeN(toolsettings->sculpt); + } + if (toolsettings->uvsculpt) { + BKE_paint_free(&toolsettings->uvsculpt->paint); + MEM_freeN(toolsettings->uvsculpt); + } + BKE_paint_free(&toolsettings->imapaint.paint); + + /* free Grease Pencil Drawing Brushes */ + BKE_gpencil_free_brushes(&toolsettings->gp_brushes); + BLI_freelistN(&toolsettings->gp_brushes); + + /* free Grease Pencil interpolation curve */ + if (toolsettings->gp_interpolate.custom_ipo) { + curvemapping_free(toolsettings->gp_interpolate.custom_ipo); + } + + MEM_freeN(toolsettings); +} + /** * Only copy internal data of Scene ID from source to already allocated/initialized destination. * You probably nerver want to use that directly, use id_copy or BKE_id_copy_ex for typical needs. @@ -166,7 +243,6 @@ void BKE_scene_copy_data(Main *bmain, Scene *sce_dst, const Scene *sce_src, cons sce_dst->ed = NULL; sce_dst->depsgraph_hash = NULL; - sce_dst->obedit = NULL; sce_dst->fps_info = NULL; /* layers and collections */ @@ -224,41 +300,7 @@ void BKE_scene_copy_data(Main *bmain, Scene *sce_dst, const Scene *sce_src, cons curvemapping_copy_data(&sce_dst->r.mblur_shutter_curve, &sce_src->r.mblur_shutter_curve); /* tool settings */ - if (sce_dst->toolsettings != NULL) { - ToolSettings *ts = sce_dst->toolsettings = MEM_dupallocN(sce_dst->toolsettings); - if (ts->vpaint) { - ts->vpaint = MEM_dupallocN(ts->vpaint); - BKE_paint_copy(&ts->vpaint->paint, &ts->vpaint->paint, flag_subdata); - } - if (ts->wpaint) { - ts->wpaint = MEM_dupallocN(ts->wpaint); - BKE_paint_copy(&ts->wpaint->paint, &ts->wpaint->paint, flag_subdata); - } - if (ts->sculpt) { - ts->sculpt = MEM_dupallocN(ts->sculpt); - BKE_paint_copy(&ts->sculpt->paint, &ts->sculpt->paint, flag_subdata); - } - if (ts->uvsculpt) { - ts->uvsculpt = MEM_dupallocN(ts->uvsculpt); - BKE_paint_copy(&ts->uvsculpt->paint, &ts->uvsculpt->paint, flag_subdata); - } - - BKE_paint_copy(&ts->imapaint.paint, &ts->imapaint.paint, flag_subdata); - ts->imapaint.paintcursor = NULL; - ts->particle.paintcursor = NULL; - ts->particle.scene = NULL; - ts->particle.object = NULL; - - /* duplicate Grease Pencil Drawing Brushes */ - BLI_listbase_clear(&ts->gp_brushes); - for (bGPDbrush *brush = sce_src->toolsettings->gp_brushes.first; brush; brush = brush->next) { - bGPDbrush *newbrush = BKE_gpencil_brush_duplicate(brush); - BLI_addtail(&ts->gp_brushes, newbrush); - } - - /* duplicate Grease Pencil interpolation curve */ - ts->gp_interpolate.custom_ipo = curvemapping_copy(ts->gp_interpolate.custom_ipo); - } + sce_dst->toolsettings = BKE_toolsettings_copy(sce_dst->toolsettings, flag_subdata); /* make a private copy of the avicodecdata */ if (sce_src->r.avicodecdata) { @@ -297,7 +339,6 @@ Scene *BKE_scene_copy(Main *bmain, Scene *sce, int type) /* TODO this should/could most likely be replaced by call to more generic code at some point... * But for now, let's keep it well isolated here. */ if (type == SCE_COPY_EMPTY) { - ToolSettings *ts; ListBase rv; sce_copy = BKE_scene_add(bmain, sce->id.name + 2); @@ -332,46 +373,7 @@ Scene *BKE_scene_copy(Main *bmain, Scene *sce, int type) curvemapping_copy_data(&sce_copy->r.mblur_shutter_curve, &sce->r.mblur_shutter_curve); /* tool settings */ - sce_copy->toolsettings = MEM_dupallocN(sce->toolsettings); - - ts = sce_copy->toolsettings; - if (ts) { - if (ts->vpaint) { - ts->vpaint = MEM_dupallocN(ts->vpaint); - BKE_paint_copy(&ts->vpaint->paint, &ts->vpaint->paint, 0); - } - if (ts->wpaint) { - ts->wpaint = MEM_dupallocN(ts->wpaint); - BKE_paint_copy(&ts->wpaint->paint, &ts->wpaint->paint, 0); - } - if (ts->sculpt) { - ts->sculpt = MEM_dupallocN(ts->sculpt); - BKE_paint_copy(&ts->sculpt->paint, &ts->sculpt->paint, 0); - } - if (ts->uvsculpt) { - ts->uvsculpt = MEM_dupallocN(ts->uvsculpt); - BKE_paint_copy(&ts->uvsculpt->paint, &ts->uvsculpt->paint, 0); - } - - BKE_paint_copy(&ts->imapaint.paint, &ts->imapaint.paint, 0); - ts->imapaint.paintcursor = NULL; - id_us_plus((ID *)ts->imapaint.stencil); - id_us_plus((ID *)ts->imapaint.clone); - id_us_plus((ID *)ts->imapaint.canvas); - ts->particle.paintcursor = NULL; - ts->particle.scene = NULL; - ts->particle.object = NULL; - - /* duplicate Grease Pencil Drawing Brushes */ - BLI_listbase_clear(&ts->gp_brushes); - for (bGPDbrush *brush = sce->toolsettings->gp_brushes.first; brush; brush = brush->next) { - bGPDbrush *newbrush = BKE_gpencil_brush_duplicate(brush); - BLI_addtail(&ts->gp_brushes, newbrush); - } - - /* duplicate Grease Pencil interpolation curve */ - ts->gp_interpolate.custom_ipo = curvemapping_copy(ts->gp_interpolate.custom_ipo); - } + sce_copy->toolsettings = BKE_toolsettings_copy(sce->toolsettings, 0); /* make a private copy of the avicodecdata */ if (sce->r.avicodecdata) { @@ -493,37 +495,8 @@ void BKE_scene_free_ex(Scene *sce, const bool do_id_user) BLI_freelistN(&sce->markers); BLI_freelistN(&sce->r.views); - if (sce->toolsettings) { - if (sce->toolsettings->vpaint) { - BKE_paint_free(&sce->toolsettings->vpaint->paint); - MEM_freeN(sce->toolsettings->vpaint); - } - if (sce->toolsettings->wpaint) { - BKE_paint_free(&sce->toolsettings->wpaint->paint); - MEM_freeN(sce->toolsettings->wpaint); - } - if (sce->toolsettings->sculpt) { - BKE_paint_free(&sce->toolsettings->sculpt->paint); - MEM_freeN(sce->toolsettings->sculpt); - } - if (sce->toolsettings->uvsculpt) { - BKE_paint_free(&sce->toolsettings->uvsculpt->paint); - MEM_freeN(sce->toolsettings->uvsculpt); - } - BKE_paint_free(&sce->toolsettings->imapaint.paint); - - /* free Grease Pencil Drawing Brushes */ - BKE_gpencil_free_brushes(&sce->toolsettings->gp_brushes); - BLI_freelistN(&sce->toolsettings->gp_brushes); - - /* free Grease Pencil interpolation curve */ - if (sce->toolsettings->gp_interpolate.custom_ipo) { - curvemapping_free(sce->toolsettings->gp_interpolate.custom_ipo); - } - - MEM_freeN(sce->toolsettings); - sce->toolsettings = NULL; - } + BKE_toolsettings_free(sce->toolsettings); + sce->toolsettings = NULL; BKE_scene_free_depsgraph_hash(sce); @@ -618,7 +591,7 @@ void BKE_scene_init(Scene *sce) */ sce->r.color_mgt_flag |= R_COLOR_MANAGEMENT; - sce->r.gauss = 1.0; + sce->r.gauss = 1.5f; /* deprecated but keep for upwards compat */ sce->r.postgamma = 1.0; @@ -982,21 +955,17 @@ void BKE_scene_set_background(Main *bmain, Scene *scene) /* check for cyclic sets, for reading old files but also for definite security (py?) */ BKE_scene_validate_setscene(bmain, scene); - /* can happen when switching modes in other scenes */ - if (scene->obedit && !(scene->obedit->mode & OB_MODE_EDIT)) - scene->obedit = NULL; - /* deselect objects (for dataselect) */ for (ob = bmain->object.first; ob; ob = ob->id.next) ob->flag &= ~(SELECT | OB_FROMGROUP); /* group flags again */ for (group = bmain->group.first; group; group = group->id.next) { - FOREACH_GROUP_OBJECT(group, object) + FOREACH_GROUP_OBJECT_BEGIN(group, object) { object->flag |= OB_FROMGROUP; } - FOREACH_GROUP_OBJECT_END + FOREACH_GROUP_OBJECT_END; } /* copy layers and flags from bases to objects */ @@ -1381,7 +1350,10 @@ static bool check_rendered_viewport_visible(Main *bmain) return false; } -static void prepare_mesh_for_viewport_render(Main *bmain, Scene *scene) +/* TODO(campbell): shouldn't we be able to use 'eval_ctx->view_layer' here? + * Currently this is NULL on load, so don't. */ +static void prepare_mesh_for_viewport_render( + Main *bmain, const ViewLayer *view_layer) { /* This is needed to prepare mesh to be used by the render * engine from the viewport rendering. We do loading here @@ -1392,7 +1364,7 @@ static void prepare_mesh_for_viewport_render(Main *bmain, Scene *scene) * call loading of the edit data for the mesh objects. */ - Object *obedit = scene->obedit; + Object *obedit = OBEDIT_FROM_VIEW_LAYER(view_layer); if (obedit) { Mesh *mesh = obedit->data; if ((obedit->type == OB_MESH) && @@ -1401,7 +1373,11 @@ static void prepare_mesh_for_viewport_render(Main *bmain, Scene *scene) { if (check_rendered_viewport_visible(bmain)) { BMesh *bm = mesh->edit_btmesh->bm; - BM_mesh_bm_to_me(bm, mesh, (&(struct BMeshToMeshParams){0})); + BM_mesh_bm_to_me( + bm, mesh, + (&(struct BMeshToMeshParams){ + .calc_object_remap = true, + })); DEG_id_tag_update(&mesh->id, 0); } } @@ -1411,17 +1387,12 @@ static void prepare_mesh_for_viewport_render(Main *bmain, Scene *scene) /* TODO(sergey): This actually should become view_layer_graph or so. * Same applies to update_for_newframe. */ -void BKE_scene_graph_update_tagged(EvaluationContext *eval_ctx, - Depsgraph *depsgraph, - Main *bmain, - Scene *scene, - ViewLayer *view_layer) +void BKE_scene_graph_update_tagged(Depsgraph *depsgraph, + Main *bmain) { - /* TODO(sergey): Temporary solution for until pipeline.c is ported. */ - if (view_layer == NULL) { - view_layer = DEG_get_evaluated_view_layer(depsgraph); - BLI_assert(view_layer != NULL); - } + Scene *scene = DEG_get_input_scene(depsgraph); + ViewLayer *view_layer = DEG_get_input_view_layer(depsgraph); + /* TODO(sergey): Some functions here are changing global state, * for example, clearing update tags from bmain. */ @@ -1430,13 +1401,13 @@ void BKE_scene_graph_update_tagged(EvaluationContext *eval_ctx, /* Uncomment this to check if graph was properly tagged for update. */ // DEG_debug_graph_relations_validate(depsgraph, bmain, scene); /* Flush editing data if needed. */ - prepare_mesh_for_viewport_render(bmain, scene); + prepare_mesh_for_viewport_render(bmain, view_layer); /* Flush recalc flags to dependencies. */ DEG_graph_flush_update(bmain, depsgraph); /* Update all objects: drivers, matrices, displists, etc. flags set * by depgraph or manual, no layer check here, gets correct flushed. */ - DEG_evaluate_on_refresh(eval_ctx, depsgraph); + DEG_evaluate_on_refresh(depsgraph); /* Update sound system animation (TODO, move to depsgraph). */ BKE_sound_update_scene(bmain, scene); /* Inform editors about possible changes. */ @@ -1446,17 +1417,12 @@ void BKE_scene_graph_update_tagged(EvaluationContext *eval_ctx, } /* applies changes right away, does all sets too */ -void BKE_scene_graph_update_for_newframe(EvaluationContext *eval_ctx, - Depsgraph *depsgraph, - Main *bmain, - Scene *scene, - ViewLayer *view_layer) +void BKE_scene_graph_update_for_newframe(Depsgraph *depsgraph, + Main *bmain) { - /* TODO(sergey): Temporary solution for until pipeline.c is ported. */ - if (view_layer == NULL) { - view_layer = DEG_get_evaluated_view_layer(depsgraph); - BLI_assert(view_layer != NULL); - } + Scene *scene = DEG_get_input_scene(depsgraph); + ViewLayer *view_layer = DEG_get_input_view_layer(depsgraph); + /* TODO(sergey): Some functions here are changing global state, * for example, clearing update tags from bmain. */ @@ -1481,7 +1447,7 @@ void BKE_scene_graph_update_for_newframe(EvaluationContext *eval_ctx, /* Update all objects: drivers, matrices, displists, etc. flags set * by depgraph or manual, no layer check here, gets correct flushed. */ - DEG_evaluate_on_framechange(eval_ctx, bmain, depsgraph, ctime); + DEG_evaluate_on_framechange(bmain, depsgraph, ctime); /* Update sound system animation (TODO, move to depsgraph). */ BKE_sound_update_scene(bmain, scene); /* Notify editors and python about recalc. */ @@ -2222,7 +2188,7 @@ Depsgraph *BKE_scene_get_depsgraph(Scene *scene, { *key_ptr = MEM_mallocN(sizeof(DepsgraphKey), __func__); **key_ptr = key; - *depsgraph_ptr = DEG_graph_new(); + *depsgraph_ptr = DEG_graph_new(scene, view_layer, DAG_EVAL_VIEWPORT); } depsgraph = *depsgraph_ptr; } diff --git a/source/blender/blenkernel/intern/screen.c b/source/blender/blenkernel/intern/screen.c index 754f59d2e33..c1b3a4ae0c8 100644 --- a/source/blender/blenkernel/intern/screen.c +++ b/source/blender/blenkernel/intern/screen.c @@ -39,8 +39,6 @@ #include "MEM_guardedalloc.h" -#include "GPU_compositing.h" - #include "DNA_scene_types.h" #include "DNA_screen_types.h" #include "DNA_space_types.h" @@ -182,7 +180,7 @@ ARegion *BKE_area_region_copy(SpaceType *st, ARegion *ar) BLI_listbase_clear(&newar->panels_category); BLI_listbase_clear(&newar->panels_category_active); BLI_listbase_clear(&newar->ui_lists); - newar->swinid = 0; + newar->visible = 0; newar->manipulator_map = NULL; newar->regiontimer = NULL; newar->headerstr = NULL; @@ -684,29 +682,6 @@ float BKE_screen_view3d_zoom_from_fac(float zoomfac) return ((sqrtf(4.0f * zoomfac) - (float)M_SQRT2) * 50.0f); } -void BKE_screen_gpu_fx_validate(GPUFXSettings *fx_settings) -{ - /* currently we use DOF from the camera _only_, - * so we never allocate this, only copy from the Camera */ -#if 0 - if ((fx_settings->dof == NULL) && - (fx_settings->fx_flag & GPU_FX_FLAG_DOF)) - { - GPUDOFSettings *fx_dof; - fx_dof = fx_settings->dof = MEM_callocN(sizeof(GPUDOFSettings), __func__); - } -#endif - - if ((fx_settings->ssao == NULL) && - (fx_settings->fx_flag & GPU_FX_FLAG_SSAO)) - { - GPUSSAOSettings *fx_ssao; - fx_ssao = fx_settings->ssao = MEM_callocN(sizeof(GPUSSAOSettings), __func__); - - GPU_fx_compositor_init_ssao_settings(fx_ssao); - } -} - bool BKE_screen_is_fullscreen_area(const bScreen *screen) { return ELEM(screen->state, SCREENMAXIMIZED, SCREENFULL); diff --git a/source/blender/blenkernel/intern/seqeffects.c b/source/blender/blenkernel/intern/seqeffects.c index ee80438db64..49f120de250 100644 --- a/source/blender/blenkernel/intern/seqeffects.c +++ b/source/blender/blenkernel/intern/seqeffects.c @@ -52,6 +52,7 @@ #include "IMB_imbuf_types.h" #include "IMB_imbuf.h" #include "IMB_colormanagement.h" +#include "IMB_metadata.h" #include "BLI_math_color_blend.h" diff --git a/source/blender/blenkernel/intern/sequencer.c b/source/blender/blenkernel/intern/sequencer.c index 424f4269f3c..58b83a754d8 100644 --- a/source/blender/blenkernel/intern/sequencer.c +++ b/source/blender/blenkernel/intern/sequencer.c @@ -86,6 +86,7 @@ #include "IMB_imbuf.h" #include "IMB_imbuf_types.h" #include "IMB_colormanagement.h" +#include "IMB_metadata.h" #include "BKE_context.h" #include "BKE_sound.h" @@ -946,6 +947,8 @@ void BKE_sequence_reload_new_file(Scene *scene, Sequence *seq, const bool lock_r return; } + IMB_anim_load_metadata(sanim->anim); + seq->len = IMB_anim_get_duration(sanim->anim, seq->strip->proxy ? seq->strip->proxy->tc : IMB_TC_RECORD_RUN); seq->anim_preseek = IMB_anim_get_preseek(sanim->anim); @@ -1680,6 +1683,11 @@ static bool seq_proxy_get_fname(Editing *ed, Sequence *seq, int cfra, int render else if (seq->type == SEQ_TYPE_IMAGE) { fname[0] = 0; } + else { + /* We could make a name here, except non-movie's don't generate proxies, + * cancel until other types of sequence strips are supported. */ + return false; + } BLI_path_append(dir, sizeof(dir), fname); BLI_path_abs(name, G.main->name); } @@ -2954,7 +2962,7 @@ static ImBuf *seq_render_movie_strip(const SeqRenderData *context, Sequence *seq int totviews; int i; - if (totfiles != BLI_listbase_count_ex(&seq->anims, totfiles + 1)) + if (totfiles != BLI_listbase_count_at_most(&seq->anims, totfiles + 1)) goto monoview_movie; totviews = BKE_scene_multiview_num_views_get(&context->scene->r); @@ -3264,9 +3272,10 @@ static ImBuf *seq_render_scene_strip(const SeqRenderData *context, Sequence *seq // have_seq = (scene->r.scemode & R_DOSEQ) && scene->ed && scene->ed->seqbase.first); /* UNUSED */ have_comp = (scene->r.scemode & R_DOCOMP) && scene->use_nodes && scene->nodetree; - /* Get depsgraph and scene layer for the strip. */ + /* Get view layer for the strip. */ ViewLayer *view_layer = BKE_view_layer_from_scene_get(scene); - Depsgraph *depsgraph = BKE_scene_get_depsgraph(scene, view_layer, true); + /* Depsgraph will be NULL when doing rendering. */ + Depsgraph *depsgraph = NULL; orig_data.scemode = scene->r.scemode; orig_data.cfra = scene->r.cfra; @@ -3323,14 +3332,16 @@ static ImBuf *seq_render_scene_strip(const SeqRenderData *context, Sequence *seq context->scene->r.seq_prev_type = 3 /* == OB_SOLID */; /* opengl offscreen render */ - context->eval_ctx->engine_type = RE_engines_find(scene->view_render.engine_id); - BKE_scene_graph_update_for_newframe(context->eval_ctx, depsgraph, context->bmain, scene, view_layer); + RenderEngineType *engine_type = RE_engines_find(scene->view_render.engine_id); + depsgraph = BKE_scene_get_depsgraph(scene, view_layer, true); + BKE_scene_graph_update_for_newframe(depsgraph, context->bmain); ibuf = sequencer_view3d_cb( /* set for OpenGL render (NULL when scrubbing) */ - context->eval_ctx, scene, view_layer, camera, width, height, IB_rect, + context->eval_ctx, scene, view_layer, engine_type, + camera, width, height, IB_rect, draw_flags, context->scene->r.seq_prev_type, scene->r.alphamode, context->gpu_samples, viewname, - context->gpu_fx, context->gpu_offscreen, err_out); + context->gpu_offscreen, err_out); if (ibuf == NULL) { fprintf(stderr, "seq_render_scene_strip failed to get opengl buffer: %s\n", err_out); } @@ -3355,15 +3366,7 @@ static ImBuf *seq_render_scene_strip(const SeqRenderData *context, Sequence *seq if (re == NULL) re = RE_NewSceneRender(scene); - /* NOTE: Without this tag rendering from command line fails. - * TODO(sergey): Need some proper solution with ported - * BKE_scene_set_background() or DEG_on_visible_change() ? - */ - RE_SetDepsgraph(re, depsgraph); - DEG_graph_id_tag_update(context->bmain, depsgraph, &scene->id, 0); - - BKE_scene_graph_update_for_newframe(context->eval_ctx, depsgraph, context->bmain, scene, view_layer); - RE_BlenderFrame(re, context->bmain, scene, NULL, camera, scene->lay, frame, false); + RE_BlenderFrame(re, context->bmain, scene, view_layer, camera, scene->lay, frame, false); /* restore previous state after it was toggled on & off by RE_BlenderFrame */ G.is_rendering = is_rendering; @@ -3421,8 +3424,8 @@ finally: scene->r.cfra = orig_data.cfra; scene->r.subframe = orig_data.subframe; - if (is_frame_update) { - BKE_scene_graph_update_for_newframe(context->eval_ctx, depsgraph, context->bmain, scene, view_layer); + if (is_frame_update && (depsgraph != NULL)) { + BKE_scene_graph_update_for_newframe(depsgraph, context->bmain); } #ifdef DURIAN_CAMERA_SWITCH @@ -5167,6 +5170,40 @@ void BKE_sequence_init_colorspace(Sequence *seq) } } +float BKE_sequence_get_fps(Scene *scene, Sequence *seq) +{ + switch (seq->type) { + case SEQ_TYPE_MOVIE: + { + seq_open_anim_file(scene, seq, true); + if (BLI_listbase_is_empty(&seq->anims)) { + return 0.0f; + } + StripAnim *strip_anim = seq->anims.first; + if (strip_anim->anim == NULL) { + return 0.0f; + } + short frs_sec; + float frs_sec_base; + if (IMB_anim_get_fps(strip_anim->anim, &frs_sec, &frs_sec_base, true)) { + return (float)frs_sec / frs_sec_base; + } + break; + } + case SEQ_TYPE_MOVIECLIP: + if (seq->clip != NULL) { + return BKE_movieclip_get_fps(seq->clip); + } + break; + case SEQ_TYPE_SCENE: + if (seq->scene != NULL) { + return (float)seq->scene->r.frs_sec / seq->scene->r.frs_sec_base; + } + break; + } + return 0.0f; +} + /* NOTE: this function doesn't fill in image names */ Sequence *BKE_sequencer_add_image_strip(bContext *C, ListBase *seqbasep, SeqLoadInfo *seq_load) { @@ -5359,6 +5396,8 @@ Sequence *BKE_sequencer_add_movie_strip(bContext *C, ListBase *seqbasep, SeqLoad } } + IMB_anim_load_metadata(anim_arr[0]); + seq->anim_preseek = IMB_anim_get_preseek(anim_arr[0]); BLI_strncpy(seq->name + 2, "Movie", SEQ_NAME_MAXSTR - 2); BKE_sequence_base_unique_name_recursive(&scene->ed->seqbase, seq); diff --git a/source/blender/blenkernel/intern/smoke.c b/source/blender/blenkernel/intern/smoke.c index 9f9818127bc..9215d56eb30 100644 --- a/source/blender/blenkernel/intern/smoke.c +++ b/source/blender/blenkernel/intern/smoke.c @@ -72,7 +72,6 @@ #include "BKE_customdata.h" #include "BKE_deform.h" #include "BKE_DerivedMesh.h" -#include "BKE_global.h" #include "BKE_effect.h" #include "BKE_main.h" #include "BKE_modifier.h" @@ -170,11 +169,11 @@ void smoke_reallocate_highres_fluid(SmokeDomainSettings *sds, float dx, int res[ } /* smoke_turbulence_init uses non-threadsafe functions from fftw3 lib (like fftw_plan & co). */ - BLI_lock_thread(LOCK_FFTW); + BLI_thread_lock(LOCK_FFTW); sds->wt = smoke_turbulence_init(res, sds->amplify + 1, sds->noise, BKE_tempdir_session(), use_fire, use_colors); - BLI_unlock_thread(LOCK_FFTW); + BLI_thread_unlock(LOCK_FFTW); sds->res_wt[0] = res[0] * (sds->amplify + 1); sds->res_wt[1] = res[1] * (sds->amplify + 1); @@ -525,8 +524,8 @@ void smokeModifier_createType(struct SmokeModifierData *smd) smd->domain->burning_rate = 0.75f; smd->domain->flame_smoke = 1.0f; smd->domain->flame_vorticity = 0.5f; - smd->domain->flame_ignition = 1.25f; - smd->domain->flame_max_temp = 1.75f; + smd->domain->flame_ignition = 1.5f; + smd->domain->flame_max_temp = 3.0f; /* color */ smd->domain->flame_smoke_color[0] = 0.7f; smd->domain->flame_smoke_color[1] = 0.7f; @@ -553,6 +552,8 @@ void smokeModifier_createType(struct SmokeModifierData *smd) smd->domain->coba = NULL; smd->domain->coba_field = FLUID_FIELD_DENSITY; + + smd->domain->clipping = 1e-3f; } else if (smd->type & MOD_SMOKE_TYPE_FLOW) { @@ -1287,6 +1288,8 @@ static void emit_from_particles( curvemapping_changed_all(psys->part->clumpcurve); if ((psys->part->child_flag & PART_CHILD_USE_ROUGH_CURVE) && psys->part->roughcurve) curvemapping_changed_all(psys->part->roughcurve); + if ((psys->part->child_flag & PART_CHILD_USE_TWIST_CURVE) && psys->part->twistcurve) + curvemapping_changed_all(psys->part->twistcurve); /* initialize particle cache */ if (psys->part->type == PART_HAIR) { diff --git a/source/blender/blenkernel/intern/softbody.c b/source/blender/blenkernel/intern/softbody.c index 3cfa8787f4b..1fb95bd3115 100644 --- a/source/blender/blenkernel/intern/softbody.c +++ b/source/blender/blenkernel/intern/softbody.c @@ -1580,12 +1580,12 @@ static void sb_sfesf_threads_run(const struct EvaluationContext *eval_ctx, Scene sb_threads[i].tot= totthread; } if (totthread > 1) { - BLI_init_threads(&threads, exec_scan_for_ext_spring_forces, totthread); + BLI_threadpool_init(&threads, exec_scan_for_ext_spring_forces, totthread); for (i=0; i<totthread; i++) - BLI_insert_thread(&threads, &sb_threads[i]); + BLI_threadpool_insert(&threads, &sb_threads[i]); - BLI_end_threads(&threads); + BLI_threadpool_end(&threads); } else exec_scan_for_ext_spring_forces(&sb_threads[0]); @@ -2192,12 +2192,12 @@ static void sb_cf_threads_run(Scene *scene, Object *ob, float forcetime, float t if (totthread > 1) { - BLI_init_threads(&threads, exec_softbody_calc_forces, totthread); + BLI_threadpool_init(&threads, exec_softbody_calc_forces, totthread); for (i=0; i<totthread; i++) - BLI_insert_thread(&threads, &sb_threads[i]); + BLI_threadpool_insert(&threads, &sb_threads[i]); - BLI_end_threads(&threads); + BLI_threadpool_end(&threads); } else exec_softbody_calc_forces(&sb_threads[0]); diff --git a/source/blender/blenkernel/intern/speaker.c b/source/blender/blenkernel/intern/speaker.c index 9d604a9382a..1d2e12f34ac 100644 --- a/source/blender/blenkernel/intern/speaker.c +++ b/source/blender/blenkernel/intern/speaker.c @@ -32,7 +32,6 @@ #include "BLI_utildefines.h" #include "BKE_animsys.h" -#include "BKE_global.h" #include "BKE_library.h" #include "BKE_library_query.h" #include "BKE_library_remap.h" diff --git a/source/blender/blenkernel/intern/subsurf_ccg.c b/source/blender/blenkernel/intern/subsurf_ccg.c index 1c3ff352126..9280341b4e4 100644 --- a/source/blender/blenkernel/intern/subsurf_ccg.c +++ b/source/blender/blenkernel/intern/subsurf_ccg.c @@ -361,7 +361,7 @@ static int ss_sync_from_uv(CCGSubSurf *ss, CCGSubSurf *origss, DerivedMesh *dm, #ifdef USE_DYNSIZE CCGVertHDL fverts[nverts]; #else - BLI_array_empty(fverts); + BLI_array_clear(fverts); BLI_array_grow_items(fverts, nverts); #endif @@ -400,7 +400,7 @@ static int ss_sync_from_uv(CCGSubSurf *ss, CCGSubSurf *origss, DerivedMesh *dm, #ifdef USE_DYNSIZE CCGVertHDL fverts[nverts]; #else - BLI_array_empty(fverts); + BLI_array_clear(fverts); BLI_array_grow_items(fverts, nverts); #endif @@ -744,7 +744,7 @@ static void ss_sync_ccg_from_derivedmesh(CCGSubSurf *ss, #ifdef USE_DYNSIZE CCGVertHDL fVerts[mp->totloop]; #else - BLI_array_empty(fVerts); + BLI_array_clear(fVerts); BLI_array_grow_items(fVerts, mp->totloop); #endif @@ -4583,7 +4583,7 @@ static void set_ccgdm_all_geometry(CCGDerivedMesh *ccgdm, *((int *)ccgSubSurf_getFaceUserData(ss, f)) = vertNum; #ifndef USE_DYNSIZE - BLI_array_empty(loopidx); + BLI_array_clear(loopidx); BLI_array_grow_items(loopidx, numVerts); #endif for (s = 0; s < numVerts; s++) { @@ -4591,7 +4591,7 @@ static void set_ccgdm_all_geometry(CCGDerivedMesh *ccgdm, } #ifndef USE_DYNSIZE - BLI_array_empty(vertidx); + BLI_array_clear(vertidx); BLI_array_grow_items(vertidx, numVerts); #endif for (s = 0; s < numVerts; s++) { diff --git a/source/blender/blenkernel/intern/text.c b/source/blender/blenkernel/intern/text.c index 4ae9818f891..cd9b8ae339d 100644 --- a/source/blender/blenkernel/intern/text.c +++ b/source/blender/blenkernel/intern/text.c @@ -120,13 +120,56 @@ * */ + +/* Undo opcodes */ + +enum { + /* Complex editing */ + /* 1 - opcode is followed by 1 byte for ascii character and opcode (repeat)) */ + /* 2 - opcode is followed by 2 bytes for utf-8 character and opcode (repeat)) */ + /* 3 - opcode is followed by 3 bytes for utf-8 character and opcode (repeat)) */ + /* 4 - opcode is followed by 4 bytes for unicode character and opcode (repeat)) */ + UNDO_INSERT_1 = 013, + UNDO_INSERT_2 = 014, + UNDO_INSERT_3 = 015, + UNDO_INSERT_4 = 016, + + UNDO_BS_1 = 017, + UNDO_BS_2 = 020, + UNDO_BS_3 = 021, + UNDO_BS_4 = 022, + + UNDO_DEL_1 = 023, + UNDO_DEL_2 = 024, + UNDO_DEL_3 = 025, + UNDO_DEL_4 = 026, + + /* Text block (opcode is followed + * by 4 character length ID + the text + * block itself + the 4 character length + * ID (repeat) and opcode (repeat)) */ + UNDO_DBLOCK = 027, /* Delete block */ + UNDO_IBLOCK = 030, /* Insert block */ + + /* Misc */ + UNDO_INDENT = 032, + UNDO_UNINDENT = 033, + UNDO_COMMENT = 034, + UNDO_UNCOMMENT = 035, + + UNDO_MOVE_LINES_UP = 036, + UNDO_MOVE_LINES_DOWN = 037, + + UNDO_DUPLICATE = 040, +}; + /***/ static void txt_pop_first(Text *text); static void txt_pop_last(Text *text); -static void txt_undo_add_blockop(Text *text, int op, const char *buf); +static void txt_undo_add_blockop(Text *text, TextUndoBuf *utxt, int op, const char *buf); static void txt_delete_line(Text *text, TextLine *line); -static void txt_delete_sel(Text *text); +static void txt_delete_sel(Text *text, TextUndoBuf *utxt); static void txt_make_dirty(Text *text); /***/ @@ -144,13 +187,6 @@ int txt_get_undostate(void) return undoing; } -static void init_undo_text(Text *text) -{ - text->undo_pos = -1; - text->undo_len = TXT_INIT_UNDO; - text->undo_buf = MEM_mallocN(text->undo_len, "undo buf"); -} - /** * \note caller must handle `undo_buf` and `compiled` members. */ @@ -178,7 +214,6 @@ void BKE_text_free(Text *text) BKE_text_free_lines(text); MEM_SAFE_FREE(text->name); - MEM_SAFE_FREE(text->undo_buf); #ifdef WITH_PYTHON BPY_text_free_code(text); #endif @@ -192,8 +227,6 @@ void BKE_text_init(Text *ta) ta->name = NULL; - init_undo_text(ta); - ta->nlines = 1; ta->flags = TXT_ISDIRTY | TXT_ISMEM; if ((U.flag & USER_TXT_TABSTOSPACES_DISABLE) == 0) @@ -375,10 +408,6 @@ bool BKE_text_reload(Text *text) txt_make_dirty(text); /* clear undo buffer */ - MEM_freeN(text->undo_buf); - init_undo_text(text); - - if (BLI_stat(filepath_abs, &st) != -1) { text->mtime = st.st_mtime; } @@ -427,8 +456,6 @@ Text *BKE_text_load_ex(Main *bmain, const char *file, const char *relpath, const } /* clear undo buffer */ - init_undo_text(ta); - if (BLI_stat(filepath_abs, &st) != -1) { ta->mtime = st.st_mtime; } @@ -482,8 +509,6 @@ void BKE_text_copy_data(Main *UNUSED(bmain), Text *ta_dst, const Text *ta_src, c ta_dst->curl = ta_dst->sell = ta_dst->lines.first; ta_dst->curc = ta_dst->selc = 0; - - init_undo_text(ta_dst); } Text *BKE_text_copy(Main *bmain, const Text *ta) @@ -498,25 +523,29 @@ void BKE_text_make_local(Main *bmain, Text *text, const bool lib_local) BKE_id_make_local_generic(bmain, &text->id, true, lib_local); } -void BKE_text_clear(Text *text) /* called directly from rna */ +void BKE_text_clear(Text *text, TextUndoBuf *utxt) /* called directly from rna */ { int oldstate; - oldstate = txt_get_undostate(); - txt_set_undostate(1); + if (utxt) { + oldstate = txt_get_undostate(); + } + txt_set_undostate(utxt != NULL); + txt_sel_all(text); - txt_delete_sel(text); + txt_delete_sel(text, utxt); + txt_set_undostate(oldstate); txt_make_dirty(text); } -void BKE_text_write(Text *text, const char *str) /* called directly from rna */ +void BKE_text_write(Text *text, TextUndoBuf *utxt, const char *str) /* called directly from rna */ { int oldstate; oldstate = txt_get_undostate(); - txt_insert_buf(text, str); + txt_insert_buf(text, utxt, str); txt_move_eof(text, 0); txt_set_undostate(oldstate); @@ -1109,7 +1138,7 @@ bool txt_has_sel(Text *text) return ((text->curl != text->sell) || (text->curc != text->selc)); } -static void txt_delete_sel(Text *text) +static void txt_delete_sel(Text *text, TextUndoBuf *utxt) { TextLine *tmpl; char *buf; @@ -1123,7 +1152,7 @@ static void txt_delete_sel(Text *text) if (!undoing) { buf = txt_sel_to_buf(text); - txt_undo_add_blockop(text, UNDO_DBLOCK, buf); + txt_undo_add_blockop(text, utxt, UNDO_DBLOCK, buf); MEM_freeN(buf); } @@ -1364,7 +1393,7 @@ char *txt_sel_to_buf(Text *text) return buf; } -void txt_insert_buf(Text *text, const char *in_buffer) +void txt_insert_buf(Text *text, TextUndoBuf *utxt, const char *in_buffer) { int l = 0, u, len; size_t i = 0, j; @@ -1373,22 +1402,22 @@ void txt_insert_buf(Text *text, const char *in_buffer) if (!in_buffer) return; - txt_delete_sel(text); + txt_delete_sel(text, utxt); len = strlen(in_buffer); buffer = BLI_strdupn(in_buffer, len); len += txt_extended_ascii_as_utf8(&buffer); - if (!undoing) txt_undo_add_blockop(text, UNDO_IBLOCK, buffer); + if (!undoing) txt_undo_add_blockop(text, utxt, UNDO_IBLOCK, buffer); u = undoing; undoing = 1; /* Read the first line (or as close as possible */ while (buffer[i] && buffer[i] != '\n') - txt_add_raw_char(text, BLI_str_utf8_as_unicode_step(buffer, &i)); + txt_add_raw_char(text, utxt, BLI_str_utf8_as_unicode_step(buffer, &i)); - if (buffer[i] == '\n') txt_split_curline(text); + if (buffer[i] == '\n') txt_split_curline(text, utxt); else { undoing = u; MEM_freeN(buffer); return; } i++; @@ -1406,7 +1435,7 @@ void txt_insert_buf(Text *text, const char *in_buffer) } else { for (j = i - l; j < i && j < len; ) - txt_add_raw_char(text, BLI_str_utf8_as_unicode_step(buffer, &j)); + txt_add_raw_char(text, utxt, BLI_str_utf8_as_unicode_step(buffer, &j)); break; } } @@ -1420,33 +1449,47 @@ void txt_insert_buf(Text *text, const char *in_buffer) /* Undo functions */ /******************/ -static bool max_undo_test(Text *text, int x) +static bool max_undo_test(TextUndoBuf *utxt, int x) { - while (text->undo_pos + x >= text->undo_len) { - if (text->undo_len * 2 > TXT_MAX_UNDO) { - /* XXX error("Undo limit reached, buffer cleared\n"); */ - MEM_freeN(text->undo_buf); - init_undo_text(text); - return false; - } - else { - void *tmp = text->undo_buf; - text->undo_buf = MEM_callocN(text->undo_len * 2, "undo buf"); - memcpy(text->undo_buf, tmp, text->undo_len); - text->undo_len *= 2; - MEM_freeN(tmp); - } - } + /* Normally over-allocating is preferred, + * however in this case the buffer is small enough and re-allocation + * fast enough for each undo step that it's not a problem to allocate each time. + * This also saves on some memory when we have many text buffers + * that would have an empty undo memory allocated. + */ + /* Add one for the null terminator. */ + utxt->len = utxt->pos + x + 1; + if (utxt->len > TXT_MAX_UNDO) { + /* XXX error("Undo limit reached, buffer cleared\n"); */ + MEM_freeN(utxt->buf); + return false; + } + else { + /* Small reallocations on each undo step is fine. */ + utxt->buf = MEM_recallocN(utxt->buf, utxt->len); + } return true; } +static void txt_undo_end(Text *UNUSED(text), TextUndoBuf *utxt) +{ + int undo_pos_end = utxt->pos + 1; + BLI_assert(undo_pos_end + 1 == utxt->len); + utxt->buf[undo_pos_end] = '\0'; +} + +/* Call once undo is done. */ +#ifndef NDEBUG + +#endif + #if 0 /* UNUSED */ -static void dump_buffer(Text *text) +static void dump_buffer(TextUndoBuf *utxt) { int i = 0; - - while (i++ < text->undo_pos) printf("%d: %d %c\n", i, text->undo_buf[i], text->undo_buf[i]); + + while (i++ < utxt->undo_pos) printf("%d: %d %c\n", i, utxt->buf[i], utxt->buf[i]); } /* Note: this function is outdated and must be updated if needed for future use */ @@ -1461,10 +1504,10 @@ void txt_print_undo(Text *text) printf("---< Undo Buffer >---\n"); - printf("UndoPosition is %d\n", text->undo_pos); + printf("UndoPosition is %d\n", utxt->pos); - while (i <= text->undo_pos) { - op = text->undo_buf[i]; + while (i <= utxt->pos) { + op = utxt->buf[i]; if (op == UNDO_INSERT_1) { ops = "Insert ascii "; @@ -1530,15 +1573,15 @@ void txt_print_undo(Text *text) printf(" - Char is "); switch (op) { case UNDO_INSERT_1: case UNDO_BS_1: case UNDO_DEL_1: - printf("%c", text->undo_buf[i]); + printf("%c", utxt->buf[i]); i++; break; case UNDO_INSERT_2: case UNDO_BS_2: case UNDO_DEL_2: - printf("%c%c", text->undo_buf[i], text->undo_buf[i + 1]); + printf("%c%c", utxt->buf[i], utxt->buf[i + 1]); i += 2; break; case UNDO_INSERT_3: case UNDO_BS_3: case UNDO_DEL_3: - printf("%c%c%c", text->undo_buf[i], text->undo_buf[i + 1], text->undo_buf[i + 2]); + printf("%c%c%c", utxt->buf[i], utxt->buf[i + 1], utxt->buf[i + 2]); i += 3; break; case UNDO_INSERT_4: case UNDO_BS_4: case UNDO_DEL_4: @@ -1546,10 +1589,10 @@ void txt_print_undo(Text *text) unsigned int uc; char c[BLI_UTF8_MAX + 1]; size_t c_len; - uc = text->undo_buf[i]; i++; - uc = uc + (text->undo_buf[i] << 8); i++; - uc = uc + (text->undo_buf[i] << 16); i++; - uc = uc + (text->undo_buf[i] << 24); i++; + uc = utxt->buf[i]; i++; + uc = uc + (utxt->buf[i] << 8); i++; + uc = uc + (utxt->buf[i] << 16); i++; + uc = uc + (utxt->buf[i] << 24); i++; c_len = BLI_str_utf8_from_unicode(uc, c); c[c_len] = '\0'; puts(c); @@ -1560,44 +1603,44 @@ void txt_print_undo(Text *text) else if (op == UNDO_DBLOCK || op == UNDO_IBLOCK) { i++; - linep = text->undo_buf[i]; i++; - linep = linep + (text->undo_buf[i] << 8); i++; - linep = linep + (text->undo_buf[i] << 16); i++; - linep = linep + (text->undo_buf[i] << 24); i++; + linep = utxt->buf[i]; i++; + linep = linep + (utxt->buf[i] << 8); i++; + linep = linep + (utxt->buf[i] << 16); i++; + linep = linep + (utxt->buf[i] << 24); i++; printf(" (length %d) <", linep); while (linep > 0) { - putchar(text->undo_buf[i]); + putchar(utxt->buf[i]); linep--; i++; } - linep = text->undo_buf[i]; i++; - linep = linep + (text->undo_buf[i] << 8); i++; - linep = linep + (text->undo_buf[i] << 16); i++; - linep = linep + (text->undo_buf[i] << 24); i++; + linep = utxt->buf[i]; i++; + linep = linep + (utxt->buf[i] << 8); i++; + linep = linep + (utxt->buf[i] << 16); i++; + linep = linep + (utxt->buf[i] << 24); i++; printf("> (%d)", linep); } else if (op == UNDO_INDENT || op == UNDO_UNINDENT) { i++; - charp = text->undo_buf[i]; i++; - charp = charp + (text->undo_buf[i] << 8); i++; + charp = utxt->buf[i]; i++; + charp = charp + (utxt->buf[i] << 8); i++; - linep = text->undo_buf[i]; i++; - linep = linep + (text->undo_buf[i] << 8); i++; - linep = linep + (text->undo_buf[i] << 16); i++; - linep = linep + (text->undo_buf[i] << 24); i++; + linep = utxt->buf[i]; i++; + linep = linep + (utxt->buf[i] << 8); i++; + linep = linep + (utxt->buf[i] << 16); i++; + linep = linep + (utxt->buf[i] << 24); i++; printf("to <%d, %d> ", linep, charp); - charp = text->undo_buf[i]; i++; - charp = charp + (text->undo_buf[i] << 8); i++; + charp = utxt->buf[i]; i++; + charp = charp + (utxt->buf[i] << 8); i++; - linep = text->undo_buf[i]; i++; - linep = linep + (text->undo_buf[i] << 8); i++; - linep = linep + (text->undo_buf[i] << 16); i++; - linep = linep + (text->undo_buf[i] << 24); i++; + linep = utxt->buf[i]; i++; + linep = linep + (utxt->buf[i] << 8); i++; + linep = linep + (utxt->buf[i] << 16); i++; + linep = linep + (utxt->buf[i] << 24); i++; printf("from <%d, %d>", linep, charp); } @@ -1628,104 +1671,114 @@ static void txt_undo_store_uint32(char *undo_buf, int *undo_pos, unsigned int va (*undo_pos)++; } -/* store the cur cursor to the undo buffer */ -static void txt_undo_store_cur(Text *text) +/* store the cur cursor to the undo buffer (6 bytes)*/ +static void txt_undo_store_cur(Text *text, TextUndoBuf *utxt) { - txt_undo_store_uint16(text->undo_buf, &text->undo_pos, text->curc); - txt_undo_store_uint32(text->undo_buf, &text->undo_pos, txt_get_span(text->lines.first, text->curl)); + txt_undo_store_uint16(utxt->buf, &utxt->pos, text->curc); + txt_undo_store_uint32(utxt->buf, &utxt->pos, txt_get_span(text->lines.first, text->curl)); } -/* store the sel cursor to the undo buffer */ -static void txt_undo_store_sel(Text *text) +/* store the sel cursor to the undo buffer (6 bytes) */ +static void txt_undo_store_sel(Text *text, TextUndoBuf *utxt) { - txt_undo_store_uint16(text->undo_buf, &text->undo_pos, text->selc); - txt_undo_store_uint32(text->undo_buf, &text->undo_pos, txt_get_span(text->lines.first, text->sell)); + txt_undo_store_uint16(utxt->buf, &utxt->pos, text->selc); + txt_undo_store_uint32(utxt->buf, &utxt->pos, txt_get_span(text->lines.first, text->sell)); } -/* store both cursors to the undo buffer */ -static void txt_undo_store_cursors(Text *text) +/* store both cursors to the undo buffer (12 bytes) */ +static void txt_undo_store_cursors(Text *text, TextUndoBuf *utxt) { - txt_undo_store_cur(text); - txt_undo_store_sel(text); + txt_undo_store_cur(text, utxt); + txt_undo_store_sel(text, utxt); } /* store an operator along with a block of data */ -static void txt_undo_add_blockop(Text *text, int op, const char *buf) +static void txt_undo_add_blockop(Text *text, TextUndoBuf *utxt, int op, const char *buf) { unsigned int length = strlen(buf); - - if (!max_undo_test(text, length + 11 + 12)) - return; - - text->undo_pos++; - text->undo_buf[text->undo_pos] = op; - text->undo_pos++; - - txt_undo_store_cursors(text); - - txt_undo_store_uint32(text->undo_buf, &text->undo_pos, length); - - strncpy(text->undo_buf + text->undo_pos, buf, length); - text->undo_pos += length; - txt_undo_store_uint32(text->undo_buf, &text->undo_pos, length); - text->undo_buf[text->undo_pos] = op; - - text->undo_buf[text->undo_pos + 1] = 0; + if (!max_undo_test(utxt, 2 + 12 + 4 + length + 4 + 1)) { + return; + } + /* 2 bytes */ + utxt->pos++; + utxt->buf[utxt->pos] = op; + utxt->pos++; + /* 12 bytes */ + txt_undo_store_cursors(text, utxt); + /* 4 bytes */ + txt_undo_store_uint32(utxt->buf, &utxt->pos, length); + /* 'length' bytes */ + strncpy(utxt->buf + utxt->pos, buf, length); + utxt->pos += length; + /* 4 bytes */ + txt_undo_store_uint32(utxt->buf, &utxt->pos, length); + /* 1 byte */ + utxt->buf[utxt->pos] = op; + + txt_undo_end(text, utxt); } /* store a regular operator */ -void txt_undo_add_op(Text *text, int op) +void txt_undo_add_op(Text *text, TextUndoBuf *utxt, int op) { - if (!max_undo_test(text, 15)) + if (!max_undo_test(utxt, 2 + 12 + 1)) { return; + } - text->undo_pos++; - text->undo_buf[text->undo_pos] = op; + /* 2 bytes */ + utxt->pos++; + utxt->buf[utxt->pos] = op; + utxt->pos++; + /* 12 bytes */ + txt_undo_store_cursors(text, utxt); + /* 1 byte */ + utxt->buf[utxt->pos] = op; - text->undo_pos++; - - txt_undo_store_cursors(text); - - text->undo_buf[text->undo_pos] = op; - text->undo_buf[text->undo_pos + 1] = 0; + txt_undo_end(text, utxt); } /* store an operator for a single character */ -static void txt_undo_add_charop(Text *text, int op_start, unsigned int c) +static void txt_undo_add_charop(Text *text, TextUndoBuf *utxt, int op_start, unsigned int c) { char utf8[BLI_UTF8_MAX]; size_t i, utf8_size = BLI_str_utf8_from_unicode(c, utf8); - if (!max_undo_test(text, 3 + utf8_size + 12)) - return; - - text->undo_pos++; - - if (utf8_size < 4) { - text->undo_buf[text->undo_pos] = op_start + utf8_size - 1; - text->undo_pos++; - - txt_undo_store_cur(text); - + if (utf8_size < 4 && 0) { + if (!max_undo_test(utxt, 2 + 6 + utf8_size + 1)) { + return; + } + /* 2 bytes */ + utxt->pos++; + utxt->buf[utxt->pos] = op_start + utf8_size - 1; + utxt->pos++; + /* 6 bytes */ + txt_undo_store_cur(text, utxt); + /* 'utf8_size' bytes */ for (i = 0; i < utf8_size; i++) { - text->undo_buf[text->undo_pos] = utf8[i]; - text->undo_pos++; + utxt->buf[utxt->pos] = utf8[i]; + utxt->pos++; } - - text->undo_buf[text->undo_pos] = op_start + utf8_size - 1; + /* 1 byte */ + utxt->buf[utxt->pos] = op_start + utf8_size - 1; } else { - text->undo_buf[text->undo_pos] = op_start + 3; - text->undo_pos++; - - txt_undo_store_cursors(text); - - txt_undo_store_uint32(text->undo_buf, &text->undo_pos, c); - text->undo_buf[text->undo_pos] = op_start + 3; + if (!max_undo_test(utxt, 2 + 6 + 4 + 1)) { + return; + } + /* 2 bytes */ + utxt->pos++; + utxt->buf[utxt->pos] = op_start + 3; + utxt->pos++; + /* 6 bytes */ + txt_undo_store_cur(text, utxt); + /* 4 bytes */ + txt_undo_store_uint32(utxt->buf, &utxt->pos, c); + /* 1 byte */ + utxt->buf[utxt->pos] = op_start + 3; } - text->undo_buf[text->undo_pos + 1] = 0; + txt_undo_end(text, utxt); } /* extends Link */ @@ -1739,7 +1792,7 @@ struct LinkInt { * of the lines that should not be indented back. */ static void txt_undo_add_unprefix_op( - Text *text, char undo_op, + Text *text, TextUndoBuf *utxt, char undo_op, const ListBase *line_index_mask, const int line_index_mask_len) { struct LinkInt *idata; @@ -1747,30 +1800,35 @@ static void txt_undo_add_unprefix_op( 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)) { + if (!max_undo_test(utxt, 2 + 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_op; - text->undo_pos++; - /* Adding number of line numbers to read */ - txt_undo_store_uint32(text->undo_buf, &text->undo_pos, line_index_mask_len); + /* 2 bytes */ + utxt->pos++; + utxt->buf[utxt->pos] = undo_op; + utxt->pos++; + /* Adding number of line numbers to read + * 4 bytes */ + txt_undo_store_uint32(utxt->buf, &utxt->pos, line_index_mask_len); - /* Adding linenumbers of lines that shall not be indented if undoing */ + /* Adding linenumbers of lines that shall not be indented if undoing. + * 'line_index_mask_len * 4' bytes */ 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_op; + txt_undo_store_uint32(utxt->buf, &utxt->pos, idata->value); + } + + /* Adding number of line numbers to read again. + * 4 bytes */ + txt_undo_store_uint32(utxt->buf, &utxt->pos, line_index_mask_len); + /* Adding current selection. + * 12 bytes */ + txt_undo_store_cursors(text, utxt); + /* Closing with OP (same as above). + * 1 byte */ + utxt->buf[utxt->pos] = undo_op; /* Marking as last undo operation */ - text->undo_buf[text->undo_pos + 1] = 0; + txt_undo_end(text, utxt); } static unsigned short txt_undo_read_uint16(const char *undo_buf, int *undo_pos) @@ -1913,7 +1971,7 @@ static unsigned int txt_redo_read_unicode(const char *undo_buf, int *undo_pos, s unicode = BLI_str_utf8_as_unicode(utf8); break; case 4: /* 32-bit unicode symbol */ - unicode = txt_undo_read_uint32(undo_buf, undo_pos); + unicode = txt_redo_read_uint32(undo_buf, undo_pos); break; default: /* should never happen */ @@ -1925,9 +1983,9 @@ static unsigned int txt_redo_read_unicode(const char *undo_buf, int *undo_pos, s return unicode; } -void txt_do_undo(Text *text) +void txt_do_undo(Text *text, TextUndoBuf *utxt) { - int op = text->undo_buf[text->undo_pos]; + int op = utxt->buf[utxt->pos]; int prev_flags; unsigned int linep; unsigned int uni_char; @@ -1936,11 +1994,11 @@ void txt_do_undo(Text *text) unsigned short charp; char *buf; - if (text->undo_pos < 0) { + if (utxt->pos < 0) { return; } - text->undo_pos--; + utxt->pos--; undoing = 1; @@ -1949,16 +2007,16 @@ void txt_do_undo(Text *text) case UNDO_INSERT_2: case UNDO_INSERT_3: case UNDO_INSERT_4: - text->undo_pos -= op - UNDO_INSERT_1 + 1; + utxt->pos -= op - UNDO_INSERT_1 + 1; /* get and restore the cursors */ - txt_undo_read_cur(text->undo_buf, &text->undo_pos, &curln, &curc); + txt_undo_read_cur(utxt->buf, &utxt->pos, &curln, &curc); txt_move_to(text, curln, curc, 0); txt_move_to(text, curln, curc, 1); - txt_delete_char(text); + txt_delete_char(text, utxt); - text->undo_pos--; + utxt->pos--; break; case UNDO_BS_1: @@ -1966,16 +2024,16 @@ void txt_do_undo(Text *text) case UNDO_BS_3: case UNDO_BS_4: charp = op - UNDO_BS_1 + 1; - uni_char = txt_undo_read_unicode(text->undo_buf, &text->undo_pos, charp); + uni_char = txt_undo_read_unicode(utxt->buf, &utxt->pos, charp); /* get and restore the cursors */ - txt_undo_read_cur(text->undo_buf, &text->undo_pos, &curln, &curc); + txt_undo_read_cur(utxt->buf, &utxt->pos, &curln, &curc); txt_move_to(text, curln, curc, 0); txt_move_to(text, curln, curc, 1); - txt_add_char(text, uni_char); + txt_add_char(text, utxt, uni_char); - text->undo_pos--; + utxt->pos--; break; case UNDO_DEL_1: @@ -1983,50 +2041,50 @@ void txt_do_undo(Text *text) case UNDO_DEL_3: case UNDO_DEL_4: charp = op - UNDO_DEL_1 + 1; - uni_char = txt_undo_read_unicode(text->undo_buf, &text->undo_pos, charp); + uni_char = txt_undo_read_unicode(utxt->buf, &utxt->pos, charp); /* get and restore the cursors */ - txt_undo_read_cur(text->undo_buf, &text->undo_pos, &curln, &curc); + txt_undo_read_cur(utxt->buf, &utxt->pos, &curln, &curc); txt_move_to(text, curln, curc, 0); txt_move_to(text, curln, curc, 1); - txt_add_char(text, uni_char); + txt_add_char(text, utxt, uni_char); txt_move_left(text, 0); - text->undo_pos--; + utxt->pos--; break; case UNDO_DBLOCK: { int i; /* length of the string in the buffer */ - linep = txt_undo_read_uint32(text->undo_buf, &text->undo_pos); + linep = txt_undo_read_uint32(utxt->buf, &utxt->pos); buf = MEM_mallocN(linep + 1, "dblock buffer"); for (i = 0; i < linep; i++) { - buf[(linep - 1) - i] = text->undo_buf[text->undo_pos]; - text->undo_pos--; + buf[(linep - 1) - i] = utxt->buf[utxt->pos]; + utxt->pos--; } buf[i] = 0; /* skip over the length that was stored again */ - text->undo_pos -= 4; + utxt->pos -= 4; /* Get the cursor positions */ - txt_undo_read_cursors(text->undo_buf, &text->undo_pos, &curln, &curc, &selln, &selc); + txt_undo_read_cursors(utxt->buf, &utxt->pos, &curln, &curc, &selln, &selc); /* move cur to location that needs buff inserted */ txt_move_to(text, curln, curc, 0); - txt_insert_buf(text, buf); + txt_insert_buf(text, utxt, buf); MEM_freeN(buf); /* restore the cursors */ txt_move_to(text, curln, curc, 0); txt_move_to(text, selln, selc, 1); - text->undo_pos--; + utxt->pos--; break; } @@ -2034,23 +2092,23 @@ void txt_do_undo(Text *text) { int i; /* length of the string in the buffer */ - linep = txt_undo_read_uint32(text->undo_buf, &text->undo_pos); + linep = txt_undo_read_uint32(utxt->buf, &utxt->pos); /* txt_backspace_char removes utf8-characters, not bytes */ buf = MEM_mallocN(linep + 1, "iblock buffer"); for (i = 0; i < linep; i++) { - buf[(linep - 1) - i] = text->undo_buf[text->undo_pos]; - text->undo_pos--; + buf[(linep - 1) - i] = utxt->buf[utxt->pos]; + utxt->pos--; } buf[i] = 0; linep = BLI_strlen_utf8(buf); MEM_freeN(buf); /* skip over the length that was stored again */ - text->undo_pos -= 4; + utxt->pos -= 4; /* get and restore the cursors */ - txt_undo_read_cursors(text->undo_buf, &text->undo_pos, &curln, &curc, &selln, &selc); + txt_undo_read_cursors(utxt->buf, &utxt->pos, &curln, &curc, &selln, &selc); txt_move_to(text, curln, curc, 0); txt_move_to(text, selln, selc, 1); @@ -2066,9 +2124,9 @@ void txt_do_undo(Text *text) text->flags = prev_flags; } - txt_delete_selected(text); + txt_delete_selected(text, utxt); - text->undo_pos--; + utxt->pos--; break; } case UNDO_INDENT: @@ -2077,37 +2135,37 @@ void txt_do_undo(Text *text) case UNDO_MOVE_LINES_UP: case UNDO_MOVE_LINES_DOWN: /* get and restore the cursors */ - txt_undo_read_cursors(text->undo_buf, &text->undo_pos, &curln, &curc, &selln, &selc); + txt_undo_read_cursors(utxt->buf, &utxt->pos, &curln, &curc, &selln, &selc); txt_move_to(text, curln, curc, 0); txt_move_to(text, selln, selc, 1); if (op == UNDO_INDENT) { - txt_unindent(text); + txt_unindent(text, utxt); } else if (op == UNDO_COMMENT) { - txt_uncomment(text); + txt_uncomment(text, utxt); } else if (op == UNDO_DUPLICATE) { txt_delete_line(text, text->curl->next); } else if (op == UNDO_MOVE_LINES_UP) { - txt_move_lines(text, TXT_MOVE_LINE_DOWN); + txt_move_lines(text, utxt, TXT_MOVE_LINE_DOWN); } else if (op == UNDO_MOVE_LINES_DOWN) { - txt_move_lines(text, TXT_MOVE_LINE_UP); + txt_move_lines(text, utxt, TXT_MOVE_LINE_UP); } - text->undo_pos--; + utxt->pos--; break; case UNDO_UNINDENT: case UNDO_UNCOMMENT: { - void (*txt_prefix_fn)(Text *); - void (*txt_unprefix_fn)(Text *); + void (*txt_prefix_fn)(Text *, TextUndoBuf *); + void (*txt_unprefix_fn)(Text *, TextUndoBuf *); int count; int i; /* Get and restore the cursors */ - txt_undo_read_cursors(text->undo_buf, &text->undo_pos, &curln, &curc, &selln, &selc); + txt_undo_read_cursors(utxt->buf, &utxt->pos, &curln, &curc, &selln, &selc); txt_move_to(text, curln, curc, 0); txt_move_to(text, selln, selc, 1); @@ -2121,30 +2179,30 @@ void txt_do_undo(Text *text) txt_unprefix_fn = txt_uncomment; } - txt_prefix_fn(text); + txt_prefix_fn(text, utxt); /* Get the count */ - count = txt_undo_read_uint32(text->undo_buf, &text->undo_pos); + count = txt_undo_read_uint32(utxt->buf, &utxt->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); + txt_move_to(text, txt_undo_read_uint32(utxt->buf, &utxt->pos), 0, 0); /* Un-un-unindent/comment */ - txt_unprefix_fn(text); + txt_unprefix_fn(text, utxt); } /* 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); + txt_undo_read_uint32(utxt->buf, &utxt->pos); /* Jump over closing OP byte */ - text->undo_pos--; + utxt->pos--; break; } default: //XXX error("Undo buffer error - resetting"); - text->undo_pos = -1; + utxt->pos = -1; break; } @@ -2152,7 +2210,7 @@ void txt_do_undo(Text *text) undoing = 0; } -void txt_do_redo(Text *text) +void txt_do_redo(Text *text, TextUndoBuf *utxt) { char op; char *buf; @@ -2162,11 +2220,11 @@ void txt_do_redo(Text *text) unsigned int curln, selln; unsigned short curc, selc; - text->undo_pos++; - op = text->undo_buf[text->undo_pos]; + utxt->pos++; + op = utxt->buf[utxt->pos]; if (!op) { - text->undo_pos--; + utxt->pos--; return; } @@ -2177,35 +2235,35 @@ void txt_do_redo(Text *text) case UNDO_INSERT_2: case UNDO_INSERT_3: case UNDO_INSERT_4: - text->undo_pos++; + utxt->pos++; /* get and restore the cursors */ - txt_redo_read_cur(text->undo_buf, &text->undo_pos, &curln, &curc); + txt_redo_read_cur(utxt->buf, &utxt->pos, &curln, &curc); txt_move_to(text, curln, curc, 0); txt_move_to(text, curln, curc, 1); charp = op - UNDO_INSERT_1 + 1; - uni_uchar = txt_redo_read_unicode(text->undo_buf, &text->undo_pos, charp); + uni_uchar = txt_redo_read_unicode(utxt->buf, &utxt->pos, charp); - txt_add_char(text, uni_uchar); + txt_add_char(text, utxt, uni_uchar); break; case UNDO_BS_1: case UNDO_BS_2: case UNDO_BS_3: case UNDO_BS_4: - text->undo_pos++; + utxt->pos++; /* get and restore the cursors */ - txt_redo_read_cur(text->undo_buf, &text->undo_pos, &curln, &curc); + txt_redo_read_cur(utxt->buf, &utxt->pos, &curln, &curc); txt_move_to(text, curln, curc, 0); txt_move_to(text, curln, curc, 1); - text->undo_pos += op - UNDO_BS_1 + 1; + utxt->pos += op - UNDO_BS_1 + 1; /* move right so we backspace the correct char */ txt_move_right(text, 0); - txt_backspace_char(text); + txt_backspace_char(text, utxt); break; @@ -2213,60 +2271,60 @@ void txt_do_redo(Text *text) case UNDO_DEL_2: case UNDO_DEL_3: case UNDO_DEL_4: - text->undo_pos++; + utxt->pos++; /* get and restore the cursors */ - txt_redo_read_cur(text->undo_buf, &text->undo_pos, &curln, &curc); + txt_redo_read_cur(utxt->buf, &utxt->pos, &curln, &curc); txt_move_to(text, curln, curc, 0); txt_move_to(text, curln, curc, 1); - text->undo_pos += op - UNDO_DEL_1 + 1; + utxt->pos += op - UNDO_DEL_1 + 1; - txt_delete_char(text); + txt_delete_char(text, utxt); break; case UNDO_DBLOCK: - text->undo_pos++; + utxt->pos++; /* get and restore the cursors */ - txt_redo_read_cursors(text->undo_buf, &text->undo_pos, &curln, &curc, &selln, &selc); + txt_redo_read_cursors(utxt->buf, &utxt->pos, &curln, &curc, &selln, &selc); txt_move_to(text, curln, curc, 0); txt_move_to(text, selln, selc, 1); /* length of the block */ - linep = txt_redo_read_uint32(text->undo_buf, &text->undo_pos); + linep = txt_redo_read_uint32(utxt->buf, &utxt->pos); - text->undo_pos += linep; + utxt->pos += linep; /* skip over the length that was stored again */ - text->undo_pos += 4; + utxt->pos += 4; - txt_delete_sel(text); + txt_delete_sel(text, utxt); break; case UNDO_IBLOCK: - text->undo_pos++; + utxt->pos++; /* get and restore the cursors */ - txt_redo_read_cursors(text->undo_buf, &text->undo_pos, &curln, &curc, &selln, &selc); + txt_redo_read_cursors(utxt->buf, &utxt->pos, &curln, &curc, &selln, &selc); txt_move_to(text, curln, curc, 0); txt_move_to(text, curln, curc, 1); /* length of the block */ - linep = txt_redo_read_uint32(text->undo_buf, &text->undo_pos); + linep = txt_redo_read_uint32(utxt->buf, &utxt->pos); buf = MEM_mallocN(linep + 1, "iblock buffer"); - memcpy(buf, &text->undo_buf[text->undo_pos], linep); - text->undo_pos += linep; + memcpy(buf, &utxt->buf[utxt->pos], linep); + utxt->pos += linep; buf[linep] = 0; - txt_insert_buf(text, buf); + txt_insert_buf(text, utxt, buf); MEM_freeN(buf); /* skip over the length that was stored again */ - text->undo_pos += 4; + utxt->pos += 4; break; @@ -2276,38 +2334,38 @@ void txt_do_redo(Text *text) case UNDO_DUPLICATE: case UNDO_MOVE_LINES_UP: case UNDO_MOVE_LINES_DOWN: - text->undo_pos++; + utxt->pos++; /* get and restore the cursors */ - txt_redo_read_cursors(text->undo_buf, &text->undo_pos, &curln, &curc, &selln, &selc); + txt_redo_read_cursors(utxt->buf, &utxt->pos, &curln, &curc, &selln, &selc); txt_move_to(text, curln, curc, 0); txt_move_to(text, selln, selc, 1); if (op == UNDO_INDENT) { - txt_indent(text); + txt_indent(text, utxt); } else if (op == UNDO_COMMENT) { - txt_comment(text); + txt_comment(text, utxt); } else if (op == UNDO_UNCOMMENT) { - txt_uncomment(text); + txt_uncomment(text, utxt); } else if (op == UNDO_DUPLICATE) { - txt_duplicate_line(text); + txt_duplicate_line(text, utxt); } else if (op == UNDO_MOVE_LINES_UP) { /* offset the cursor by + 1 */ txt_move_to(text, curln + 1, curc, 0); txt_move_to(text, selln + 1, selc, 1); - txt_move_lines(text, TXT_MOVE_LINE_UP); + txt_move_lines(text, utxt, TXT_MOVE_LINE_UP); } else if (op == UNDO_MOVE_LINES_DOWN) { /* offset the cursor by - 1 */ txt_move_to(text, curln - 1, curc, 0); txt_move_to(text, selln - 1, selc, 1); - txt_move_lines(text, TXT_MOVE_LINE_DOWN); + txt_move_lines(text, utxt, TXT_MOVE_LINE_DOWN); } /* re-restore the cursors since they got moved when redoing */ @@ -2320,24 +2378,24 @@ void txt_do_redo(Text *text) int count; int i; - text->undo_pos++; + utxt->pos++; /* Scan all the stuff described in txt_undo_add_unindent_op */ - count = txt_redo_read_uint32(text->undo_buf, &text->undo_pos); + count = txt_redo_read_uint32(utxt->buf, &utxt->pos); for (i = 0; i < count; i++) { - txt_redo_read_uint32(text->undo_buf, &text->undo_pos); + txt_redo_read_uint32(utxt->buf, &utxt->pos); } /* Count again */ - txt_redo_read_uint32(text->undo_buf, &text->undo_pos); + txt_redo_read_uint32(utxt->buf, &utxt->pos); /* Get the selection and re-unindent */ - txt_redo_read_cursors(text->undo_buf, &text->undo_pos, &curln, &curc, &selln, &selc); + txt_redo_read_cursors(utxt->buf, &utxt->pos, &curln, &curc, &selln, &selc); txt_move_to(text, curln, curc, 0); txt_move_to(text, selln, selc, 1); - txt_unindent(text); + txt_unindent(text, utxt); break; } default: //XXX error("Undo buffer error - resetting"); - text->undo_pos = -1; + utxt->pos = -1; break; } @@ -2349,16 +2407,16 @@ void txt_do_redo(Text *text) /* Line editing functions */ /**************************/ -void txt_split_curline(Text *text) +void txt_split_curline(Text *text, TextUndoBuf *utxt) { TextLine *ins; char *left, *right; if (!text->curl) return; - txt_delete_sel(text); + txt_delete_sel(text, utxt); - if (!undoing) txt_undo_add_charop(text, UNDO_INSERT_1, '\n'); + if (!undoing) txt_undo_add_charop(text, utxt, UNDO_INSERT_1, '\n'); /* Make the two half strings */ @@ -2430,7 +2488,7 @@ static void txt_combine_lines(Text *text, TextLine *linea, TextLine *lineb) txt_clean_text(text); } -void txt_duplicate_line(Text *text) +void txt_duplicate_line(Text *text, TextUndoBuf *utxt) { TextLine *textline; @@ -2443,18 +2501,18 @@ void txt_duplicate_line(Text *text) txt_make_dirty(text); txt_clean_text(text); - if (!undoing) txt_undo_add_op(text, UNDO_DUPLICATE); + if (!undoing) txt_undo_add_op(text, utxt, UNDO_DUPLICATE); } } -void txt_delete_char(Text *text) +void txt_delete_char(Text *text, TextUndoBuf *utxt) { unsigned int c = '\n'; if (!text->curl) return; if (txt_has_sel(text)) { /* deleting a selection */ - txt_delete_sel(text); + txt_delete_sel(text, utxt); txt_make_dirty(text); return; } @@ -2480,24 +2538,24 @@ void txt_delete_char(Text *text) txt_make_dirty(text); txt_clean_text(text); - if (!undoing) txt_undo_add_charop(text, UNDO_DEL_1, c); + if (!undoing) txt_undo_add_charop(text, utxt, UNDO_DEL_1, c); } -void txt_delete_word(Text *text) +void txt_delete_word(Text *text, TextUndoBuf *utxt) { txt_jump_right(text, true, true); - txt_delete_sel(text); + txt_delete_sel(text, utxt); txt_make_dirty(text); } -void txt_backspace_char(Text *text) +void txt_backspace_char(Text *text, TextUndoBuf *utxt) { unsigned int c = '\n'; if (!text->curl) return; if (txt_has_sel(text)) { /* deleting a selection */ - txt_delete_sel(text); + txt_delete_sel(text, utxt); txt_make_dirty(text); return; } @@ -2529,13 +2587,13 @@ void txt_backspace_char(Text *text) txt_make_dirty(text); txt_clean_text(text); - if (!undoing) txt_undo_add_charop(text, UNDO_BS_1, c); + if (!undoing) txt_undo_add_charop(text, utxt, UNDO_BS_1, c); } -void txt_backspace_word(Text *text) +void txt_backspace_word(Text *text, TextUndoBuf *utxt) { txt_jump_left(text, true, true); - txt_delete_sel(text); + txt_delete_sel(text, utxt); txt_make_dirty(text); } @@ -2544,17 +2602,17 @@ void txt_backspace_word(Text *text) * Remember to change this string according to max tab size */ static char tab_to_spaces[] = " "; -static void txt_convert_tab_to_spaces(Text *text) +static void txt_convert_tab_to_spaces(Text *text, TextUndoBuf *utxt) { /* sb aims to pad adjust the tab-width needed so that the right number of spaces * is added so that the indention of the line is the right width (i.e. aligned * to multiples of TXT_TABSIZE) */ const char *sb = &tab_to_spaces[text->curc % TXT_TABSIZE]; - txt_insert_buf(text, sb); + txt_insert_buf(text, utxt, sb); } -static bool txt_add_char_intern(Text *text, unsigned int add, bool replace_tabs) +static bool txt_add_char_intern(Text *text, TextUndoBuf *utxt, unsigned int add, bool replace_tabs) { char *tmp, ch[BLI_UTF8_MAX]; size_t add_len; @@ -2562,19 +2620,19 @@ static bool txt_add_char_intern(Text *text, unsigned int add, bool replace_tabs) if (!text->curl) return 0; if (add == '\n') { - txt_split_curline(text); + txt_split_curline(text, utxt); return true; } /* insert spaces rather than tabs */ if (add == '\t' && replace_tabs) { - txt_convert_tab_to_spaces(text); + txt_convert_tab_to_spaces(text, utxt); return true; } - txt_delete_sel(text); + txt_delete_sel(text, utxt); - if (!undoing) txt_undo_add_charop(text, UNDO_INSERT_1, add); + if (!undoing) txt_undo_add_charop(text, utxt, UNDO_INSERT_1, add); add_len = BLI_str_utf8_from_unicode(add, ch); @@ -2596,23 +2654,23 @@ static bool txt_add_char_intern(Text *text, unsigned int add, bool replace_tabs) return 1; } -bool txt_add_char(Text *text, unsigned int add) +bool txt_add_char(Text *text, TextUndoBuf *utxt, unsigned int add) { - return txt_add_char_intern(text, add, (text->flags & TXT_TABSTOSPACES) != 0); + return txt_add_char_intern(text, utxt, add, (text->flags & TXT_TABSTOSPACES) != 0); } -bool txt_add_raw_char(Text *text, unsigned int add) +bool txt_add_raw_char(Text *text, TextUndoBuf *utxt, unsigned int add) { - return txt_add_char_intern(text, add, 0); + return txt_add_char_intern(text, utxt, add, 0); } -void txt_delete_selected(Text *text) +void txt_delete_selected(Text *text, TextUndoBuf *utxt) { - txt_delete_sel(text); + txt_delete_sel(text, utxt); txt_make_dirty(text); } -bool txt_replace_char(Text *text, unsigned int add) +bool txt_replace_char(Text *text, TextUndoBuf *utxt, unsigned int add) { unsigned int del; size_t del_size = 0, add_size; @@ -2622,7 +2680,7 @@ bool txt_replace_char(Text *text, unsigned int add) /* If text is selected or we're at the end of the line just use txt_add_char */ if (text->curc == text->curl->len || txt_has_sel(text) || add == '\n') { - return txt_add_char(text, add); + return txt_add_char(text, utxt, add); } del = BLI_str_utf8_as_unicode_and_size(text->curl->line + text->curc, &del_size); @@ -2650,10 +2708,10 @@ bool txt_replace_char(Text *text, unsigned int add) /* Should probably create a new op for this */ if (!undoing) { - txt_undo_add_charop(text, UNDO_INSERT_1, add); + txt_undo_add_charop(text, utxt, UNDO_INSERT_1, add); text->curc -= add_size; txt_pop_sel(text); - txt_undo_add_charop(text, UNDO_DEL_1, del); + txt_undo_add_charop(text, utxt, UNDO_DEL_1, del); text->curc += add_size; txt_pop_sel(text); } @@ -2793,7 +2851,7 @@ static void txt_select_unprefix( /* caller must handle undo */ } -void txt_comment(Text *text) +void txt_comment(Text *text, TextUndoBuf *utxt) { const char *prefix = "#"; @@ -2804,11 +2862,11 @@ void txt_comment(Text *text) txt_select_prefix(text, prefix); if (!undoing) { - txt_undo_add_op(text, UNDO_COMMENT); + txt_undo_add_op(text, utxt, UNDO_COMMENT); } } -void txt_uncomment(Text *text) +void txt_uncomment(Text *text, TextUndoBuf *utxt) { const char *prefix = "#"; ListBase line_index_mask; @@ -2821,13 +2879,13 @@ void txt_uncomment(Text *text) txt_select_unprefix(text, prefix, &line_index_mask, &line_index_mask_len); if (!undoing) { - txt_undo_add_unprefix_op(text, UNDO_UNCOMMENT, &line_index_mask, line_index_mask_len); + txt_undo_add_unprefix_op(text, utxt, UNDO_UNCOMMENT, &line_index_mask, line_index_mask_len); } BLI_freelistN(&line_index_mask); } -void txt_indent(Text *text) +void txt_indent(Text *text, TextUndoBuf *utxt) { const char *prefix = (text->flags & TXT_TABSTOSPACES) ? tab_to_spaces : "\t"; @@ -2838,11 +2896,11 @@ void txt_indent(Text *text) txt_select_prefix(text, prefix); if (!undoing) { - txt_undo_add_op(text, UNDO_INDENT); + txt_undo_add_op(text, utxt, UNDO_INDENT); } } -void txt_unindent(Text *text) +void txt_unindent(Text *text, TextUndoBuf *utxt) { const char *prefix = (text->flags & TXT_TABSTOSPACES) ? tab_to_spaces : "\t"; ListBase line_index_mask; @@ -2855,13 +2913,13 @@ void txt_unindent(Text *text) txt_select_unprefix(text, prefix, &line_index_mask, &line_index_mask_len); if (!undoing) { - txt_undo_add_unprefix_op(text, UNDO_UNINDENT, &line_index_mask, line_index_mask_len); + txt_undo_add_unprefix_op(text, utxt, UNDO_UNINDENT, &line_index_mask, line_index_mask_len); } BLI_freelistN(&line_index_mask); } -void txt_move_lines(struct Text *text, const int direction) +void txt_move_lines(struct Text *text, TextUndoBuf *utxt, const int direction) { TextLine *line_other; @@ -2888,7 +2946,7 @@ void txt_move_lines(struct Text *text, const int direction) txt_clean_text(text); if (!undoing) { - txt_undo_add_op(text, (direction == TXT_MOVE_LINE_DOWN) ? UNDO_MOVE_LINES_DOWN : UNDO_MOVE_LINES_UP); + txt_undo_add_op(text, utxt, (direction == TXT_MOVE_LINE_DOWN) ? UNDO_MOVE_LINES_DOWN : UNDO_MOVE_LINES_UP); } } diff --git a/source/blender/blenkernel/intern/texture.c b/source/blender/blenkernel/intern/texture.c index fcedd880615..250408642bb 100644 --- a/source/blender/blenkernel/intern/texture.c +++ b/source/blender/blenkernel/intern/texture.c @@ -55,7 +55,6 @@ #include "IMB_imbuf.h" -#include "BKE_global.h" #include "BKE_main.h" #include "BKE_colorband.h" @@ -412,6 +411,7 @@ void BKE_texture_mtex_default(MTex *mtex) mtex->kinkfac = 1.0f; mtex->kinkampfac = 1.0f; mtex->roughfac = 1.0f; + mtex->twistfac = 1.0f; mtex->padensfac = 1.0f; mtex->lifefac = 1.0f; mtex->sizefac = 1.0f; @@ -1206,17 +1206,17 @@ void BKE_texture_get_value( BKE_texture_get_value_ex(scene, texture, tex_co, texres, NULL, use_color_management); } -static void texture_nodes_fetch_images_for_pool(bNodeTree *ntree, struct ImagePool *pool) +static void texture_nodes_fetch_images_for_pool(Tex *texture, bNodeTree *ntree, struct ImagePool *pool) { for (bNode *node = ntree->nodes.first; node; node = node->next) { if (node->type == SH_NODE_TEX_IMAGE && node->id != NULL) { Image *image = (Image *)node->id; - BKE_image_pool_acquire_ibuf(image, NULL, pool); + BKE_image_pool_acquire_ibuf(image, &texture->iuser, pool); } else if (node->type == NODE_GROUP && node->id != NULL) { /* TODO(sergey): Do we need to control recursion here? */ bNodeTree *nested_tree = (bNodeTree *)node->id; - texture_nodes_fetch_images_for_pool(nested_tree, pool); + texture_nodes_fetch_images_for_pool(texture, nested_tree, pool); } } } @@ -1225,12 +1225,12 @@ static void texture_nodes_fetch_images_for_pool(bNodeTree *ntree, struct ImagePo void BKE_texture_fetch_images_for_pool(Tex *texture, struct ImagePool *pool) { if (texture->nodetree != NULL) { - texture_nodes_fetch_images_for_pool(texture->nodetree, pool); + texture_nodes_fetch_images_for_pool(texture, texture->nodetree, pool); } else { if (texture->type == TEX_IMAGE) { if (texture->ima != NULL) { - BKE_image_pool_acquire_ibuf(texture->ima, NULL, pool); + BKE_image_pool_acquire_ibuf(texture->ima, &texture->iuser, pool); } } } diff --git a/source/blender/blenkernel/intern/tracking_region_tracker.c b/source/blender/blenkernel/intern/tracking_region_tracker.c index dd7def16ca8..106dd125575 100644 --- a/source/blender/blenkernel/intern/tracking_region_tracker.c +++ b/source/blender/blenkernel/intern/tracking_region_tracker.c @@ -189,7 +189,7 @@ void tracking_configure_tracker(const MovieTrackingTrack *track, float *mask, options->image1_mask = NULL; } -/* Peform tracking from a reference_marker to destination_ibuf. +/* Perform tracking from a reference_marker to destination_ibuf. * Uses marker as an initial position guess. * * Returns truth if tracker returned success, puts result diff --git a/source/blender/blenkernel/intern/tracking_util.c b/source/blender/blenkernel/intern/tracking_util.c index d8e98291117..8c1b846db84 100644 --- a/source/blender/blenkernel/intern/tracking_util.c +++ b/source/blender/blenkernel/intern/tracking_util.c @@ -787,9 +787,9 @@ static ImBuf *accessor_get_ibuf(TrackingImageAccessor *accessor, * in the cache which is nice on the one hand (faster re-use of the * frames) but on the other hand it bumps the memory usage up. */ - BLI_lock_thread(LOCK_MOVIECLIP); + BLI_thread_lock(LOCK_MOVIECLIP); IMB_float_from_rect(orig_ibuf); - BLI_unlock_thread(LOCK_MOVIECLIP); + BLI_thread_unlock(LOCK_MOVIECLIP); final_ibuf = orig_ibuf; } /* Downscale if needed. */ diff --git a/source/blender/blenkernel/intern/undo_system.c b/source/blender/blenkernel/intern/undo_system.c new file mode 100644 index 00000000000..fd62650e898 --- /dev/null +++ b/source/blender/blenkernel/intern/undo_system.c @@ -0,0 +1,846 @@ +/* + * ***** 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. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/blenkernel/intern/undo_system.c + * \ingroup bke + * + * Used by ED_undo.h, internal implementation. + */ + +#include <string.h> + +#include "CLG_log.h" + +#include "BLI_utildefines.h" +#include "BLI_sys_types.h" +#include "BLI_listbase.h" +#include "BLI_string.h" +#include "BLI_sort_utils.h" + +#include "DNA_listBase.h" +#include "DNA_windowmanager_types.h" + +#include "BKE_context.h" +#include "BKE_global.h" +#include "BKE_library_override.h" +#include "BKE_main.h" +#include "BKE_undo_system.h" + +#include "MEM_guardedalloc.h" + +#define undo_stack _wm_undo_stack_disallow /* pass in as a variable always. */ + +/** Odd requirement of Blender that we always keep a memfile undo in the stack. */ +#define WITH_GLOBAL_UNDO_KEEP_ONE + +/** Make sure all ID's created at the point we add an undo step that uses ID's. */ +#define WITH_GLOBAL_UNDO_ENSURE_UPDATED + +/** We only need this locally. */ +static CLG_LogRef LOG = {"bke.undosys"}; + +/* -------------------------------------------------------------------- */ +/** \name Internal Nested Undo Checks + * + * Make sure we're not running undo operations from 'step_encode', 'step_decode' callbacks. + * bugs caused by this situation aren't _that_ hard to spot but aren't always so obvious. + * Best we have a check which shows the problem immediately. + * + * \{ */ +#define WITH_NESTED_UNDO_CHECK + +#ifdef WITH_NESTED_UNDO_CHECK +static bool g_undo_callback_running = false; +# define UNDO_NESTED_ASSERT(state) BLI_assert(g_undo_callback_running == state) +# define UNDO_NESTED_CHECK_BEGIN { \ + UNDO_NESTED_ASSERT(false); \ + g_undo_callback_running = true; \ +} ((void)0) +# define UNDO_NESTED_CHECK_END { \ + UNDO_NESTED_ASSERT(true); \ + g_undo_callback_running = false; \ +} ((void)0) +#else +# define UNDO_NESTED_ASSERT(state) ((void)0) +# define UNDO_NESTED_CHECK_BEGIN ((void)0) +# define UNDO_NESTED_CHECK_END ((void)0) +#endif +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Public Undo Types + * + * Unfortunately we need this for a handful of places. + */ +const UndoType *BKE_UNDOSYS_TYPE_IMAGE = NULL; +const UndoType *BKE_UNDOSYS_TYPE_MEMFILE = NULL; +const UndoType *BKE_UNDOSYS_TYPE_PAINTCURVE = NULL; +const UndoType *BKE_UNDOSYS_TYPE_PARTICLE = NULL; +const UndoType *BKE_UNDOSYS_TYPE_SCULPT = NULL; +const UndoType *BKE_UNDOSYS_TYPE_TEXT = NULL; +/** \} */ + +/* UndoType */ + +static ListBase g_undo_types = {NULL, NULL}; + +static const UndoType *BKE_undosys_type_from_context(bContext *C) +{ + for (const UndoType *ut = g_undo_types.first; ut; ut = ut->next) { + /* No poll means we don't check context. */ + if (ut->poll && ut->poll(C)) { + return ut; + } + } + return NULL; +} + +/* -------------------------------------------------------------------- */ +/** \name Internal Callback Wrappers + * + * #UndoRefID is simply a way to avoid inlining name copy and lookups, + * since it's easy to forget a single case when done inline (crashing in some cases). + * + * \{ */ + +static void undosys_id_ref_store(void *UNUSED(user_data), UndoRefID *id_ref) +{ + BLI_assert(id_ref->name[0] == '\0'); + if (id_ref->ptr) { + BLI_strncpy(id_ref->name, id_ref->ptr->name, sizeof(id_ref->name)); + /* Not needed, just prevents stale data access. */ + id_ref->ptr = NULL; + } +} + +static void undosys_id_ref_resolve(void *user_data, UndoRefID *id_ref) +{ + /* Note: we could optimize this, for now it's not too bad since it only runs when we access undo! */ + Main *bmain = user_data; + ListBase *lb = which_libbase(bmain, GS(id_ref->name)); + for (ID *id = lb->first; id; id = id->next) { + if (STREQ(id_ref->name, id->name) && (id->lib == NULL)) { + id_ref->ptr = id; + break; + } + } +} + +static bool undosys_step_encode(bContext *C, UndoStep *us) +{ + CLOG_INFO(&LOG, 2, "addr=%p, name='%s', type='%s'", us, us->name, us->type->name); + UNDO_NESTED_CHECK_BEGIN; + bool ok = us->type->step_encode(C, us); + UNDO_NESTED_CHECK_END; + if (ok) { + if (us->type->step_foreach_ID_ref != NULL) { + /* Don't use from context yet because sometimes context is fake and not all members are filled in. */ + Main *bmain = G.main; + us->type->step_foreach_ID_ref(us, undosys_id_ref_store, bmain); + } + } + if (ok == false) { + CLOG_INFO(&LOG, 2, "encode callback didn't create undo step"); + } + return ok; +} + +static void undosys_step_decode(bContext *C, UndoStep *us, int dir) +{ + CLOG_INFO(&LOG, 2, "addr=%p, name='%s', type='%s'", us, us->name, us->type->name); + if (us->type->step_foreach_ID_ref) { + /* Don't use from context yet because sometimes context is fake and not all members are filled in. */ + Main *bmain = G.main; + us->type->step_foreach_ID_ref(us, undosys_id_ref_resolve, bmain); + } + + UNDO_NESTED_CHECK_BEGIN; + us->type->step_decode(C, us, dir); + UNDO_NESTED_CHECK_END; +} + +static void undosys_step_free_and_unlink(UndoStack *ustack, UndoStep *us) +{ + CLOG_INFO(&LOG, 2, "addr=%p, name='%s', type='%s'", us, us->name, us->type->name); + UNDO_NESTED_CHECK_BEGIN; + us->type->step_free(us); + UNDO_NESTED_CHECK_END; + + BLI_remlink(&ustack->steps, us); + MEM_freeN(us); +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Undo Stack + * \{ */ + +#ifndef NDEBUG +static void undosys_stack_validate(UndoStack *ustack, bool expect_non_empty) +{ + if (ustack->step_active != NULL) { + BLI_assert(!BLI_listbase_is_empty(&ustack->steps)); + BLI_assert(BLI_findindex(&ustack->steps, ustack->step_active) != -1); + } + if (expect_non_empty) { + BLI_assert(!BLI_listbase_is_empty(&ustack->steps)); + } +} +#else +static void undosys_stack_validate(UndoStack *ustack, bool expect_non_empty) +{ + UNUSED_VARS(ustack, expect_non_empty); +} +#endif + +UndoStack *BKE_undosys_stack_create(void) +{ + UndoStack *ustack = MEM_callocN(sizeof(UndoStack), __func__); + return ustack; +} + +void BKE_undosys_stack_destroy(UndoStack *ustack) +{ + BKE_undosys_stack_clear(ustack); + MEM_freeN(ustack); +} + +void BKE_undosys_stack_clear(UndoStack *ustack) +{ + UNDO_NESTED_ASSERT(false); + CLOG_INFO(&LOG, 1, "steps=%d", BLI_listbase_count(&ustack->steps)); + for (UndoStep *us = ustack->steps.last, *us_prev; us; us = us_prev) { + us_prev = us->prev; + undosys_step_free_and_unlink(ustack, us); + } + BLI_listbase_clear(&ustack->steps); + ustack->step_active = NULL; +} + +static bool undosys_stack_push_main(UndoStack *ustack, const char *name, struct Main *bmain) +{ + UNDO_NESTED_ASSERT(false); + CLOG_INFO(&LOG, 1, "'%s'", name); + bContext *C_temp = CTX_create(); + CTX_data_main_set(C_temp, bmain); + bool ok = BKE_undosys_step_push_with_type(ustack, C_temp, name, BKE_UNDOSYS_TYPE_MEMFILE); + CTX_free(C_temp); + return ok; +} + +void BKE_undosys_stack_init_from_main(UndoStack *ustack, struct Main *bmain) +{ + UNDO_NESTED_ASSERT(false); + undosys_stack_push_main(ustack, "original", bmain); +} + +/* name optional */ +bool BKE_undosys_stack_has_undo(UndoStack *ustack, const char *name) +{ + if (name) { + UndoStep *us = BLI_rfindstring(&ustack->steps, name, offsetof(UndoStep, name)); + return us && us->prev; + } + + return !BLI_listbase_is_empty(&ustack->steps); +} + +UndoStep *BKE_undosys_stack_active_with_type(UndoStack *ustack, const UndoType *ut) +{ + UndoStep *us = ustack->step_active; + while (us && (us->type != ut)) { + us = us->prev; + } + return us; +} + +UndoStep *BKE_undosys_stack_init_or_active_with_type(UndoStack *ustack, const UndoType *ut) +{ + UNDO_NESTED_ASSERT(false); + CLOG_INFO(&LOG, 1, "type='%s'", ut->name); + if (ustack->step_init && (ustack->step_init->type == ut)) { + return ustack->step_init; + } + return BKE_undosys_stack_active_with_type(ustack, ut); +} + +/** + * \param steps: Limit the number of undo steps. + * \param memory_limit: Limit the amount of memory used by the undo stack. + */ +void BKE_undosys_stack_limit_steps_and_memory(UndoStack *ustack, int steps, size_t memory_limit) +{ + UNDO_NESTED_ASSERT(false); + if (!(steps || memory_limit)) { + return; + } + + CLOG_INFO(&LOG, 1, "steps=%d, memory_limit=%zu", steps, memory_limit); + UndoStep *us; +#ifdef WITH_GLOBAL_UNDO_KEEP_ONE + UndoStep *us_exclude = NULL; +#endif + /* keep at least two (original + other) */ + size_t data_size_all = 0; + size_t us_count = 0; + for (us = ustack->steps.last; us && us->prev; us = us->prev) { + if (memory_limit) { + data_size_all += us->data_size; + if (data_size_all > memory_limit) { + break; + } + } + if (steps) { + if (us_count == steps) { + break; + } + if (us->skip == false) { + us_count += 1; + } + } + } + + if (us) { + if (us->prev && us->prev->prev) { + us = us->prev; + } + +#ifdef WITH_GLOBAL_UNDO_KEEP_ONE + /* Hack, we need to keep at least one BKE_UNDOSYS_TYPE_MEMFILE. */ + if (us->type != BKE_UNDOSYS_TYPE_MEMFILE) { + us_exclude = us->prev; + while (us_exclude && us->type != BKE_UNDOSYS_TYPE_MEMFILE) { + us_exclude = us_exclude->prev; + } + if (us_exclude) { + BLI_remlink(&ustack->steps, us_exclude); + } + } +#endif + /* Free from first to last, free functions may update de-duplication info (see #MemFileUndoStep). */ + while (ustack->steps.first != us) { + UndoStep *us_first = ustack->steps.first; + BLI_assert(us_first != ustack->step_active); + undosys_step_free_and_unlink(ustack, us_first); + } + +#ifdef WITH_GLOBAL_UNDO_KEEP_ONE + if (us_exclude) { + BLI_addhead(&ustack->steps, us_exclude); + } +#endif + } +} + +/** \} */ + +UndoStep *BKE_undosys_step_push_init_with_type(UndoStack *ustack, bContext *C, const char *name, const UndoType *ut) +{ + UNDO_NESTED_ASSERT(false); + /* We could detect and clean this up (but it should never happen!). */ + BLI_assert(ustack->step_init == NULL); + if (ut->step_encode_init) { + undosys_stack_validate(ustack, false); + UndoStep *us = MEM_callocN(ut->step_size, __func__); + CLOG_INFO(&LOG, 1, "addr=%p, name='%s', type='%s'", us, name, ut->name); + if (name != NULL) { + BLI_strncpy(us->name, name, sizeof(us->name)); + } + us->type = ut; + ustack->step_init = us; + ut->step_encode_init(C, us); + undosys_stack_validate(ustack, true); + return us; + } + else { + return NULL; + } +} + +UndoStep *BKE_undosys_step_push_init(UndoStack *ustack, bContext *C, const char *name) +{ + UNDO_NESTED_ASSERT(false); + /* We could detect and clean this up (but it should never happen!). */ + BLI_assert(ustack->step_init == NULL); + const UndoType *ut = BKE_undosys_type_from_context(C); + if (ut == NULL) { + return NULL; + } + return BKE_undosys_step_push_init_with_type(ustack, C, name, ut); +} + +bool BKE_undosys_step_push_with_type(UndoStack *ustack, bContext *C, const char *name, const UndoType *ut) +{ + UNDO_NESTED_ASSERT(false); + undosys_stack_validate(ustack, false); + bool is_not_empty = ustack->step_active != NULL; + + /* Might not be final place for this to be called - probably only want to call it from some + * undo handlers, not all of them? */ + BKE_main_override_static_operations_create(CTX_data_main(C)); + + /* Remove all undos after (also when 'ustack->step_active == NULL'). */ + while (ustack->steps.last != ustack->step_active) { + UndoStep *us_iter = ustack->steps.last; + undosys_step_free_and_unlink(ustack, us_iter); + undosys_stack_validate(ustack, is_not_empty); + } + + if (ustack->step_active) { + BLI_assert(BLI_findindex(&ustack->steps, ustack->step_active) != -1); + } + +#ifdef WITH_GLOBAL_UNDO_ENSURE_UPDATED + if (ut->step_foreach_ID_ref != NULL) { + Main *bmain = G.main; + if (bmain->is_memfile_undo_written == false) { + const char *name_internal = "MemFile Internal"; + if (undosys_stack_push_main(ustack, name_internal, bmain)) { + UndoStep *us = ustack->steps.last; + BLI_assert(STREQ(us->name, name_internal)); + us->skip = true; + } + } + } +#endif + + UndoStep *us = ustack->step_init ? ustack->step_init : MEM_callocN(ut->step_size, __func__); + ustack->step_init = NULL; + if (us->name[0] == '\0') { + BLI_strncpy(us->name, name, sizeof(us->name)); + } + us->type = ut; + /* initialized, not added yet. */ + + if (undosys_step_encode(C, us)) { + ustack->step_active = us; + BLI_addtail(&ustack->steps, us); + undosys_stack_validate(ustack, true); + return true; + } + else { + MEM_freeN(us); + undosys_stack_validate(ustack, true); + return false; + } +} + +bool BKE_undosys_step_push(UndoStack *ustack, bContext *C, const char *name) +{ + UNDO_NESTED_ASSERT(false); + const UndoType *ut = ustack->step_init ? ustack->step_init->type : BKE_undosys_type_from_context(C); + if (ut == NULL) { + return false; + } + return BKE_undosys_step_push_with_type(ustack, C, name, ut); +} + + +/** + * Useful when we want to diff against previous undo data but can't be sure the types match. + */ +UndoStep *BKE_undosys_step_same_type_next(UndoStep *us) +{ + if (us) { + const UndoType *ut = us->type; + while ((us = us->next)) { + if (us->type == ut) { + return us; + } + } + + } + return us; +} + +/** + * Useful when we want to diff against previous undo data but can't be sure the types match. + */ +UndoStep *BKE_undosys_step_same_type_prev(UndoStep *us) +{ + if (us) { + const UndoType *ut = us->type; + while ((us = us->prev)) { + if (us->type == ut) { + return us; + } + } + + } + return us; +} + +UndoStep *BKE_undosys_step_find_by_name_with_type(UndoStack *ustack, const char *name, const UndoType *ut) +{ + for (UndoStep *us = ustack->steps.last; us; us = us->prev) { + if (us->type == ut) { + if (STREQ(name, us->name)) { + return us; + } + } + } + return NULL; +} + +UndoStep *BKE_undosys_step_find_by_name(UndoStack *ustack, const char *name) +{ + return BLI_rfindstring(&ustack->steps, name, offsetof(UndoStep, name)); +} + +UndoStep *BKE_undosys_step_find_by_type(UndoStack *ustack, const UndoType *ut) +{ + for (UndoStep *us = ustack->steps.last; us; us = us->prev) { + if (us->type == ut) { + return us; + } + } + return NULL; +} + +bool BKE_undosys_step_undo_with_data_ex( + UndoStack *ustack, bContext *C, UndoStep *us, + bool use_skip) +{ + UNDO_NESTED_ASSERT(false); + if (us) { + undosys_stack_validate(ustack, true); + } + UndoStep *us_prev = us ? us->prev : NULL; + if (us && us->type->mode == BKE_UNDOTYPE_MODE_STORE) { + /* The current state is a copy, we need to load the previous state. */ + us = us_prev; + } + + if (us != NULL) { + CLOG_INFO(&LOG, 1, "addr=%p, name='%s', type='%s'", us, us->name, us->type->name); + undosys_step_decode(C, us, -1); + ustack->step_active = us_prev; + undosys_stack_validate(ustack, true); + if (use_skip) { + if (ustack->step_active && ustack->step_active->skip) { + CLOG_INFO(&LOG, 2, "undo continue with skip %p '%s', type='%s'", us, us->name, us->type->name); + BKE_undosys_step_undo_with_data(ustack, C, ustack->step_active); + } + } + return true; + } + return false; +} +bool BKE_undosys_step_undo_with_data(UndoStack *ustack, bContext *C, UndoStep *us) +{ + return BKE_undosys_step_undo_with_data_ex(ustack, C, us, true); +} + +bool BKE_undosys_step_undo(UndoStack *ustack, bContext *C) +{ + return BKE_undosys_step_undo_with_data(ustack, C, ustack->step_active); +} + +void BKE_undosys_step_undo_from_index(UndoStack *ustack, bContext *C, int index) +{ + UndoStep *us = BLI_findlink(&ustack->steps, index); + BLI_assert(us->skip == false); + BKE_undosys_step_load_data(ustack, C, us); +} + +bool BKE_undosys_step_redo_with_data_ex( + UndoStack *ustack, bContext *C, UndoStep *us, + bool use_skip) +{ + UNDO_NESTED_ASSERT(false); + UndoStep *us_next = us ? us->next : NULL; + /* Unlike undo accumulate, we always use the next. */ + us = us_next; + + if (us != NULL) { + CLOG_INFO(&LOG, 1, "addr=%p, name='%s', type='%s'", us, us->name, us->type->name); + undosys_step_decode(C, us, 1); + ustack->step_active = us_next; + if (use_skip) { + if (ustack->step_active && ustack->step_active->skip) { + CLOG_INFO(&LOG, 2, "redo continue with skip %p '%s', type='%s'", us, us->name, us->type->name); + BKE_undosys_step_redo_with_data(ustack, C, ustack->step_active); + } + } + return true; + } + return false; +} +bool BKE_undosys_step_redo_with_data(UndoStack *ustack, bContext *C, UndoStep *us) +{ + return BKE_undosys_step_redo_with_data_ex(ustack, C, us, true); +} + +bool BKE_undosys_step_redo(UndoStack *ustack, bContext *C) +{ + return BKE_undosys_step_redo_with_data(ustack, C, ustack->step_active); +} + +bool BKE_undosys_step_load_data(UndoStack *ustack, bContext *C, UndoStep *us) +{ + UNDO_NESTED_ASSERT(false); + const int index_active = BLI_findindex(&ustack->steps, ustack->step_active); + const int index_target = BLI_findindex(&ustack->steps, us); + BLI_assert(!ELEM(-1, index_active, index_target)); + bool ok = true; + + if (index_target < index_active) { + uint i = index_active - index_target; + while (i-- && ok) { + ok = BKE_undosys_step_undo_with_data_ex(ustack, C, ustack->step_active, false); + } + } + else if (index_target > index_active) { + uint i = index_target - index_active; + while (i-- && ok) { + ok = BKE_undosys_step_redo_with_data_ex(ustack, C, ustack->step_active, false); + } + } + + if (ok) { + BLI_assert(ustack->step_active == us); + } + + return ok; +} + +bool BKE_undosys_step_undo_compat_only(UndoStack *ustack, bContext *C, int step) +{ + if (step == 0) { + return BKE_undosys_step_undo_with_data(ustack, C, ustack->step_active); + } + else if (step == 1) { + return BKE_undosys_step_undo(ustack, C); + } + else { + return BKE_undosys_step_redo(ustack, C); + } +} +/** + * Similar to #WM_operatortype_append + */ +UndoType *BKE_undosys_type_append(void (*undosys_fn)(UndoType *)) +{ + UndoType *ut; + + ut = MEM_callocN(sizeof(UndoType), __func__); + + undosys_fn(ut); + + BLI_assert(ut->mode != 0); + + BLI_addtail(&g_undo_types, ut); + + return ut; +} + +void BKE_undosys_type_free_all(void) +{ + UndoType *ut; + while ((ut = BLI_pophead(&g_undo_types))) { + MEM_freeN(ut); + } +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name ID Reference Utilities + * + * Unfortunately we need this for a handful of places. + */ + +static void UNUSED_FUNCTION(BKE_undosys_foreach_ID_ref( + UndoStack *ustack, UndoTypeForEachIDRefFn foreach_ID_ref_fn, void *user_data)) +{ + for (UndoStep *us = ustack->steps.first; us; us = us->next) { + const UndoType *ut = us->type; + if (ut->step_foreach_ID_ref != NULL) { + ut->step_foreach_ID_ref(us, foreach_ID_ref_fn, user_data); + } + } +} + +typedef struct UndoIDPtrMapItem { + /** Never changes (matches undo data). Use as sort key for binary search. */ + const void *ptr; + /** Write the new pointers here. */ + uint index; +} UndoIDPtrMapItem; + +typedef struct UndoIDPtrMap { + UndoRefID *refs; + /** + * Pointer map, update 'dst' members before use. + * This is always sorted (adds some overhead when adding, in practice it's acceptable since). + */ + UndoIDPtrMapItem *pmap; + + /** Length for both 'refs' & 'pmap' */ + uint len; + uint len_alloc; +} UndoIDPtrMap; + +#ifdef DEBUG +# define PMAP_DEFAULT_ALLOC 1 +#else +# define PMAP_DEFAULT_ALLOC 32 +#endif + +void BKE_undosys_ID_map_foreach_ID_ref( + UndoIDPtrMap *map, + UndoTypeForEachIDRefFn foreach_ID_ref_fn, void *user_data) +{ + for (uint i = 0; i < map->len; i++) { + foreach_ID_ref_fn(user_data, &map->refs[i]); + } +} + +/** + * Return true when found, otherwise index is set to the index we should insert. + */ +static bool undosys_ID_map_lookup_index(const UndoIDPtrMap *map, const void *key, uint *r_index) +{ + const UndoIDPtrMapItem *pmap = map->pmap; + const uint len = map->len; + if (len == 0) { + if (*r_index) { + *r_index = 0; + } + return false; + } + int min = 0, max = len - 1; + while (min <= max) { + const uint mid = (min + max) / 2; + if (pmap[mid].ptr < key) { + min = mid + 1; + } + else if (pmap[mid].ptr == key) { + if (r_index) { + *r_index = mid; + } + return true; + } + else if (pmap[mid].ptr > key) { + max = mid - 1; + } + } + if (r_index) { + *r_index = min; + } + return false; +} + +/** + * A set of ID's use for efficient decoding, so we can map pointers back to the newly loaded data + * without performing full look ups each time. + * + * This can be used as an old_pointer -> new_pointer lookup. + */ +UndoIDPtrMap *BKE_undosys_ID_map_create(void) +{ + UndoIDPtrMap *map = MEM_mallocN(sizeof(*map), __func__); + map->len_alloc = PMAP_DEFAULT_ALLOC; + map->refs = MEM_mallocN(sizeof(*map->refs) * map->len_alloc, __func__); + map->pmap = MEM_mallocN(sizeof(*map->pmap) * map->len_alloc, __func__); + map->len = 0; + return map; +} +void BKE_undosys_ID_map_destroy(UndoIDPtrMap *idpmap) +{ + MEM_SAFE_FREE(idpmap->refs); + MEM_SAFE_FREE(idpmap->pmap); + MEM_freeN(idpmap); +} + +void BKE_undosys_ID_map_add(UndoIDPtrMap *map, ID *id) +{ + uint index; + if (id->lib != NULL) { + return; + } + + if (undosys_ID_map_lookup_index(map, id, &index)) { + return; /* exists. */ + } + + const uint len_src = map->len; + const uint len_dst = map->len + 1; + if (len_dst > map->len_alloc) { + map->len_alloc *= 2; + BLI_assert(map->len_alloc >= len_dst); + map->pmap = MEM_reallocN(map->pmap, sizeof(*map->pmap) * map->len_alloc); + map->refs = MEM_reallocN(map->refs, sizeof(*map->refs) * map->len_alloc); + } + +#if 0 /* Will be done automatically in callback. */ + BLI_strncpy(map->refs[len_src].name, id->name, sizeof(id->name)); +#else + map->refs[len_src].name[0] = '\0'; +#endif + map->refs[len_src].ptr = id; + + if (len_src != 0 && index != len_src) { + memmove(&map->pmap[index + 1], &map->pmap[index], sizeof(*map->pmap) * (len_src - index)); + } + map->pmap[index].ptr = id; + map->pmap[index].index = len_src; + + map->len = len_dst; +} + +ID *BKE_undosys_ID_map_lookup(const UndoIDPtrMap *map, const ID *id_src) +{ + /* We should only ever lookup indices which exist! */ + uint index; + if (!undosys_ID_map_lookup_index(map, id_src, &index)) { + BLI_assert(0); + } + index = map->pmap[index].index; + ID *id_dst = map->refs[index].ptr; + BLI_assert(id_dst != NULL); + BLI_assert(STREQ(id_dst->name, map->refs[index].name)); + return id_dst; +} + +void BKE_undosys_ID_map_add_with_prev(UndoIDPtrMap *map, ID *id, ID **id_prev) +{ + if (id == *id_prev) { + return; + } + *id_prev = id; + BKE_undosys_ID_map_add(map, id); +} + +ID *BKE_undosys_ID_map_lookup_with_prev(const UndoIDPtrMap *map, ID *id_src, ID *id_prev_match[2]) +{ + if (id_src == id_prev_match[0]) { + return id_prev_match[1]; + } + else { + ID *id_dst = BKE_undosys_ID_map_lookup(map, id_src); + id_prev_match[0] = id_src; + id_prev_match[1] = id_dst; + return id_dst; + } +} + +/** \} */ diff --git a/source/blender/blenkernel/intern/workspace.c b/source/blender/blenkernel/intern/workspace.c index 8554cf0fb28..afceea9dd5f 100644 --- a/source/blender/blenkernel/intern/workspace.c +++ b/source/blender/blenkernel/intern/workspace.c @@ -38,6 +38,7 @@ #include "BKE_main.h" #include "BKE_scene.h" #include "BKE_screen.h" +#include "BKE_object.h" #include "BKE_workspace.h" #include "DNA_object_types.h" @@ -45,6 +46,8 @@ #include "DNA_screen_types.h" #include "DNA_workspace_types.h" +#include "DEG_depsgraph.h" + #include "MEM_guardedalloc.h" @@ -166,6 +169,7 @@ void BKE_workspace_free(WorkSpace *workspace) BKE_workspace_relations_free(&workspace->hook_layout_relations); BKE_workspace_relations_free(&workspace->scene_viewlayer_relations); + BLI_freelistN(&workspace->owner_ids); BLI_freelistN(&workspace->layouts); BLI_freelistN(&workspace->transform_orientations); @@ -353,22 +357,22 @@ WorkSpaceLayout *BKE_workspace_layout_iter_circular( WorkSpaceLayout *iter_layout; if (iter_backward) { - BLI_LISTBASE_CIRCULAR_BACKWARD_BEGIN(&workspace->layouts, iter_layout, start) + LISTBASE_CIRCULAR_BACKWARD_BEGIN(&workspace->layouts, iter_layout, start) { if (!callback(iter_layout, arg)) { return iter_layout; } } - BLI_LISTBASE_CIRCULAR_BACKWARD_END(&workspace->layouts, iter_layout, start); + LISTBASE_CIRCULAR_BACKWARD_END(&workspace->layouts, iter_layout, start); } else { - BLI_LISTBASE_CIRCULAR_FORWARD_BEGIN(&workspace->layouts, iter_layout, start) + LISTBASE_CIRCULAR_FORWARD_BEGIN(&workspace->layouts, iter_layout, start) { if (!callback(iter_layout, arg)) { return iter_layout; } } - BLI_LISTBASE_CIRCULAR_FORWARD_END(&workspace->layouts, iter_layout, start) + LISTBASE_CIRCULAR_FORWARD_END(&workspace->layouts, iter_layout, start) } return NULL; @@ -413,21 +417,6 @@ void BKE_workspace_active_screen_set(WorkSpaceInstanceHook *hook, WorkSpace *wor BKE_workspace_hook_layout_for_workspace_set(hook, workspace, layout); } -#ifdef USE_WORKSPACE_MODE -eObjectMode BKE_workspace_object_mode_get(const WorkSpace *workspace, const Scene *scene) -{ - Base *active_base = BKE_workspace_active_base_get(workspace, scene); - return active_base ? active_base->object->mode : OB_MODE_OBJECT; -} -void BKE_workspace_object_mode_set(WorkSpace *workspace, Scene *scene, const eObjectMode mode) -{ - Base *active_base = BKE_workspace_active_base_get(workspace, scene); - if (active_base) { - active_base->object->mode = mode; - } -} -#endif - Base *BKE_workspace_active_base_get(const WorkSpace *workspace, const Scene *scene) { ViewLayer *view_layer = BKE_workspace_view_layer_get(workspace, scene); @@ -510,8 +499,7 @@ void BKE_workspace_use_scene_settings_set(WorkSpace *workspace, bool value) /* Update / evaluate */ -void BKE_workspace_update_tagged(struct EvaluationContext *eval_ctx, - Main *bmain, +void BKE_workspace_update_tagged(Main *bmain, WorkSpace *workspace, Scene *scene) { @@ -519,5 +507,21 @@ void BKE_workspace_update_tagged(struct EvaluationContext *eval_ctx, struct Depsgraph *depsgraph = BKE_scene_get_depsgraph(scene, view_layer, true); - BKE_scene_graph_update_tagged(eval_ctx, depsgraph, bmain, scene, view_layer); + BKE_scene_graph_update_tagged(depsgraph, bmain); } + + +bool BKE_workspace_owner_id_check( + const WorkSpace *workspace, const char *owner_id) +{ + if ((*owner_id == '\0') || + ((workspace->flags & WORKSPACE_USE_FILTER_BY_ORIGIN) == 0)) + { + return true; + } + else { + /* we could use hash lookup, for now this list is highly under < ~16 items. */ + return BLI_findstring(&workspace->owner_ids, owner_id, offsetof(wmOwnerID, name)) != NULL; + } +} + diff --git a/source/blender/blenkernel/intern/world.c b/source/blender/blenkernel/intern/world.c index 5da8dc563e2..e87e84736c8 100644 --- a/source/blender/blenkernel/intern/world.c +++ b/source/blender/blenkernel/intern/world.c @@ -33,6 +33,7 @@ #include <string.h> #include <stdlib.h> #include <math.h> + #include "MEM_guardedalloc.h" #include "DNA_world_types.h" @@ -196,7 +197,7 @@ void BKE_world_make_local(Main *bmain, World *wrld, const bool lib_local) void BKE_world_eval(const struct EvaluationContext *UNUSED(eval_ctx), World *world) { - if (G.debug & G_DEBUG_DEPSGRAPH) { + if (G.debug & G_DEBUG_DEPSGRAPH_EVAL) { printf("%s on %s (%p)\n", __func__, world->id.name, world); } if (!BLI_listbase_is_empty(&world->gpumaterial)) { diff --git a/source/blender/blenkernel/intern/writeffmpeg.c b/source/blender/blenkernel/intern/writeffmpeg.c index f745a840cea..0a2527bafd2 100644 --- a/source/blender/blenkernel/intern/writeffmpeg.c +++ b/source/blender/blenkernel/intern/writeffmpeg.c @@ -53,6 +53,7 @@ #include "BKE_global.h" #include "BKE_idprop.h" +#include "BKE_image.h" #include "BKE_main.h" #include "BKE_report.h" #include "BKE_sound.h" @@ -62,6 +63,8 @@ #include "ffmpeg_compat.h" +struct StampData; + typedef struct FFMpegContext { int ffmpeg_type; int ffmpeg_codec; @@ -94,6 +97,8 @@ typedef struct FFMpegContext { bool audio_deinterleave; int audio_sample_size; + struct StampData *stamp_data; + #ifdef WITH_AUDASPACE AUD_Device *audio_mixdown_device; #endif @@ -577,24 +582,33 @@ static AVStream *alloc_video_stream(FFMpegContext *context, RenderData *rd, int } if (context->ffmpeg_preset) { - char const *preset_name; + /* 'preset' is used by h.264, 'deadline' is used by webm/vp9. I'm not + * setting those properties conditionally based on the video codec, + * as the FFmpeg encoder simply ignores unknown settings anyway. */ + char const *preset_name = NULL; /* used by h.264 */ + char const *deadline_name = NULL; /* used by webm/vp9 */ switch (context->ffmpeg_preset) { - case FFM_PRESET_ULTRAFAST: preset_name = "ultrafast"; break; - case FFM_PRESET_SUPERFAST: preset_name = "superfast"; break; - case FFM_PRESET_VERYFAST: preset_name = "veryfast"; break; - case FFM_PRESET_FASTER: preset_name = "faster"; break; - case FFM_PRESET_FAST: preset_name = "fast"; break; - case FFM_PRESET_MEDIUM: preset_name = "medium"; break; - case FFM_PRESET_SLOW: preset_name = "slow"; break; - case FFM_PRESET_SLOWER: preset_name = "slower"; break; - case FFM_PRESET_VERYSLOW: preset_name = "veryslow"; break; + case FFM_PRESET_GOOD: + preset_name = "medium"; + deadline_name = "good"; + break; + case FFM_PRESET_BEST: + preset_name = "slower"; + deadline_name = "best"; + break; + case FFM_PRESET_REALTIME: + preset_name = "superfast"; + deadline_name = "realtime"; + break; default: printf("Unknown preset number %i, ignoring.\n", context->ffmpeg_preset); - preset_name = NULL; } if (preset_name != NULL) { av_dict_set(&opts, "preset", preset_name, 0); } + if (deadline_name != NULL) { + av_dict_set(&opts, "deadline", deadline_name, 0); + } } #if 0 @@ -836,6 +850,12 @@ static void ffmpeg_dict_set_float(AVDictionary **dict, const char *key, float va av_dict_set(dict, key, buffer, 0); } +static void ffmpeg_add_metadata_callback(void *data, const char *propname, char *propvalue, int len) +{ + AVDictionary **metadata = (AVDictionary **)data; + av_dict_set(metadata, propname, propvalue, 0); +} + static int start_ffmpeg_impl(FFMpegContext *context, struct RenderData *rd, int rectx, int recty, const char *suffix, ReportList *reports) { /* Handle to the output file */ @@ -994,6 +1014,11 @@ static int start_ffmpeg_impl(FFMpegContext *context, struct RenderData *rd, int goto fail; } } + + if (context->stamp_data != NULL) { + BKE_stamp_info_callback(&of->metadata, context->stamp_data, ffmpeg_add_metadata_callback, false); + } + if (avformat_write_header(of, NULL) < 0) { BKE_report(reports, RPT_ERROR, "Could not initialize streams, probably unsupported codec combination"); goto fail; @@ -1168,6 +1193,7 @@ int BKE_ffmpeg_start(void *context_v, struct Scene *scene, RenderData *rd, int r context->ffmpeg_autosplit_count = 0; context->ffmpeg_preview = preview; + context->stamp_data = BKE_stamp_info_from_scene_static(scene); success = start_ffmpeg_impl(context, rd, rectx, recty, suffix, reports); #ifdef WITH_AUDASPACE @@ -1659,7 +1685,7 @@ void BKE_ffmpeg_image_type_verify(RenderData *rd, ImageFormatData *imf) { BKE_ffmpeg_preset_set(rd, FFMPEG_PRESET_H264); rd->ffcodecdata.constant_rate_factor = FFM_CRF_MEDIUM; - rd->ffcodecdata.ffmpeg_preset = FFM_PRESET_MEDIUM; + rd->ffcodecdata.ffmpeg_preset = FFM_PRESET_GOOD; rd->ffcodecdata.type = FFMPEG_MKV; } if (rd->ffcodecdata.type == FFMPEG_OGG) { @@ -1734,6 +1760,7 @@ void *BKE_ffmpeg_context_create(void) context->ffmpeg_autosplit = 0; context->ffmpeg_autosplit_count = 0; context->ffmpeg_preview = false; + context->stamp_data = NULL; return context; } @@ -1741,9 +1768,13 @@ void *BKE_ffmpeg_context_create(void) void BKE_ffmpeg_context_free(void *context_v) { FFMpegContext *context = context_v; - if (context) { - MEM_freeN(context); + if (context == NULL) { + return; + } + if (context->stamp_data) { + MEM_freeN(context->stamp_data); } + MEM_freeN(context); } #endif /* WITH_FFMPEG */ |