From 18ce2bfac63046acb484857498caf0af7178c094 Mon Sep 17 00:00:00 2001 From: Dalai Felinto Date: Wed, 16 Aug 2017 10:31:02 +0200 Subject: [PATCH] Depsgraph/Layers: Keep original visibility when doing full scene copy Originally we were not respecting the original visibility flags of the collections. However this is required for Copy-on-write (CoW). Remember to update the svn lib tests folder. I had to update some of the json files there. Also adding a new unittest for this particular issue: Test render_layer_scene_copy_f --- source/blender/blenkernel/intern/scene.c | 22 ++++- .../intern/eval/deg_eval_copy_on_write.cc | 27 ------ tests/python/render_layer/CMakeLists.txt | 1 + .../python/render_layer/test_scene_copy_d.py | 2 +- .../python/render_layer/test_scene_copy_f.py | 94 +++++++++++++++++++ 5 files changed, 117 insertions(+), 29 deletions(-) create mode 100644 tests/python/render_layer/test_scene_copy_f.py diff --git a/source/blender/blenkernel/intern/scene.c b/source/blender/blenkernel/intern/scene.c index 5760e13b800..5d974192241 100644 --- a/source/blender/blenkernel/intern/scene.c +++ b/source/blender/blenkernel/intern/scene.c @@ -204,8 +204,24 @@ static SceneCollection *scene_collection_from_new_tree(SceneCollection *sc_refer return NULL; } +static void layer_collections_sync_flags(ListBase *layer_collections_dst, const ListBase *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_collections_sync_flags(&layer_collection_dst->layer_collections, + &layer_collection_src->layer_collections); + /* TODO(sergey/dfelinto): Overrides. */ + layer_collection_dst = layer_collection_dst->next; + layer_collection_src = layer_collection_src->next; + } +} + + /* recreate the LayerCollection tree */ -static void layer_collections_recreate(SceneLayer *sl_dst, ListBase *lb_src, SceneCollection *mc_dst, SceneCollection *mc_src) +static void layer_collections_recreate( + SceneLayer *sl_dst, ListBase *lb_src, SceneCollection *mc_dst, SceneCollection *mc_src) { for (LayerCollection *lc_src = lb_src->first; lc_src; lc_src = lc_src->next) { SceneCollection *sc_dst = scene_collection_from_new_tree(lc_src->scene_collection, mc_dst, mc_src); @@ -269,8 +285,12 @@ void BKE_scene_copy_data(Main *bmain, Scene *sce_dst, const Scene *sce_src, cons BLI_listbase_clear(&sl_dst->layer_collections); BLI_listbase_clear(&sl_dst->object_bases); BLI_listbase_clear(&sl_dst->drawdata); + layer_collections_recreate(sl_dst, &sl_src->layer_collections, mc_dst, mc_src); + /* Now we handle the syncing for visibility, selectability, ... */ + layer_collections_sync_flags(&sl_dst->layer_collections, &sl_src->layer_collections); + Object *active_ob = OBACT_NEW(sl_src); for (Base *base_src = sl_src->object_bases.first, *base_dst = sl_dst->object_bases.first; base_src; diff --git a/source/blender/depsgraph/intern/eval/deg_eval_copy_on_write.cc b/source/blender/depsgraph/intern/eval/deg_eval_copy_on_write.cc index 294e5e9651e..3184c7c9066 100644 --- a/source/blender/depsgraph/intern/eval/deg_eval_copy_on_write.cc +++ b/source/blender/depsgraph/intern/eval/deg_eval_copy_on_write.cc @@ -279,21 +279,6 @@ bool id_copy_no_main(const ID *id, ID **newid) return result; } -void layer_collections_sync_flags(ListBase *layer_collections_dst, - const ListBase *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_collections_sync_flags(&layer_collection_dst->layer_collections, - &layer_collection_src->layer_collections); - /* TODO(sergey): Overrides. */ - layer_collection_dst = layer_collection_dst->next; - layer_collection_src = layer_collection_src->next; - } -} - /* Similar to BKE_scene_copy() but does not require main. * * TODO(sergey): Get rid of this once T51804 is handled. @@ -316,18 +301,6 @@ Scene *scene_copy_no_main(Scene *scene) (Scene *)id_for_copy, SCE_COPY_LINK_OB); - /* TODO(sergey): Make this part of BKE_scene_copy(). */ - { - SceneLayer *new_scene_layer = (SceneLayer *)new_scene->render_layers.first; - const SceneLayer *scene_layer = (const SceneLayer *)scene->render_layers.first; - while (new_scene_layer != NULL) { - layer_collections_sync_flags(&new_scene_layer->layer_collections, - &scene_layer->layer_collections); - new_scene_layer = new_scene_layer->next; - scene_layer = scene_layer->next; - } - } - #ifdef NESTED_ID_NASTY_WORKAROUND nested_id_hack_restore_pointers(&scene->id, &new_scene->id); #endif diff --git a/tests/python/render_layer/CMakeLists.txt b/tests/python/render_layer/CMakeLists.txt index b3c064289a0..5ff985073e3 100644 --- a/tests/python/render_layer/CMakeLists.txt +++ b/tests/python/render_layer/CMakeLists.txt @@ -170,5 +170,6 @@ RENDER_LAYER_TEST(scene_copy_b) RENDER_LAYER_TEST(scene_copy_c) RENDER_LAYER_TEST(scene_copy_d) RENDER_LAYER_TEST(scene_copy_e) +RENDER_LAYER_TEST(scene_copy_f) RENDER_LAYER_TEST(scene_delete) RENDER_LAYER_TEST(scene_write_read) diff --git a/tests/python/render_layer/test_scene_copy_d.py b/tests/python/render_layer/test_scene_copy_d.py index 54988f49036..f398650eade 100644 --- a/tests/python/render_layer/test_scene_copy_d.py +++ b/tests/python/render_layer/test_scene_copy_d.py @@ -16,7 +16,7 @@ from render_layer_common import * class UnitTesting(RenderLayerTesting): def test_scene_layers_link(self): """ - See if scene copying 'FULL_COPY' is working for scene layers + See if scene copying 'LINK_OBJECTS' is working for scene layers """ import os ROOT = self.get_root() diff --git a/tests/python/render_layer/test_scene_copy_f.py b/tests/python/render_layer/test_scene_copy_f.py new file mode 100644 index 00000000000..fd4298675f2 --- /dev/null +++ b/tests/python/render_layer/test_scene_copy_f.py @@ -0,0 +1,94 @@ +# ############################################################ +# Importing - Same For All Render Layer Tests +# ############################################################ + +import unittest +import os +import sys + +from render_layer_common import * + + +# ############################################################ +# Testing +# ############################################################ + +class UnitTesting(RenderLayerTesting): + def test_shared_layer_collections_copy_full(self): + """ + See if scene copying 'FULL_COPY' is keeping collections visibility + and selectability. + """ + import os + import bpy + + scene = bpy.context.scene + + hide_lookup = [0, 1, 1, 0] + hide_lookup_sub = [1, 0, 1] + + hide_select_lookup = [0, 0, 1, 1] + hide_select_lookup_sub = [1, 0, 1, 0] + new_collections = [] + + # clean everything + for layer in scene.render_layers: + while layer.collections: + layer.collections.unlink(layer.collections[0]) + + # create new collections + for i in range(4): + collection = scene.master_collection.collections.new(str(i)) + new_collections.append(collection) + + for j in range(3): + sub_collection = collection.collections.new("{0}:{1}".format(i, j)) + + # link to the original scene + for layer in scene.render_layers: + for i, collection in enumerate(new_collections): + layer.collections.link(collection) + self.assertEqual(layer.collections[-1], layer.collections[i]) + + layer.collections[i].hide = hide_lookup[i] + layer.collections[i].hide_select = hide_select_lookup[i] + + for j, sub_collection in enumerate(layer.collections[i].collections): + sub_collection.hide = hide_lookup_sub[j] + sub_collection.hide_select = hide_select_lookup_sub[j] + + # copy scene + bpy.ops.scene.new(type='FULL_COPY') + new_scene = bpy.context.scene + self.assertNotEqual(scene, new_scene) + + # update depsgrah + scene.update() # update depsgraph + + # compare scenes + for h, layer in enumerate(scene.render_layers): + new_layer = new_scene.render_layers[h] + + for i, collection in enumerate(layer.collections): + new_collection = new_layer.collections[i] + self.assertEqual(collection.hide, new_collection.hide) + self.assertEqual(collection.hide_select, new_collection.hide_select) + + for j, sub_collection in enumerate(layer.collections[i].collections): + new_sub_collection = new_collection.collections[j] + self.assertEqual(sub_collection.hide, new_sub_collection.hide) + self.assertEqual(sub_collection.hide_select, new_sub_collection.hide_select) + + +# ############################################################ +# Main - Same For All Render Layer Tests +# ############################################################ + +if __name__ == '__main__': + import sys + + extra_arguments = sys.argv[sys.argv.index("--") + 1:] if "--" in sys.argv else [] + sys.argv = [__file__] + (sys.argv[sys.argv.index("--") + 2:] if "--" in sys.argv else []) + + UnitTesting._extra_arguments = extra_arguments + unittest.main()