From c205de020365eddbbc0f0cde0ad02dda91126807 Mon Sep 17 00:00:00 2001 From: Bastien Montagne Date: Thu, 19 Jul 2018 16:48:21 +0200 Subject: Fix T55973: [2.8] Crash when 'apply pose as rest pose' when bone scale is 0,0,0. `BKE_pose_rebuild()` should (ideally) always trigger a rebuild of the depsgraph, since it can add or remove posechannels. This function now takes a Main parameter to ensure that related depsgraphes are tagged as dirty (kept it optional, for some corner cases). We should also probably double-check calls to that function, think in theory it should only be called from depsgraph itself? But for now... --- source/blender/blenkernel/BKE_armature.h | 2 +- source/blender/blenkernel/BKE_object.h | 2 +- source/blender/blenkernel/intern/armature.c | 32 ++++++++++++++++------ source/blender/blenkernel/intern/library.c | 2 +- source/blender/blenkernel/intern/object.c | 14 ++++++---- source/blender/blenkernel/intern/scene.c | 2 +- .../intern/builder/deg_builder_nodes_rig.cc | 3 +- source/blender/draw/intern/draw_armature.c | 2 +- source/blender/editors/armature/armature_utils.c | 2 +- source/blender/editors/object/object_add.c | 2 +- source/blender/editors/object/object_relations.c | 4 +-- source/blender/makesrna/intern/rna_object.c | 8 ++++-- 12 files changed, 47 insertions(+), 28 deletions(-) (limited to 'source/blender') diff --git a/source/blender/blenkernel/BKE_armature.h b/source/blender/blenkernel/BKE_armature.h index e1bfb05fb59..21d880cf2a7 100644 --- a/source/blender/blenkernel/BKE_armature.h +++ b/source/blender/blenkernel/BKE_armature.h @@ -100,7 +100,7 @@ void BKE_armature_where_is(struct bArmature *arm); void BKE_armature_where_is_bone(struct Bone *bone, struct Bone *prevbone, const bool use_recursion); void BKE_pose_clear_pointers(struct bPose *pose); void BKE_pose_remap_bone_pointers(struct bArmature *armature, struct bPose *pose); -void BKE_pose_rebuild(struct Object *ob, struct bArmature *arm); +void BKE_pose_rebuild(struct Main *bmain, struct Object *ob, struct bArmature *arm); void BKE_pose_where_is(struct Depsgraph *depsgraph, struct Scene *scene, struct Object *ob); void BKE_pose_where_is_bone(struct Depsgraph *depsgraph, struct Scene *scene, struct Object *ob, struct bPoseChannel *pchan, float ctime, bool do_extra); void BKE_pose_where_is_bone_tail(struct bPoseChannel *pchan); diff --git a/source/blender/blenkernel/BKE_object.h b/source/blender/blenkernel/BKE_object.h index 0122185fd2a..79e4f1d448a 100644 --- a/source/blender/blenkernel/BKE_object.h +++ b/source/blender/blenkernel/BKE_object.h @@ -75,7 +75,7 @@ bool BKE_object_support_modifier_type_check(const struct Object *ob, int modifie void BKE_object_link_modifiers(struct Scene *scene, struct Object *ob_dst, const struct Object *ob_src); void BKE_object_free_modifiers(struct Object *ob, const int flag); -void BKE_object_make_proxy(struct Object *ob, struct Object *target, struct Object *gob); +void BKE_object_make_proxy(struct Main *bmain, struct Object *ob, struct Object *target, struct Object *gob); void BKE_object_copy_proxy_drivers(struct Object *ob, struct Object *target); bool BKE_object_exists_check(struct Main *bmain, const struct Object *obtest); diff --git a/source/blender/blenkernel/intern/armature.c b/source/blender/blenkernel/intern/armature.c index bd9ee7c9e5f..6be4574a62e 100644 --- a/source/blender/blenkernel/intern/armature.c +++ b/source/blender/blenkernel/intern/armature.c @@ -71,6 +71,8 @@ #include "BKE_object.h" #include "BKE_scene.h" +#include "DEG_depsgraph_build.h" + #include "BIK_api.h" /* **************** Generic Functions, data level *************** */ @@ -1951,9 +1953,14 @@ void BKE_pose_remap_bone_pointers(bArmature *armature, bPose *pose) BLI_ghash_free(bone_hash, NULL, NULL); } -/* only after leave editmode, duplicating, validating older files, library syncing */ -/* NOTE: pose->flag is set for it */ -void BKE_pose_rebuild(Object *ob, bArmature *arm) +/** + * Only after leave editmode, duplicating, validating older files, library syncing. + * + * \note pose->flag is set for it. + * + * \param bmain May be NULL, only used to tag depsgraph as being dirty... + */ +void BKE_pose_rebuild(Main *bmain, Object *ob, bArmature *arm) { Bone *bone; bPose *pose; @@ -1998,12 +2005,17 @@ void BKE_pose_rebuild(Object *ob, bArmature *arm) pose_proxy_synchronize(ob, ob->proxy, arm->layer_protected); } - BKE_pose_update_constraint_flags(ob->pose); /* for IK detection for example */ + BKE_pose_update_constraint_flags(pose); /* for IK detection for example */ + + pose->flag &= ~POSE_RECALC; + pose->flag |= POSE_WAS_REBUILT; - ob->pose->flag &= ~POSE_RECALC; - ob->pose->flag |= POSE_WAS_REBUILT; + BKE_pose_channels_hash_make(pose); - BKE_pose_channels_hash_make(ob->pose); + /* Rebuilding poses forces us to also rebuild the dependency graph, since there is one node per pose/bone... */ + if (bmain != NULL) { + DEG_relations_tag_update(bmain); + } } /* ********************** THE POSE SOLVER ******************* */ @@ -2277,8 +2289,10 @@ void BKE_pose_where_is(struct Depsgraph *depsgraph, Scene *scene, Object *ob) if (ELEM(NULL, arm, scene)) return; - if ((ob->pose == NULL) || (ob->pose->flag & POSE_RECALC)) - BKE_pose_rebuild(ob, arm); + if ((ob->pose == NULL) || (ob->pose->flag & POSE_RECALC)) { + /* WARNING! passing NULL bmain here means we won't tag depsgraph's as dirty - hopefully this is OK. */ + BKE_pose_rebuild(NULL, ob, arm); + } ctime = BKE_scene_frame_get(scene); /* not accurate... */ diff --git a/source/blender/blenkernel/intern/library.c b/source/blender/blenkernel/intern/library.c index c2cdc8df1e6..351214ed72b 100644 --- a/source/blender/blenkernel/intern/library.c +++ b/source/blender/blenkernel/intern/library.c @@ -2464,7 +2464,7 @@ void BKE_library_make_local( * Try "make all local" in 04_01_H.lighting.blend from Agent327 without this, e.g. */ for (Object *ob = bmain->object.first; ob; ob = ob->id.next) { if (ob->data != NULL && ob->type == OB_ARMATURE && ob->pose != NULL && ob->pose->flag & POSE_RECALC) { - BKE_pose_rebuild(ob, ob->data); + BKE_pose_rebuild(bmain, ob, ob->data); } } diff --git a/source/blender/blenkernel/intern/object.c b/source/blender/blenkernel/intern/object.c index 14794bd7061..33ea13c9a38 100644 --- a/source/blender/blenkernel/intern/object.c +++ b/source/blender/blenkernel/intern/object.c @@ -1150,7 +1150,7 @@ void BKE_object_transform_copy(Object *ob_tar, const Object *ob_src) * * \param flag Copying options (see BKE_library.h's LIB_ID_COPY_... flags for more). */ -void BKE_object_copy_data(Main *UNUSED(bmain), Object *ob_dst, const Object *ob_src, const int flag) +void BKE_object_copy_data(Main *bmain, Object *ob_dst, const Object *ob_src, const int flag) { ModifierData *md; @@ -1180,7 +1180,7 @@ void BKE_object_copy_data(Main *UNUSED(bmain), Object *ob_dst, const Object *ob_ copy_object_pose(ob_dst, ob_src, flag_subdata); /* backwards compat... non-armatures can get poses in older files? */ if (ob_src->type == OB_ARMATURE) - BKE_pose_rebuild(ob_dst, ob_dst->data); + BKE_pose_rebuild(bmain, ob_dst, ob_dst->data); } defgroup_copy_list(&ob_dst->defbase, &ob_src->defbase); BKE_object_facemap_copy_list(&ob_dst->fmaps, &ob_src->fmaps); @@ -1359,7 +1359,7 @@ void BKE_object_copy_proxy_drivers(Object *ob, Object *target) /* local_object->proxy == pointer to library object, saved in files and read */ /* local_object->proxy_group == pointer to collection dupli-object, saved in files and read */ -void BKE_object_make_proxy(Object *ob, Object *target, Object *cob) +void BKE_object_make_proxy(Main *bmain, Object *ob, Object *target, Object *cob) { /* paranoia checks */ if (ID_IS_LINKED(ob) || !ID_IS_LINKED(target)) { @@ -1434,7 +1434,7 @@ void BKE_object_make_proxy(Object *ob, Object *target, Object *cob) if (target->type == OB_ARMATURE) { copy_object_pose(ob, target, 0); /* data copy, object pointers in constraints */ BKE_pose_rest(ob->pose); /* clear all transforms in channels */ - BKE_pose_rebuild(ob, ob->data); /* set all internal links */ + BKE_pose_rebuild(bmain, ob, ob->data); /* set all internal links */ armature_set_id_extern(ob); } @@ -2698,8 +2698,10 @@ void BKE_object_handle_update_ex(Depsgraph *depsgraph, * with poses we do it ahead of BKE_object_where_is_calc to ensure animation * is evaluated on the rebuilt pose, otherwise we get incorrect poses * on file load */ - if (ob->pose == NULL || (ob->pose->flag & POSE_RECALC)) - BKE_pose_rebuild(ob, ob->data); + if (ob->pose == NULL || (ob->pose->flag & POSE_RECALC)) { + /* No need to pass bmain here, we assume we do not need to rebuild DEG from here... */ + BKE_pose_rebuild(NULL, ob, ob->data); + } } } /* XXX new animsys warning: depsgraph tag OB_RECALC_DATA should not skip drivers, diff --git a/source/blender/blenkernel/intern/scene.c b/source/blender/blenkernel/intern/scene.c index f99a30b75d0..3650fa21c1c 100644 --- a/source/blender/blenkernel/intern/scene.c +++ b/source/blender/blenkernel/intern/scene.c @@ -1288,7 +1288,7 @@ static void scene_armature_depsgraph_workaround(Main *bmain, Depsgraph *depsgrap for (ob = bmain->object.first; ob; ob = ob->id.next) { if (ob->type == OB_ARMATURE && ob->adt && ob->adt->recalc & ADT_RECALC_ANIM) { if (ob->pose == NULL || (ob->pose->flag & POSE_RECALC)) { - BKE_pose_rebuild(ob, ob->data); + BKE_pose_rebuild(bmain, ob, ob->data); } } } diff --git a/source/blender/depsgraph/intern/builder/deg_builder_nodes_rig.cc b/source/blender/depsgraph/intern/builder/deg_builder_nodes_rig.cc index 00d7a5da455..043148a0f70 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_nodes_rig.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_nodes_rig.cc @@ -161,7 +161,8 @@ void DepsgraphNodeBuilder::build_rig(Object *object) build_armature(armature); /* Rebuild pose if not up to date. */ if (object->pose == NULL || (object->pose->flag & POSE_RECALC)) { - BKE_pose_rebuild(object, armature); + /* By definition, no need to tag depsgraph as dirty from here, so we can pass NULL bmain. */ + BKE_pose_rebuild(NULL, object, armature); /* XXX: Without this animation gets lost in certain circumstances * after loading file. Need to investigate further since it does * not happen with simple scenes.. diff --git a/source/blender/draw/intern/draw_armature.c b/source/blender/draw/intern/draw_armature.c index b49ca4d0d00..8b90d328541 100644 --- a/source/blender/draw/intern/draw_armature.c +++ b/source/blender/draw/intern/draw_armature.c @@ -1623,7 +1623,7 @@ static void draw_armature_pose(Object *ob, const float const_color[4]) /* We can't safely draw non-updated pose, might contain NULL bone pointers... */ if (ob->pose->flag & POSE_RECALC) { - BKE_pose_rebuild(ob, arm); + BKE_pose_rebuild(NULL, ob, arm); } // if (!(base->flag & OB_FROMDUPLI)) // TODO diff --git a/source/blender/editors/armature/armature_utils.c b/source/blender/editors/armature/armature_utils.c index 02d45a4e041..c93bfb5d8c3 100644 --- a/source/blender/editors/armature/armature_utils.c +++ b/source/blender/editors/armature/armature_utils.c @@ -681,7 +681,7 @@ void ED_armature_from_edit(Main *bmain, bArmature *arm) /* so all users of this armature should get rebuilt */ for (obt = bmain->object.first; obt; obt = obt->id.next) { if (obt->data == arm) { - BKE_pose_rebuild(obt, arm); + BKE_pose_rebuild(bmain, obt, arm); } } diff --git a/source/blender/editors/object/object_add.c b/source/blender/editors/object/object_add.c index a8917f4c4aa..8c60dd01e89 100644 --- a/source/blender/editors/object/object_add.c +++ b/source/blender/editors/object/object_add.c @@ -2222,7 +2222,7 @@ static Base *object_add_duplicate_internal(Main *bmain, Scene *scene, ViewLayer ID_NEW_REMAP_US2(obn->data) else { obn->data = ID_NEW_SET(obn->data, BKE_armature_copy(bmain, obn->data)); - BKE_pose_rebuild(obn, obn->data); + BKE_pose_rebuild(bmain, obn, obn->data); didit = 1; } id_us_min(id); diff --git a/source/blender/editors/object/object_relations.c b/source/blender/editors/object/object_relations.c index 324b6eca34a..2c3ff8b6afe 100644 --- a/source/blender/editors/object/object_relations.c +++ b/source/blender/editors/object/object_relations.c @@ -360,7 +360,7 @@ static int make_proxy_exec(bContext *C, wmOperator *op) newob = BKE_object_add_from(bmain, scene, view_layer, OB_EMPTY, name, gob ? gob : ob); /* set layers OK */ - BKE_object_make_proxy(newob, ob, gob); + BKE_object_make_proxy(bmain, newob, ob, gob); /* Set back pointer immediately so dependency graph knows that this is * is a proxy and will act accordingly. Otherwise correctness of graph @@ -1809,7 +1809,7 @@ static void single_obdata_users(Main *bmain, Scene *scene, ViewLayer *view_layer case OB_ARMATURE: DEG_id_tag_update(&ob->id, OB_RECALC_DATA); ob->data = ID_NEW_SET(ob->data, BKE_armature_copy(bmain, ob->data)); - BKE_pose_rebuild(ob, ob->data); + BKE_pose_rebuild(bmain, ob, ob->data); break; case OB_SPEAKER: ob->data = ID_NEW_SET(ob->data, BKE_speaker_copy(bmain, ob->data)); diff --git a/source/blender/makesrna/intern/rna_object.c b/source/blender/makesrna/intern/rna_object.c index 2bdfbade53a..ac1a6d512c3 100644 --- a/source/blender/makesrna/intern/rna_object.c +++ b/source/blender/makesrna/intern/rna_object.c @@ -356,10 +356,12 @@ static void rna_Object_data_set(PointerRNA *ptr, PointerRNA value) ob->data = id; test_object_materials(G_MAIN, ob, id); - if (GS(id->name) == ID_CU) + if (GS(id->name) == ID_CU) { BKE_curve_type_test(ob); - else if (ob->type == OB_ARMATURE) - BKE_pose_rebuild(ob, ob->data); + } + else if (ob->type == OB_ARMATURE) { + BKE_pose_rebuild(G_MAIN, ob, ob->data); + } } } -- cgit v1.2.3