[Bf-blender-cvs] [d7ba1ada820] blender2.8: Fix T54136: Crash when deleting an object that is in an instanced group

Dalai Felinto noreply at git.blender.org
Thu Feb 22 21:17:59 CET 2018


Commit: d7ba1ada8208f6f846b3705f5c6d9933261a625f
Author: Dalai Felinto
Date:   Thu Feb 22 17:16:39 2018 -0300
Branches: blender2.8
https://developer.blender.org/rBd7ba1ada8208f6f846b3705f5c6d9933261a625f

Fix T54136: Crash when deleting an object that is in an instanced group

We were not cleaning up groups after deleting objects, leaving groups with
Bases that had no object.

It includes a unittest.

Reviewers: mont29

===================================================================

M	source/blender/blenkernel/intern/library_remap.c
M	tests/python/view_layer/CMakeLists.txt
A	tests/python/view_layer/test_group_e.py

===================================================================

diff --git a/source/blender/blenkernel/intern/library_remap.c b/source/blender/blenkernel/intern/library_remap.c
index 6d4c4082810..e689461636d 100644
--- a/source/blender/blenkernel/intern/library_remap.c
+++ b/source/blender/blenkernel/intern/library_remap.c
@@ -279,6 +279,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)) {
@@ -297,6 +317,8 @@ static void libblock_remap_data_preprocess(IDRemap *r_id_remap_data)
 					{
 						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
 				}
@@ -305,7 +327,10 @@ static void libblock_remap_data_preprocess(IDRemap *r_id_remap_data)
 					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;
 		}
diff --git a/tests/python/view_layer/CMakeLists.txt b/tests/python/view_layer/CMakeLists.txt
index cc5a3ba54b1..77a56fb47f9 100644
--- a/tests/python/view_layer/CMakeLists.txt
+++ b/tests/python/view_layer/CMakeLists.txt
@@ -94,6 +94,7 @@ VIEW_LAYER_TEST(group_a)
 VIEW_LAYER_TEST(group_b)
 VIEW_LAYER_TEST(group_c)
 VIEW_LAYER_TEST(group_d)
+VIEW_LAYER_TEST(group_e)
 VIEW_LAYER_TEST(object_add_cylinder)
 VIEW_LAYER_TEST(object_add_empty)
 VIEW_LAYER_TEST(object_add_torus)
diff --git a/tests/python/view_layer/test_group_e.py b/tests/python/view_layer/test_group_e.py
new file mode 100644
index 00000000000..566c043572e
--- /dev/null
+++ b/tests/python/view_layer/test_group_e.py
@@ -0,0 +1,72 @@
+# ############################################################
+# Importing - Same For All Render Layer Tests
+# ############################################################
+
+import unittest
+import os
+import sys
+
+from view_layer_common import *
+
+
+# ############################################################
+# Testing
+# ############################################################
+
+class UnitTesting(ViewLayerTesting):
+    def test_group_delete_object(self):
+        """
+        See if we can safely remove instanced objects
+        """
+        import bpy
+        scene = bpy.context.scene
+        view_layer = bpy.context.view_layer
+        ob = bpy.context.object
+
+        # clean up the scene a bit
+        for o in (o for o in view_layer.objects if o != ob):
+            view_layer.collections[0].collection.objects.unlink(o)
+
+        for v in (v for v in scene.view_layers if v != view_layer):
+            scene.view_layers.remove(v)
+
+        # update depsgraph
+        scene.update()
+
+        # create group
+        group = bpy.data.groups.new("Switch")
+        group.objects.link(ob)
+
+        # update depsgraph
+        scene.update()
+
+        # instance the group
+        empty = bpy.data.objects.new("Empty", None)
+        bpy.context.scene_collection.objects.link(empty)
+        layer_collection = bpy.context.layer_collection
+        empty.dupli_type = 'GROUP'
+        empty.dupli_group = group
+
+        # prepare to delete the original object
+        # we could just pass an overridden context
+        # but let's do it the old fashion way
+        view_layer.objects.active = ob
+        ob.select_set('SELECT')
+        self.assertTrue(ob.select_get())
+        empty.select_set('DESELECT')
+        self.assertFalse(empty.select_get())
+
+        # update depsgraph
+        scene.update()
+
+        # delete the original object
+        bpy.ops.object.delete()
+
+
+# ############################################################
+# Main - Same For All Render Layer Tests
+# ############################################################
+
+if __name__ == '__main__':
+    UnitTesting._extra_arguments = setup_extra_arguments(__file__)
+    unittest.main()



More information about the Bf-blender-cvs mailing list