Fix T63332: backup and restore bPoseChannel_Runtime data during COW.
authorAlexander Gavrilov <angavrilov@gmail.com>
Thu, 18 Apr 2019 18:19:57 +0000 (21:19 +0300)
committerAlexander Gavrilov <angavrilov@gmail.com>
Thu, 18 Apr 2019 18:32:17 +0000 (21:32 +0300)
source/blender/blenkernel/BKE_action.h
source/blender/blenkernel/intern/action.c
source/blender/blenkernel/intern/armature.c
source/blender/blenkernel/intern/armature_update.c
source/blender/blenloader/intern/readfile.c
source/blender/depsgraph/intern/eval/deg_eval_copy_on_write.cc

index 08237be..69f3070 100644 (file)
@@ -35,6 +35,7 @@ struct bActionGroup;
 struct bItasc;
 struct bPose;
 struct bPoseChannel;
+struct bPoseChannel_Runtime;
 
 /* Kernel prototypes */
 #ifdef __cplusplus
@@ -132,7 +133,10 @@ void action_groups_clear_tempflags(struct bAction *act);
 void BKE_pose_channel_free(struct bPoseChannel *pchan);
 void BKE_pose_channel_free_ex(struct bPoseChannel *pchan, bool do_id_user);
 
-void BKE_pose_channel_free_bbone_cache(struct bPoseChannel *pchan);
+void BKE_pose_channel_runtime_reset(struct bPoseChannel_Runtime *runtime);
+void BKE_pose_channel_runtime_free(struct bPoseChannel_Runtime *runtime);
+
+void BKE_pose_channel_free_bbone_cache(struct bPoseChannel_Runtime *runtime);
 
 void BKE_pose_channels_free(struct bPose *pose);
 void BKE_pose_channels_free_ex(struct bPose *pose, bool do_id_user);
index a3b7df6..885ddc5 100644 (file)
@@ -793,15 +793,25 @@ void BKE_pose_channel_free_ex(bPoseChannel *pchan, bool do_id_user)
   /* Cached data, for new draw manager rendering code. */
   MEM_SAFE_FREE(pchan->draw_data);
 
-  /* Cached B-Bone shape data. */
-  BKE_pose_channel_free_bbone_cache(pchan);
+  /* Cached B-Bone shape and other data. */
+  BKE_pose_channel_runtime_free(&pchan->runtime);
 }
 
-/** Deallocates runtime cache of a pose channel's B-Bone shape. */
-void BKE_pose_channel_free_bbone_cache(bPoseChannel *pchan)
+/** Clears the runtime cache of a pose channel without free. */
+void BKE_pose_channel_runtime_reset(bPoseChannel_Runtime *runtime)
 {
-  bPoseChannel_Runtime *runtime = &pchan->runtime;
+  memset(runtime, 0, sizeof(*runtime));
+}
 
+/** Deallocates runtime cache of a pose channel */
+void BKE_pose_channel_runtime_free(bPoseChannel_Runtime *runtime)
+{
+  BKE_pose_channel_free_bbone_cache(runtime);
+}
+
+/** Deallocates runtime cache of a pose channel's B-Bone shape. */
+void BKE_pose_channel_free_bbone_cache(bPoseChannel_Runtime *runtime)
+{
   runtime->bbone_segments = 0;
   MEM_SAFE_FREE(runtime->bbone_rest_mats);
   MEM_SAFE_FREE(runtime->bbone_pose_mats);
index 6972165..91c7602 100644 (file)
@@ -948,9 +948,7 @@ static void allocate_bbone_cache(bPoseChannel *pchan, int segments)
   bPoseChannel_Runtime *runtime = &pchan->runtime;
 
   if (runtime->bbone_segments != segments) {
-    if (runtime->bbone_segments != 0) {
-      BKE_pose_channel_free_bbone_cache(pchan);
-    }
+    BKE_pose_channel_free_bbone_cache(runtime);
 
     runtime->bbone_segments = segments;
     runtime->bbone_rest_mats = MEM_malloc_arrayN(
@@ -1020,7 +1018,7 @@ void BKE_pchan_bbone_segments_cache_copy(bPoseChannel *pchan, bPoseChannel *pcha
   int segments = runtime_from->bbone_segments;
 
   if (segments <= 1) {
-    BKE_pose_channel_free_bbone_cache(pchan);
+    BKE_pose_channel_free_bbone_cache(&pchan->runtime);
   }
   else {
     allocate_bbone_cache(pchan, segments);
index e6e9b56..bf33b1c 100644 (file)
@@ -613,7 +613,7 @@ void BKE_pose_eval_init(struct Depsgraph *depsgraph, Scene *UNUSED(scene), Objec
 
     /* Free B-Bone shape data cache if it's not a B-Bone. */
     if (pchan->bone == NULL || pchan->bone->segments <= 1) {
-      BKE_pose_channel_free_bbone_cache(pchan);
+      BKE_pose_channel_free_bbone_cache(&pchan->runtime);
     }
   }
 
@@ -723,7 +723,7 @@ void BKE_pose_bone_done(struct Depsgraph *depsgraph, struct Object *object, int
     copy_m4_m4(pchan_orig->constinv, pchan->constinv);
     BKE_pose_where_is_bone_tail(pchan_orig);
     if (pchan->bone == NULL || pchan->bone->segments <= 1) {
-      BKE_pose_channel_free_bbone_cache(pchan_orig);
+      BKE_pose_channel_free_bbone_cache(&pchan_orig->runtime);
     }
   }
 }
index 6acf0a7..6e3c459 100644 (file)
@@ -5502,7 +5502,7 @@ static void direct_link_pose(FileData *fd, bPose *pose)
     CLAMP(pchan->rotmode, ROT_MODE_MIN, ROT_MODE_MAX);
 
     pchan->draw_data = NULL;
-    memset(&pchan->runtime, 0, sizeof(pchan->runtime));
+    BKE_pose_channel_runtime_reset(&pchan->runtime);
   }
   pose->ikdata = NULL;
   if (pose->ikparam != NULL) {
index 01b712f..d134bc1 100644 (file)
@@ -841,6 +841,9 @@ class ModifierDataBackupID {
 /* Storage for backed up runtime modifier data. */
 typedef map<ModifierDataBackupID, void *> ModifierRuntimeDataBackup;
 
+/* Storage for backed up pose channel runtime data. */
+typedef map<bPoseChannel *, bPoseChannel_Runtime> PoseChannelRuntimeDataBackup;
+
 struct ObjectRuntimeBackup {
   ObjectRuntimeBackup() : base_flag(0), base_local_view_bits(0)
   {
@@ -853,16 +856,19 @@ struct ObjectRuntimeBackup {
    * pointers. */
   void init_from_object(Object *object);
   void backup_modifier_runtime_data(Object *object);
+  void backup_pose_channel_runtime_data(Object *object);
 
   /* Restore all fields to the given object. */
   void restore_to_object(Object *object);
   /* NOTE: Will free all runtime data which has not been restored. */
   void restore_modifier_runtime_data(Object *object);
+  void restore_pose_channel_runtime_data(Object *object);
 
   Object_Runtime runtime;
   short base_flag;
   unsigned short base_local_view_bits;
   ModifierRuntimeDataBackup modifier_runtime_data;
+  PoseChannelRuntimeDataBackup pose_channel_runtime_data;
 };
 
 void ObjectRuntimeBackup::init_from_object(Object *object)
@@ -884,6 +890,8 @@ void ObjectRuntimeBackup::init_from_object(Object *object)
   base_local_view_bits = object->base_local_view_bits;
   /* Backup tuntime data of all modifiers. */
   backup_modifier_runtime_data(object);
+  /* Backup runtime data of all pose channels. */
+  backup_pose_channel_runtime_data(object);
 }
 
 inline ModifierDataBackupID create_modifier_data_id(const ModifierData *modifier_data)
@@ -905,6 +913,19 @@ void ObjectRuntimeBackup::backup_modifier_runtime_data(Object *object)
   }
 }
 
+void ObjectRuntimeBackup::backup_pose_channel_runtime_data(Object *object)
+{
+  if (object->pose != NULL) {
+    LISTBASE_FOREACH (bPoseChannel *, pchan, &object->pose->chanbase) {
+      /* This is NULL in Edit mode. */
+      if (pchan->orig_pchan != NULL) {
+        pose_channel_runtime_data[pchan->orig_pchan] = pchan->runtime;
+        BKE_pose_channel_runtime_reset(&pchan->runtime);
+      }
+    }
+  }
+}
+
 void ObjectRuntimeBackup::restore_to_object(Object *object)
 {
   Mesh *mesh_orig = object->runtime.mesh_orig;
@@ -941,6 +962,7 @@ void ObjectRuntimeBackup::restore_to_object(Object *object)
   /* Restore modifier's runtime data.
    * NOTE: Data of unused modifiers will be freed there. */
   restore_modifier_runtime_data(object);
+  restore_pose_channel_runtime_data(object);
 }
 
 void ObjectRuntimeBackup::restore_modifier_runtime_data(Object *object)
@@ -967,6 +989,26 @@ void ObjectRuntimeBackup::restore_modifier_runtime_data(Object *object)
   }
 }
 
+void ObjectRuntimeBackup::restore_pose_channel_runtime_data(Object *object)
+{
+  if (object->pose != NULL) {
+    LISTBASE_FOREACH (bPoseChannel *, pchan, &object->pose->chanbase) {
+      /* This is NULL in Edit mode. */
+      if (pchan->orig_pchan != NULL) {
+        PoseChannelRuntimeDataBackup::iterator runtime_data_iterator =
+            pose_channel_runtime_data.find(pchan->orig_pchan);
+        if (runtime_data_iterator != pose_channel_runtime_data.end()) {
+          pchan->runtime = runtime_data_iterator->second;
+          pose_channel_runtime_data.erase(runtime_data_iterator);
+        }
+      }
+    }
+  }
+  for (PoseChannelRuntimeDataBackup::value_type &value : pose_channel_runtime_data) {
+    BKE_pose_channel_runtime_free(&value.second);
+  }
+}
+
 class RuntimeBackup {
  public:
   RuntimeBackup() : drawdata_ptr(NULL)