Merge branch 'master' into blender2.8
authorCampbell Barton <ideasman42@gmail.com>
Fri, 19 Jan 2018 10:44:03 +0000 (21:44 +1100)
committerCampbell Barton <ideasman42@gmail.com>
Fri, 19 Jan 2018 10:47:57 +0000 (21:47 +1100)
19 files changed:
1  2 
source/blender/blenkernel/intern/group.c
source/blender/depsgraph/intern/builder/deg_builder_nodes.cc
source/blender/depsgraph/intern/builder/deg_builder_nodes_layer_collection.cc
source/blender/depsgraph/intern/builder/deg_builder_nodes_rig.cc
source/blender/depsgraph/intern/builder/deg_builder_nodes_view_layer.cc
source/blender/depsgraph/intern/builder/deg_builder_relations.cc
source/blender/depsgraph/intern/builder/deg_builder_relations_layer_collection.cc
source/blender/depsgraph/intern/builder/deg_builder_relations_rig.cc
source/blender/depsgraph/intern/builder/deg_builder_relations_view_layer.cc
source/blender/depsgraph/intern/depsgraph.cc
source/blender/depsgraph/intern/depsgraph_build.cc
source/blender/depsgraph/intern/depsgraph_tag.cc
source/blender/editors/render/render_update.c
source/blender/editors/space_outliner/outliner_collections.c
source/blender/editors/space_outliner/outliner_tree.c
source/blender/editors/transform/transform.c
source/blender/makesdna/DNA_windowmanager_types.h
source/blender/makesrna/intern/rna_wm.c
source/blender/windowmanager/intern/wm_event_system.c

index 8295fafba56121adde78746d005e013c471b4a18,6dc8cc5aff1c30ddfaa8049e276232ff3c6576bf..ca6d92efa80cfa6ce35876d58688e1ae78489893
@@@ -369,45 -367,12 +369,45 @@@ void BKE_group_handle_recalc_and_update
  #endif
        {
                /* only do existing tags, as set by regular depsgraph */
 -              for (go = group->gobject.first; go; go = go->next) {
 -                      if (go->ob) {
 -                              if (go->ob->recalc) {
 -                                      BKE_object_handle_update(eval_ctx, scene, go->ob);
 -                              }
 +              FOREACH_GROUP_OBJECT(group, object)
 +              {
 +                      if (object->id.recalc & ID_RECALC_ALL) {
 +                              BKE_object_handle_update(eval_ctx, scene, object);
                        }
                }
-       LINKLIST_FOREACH (LayerCollection *, layer_collection, layer_collections) {
 +              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);
 +}
index 3502ca694146e01dffc0aa755221e2b878158cbe,8d20a671202f3e5205e20711f4897cb764a51f62..ddae761cea0c32b2f76c99fa4a556cfac34326d1
@@@ -428,40 -304,34 +428,40 @@@ void DepsgraphNodeBuilder::build_group(
                return;
        }
        group_id->tag |= LIB_TAG_DOIT;
 -
 -      BLI_LISTBASE_FOREACH (GroupObject *, go, &group->gobject) {
 -              build_object(base, go->ob);
 +      /* Build group objects. */
-       LINKLIST_FOREACH(Base *, base, &group->view_layer->object_bases) {
++      BLI_LISTBASE_FOREACH (Base *, base, &group->view_layer->object_bases) {
 +              build_object(NULL, base->object, DEG_ID_LINKED_INDIRECTLY);
        }
 +      /* Operation to evaluate the whole view layer.
 +       *
 +       * NOTE: We re-use DONE opcode even though the function does everything.
 +       * This way we wouldn't need to worry about possible relations from DONE,
 +       * regardless whether it's a group or scene or something else.
 +       */
 +      add_id_node(group_id);
 +      Group *group_cow = get_cow_datablock(group);
 +      add_operation_node(group_id,
 +                         DEG_NODE_TYPE_LAYER_COLLECTIONS,
 +                         function_bind(BKE_group_eval_view_layers,
 +                                       _1,
 +                                       group_cow),
 +                         DEG_OPCODE_VIEW_LAYER_DONE);
  }
  
 -void DepsgraphNodeBuilder::build_object(Base *base, Object *object)
 +void DepsgraphNodeBuilder::build_object(Base *base,
 +                                        Object *object,
 +                                        eDepsNode_LinkedState_Type linked_state)
  {
 -      const bool has_object = (object->id.tag & LIB_TAG_DOIT);
 -      IDDepsNode *id_node = (has_object)
 -              ? graph_->find_id_node(&object->id)
 -              : add_id_node(&object->id);
 -      /* Update node layers.
 -       * Do it for both new and existing ID nodes. This is so because several
 -       * bases might be sharing same object.
 -       */
 -      if (base != NULL) {
 -              id_node->layers |= base->lay;
 -      }
 -      if (object->type == OB_CAMERA) {
 -              /* Camera should always be updated, it used directly by viewport.
 -               *
 -               * TODO(sergey): Make it only for active scene camera.
 -               */
 -              id_node->layers |= (unsigned int)(-1);
 -      }
        /* Skip rest of components if the ID node was already there. */
 -      if (has_object) {
 +      if (object->id.tag & LIB_TAG_DOIT) {
 +              IDDepsNode *id_node = find_id_node(&object->id);
 +              /* We need to build some extra stuff if object becomes linked
 +               * directly.
 +               */
 +              if (id_node->linked_state == DEG_ID_LINKED_INDIRECTLY) {
 +                      build_object_flags(base, object, linked_state);
 +              }
 +              id_node->linked_state = max(id_node->linked_state, linked_state);
                return;
        }
        object->id.tag |= LIB_TAG_DOIT;
@@@ -815,10 -627,11 +815,10 @@@ void DepsgraphNodeBuilder::build_rigidb
        sim_node->owner->entry_operation = sim_node;
        sim_node->owner->exit_operation  = sim_node;
  
 -
        /* objects - simulation participants */
        if (rbw->group) {
-               LINKLIST_FOREACH (Base *, base, &rbw->group->view_layer->object_bases) {
 -              BLI_LISTBASE_FOREACH (GroupObject *, go, &rbw->group->gobject) {
 -                      Object *object = go->ob;
++              BLI_LISTBASE_FOREACH (Base *, base, &rbw->group->view_layer->object_bases) {
 +                      Object *object = base->object;
  
                        if (!object || (object->type != OB_MESH))
                                continue;
@@@ -870,24 -674,15 +870,24 @@@ void DepsgraphNodeBuilder::build_partic
                           DEG_OPCODE_PARTICLE_SYSTEM_EVAL_INIT);
  
        /* particle systems */
-       LINKLIST_FOREACH (ParticleSystem *, psys, &object->particlesystem) {
+       BLI_LISTBASE_FOREACH (ParticleSystem *, psys, &object->particlesystem) {
                ParticleSettings *part = psys->part;
  
 -              /* particle settings */
 -              // XXX: what if this is used more than once!
 -              build_animdata(&part->id);
 +              /* Build particle settings operations.
 +               *
 +               * NOTE: The call itself ensures settings are only build once.
 +               */
 +              build_particle_settings(part);
 +
 +              /* Update on particle settings change. */
 +              add_operation_node(psys_comp,
 +                                 function_bind(BKE_particle_system_settings_eval,
 +                                               _1,
 +                                               psys),
 +                                 DEG_OPCODE_PARTICLE_SETTINGS_EVAL,
 +                                 psys->name);
  
 -              /* this particle system */
 -              // TODO: for now, this will just be a placeholder "ubereval" node
 +              /* Particle system evaluation. */
                add_operation_node(psys_comp,
                                   NULL,
                                   DEG_OPCODE_PARTICLE_SYSTEM_EVAL,
@@@ -1206,32 -945,24 +1206,32 @@@ void DepsgraphNodeBuilder::build_lamp(O
  
  void DepsgraphNodeBuilder::build_nodetree(bNodeTree *ntree)
  {
 -      if (!ntree)
 +      if (ntree == NULL) {
                return;
 -
 +      }
        /* nodetree itself */
        ID *ntree_id = &ntree->id;
 -      OperationDepsNode *op_node;
 -
 +      add_id_node(ntree_id);
 +      bNodeTree *ntree_cow = get_cow_datablock(ntree);
 +      /* Animation, */
        build_animdata(ntree_id);
 -
 -      /* Parameters for drivers. */
 -      op_node = add_operation_node(ntree_id,
 -                                   DEG_NODE_TYPE_PARAMETERS,
 -                                   NULL,
 -                                   DEG_OPCODE_PARAMETERS_EVAL);
 -      op_node->set_as_exit();
 -
 +      /* Shading update. */
 +      add_operation_node(ntree_id,
 +                         DEG_NODE_TYPE_SHADING,
 +                         NULL,
 +                         DEG_OPCODE_MATERIAL_UPDATE);
 +      /* NOTE: We really pass original and CoW node trees here, this is how the
 +       * callback works. Ideally we need to find a better way for that.
 +       */
 +      add_operation_node(ntree_id,
 +                         DEG_NODE_TYPE_SHADING_PARAMETERS,
 +                         function_bind(BKE_nodetree_shading_params_eval,
 +                                       _1,
 +                                       ntree_cow,
 +                                       ntree),
 +                         DEG_OPCODE_MATERIAL_UPDATE);
        /* nodetree's nodes... */
-       LINKLIST_FOREACH (bNode *, bnode, &ntree->nodes) {
+       BLI_LISTBASE_FOREACH (bNode *, bnode, &ntree->nodes) {
                ID *id = bnode->id;
                if (id == NULL) {
                        continue;
index 79316e4702248f4ea5ceca62ceb2b67a8bb644da,0000000000000000000000000000000000000000..137a79e7276c46d3b1383de7cc4e86ecf45bace5
mode 100644,000000..100644
--- /dev/null
@@@ -1,126 -1,0 +1,126 @@@
-       LINKLIST_FOREACH (LayerCollection *, layer_collection, layer_collections) {
 +/*
 + * ***** 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.
 + *
 + * The Original Code is Copyright (C) 2013 Blender Foundation.
 + * All rights reserved.
 + *
 + * Original Author: Joshua Leung
 + * Contributor(s): Based on original depsgraph.c code - Blender Foundation (2005-2013)
 + *
 + * ***** END GPL LICENSE BLOCK *****
 + */
 +
 +/** \file blender/depsgraph/intern/builder/deg_builder_nodes_layer_collection.cc
 + *  \ingroup depsgraph
 + *
 + * Methods for constructing depsgraph's nodes
 + */
 +
 +#include "intern/builder/deg_builder_nodes.h"
 +
 +#include <stdio.h>
 +#include <stdlib.h>
 +
 +#include "MEM_guardedalloc.h"
 +
 +extern "C" {
 +#include "BLI_utildefines.h"
 +#include "BLI_listbase.h"
 +#include "BLI_string.h"
 +
 +#include "BKE_layer.h"
 +
 +#include "DNA_scene_types.h"
 +
 +#include "DEG_depsgraph.h"
 +#include "DEG_depsgraph_build.h"
 +} /* extern "C" */
 +
 +#include "intern/builder/deg_builder.h"
 +#include "intern/eval/deg_eval_copy_on_write.h"
 +#include "intern/nodes/deg_node.h"
 +#include "intern/nodes/deg_node_component.h"
 +#include "intern/nodes/deg_node_operation.h"
 +#include "intern/depsgraph_types.h"
 +#include "intern/depsgraph_intern.h"
 +#include "util/deg_util_foreach.h"
 +
 +namespace DEG {
 +
 +void DepsgraphNodeBuilder::build_layer_collection(
 +        ID *owner_id,
 +        LayerCollection *layer_collection,
 +        LayerCollectionState *state)
 +{
 +      /* TODO(sergey): This will attempt to create component for each collection.
 +       * Harmless but could be optimized.
 +       */
 +      ComponentDepsNode *comp = add_component_node(
 +              owner_id,
 +              DEG_NODE_TYPE_LAYER_COLLECTIONS);
 +
 +      add_operation_node(comp,
 +                         function_bind(BKE_layer_eval_layer_collection,
 +                                       _1,
 +                                       layer_collection,
 +                                       state->parent),
 +                         DEG_OPCODE_VIEW_LAYER_EVAL,
 +                         layer_collection->scene_collection->name,
 +                         state->index);
 +      ++state->index;
 +
 +      /* Recurs into nested layer collections. */
 +      LayerCollection *parent = state->parent;
 +      state->parent = layer_collection;
 +      build_layer_collections(owner_id, &layer_collection->layer_collections, state);
 +      state->parent = parent;
 +}
 +
 +void DepsgraphNodeBuilder::build_layer_collections(ID *owner_id,
 +                                                   ListBase *layer_collections,
 +                                                   LayerCollectionState *state)
 +{
++      BLI_LISTBASE_FOREACH (LayerCollection *, layer_collection, layer_collections) {
 +              build_layer_collection(owner_id, layer_collection, state);
 +      }
 +}
 +
 +void DepsgraphNodeBuilder::build_view_layer_collections(
 +        ID *owner_id,
 +        ViewLayer *view_layer)
 +{
 +      LayerCollectionState state;
 +      state.index = 0;
 +      ComponentDepsNode *comp = add_component_node(
 +              owner_id,
 +              DEG_NODE_TYPE_LAYER_COLLECTIONS);
 +      add_operation_node(comp,
 +                         function_bind(BKE_layer_eval_layer_collection_pre,
 +                                       _1,
 +                                       owner_id,
 +                                       view_layer),
 +                         DEG_OPCODE_VIEW_LAYER_INIT);
 +      add_operation_node(comp,
 +                         function_bind(BKE_layer_eval_layer_collection_post,
 +                                       _1,
 +                                       view_layer),
 +                         DEG_OPCODE_VIEW_LAYER_DONE);
 +      state.parent = NULL;
 +      build_layer_collections(owner_id, &view_layer->layer_collections, &state);
 +}
 +
 +}  // namespace DEG
index 531ea55cf5c854f6e67ed93e6afa928ea0d742e8,177a0ec4358f6fa3c6f88ba7f895efefbfb4cb31..2fc42efa440009a1409d0bc6588071d90c456e9f
@@@ -247,7 -195,7 +247,7 @@@ void DepsgraphNodeBuilder::build_rig(Ob
        op_node->set_as_exit();
  
        /* bones */
-       LINKLIST_FOREACH (bPoseChannel *, pchan, &object_cow->pose->chanbase) {
 -      BLI_LISTBASE_FOREACH (bPoseChannel *, pchan, &object->pose->chanbase) {
++      BLI_LISTBASE_FOREACH (bPoseChannel *, pchan, &object_cow->pose->chanbase) {
                /* Node for bone evaluation. */
                op_node = add_operation_node(&object->id, DEG_NODE_TYPE_BONE, pchan->name, NULL,
                                             DEG_OPCODE_BONE_LOCAL);
                 *   base transforms of a bunch of bones is done)
                 *
                 * Unsolved Issues:
 -               * - Care is needed to ensure that multi-headed trees work out the same as in ik-tree building
 -               * - Animated chain-lengths are a problem...
 +               * - Care is needed to ensure that multi-headed trees work out the same
 +               *   as in ik-tree building
 +               * - Animated chain-lengths are a problem.
                 */
-               LINKLIST_FOREACH (bConstraint *, con, &pchan->constraints) {
+               BLI_LISTBASE_FOREACH (bConstraint *, con, &pchan->constraints) {
                        switch (con->type) {
                                case CONSTRAINT_TYPE_KINEMATIC:
                                        build_ik_pose(object, pchan, con);
@@@ -321,52 -257,33 +321,52 @@@ void DepsgraphNodeBuilder::build_proxy_
  {
        bArmature *arm = (bArmature *)object->data;
        OperationDepsNode *op_node;
 -
 -      build_animdata(&arm->id);
 -
 +      Object *object_cow;
 +      if (DEG_depsgraph_use_copy_on_write()) {
 +              /* NOTE: We need to expand both object and armature, so this way we can
 +               * safely create object level pose.
 +               */
 +              object_cow = expand_cow_datablock(object);
 +      }
 +      else {
 +              object_cow = object;
 +      }
 +      /* Sanity check. */
        BLI_assert(object->pose != NULL);
 -
 +      /* Animation. */
 +      build_animdata(&arm->id);
        /* speed optimization for animation lookups */
        BKE_pose_channels_hash_make(object->pose);
 -      if (object->pose->flag & POSE_CONSTRAINTS_NEED_UPDATE_FLAGS) {
 -              BKE_pose_update_constraint_flags(object->pose);
 +      if (object_cow->pose->flag & POSE_CONSTRAINTS_NEED_UPDATE_FLAGS) {
 +              BKE_pose_update_constraint_flags(object_cow->pose);
        }
 -
        op_node = add_operation_node(&object->id,
                                     DEG_NODE_TYPE_EVAL_POSE,
 -                                   function_bind(BKE_pose_eval_proxy_copy, _1, object),
 +                                   function_bind(BKE_pose_eval_proxy_copy,
 +                                                 _1,
 +                                                 object_cow),
                                     DEG_OPCODE_POSE_INIT);
        op_node->set_as_entry();
-       LINKLIST_FOREACH (bPoseChannel *, pchan, &object_cow->pose->chanbase) {
 -
 -      BLI_LISTBASE_FOREACH (bPoseChannel *, pchan, &object->pose->chanbase) {
 -              op_node = add_operation_node(&object->id, DEG_NODE_TYPE_BONE, pchan->name,
 -                                           NULL, DEG_OPCODE_BONE_LOCAL);
++      BLI_LISTBASE_FOREACH (bPoseChannel *, pchan, &object_cow->pose->chanbase) {
 +              /* Local bone transform. */
 +              op_node = add_operation_node(&object->id,
 +                                           DEG_NODE_TYPE_BONE,
 +                                           pchan->name,
 +                                           NULL,
 +                                           DEG_OPCODE_BONE_LOCAL);
                op_node->set_as_entry();
 -
 -              add_operation_node(&object->id, DEG_NODE_TYPE_BONE, pchan->name,
 -                                 NULL, DEG_OPCODE_BONE_READY);
 -
 -              op_node = add_operation_node(&object->id, DEG_NODE_TYPE_BONE, pchan->name,
 -                                           NULL, DEG_OPCODE_BONE_DONE);
 +              /* Bone is ready for solvers. */
 +              add_operation_node(&object->id,
 +                                 DEG_NODE_TYPE_BONE,
 +                                 pchan->name,
 +                                 NULL,
 +                                 DEG_OPCODE_BONE_READY);
 +              /* Bone is fully evaluated. */
 +              op_node = add_operation_node(&object->id,
 +                                           DEG_NODE_TYPE_BONE,
 +                                           pchan->name,
 +                                           NULL,
 +                                           DEG_OPCODE_BONE_DONE);
                op_node->set_as_exit();
  
                /* Custom properties. */
index 49772c4f8522be6b6328c9fb500154355db8f8bc,0000000000000000000000000000000000000000..4ca19f4e14fcd4b44036b987d8eef74793989f2f
mode 100644,000000..100644
--- /dev/null
@@@ -1,174 -1,0 +1,174 @@@
-               LINKLIST_FOREACH(Base *, base, &view_layer->object_bases) {
 +/*
 + * ***** 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.
 + *
 + * The Original Code is Copyright (C) 2013 Blender Foundation.
 + * All rights reserved.
 + *
 + * Original Author: Joshua Leung
 + * Contributor(s): Based on original depsgraph.c code - Blender Foundation (2005-2013)
 + *
 + * ***** END GPL LICENSE BLOCK *****
 + */
 +
 +/** \file blender/depsgraph/intern/builder/deg_builder_nodes_view_layer.cc
 + *  \ingroup depsgraph
 + *
 + * Methods for constructing depsgraph's nodes
 + */
 +
 +#include "intern/builder/deg_builder_nodes.h"
 +
 +#include <stdio.h>
 +#include <stdlib.h>
 +
 +#include "MEM_guardedalloc.h"
 +
 +#include "BLI_utildefines.h"
 +#include "BLI_blenlib.h"
 +#include "BLI_string.h"
 +
 +extern "C" {
 +#include "DNA_node_types.h"
 +#include "DNA_layer_types.h"
 +#include "DNA_object_types.h"
 +#include "DNA_scene_types.h"
 +
 +#include "BKE_layer.h"
 +#include "BKE_main.h"
 +#include "BKE_node.h"
 +} /* extern "C" */
 +
 +#include "DEG_depsgraph.h"
 +#include "DEG_depsgraph_build.h"
 +
 +#include "intern/builder/deg_builder.h"
 +#include "intern/nodes/deg_node.h"
 +#include "intern/nodes/deg_node_component.h"
 +#include "intern/nodes/deg_node_operation.h"
 +#include "intern/depsgraph_types.h"
 +#include "intern/depsgraph_intern.h"
 +#include "util/deg_util_foreach.h"
 +
 +namespace DEG {
 +
 +void DepsgraphNodeBuilder::build_view_layer(
 +        Scene *scene,
 +        ViewLayer *view_layer,
 +        eDepsNode_LinkedState_Type linked_state)
 +{
 +      /* Scene ID block. */
 +      add_id_node(&scene->id);
 +      /* Time source. */
 +      add_time_source();
 +      /* Setup currently building context. */
 +      scene_ = scene;
 +      /* Expand Scene Cow datablock to get proper pointers to bases. */
 +      Scene *scene_cow;
 +      ViewLayer *view_layer_cow;
 +      if (DEG_depsgraph_use_copy_on_write()) {
 +              /* NOTE: We need to create ID nodes for all objects coming from bases,
 +               * otherwise remapping will not replace objects with their CoW versions
 +               * for CoW bases.
 +               */
-       LINKLIST_FOREACH (CacheFile *, cachefile, &bmain_->cachefiles) {
++              BLI_LISTBASE_FOREACH (Base *, base, &view_layer->object_bases) {
 +                      Object *object = base->object;
 +                      add_id_node(&object->id, false);
 +              }
 +              /* Create ID node for nested ID of nodetree as well, otherwise remapping
 +               * will not work correct either.
 +               */
 +              if (scene->nodetree != NULL) {
 +                      add_id_node(&scene->nodetree->id, false);
 +              }
 +              /* Make sure we've got ID node, so we can get pointer to CoW datablock.
 +               */
 +              scene_cow = expand_cow_datablock(scene);
 +              view_layer_cow = (ViewLayer *)BLI_findstring(
 +                      &scene_cow->view_layers,
 +                      view_layer->name,
 +                      offsetof(ViewLayer, name));
 +      }
 +      else {
 +              scene_cow = scene;
 +              view_layer_cow = view_layer;
 +      }
 +      /* Scene objects. */
 +      int select_color = 1;
 +      /* NOTE: Base is used for function bindings as-is, so need to pass CoW base,
 +       * but object is expected to be an original one. Hence we go into some
 +       * tricks here iterating over the view layer.
 +       */
 +      for (Base *base_orig = (Base *)view_layer->object_bases.first,
 +                *base_cow = (Base *)view_layer_cow->object_bases.first;
 +           base_orig != NULL;
 +           base_orig = base_orig->next, base_cow = base_cow->next)
 +      {
 +              /* object itself */
 +              build_object(base_cow, base_orig->object, linked_state);
 +              base_orig->object->select_color = select_color++;
 +      }
 +      if (scene->camera != NULL) {
 +              build_object(NULL, scene->camera, DEG_ID_LINKED_INDIRECTLY);
 +      }
 +      /* Rigidbody. */
 +      if (scene->rigidbody_world != NULL) {
 +              build_rigidbody(scene);
 +      }
 +      /* Scene's animation and drivers. */
 +      if (scene->adt != NULL) {
 +              build_animdata(&scene->id);
 +      }
 +      /* World. */
 +      if (scene->world != NULL) {
 +              build_world(scene->world);
 +      }
 +      /* Compositor nodes */
 +      if (scene->nodetree != NULL) {
 +              build_compositor(scene);
 +      }
 +      /* Grease pencil. */
 +      if (scene->gpd != NULL) {
 +              build_gpencil(scene->gpd);
 +      }
 +      /* Cache file. */
-       LINKLIST_FOREACH (Mask *, mask, &bmain_->mask) {
++      BLI_LISTBASE_FOREACH (CacheFile *, cachefile, &bmain_->cachefiles) {
 +              build_cachefile(cachefile);
 +      }
 +      /* Masks. */
-       LINKLIST_FOREACH (MovieClip *, clip, &bmain_->movieclip) {
++      BLI_LISTBASE_FOREACH (Mask *, mask, &bmain_->mask) {
 +              build_mask(mask);
 +      }
 +      /* Movie clips. */
++      BLI_LISTBASE_FOREACH (MovieClip *, clip, &bmain_->movieclip) {
 +              build_movieclip(clip);
 +      }
 +      /* Collections. */
 +      build_view_layer_collections(&scene->id, view_layer_cow);
 +      /* Parameters evaluation for scene relations mainly. */
 +      add_operation_node(&scene->id,
 +                         DEG_NODE_TYPE_PARAMETERS,
 +                         NULL,
 +                         DEG_OPCODE_PLACEHOLDER,
 +                         "Scene Eval");
 +      /* Build all set scenes. */
 +      if (scene->set != NULL) {
 +              ViewLayer *set_view_layer = BKE_view_layer_from_scene_get(scene->set);
 +              build_view_layer(scene->set, set_view_layer, DEG_ID_LINKED_VIA_SET);
 +      }
 +}
 +
 +}  // namespace DEG
index 077bdd94f562f5d73815d5241663dbc67d813848,81daa8cfb8cd209571be7a974d7ae291f590f108..3cd239bff2852f451590d59e7224271f118c511a
@@@ -345,9 -347,9 +345,9 @@@ void DepsgraphRelationBuilder::add_forc
          bool add_absorption,
          const char *name)
  {
 -      ListBase *effectors = pdInitEffectors(scene, object, psys, eff, false);
 +      ListBase *effectors = pdInitEffectors(NULL, scene, object, psys, eff, false);
        if (effectors != NULL) {
-               LINKLIST_FOREACH(EffectorCache *, eff, effectors) {
 -              BLI_LISTBASE_FOREACH(EffectorCache *, eff, effectors) {
++              BLI_LISTBASE_FOREACH (EffectorCache *, eff, effectors) {
                        if (eff->ob != object) {
                                ComponentKey eff_key(&eff->ob->id, DEG_NODE_TYPE_TRANSFORM);
                                add_relation(eff_key, key, name);
@@@ -426,26 -429,19 +426,26 @@@ void DepsgraphRelationBuilder::build_gr
        OperationKey object_local_transform_key(&object->id,
                                                DEG_NODE_TYPE_TRANSFORM,
                                                DEG_OPCODE_TRANSFORM_LOCAL);
 -      BLI_LISTBASE_FOREACH (GroupObject *, go, &group->gobject) {
 -              if (!group_done) {
 -                      build_object(go->ob);
 +
 +      if (!group_done) {
-               LINKLIST_FOREACH(Base *, base, &group->view_layer->object_bases) {
++              BLI_LISTBASE_FOREACH (Base *, base, &group->view_layer->object_bases) {
 +                      build_object(NULL, base->object);
                }
 -              ComponentKey dupli_transform_key(&go->ob->id, DEG_NODE_TYPE_TRANSFORM);
 +              group_id->tag |= LIB_TAG_DOIT;
 +      }
 +
-       LINKLIST_FOREACH (Base *, base, &group->view_layer->object_bases) {
++      BLI_LISTBASE_FOREACH (Base *, base, &group->view_layer->object_bases) {
 +              ComponentKey dupli_transform_key(&base->object->id, DEG_NODE_TYPE_TRANSFORM);
                add_relation(dupli_transform_key, object_local_transform_key, "Dupligroup");
        }
 -      group_id->tag |= LIB_TAG_DOIT;
  }
  
 -void DepsgraphRelationBuilder::build_object(Object *object)
 +void DepsgraphRelationBuilder::build_object(Base *base, Object *object)
  {
        if (object->id.tag & LIB_TAG_DOIT) {
 +              if (base != NULL) {
 +                      build_object_flags(base, object);
 +              }
                return;
        }
        object->id.tag |= LIB_TAG_DOIT;
@@@ -961,7 -938,7 +961,7 @@@ void DepsgraphRelationBuilder::build_an
        /* Iterate over all curves and build relations. */
        PointerRNA id_ptr;
        RNA_id_pointer_create(id, &id_ptr);
-       LINKLIST_FOREACH(FCurve *, fcu, &adt->action->curves) {
 -      BLI_LISTBASE_FOREACH(FCurve *, fcu, &adt->action->curves) {
++      BLI_LISTBASE_FOREACH (FCurve *, fcu, &adt->action->curves) {
                PointerRNA ptr;
                PropertyRNA *prop;
                int index;
@@@ -1268,8 -1245,8 +1268,8 @@@ void DepsgraphRelationBuilder::build_ri
  
        /* objects - simulation participants */
        if (rbw->group) {
-               LINKLIST_FOREACH (Base *, base, &rbw->group->view_layer->object_bases) {
 -              BLI_LISTBASE_FOREACH (GroupObject *, go, &rbw->group->gobject) {
 -                      Object *object = go->ob;
++              BLI_LISTBASE_FOREACH (Base *, base, &rbw->group->view_layer->object_bases) {
 +                      Object *object = base->object;
                        if (object == NULL || object->type != OB_MESH) {
                                continue;
                        }
  
        /* constraints */
        if (rbw->constraints) {
-               LINKLIST_FOREACH (Base *, base, &rbw->constraints->view_layer->object_bases) {
 -              BLI_LISTBASE_FOREACH (GroupObject *, go, &rbw->constraints->gobject) {
 -                      Object *object = go->ob;
++              BLI_LISTBASE_FOREACH (Base *, base, &rbw->constraints->view_layer->object_bases) {
 +                      Object *object = base->object;
                        if (object == NULL || !object->rigidbody_constraint) {
                                continue;
                        }
@@@ -1358,38 -1335,14 +1358,38 @@@ void DepsgraphRelationBuilder::build_pa
                                   DEG_OPCODE_PARTICLE_SYSTEM_EVAL_INIT);
  
        /* particle systems */
-       LINKLIST_FOREACH (ParticleSystem *, psys, &object->particlesystem) {
+       BLI_LISTBASE_FOREACH (ParticleSystem *, psys, &object->particlesystem) {
                ParticleSettings *part = psys->part;
  
 -              /* particle settings */
 -              build_animdata(&part->id);
 -
 -              /* this particle system */
 -              OperationKey psys_key(&object->id, DEG_NODE_TYPE_EVAL_PARTICLES, DEG_OPCODE_PARTICLE_SYSTEM_EVAL, psys->name);
 +              /* Build particle settings relations.
 +               *
 +               * NOTE: The call itself ensures settings are only build once.
 +               */
 +              build_particle_settings(part);
 +
 +              /* This particle system. */
 +              OperationKey psys_key(&object->id,
 +                                    DEG_NODE_TYPE_EVAL_PARTICLES,
 +                                    DEG_OPCODE_PARTICLE_SYSTEM_EVAL,
 +                                    psys->name);
 +
 +              /* Update particle system when settings changes. */
 +              OperationKey particle_settings_key(&part->id,
 +                                                 DEG_NODE_TYPE_PARAMETERS,
 +                                                 DEG_OPCODE_PARTICLE_SETTINGS_EVAL);
 +              OperationKey particle_settings_recalc_clear_key(
 +                      &part->id,
 +                      DEG_NODE_TYPE_PARAMETERS,
 +                      DEG_OPCODE_PARTICLE_SETTINGS_RECALC_CLEAR);
 +              OperationKey psys_settings_key(&object->id,
 +                                             DEG_NODE_TYPE_EVAL_PARTICLES,
 +                                             DEG_OPCODE_PARTICLE_SETTINGS_EVAL,
 +                                             psys->name);
 +              add_relation(particle_settings_key, psys_settings_key, "Particle Settings Change");
 +              add_relation(psys_settings_key, psys_key, "Particle Settings Update");
 +              add_relation(psys_key,
 +                           particle_settings_recalc_clear_key,
 +                           "Particle Settings Recalc Clear");
  
                /* XXX: if particle system is later re-enabled, we must do full rebuild? */
                if (!psys_check_enabled(object, psys, G.is_rendering))
@@@ -1567,23 -1482,13 +1567,23 @@@ void DepsgraphRelationBuilder::build_ob
        /* link components to each other */
        add_relation(obdata_geom_key, geom_key, "Object Geometry Base Data");
  
 +      OperationKey obdata_ubereval_key(&object->id,
 +                                       DEG_NODE_TYPE_GEOMETRY,
 +                                       DEG_OPCODE_GEOMETRY_UBEREVAL);
 +
 +      /* Special case: modifiers and DerivedMesh creation queries scene for various
 +       * things like data mask to be used. We add relation here to ensure object is
 +       * never evaluated prior to Scene's CoW is ready.
 +       */
 +      OperationKey scene_key(&scene_->id,
 +                             DEG_NODE_TYPE_PARAMETERS,
 +                             DEG_OPCODE_PLACEHOLDER,
 +                             "Scene Eval");
 +      add_relation(scene_key, obdata_ubereval_key, "CoW Relation");
 +
        /* Modifiers */
        if (object->modifiers.first != NULL) {
-               LINKLIST_FOREACH (ModifierData *, md, &object->modifiers) {
 -              OperationKey obdata_ubereval_key(&object->id,
 -                                               DEG_NODE_TYPE_GEOMETRY,
 -                                               DEG_OPCODE_GEOMETRY_UBEREVAL);
 -
+               BLI_LISTBASE_FOREACH (ModifierData *, md, &object->modifiers) {
                        const ModifierTypeInfo *mti = modifierType_getInfo((ModifierType)md->type);
                        if (mti->updateDepsgraph) {
                                DepsNodeHandle handle = create_node_handle(obdata_ubereval_key);
@@@ -1797,14 -1669,19 +1797,14 @@@ void DepsgraphRelationBuilder::build_la
  
  void DepsgraphRelationBuilder::build_nodetree(bNodeTree *ntree)
  {
 -      if (!ntree)
 +      if (ntree == NULL) {
                return;
 -
 +      }
        ID *ntree_id = &ntree->id;
 -
        build_animdata(ntree_id);
 -
 -      OperationKey parameters_key(ntree_id,
 -                                  DEG_NODE_TYPE_PARAMETERS,
 -                                  DEG_OPCODE_PARAMETERS_EVAL);
 -
 +      ComponentKey shading_key(ntree_id, DEG_NODE_TYPE_SHADING);
        /* nodetree's nodes... */
-       LINKLIST_FOREACH (bNode *, bnode, &ntree->nodes) {
+       BLI_LISTBASE_FOREACH (bNode *, bnode, &ntree->nodes) {
                ID *id = bnode->id;
                if (id == NULL) {
                        continue;
index 452bd7b19e7c6e68adc1ca2306ed21737c4740ab,0000000000000000000000000000000000000000..9cf82b5fb47f8d31ce620e8f919dfc5004def530
mode 100644,000000..100644
--- /dev/null
@@@ -1,124 -1,0 +1,124 @@@
-       LINKLIST_FOREACH (LayerCollection *, layer_collection, layer_collections) {
 +/*
 + * ***** 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.
 + *
 + * The Original Code is Copyright (C) 2013 Blender Foundation.
 + * All rights reserved.
 + *
 + * Original Author: Joshua Leung
 + * Contributor(s): Based on original depsgraph.c code - Blender Foundation (2005-2013)
 + *
 + * ***** END GPL LICENSE BLOCK *****
 + */
 +
 +/** \file blender/depsgraph/intern/builder/deg_builder_relations_layer_collection.cc
 + *  \ingroup depsgraph
 + *
 + * Methods for constructing depsgraph
 + */
 +
 +#include "intern/builder/deg_builder_relations.h"
 +
 +#include <stdio.h>
 +#include <stdlib.h>
 +#include <cstring>  /* required for STREQ later on. */
 +
 +#include "MEM_guardedalloc.h"
 +
 +extern "C" {
 +#include "BLI_blenlib.h"
 +#include "BLI_utildefines.h"
 +
 +#include "DNA_node_types.h"
 +#include "DNA_object_types.h"
 +#include "DNA_scene_types.h"
 +
 +#include "BKE_layer.h"
 +#include "BKE_main.h"
 +#include "BKE_node.h"
 +
 +#include "DEG_depsgraph.h"
 +#include "DEG_depsgraph_build.h"
 +} /* extern "C" */
 +
 +#include "intern/builder/deg_builder.h"
 +#include "intern/builder/deg_builder_pchanmap.h"
 +
 +#include "intern/nodes/deg_node.h"
 +#include "intern/nodes/deg_node_component.h"
 +#include "intern/nodes/deg_node_operation.h"
 +
 +#include "intern/depsgraph_intern.h"
 +#include "intern/depsgraph_types.h"
 +
 +#include "util/deg_util_foreach.h"
 +
 +namespace DEG {
 +
 +void DepsgraphRelationBuilder::build_layer_collection(
 +        ID *owner_id,
 +        LayerCollection *layer_collection,
 +        LayerCollectionState *state)
 +{
 +      OperationKey layer_key(owner_id,
 +                             DEG_NODE_TYPE_LAYER_COLLECTIONS,
 +                             DEG_OPCODE_VIEW_LAYER_EVAL,
 +                             layer_collection->scene_collection->name,
 +                             state->index);
 +      add_relation(state->prev_key, layer_key, "Layer collection order");
 +
 +      ++state->index;
 +      state->prev_key = layer_key;
 +
 +      /* Recurs into nested layer collections. */
 +      build_layer_collections(owner_id, &layer_collection->layer_collections, state);
 +}
 +
 +void DepsgraphRelationBuilder::build_layer_collections(
 +        ID *owner_id,
 +        ListBase *layer_collections,
 +        LayerCollectionState *state)
 +{
++      BLI_LISTBASE_FOREACH (LayerCollection *, layer_collection, layer_collections) {
 +              /* Recurs into the layer. */
 +              build_layer_collection(owner_id, layer_collection, state);
 +      }
 +}
 +
 +void DepsgraphRelationBuilder::build_view_layer_collections(
 +        ID *owner_id,
 +        ViewLayer *view_layer)
 +{
 +      LayerCollectionState state;
 +      state.index = 0;
 +
 +      OperationKey init_key(owner_id,
 +                            DEG_NODE_TYPE_LAYER_COLLECTIONS,
 +                            DEG_OPCODE_VIEW_LAYER_INIT);
 +      OperationKey done_key(owner_id,
 +                            DEG_NODE_TYPE_LAYER_COLLECTIONS,
 +                            DEG_OPCODE_VIEW_LAYER_DONE);
 +
 +      state.init_key = init_key;
 +      state.done_key = done_key;
 +      state.prev_key = init_key;
 +
 +      build_layer_collections(owner_id, &view_layer->layer_collections, &state);
 +
 +      add_relation(state.prev_key, done_key, "Layer collection order");
 +}
 +
 +}  // namespace DEG
index 9b3e46df69a228c280d4c7ba4a26efd7c01c048a,0000000000000000000000000000000000000000..cfb98fe2f79be210a05dffaafbeed419413febdd
mode 100644,000000..100644
--- /dev/null
@@@ -1,136 -1,0 +1,136 @@@
-       LINKLIST_FOREACH(Base *, base, &view_layer->object_bases) {
 +/*
 + * ***** 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.
 + *
 + * The Original Code is Copyright (C) 2013 Blender Foundation.
 + * All rights reserved.
 + *
 + * Original Author: Joshua Leung
 + * Contributor(s): Based on original depsgraph.c code - Blender Foundation (2005-2013)
 + *
 + * ***** END GPL LICENSE BLOCK *****
 + */
 +
 +/** \file blender/depsgraph/intern/builder/deg_builder_relations_view_layer.cc
 + *  \ingroup depsgraph
 + *
 + * Methods for constructing depsgraph
 + */
 +
 +#include "intern/builder/deg_builder_relations.h"
 +
 +#include <stdio.h>
 +#include <stdlib.h>
 +#include <cstring>  /* required for STREQ later on. */
 +
 +#include "MEM_guardedalloc.h"
 +
 +#include "BLI_utildefines.h"
 +#include "BLI_blenlib.h"
 +
 +extern "C" {
 +#include "DNA_node_types.h"
 +#include "DNA_object_types.h"
 +#include "DNA_scene_types.h"
 +
 +#include "BKE_layer.h"
 +#include "BKE_main.h"
 +#include "BKE_node.h"
 +} /* extern "C" */
 +
 +#include "DEG_depsgraph.h"
 +#include "DEG_depsgraph_build.h"
 +
 +#include "intern/builder/deg_builder.h"
 +#include "intern/builder/deg_builder_pchanmap.h"
 +
 +#include "intern/nodes/deg_node.h"
 +#include "intern/nodes/deg_node_component.h"
 +#include "intern/nodes/deg_node_id.h"
 +#include "intern/nodes/deg_node_operation.h"
 +
 +#include "intern/depsgraph_intern.h"
 +#include "intern/depsgraph_types.h"
 +
 +#include "util/deg_util_foreach.h"
 +
 +namespace DEG {
 +
 +void DepsgraphRelationBuilder::build_view_layer(Scene *scene, ViewLayer *view_layer)
 +{
 +      /* Setup currently building context. */
 +      scene_ = scene;
 +      /* Scene objects. */
 +      /* NOTE: Nodes builder requires us to pass CoW base because it's being
 +       * passed to the evaluation functions. During relations builder we only
 +       * do NULL-pointer check of the base, so it's fine to pass original one.
 +       */
-       LINKLIST_FOREACH (Mask *, mask, &bmain_->mask) {
++      BLI_LISTBASE_FOREACH (Base *, base, &view_layer->object_bases) {
 +              build_object(base, base->object);
 +      }
 +      if (scene->camera != NULL) {
 +              build_object(NULL, scene->camera);
 +      }
 +      /* Rigidbody. */
 +      if (scene->rigidbody_world != NULL) {
 +              build_rigidbody(scene);
 +      }
 +      /* Scene's animation and drivers. */
 +      if (scene->adt != NULL) {
 +              build_animdata(&scene->id);
 +      }
 +      /* World. */
 +      if (scene->world != NULL) {
 +              build_world(scene->world);
 +      }
 +      /* Compositor nodes. */
 +      if (scene->nodetree != NULL) {
 +              build_compositor(scene);
 +      }
 +      /* Grease pencil. */
 +      if (scene->gpd != NULL) {
 +              build_gpencil(scene->gpd);
 +      }
 +      /* Masks. */
-       LINKLIST_FOREACH (MovieClip *, clip, &bmain_->movieclip) {
++      BLI_LISTBASE_FOREACH (Mask *, mask, &bmain_->mask) {
 +              build_mask(mask);
 +      }
 +      /* Movie clips. */
++      BLI_LISTBASE_FOREACH (MovieClip *, clip, &bmain_->movieclip) {
 +              build_movieclip(clip);
 +      }
 +      /* Collections. */
 +      build_view_layer_collections(&scene_->id, view_layer);
 +      /* TODO(sergey): Do this flush on CoW object? */
 +      foreach (OperationDepsNode *node, graph_->operations) {
 +              IDDepsNode *id_node = node->owner->owner;
 +              ID *id = id_node->id_orig;
 +              if (GS(id->name) == ID_OB) {
 +                      Object *object = (Object *)id;
 +                      object->customdata_mask |= node->customdata_mask;
 +              }
 +      }
 +      /* Build all set scenes. */
 +      if (scene->set != NULL) {
 +              ViewLayer *set_view_layer = BKE_view_layer_from_scene_get(scene->set);
 +              build_view_layer(scene->set, set_view_layer);
 +      }
 +
 +      graph_->scene = scene;
 +      graph_->view_layer = view_layer;
 +}
 +
 +}  // namespace DEG
index 5b07630240d133e3bad8a45a5cf946700d9e02e5,3884cfe49e7c50f3154de62c9dea1247a61a2d7f..902cbe039cdf608a4c420ee46b30185f5a604339
@@@ -287,23 -282,34 +287,23 @@@ void DEG_graph_relations_update(Depsgra
                /* Graph is up to date, nothing to do. */
                return;
        }
 -
 -      /* Clear all previous nodes and operations. */
 -      graph->clear_all_nodes();
 -      graph->operations.clear();
 -      BLI_gset_clear(graph->entry_tags, NULL);
 -
 -      /* Build new nodes and relations. */
 -      DEG_graph_build_from_scene(reinterpret_cast< ::Depsgraph * >(graph),
 -                                 bmain,
 -                                 scene);
 -
 -      graph->need_update = false;
 -}
 -
 -/* Rebuild dependency graph only for a given scene. */
 -void DEG_scene_relations_rebuild(Main *bmain, Scene *scene)
 -{
 -      if (scene->depsgraph != NULL) {
 -              DEG_graph_tag_relations_update(scene->depsgraph);
 -      }
 -      DEG_scene_relations_update(bmain, scene);
 +      DEG_graph_build_from_view_layer(graph, bmain, scene, view_layer);
  }
  
 -void DEG_scene_graph_free(Scene *scene)
 +/* Tag all relations for update. */
 +void DEG_relations_tag_update(Main *bmain)
  {
 -      if (scene->depsgraph) {
 -              DEG_graph_free(scene->depsgraph);
 -              scene->depsgraph = NULL;
 +      DEG_DEBUG_PRINTF("%s: Tagging relations for update.\n", __func__);
-       LINKLIST_FOREACH(Scene *, scene, &bmain->scene) {
-               LINKLIST_FOREACH(ViewLayer *, view_layer, &scene->view_layers) {
++      BLI_LISTBASE_FOREACH (Scene *, scene, &bmain->scene) {
++              BLI_LISTBASE_FOREACH (ViewLayer *, view_layer, &scene->view_layers) {
 +                      Depsgraph *depsgraph =
 +                              (Depsgraph *)BKE_scene_get_depsgraph(scene,
 +                                                                   view_layer,
 +                                                                   false);
 +                      if (depsgraph != NULL) {
 +                              DEG_graph_tag_relations_update(depsgraph);
 +                      }
 +              }
        }
  }
  
index f364ac52b38aab2eca9de2fdc014ddb4511cb495,a66c61e4c0f995d3bb6bb9e8054b85e18ee7a845..e7c1308334328a7d65cc7351229fc47752cb64c9
@@@ -319,46 -151,20 +319,46 @@@ void deg_graph_id_tag_update_single_fla
                }
        }
  }
 -#endif
  
 -}  /* namespace */
 +void deg_graph_id_tag_update(Main *bmain, Depsgraph *graph, ID *id, int flag)
 +{
 +      IDDepsNode *id_node = (graph != NULL) ? graph->find_id_node(id)
 +                                            : NULL;
 +      DEG_id_type_tag(bmain, GS(id->name));
 +      if (flag == 0) {
 +              /* TODO(sergey): Which recalc flags to set here? */
 +              id->recalc |= ID_RECALC_ALL;
 +              if (id_node != NULL) {
 +                      id_node->tag_update(graph);
 +              }
 +      }
 +      int current_flag = flag;
 +      while (current_flag != 0) {
 +              eDepsgraph_Tag tag =
 +                      (eDepsgraph_Tag)(1 << bitscan_forward_clear_i(&current_flag));
 +              deg_graph_id_tag_update_single_flag(bmain,
 +                                                  graph,
 +                                                  id,
 +                                                  id_node,
 +                                                  tag);
 +      }
 +      /* Special case for nested node tree datablocks. */
 +      id_tag_update_ntree_special(bmain, graph, id, flag);
 +}
  
 -/* Tag all nodes in ID-block for update.
 - * This is a crude measure, but is most convenient for old code.
 - */
 -void DEG_graph_id_tag_update(Main *bmain, Depsgraph *graph, ID *id)
 +void deg_id_tag_update(Main *bmain, ID *id, int flag)
  {
 -      DEG::Depsgraph *deg_graph = reinterpret_cast<DEG::Depsgraph *>(graph);
 -      DEG::IDDepsNode *node = deg_graph->find_id_node(id);
 -      lib_id_recalc_tag(bmain, id);
 -      if (node != NULL) {
 -              node->tag_update(deg_graph);
 +      deg_graph_id_tag_update(bmain, NULL, id, flag);
-       LINKLIST_FOREACH(Scene *, scene, &bmain->scene) {
-               LINKLIST_FOREACH(ViewLayer *, view_layer, &scene->view_layers) {
++      BLI_LISTBASE_FOREACH (Scene *, scene, &bmain->scene) {
++              BLI_LISTBASE_FOREACH (ViewLayer *, view_layer, &scene->view_layers) {
 +                      Depsgraph *depsgraph =
 +                              (Depsgraph *)BKE_scene_get_depsgraph(scene,
 +                                                                   view_layer,
 +                                                                   false);
 +                      if (depsgraph != NULL) {
 +                              deg_graph_id_tag_update(bmain, depsgraph, id, flag);
 +                      }
 +              }
        }
  }
  
@@@ -455,15 -356,12 +455,15 @@@ void DEG_graph_on_visible_update(Main *
  
  void DEG_on_visible_update(Main *bmain, const bool UNUSED(do_time))
  {
-       LINKLIST_FOREACH(Scene *, scene, &bmain->scene) {
-               LINKLIST_FOREACH(ViewLayer *, view_layer, &scene->view_layers) {
 -      for (Scene *scene = (Scene *)bmain->scene.first;
 -           scene != NULL;
 -           scene = (Scene *)scene->id.next)
 -      {
 -              if (scene->depsgraph != NULL) {
 -                      DEG_graph_on_visible_update(bmain, scene);
++      BLI_LISTBASE_FOREACH (Scene *, scene, &bmain->scene) {
++              BLI_LISTBASE_FOREACH (ViewLayer *, view_layer, &scene->view_layers) {
 +                      Depsgraph *depsgraph =
 +                              (Depsgraph *)BKE_scene_get_depsgraph(scene,
 +                                                                   view_layer,
 +                                                                   false);
 +                      if (depsgraph != NULL) {
 +                              DEG_graph_on_visible_update(bmain, depsgraph);
 +                      }
                }
        }
  }
index f7ede2518731d717a01d6567347d7f937fc0e282,4e02ff77a3175fb7faec95abd43887e14768d2b4..eebe69b7a197f76c0a7b878d82d18c5793f75e78
@@@ -191,23 -179,18 +191,23 @@@ void ED_render_engine_area_exit(Main *b
  void ED_render_engine_changed(Main *bmain)
  {
        /* on changing the render engine type, clear all running render engines */
 -      bScreen *sc;
 -      ScrArea *sa;
 -      Scene *scene;
 -
 -      for (sc = bmain->screen.first; sc; sc = sc->id.next)
 -              for (sa = sc->areabase.first; sa; sa = sa->next)
 +      for (bScreen *sc = bmain->screen.first; sc; sc = sc->id.next) {
 +              for (ScrArea *sa = sc->areabase.first; sa; sa = sa->next) {
                        ED_render_engine_area_exit(bmain, sa);
 -
 +              }
 +      }
        RE_FreePersistentData();
 -
 -      for (scene = bmain->scene.first; scene; scene = scene->id.next) {
 -              ED_render_id_flush_update(bmain, &scene->id);
 +      /* Inform all render engines and draw managers. */
 +      DEGEditorUpdateContext update_ctx = {NULL};
 +      update_ctx.bmain = bmain;
 +      for (Scene *scene = bmain->scene.first; scene; scene = scene->id.next) {
 +              update_ctx.scene = scene;
-               LINKLIST_FOREACH(ViewLayer *, view_layer, &scene->view_layers) {
++              BLI_LISTBASE_FOREACH(ViewLayer *, view_layer, &scene->view_layers) {
 +                      /* TDODO(sergey): Iterate over depsgraphs instead? */
 +                      update_ctx.depsgraph = BKE_scene_get_depsgraph(scene, view_layer, true);
 +                      update_ctx.view_layer = view_layer;
 +                      ED_render_id_flush_update(&update_ctx, &scene->id);
 +              }
                if (scene->nodetree) {
                        ntreeCompositUpdateRLayers(scene->nodetree);
                }
index 3726d0f62949076d3aebe8529787742aa69d6b48,0000000000000000000000000000000000000000..1ffe62fbc0053c067afc1f1474860787afde7b59
mode 100644,000000..100644
--- /dev/null
@@@ -1,853 -1,0 +1,853 @@@
-               LINKLIST_FOREACH(LinkData *, link, &data.scene_collections_array) {
 +/*
 + * ***** 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.
 + *
 + * Contributor(s): Blender Foundation, Dalai Felinto
 + *
 + * ***** END GPL LICENSE BLOCK *****
 + */
 +
 +/** \file blender/editors/space_outliner/outliner_collections.c
 + *  \ingroup spoutliner
 + */
 +
 +#include "BLI_utildefines.h"
 +#include "BLI_listbase.h"
 +
 +#include "BKE_context.h"
 +#include "BKE_collection.h"
 +#include "BKE_layer.h"
 +#include "BKE_main.h"
 +#include "BKE_report.h"
 +
 +#include "DEG_depsgraph.h"
 +#include "DEG_depsgraph_build.h"
 +
 +#include "DNA_group_types.h"
 +
 +#include "ED_screen.h"
 +
 +#include "WM_api.h"
 +#include "WM_types.h"
 +
 +#include "RNA_access.h"
 +#include "RNA_define.h"
 +#include "RNA_enum_types.h"
 +
 +#include "UI_resources.h"
 +
 +#include "outliner_intern.h" /* own include */
 +
 +/* Prototypes. */
 +static int collection_delete_exec(struct bContext *C, struct wmOperator *op);
 +
 +/* -------------------------------------------------------------------- */
 +
 +static LayerCollection *outliner_collection_active(bContext *C)
 +{
 +      TODO_LAYER_OPERATORS;
 +      /* consider that we may have overrides or objects active
 +       * leading to no active collections */
 +      return CTX_data_layer_collection(C);
 +}
 +
 +SceneCollection *outliner_scene_collection_from_tree_element(TreeElement *te)
 +{
 +      TreeStoreElem *tselem = TREESTORE(te);
 +
 +      if (tselem->type == TSE_SCENE_COLLECTION) {
 +              return te->directdata;
 +      }
 +      else if (tselem->type == TSE_LAYER_COLLECTION) {
 +              LayerCollection *lc = te->directdata;
 +              return lc->scene_collection;
 +      }
 +
 +      return NULL;
 +}
 +
 +#if 0
 +static CollectionOverride *outliner_override_active(bContext *UNUSED(C))
 +{
 +      TODO_LAYER_OPERATORS;
 +      TODO_LAYER_OVERRIDE;
 +      return NULL;
 +}
 +#endif
 +
 +/* -------------------------------------------------------------------- */
 +/* Poll functions. */
 +
 +static int collections_editor_poll(bContext *C)
 +{
 +      SpaceOops *so = CTX_wm_space_outliner(C);
 +      return (so != NULL) && (so->outlinevis == SO_COLLECTIONS);
 +}
 +
 +static int view_layer_editor_poll(bContext *C)
 +{
 +      SpaceOops *so = CTX_wm_space_outliner(C);
 +      return (so != NULL) && (so->outlinevis == SO_VIEW_LAYER);
 +}
 +
 +/* -------------------------------------------------------------------- */
 +/* collection manager operators */
 +
 +/**
 + * Recursively get the collection for a given index
 + */
 +static SceneCollection *scene_collection_from_index(ListBase *lb, const int number, int *i)
 +{
 +      for (SceneCollection *sc = lb->first; sc; sc = sc->next) {
 +              if (*i == number) {
 +                      return sc;
 +              }
 +
 +              (*i)++;
 +
 +              SceneCollection *sc_nested = scene_collection_from_index(&sc->scene_collections, number, i);
 +              if (sc_nested) {
 +                      return sc_nested;
 +              }
 +      }
 +      return NULL;
 +}
 +
 +typedef struct TreeElementFindData {
 +      SceneCollection *collection;
 +      TreeElement *r_result_te;
 +} TreeElementFindData;
 +
 +static TreeTraversalAction tree_element_find_by_scene_collection_cb(TreeElement *te, void *customdata)
 +{
 +      TreeElementFindData *data = customdata;
 +      const SceneCollection *current_element_sc = outliner_scene_collection_from_tree_element(te);
 +
 +      if (current_element_sc == data->collection) {
 +              data->r_result_te = te;
 +              return TRAVERSE_BREAK;
 +      }
 +
 +      return TRAVERSE_CONTINUE;
 +}
 +
 +static TreeElement *outliner_tree_element_from_layer_collection_index(
 +        SpaceOops *soops, ViewLayer *view_layer,
 +        const int index)
 +{
 +      LayerCollection *lc = BKE_layer_collection_from_index(view_layer, index);
 +
 +      if (lc == NULL) {
 +              return NULL;
 +      }
 +
 +      /* Find the tree element containing the LayerCollection's scene_collection. */
 +      TreeElementFindData data = {
 +              .collection = lc->scene_collection,
 +              .r_result_te = NULL,
 +      };
 +      outliner_tree_traverse(soops, &soops->tree, 0, 0, tree_element_find_by_scene_collection_cb, &data);
 +
 +      return data.r_result_te;
 +}
 +
 +static int collection_link_exec(bContext *C, wmOperator *op)
 +{
 +      Scene *scene = CTX_data_scene(C);
 +      ViewLayer *view_layer = CTX_data_view_layer(C);
 +      SceneCollection *sc_master = BKE_collection_master(&scene->id);
 +      SceneCollection *sc;
 +
 +      int scene_collection_index = RNA_enum_get(op->ptr, "scene_collection");
 +      if (scene_collection_index == 0) {
 +              sc = sc_master;
 +      }
 +      else {
 +              int index = 1;
 +              sc = scene_collection_from_index(&sc_master->scene_collections, scene_collection_index, &index);
 +              BLI_assert(sc);
 +      }
 +
 +      BKE_collection_link(view_layer, sc);
 +
 +      DEG_relations_tag_update(CTX_data_main(C));
 +
 +      /* TODO(sergey): Use proper flag for tagging here. */
 +      DEG_id_tag_update(&scene->id, 0);
 +
 +      WM_main_add_notifier(NC_SCENE | ND_LAYER, NULL);
 +      return OPERATOR_FINISHED;
 +}
 +
 +static int collection_link_invoke(bContext *C, wmOperator *op, const wmEvent *event)
 +{
 +      Scene *scene = CTX_data_scene(C);
 +      SceneCollection *master_collection = BKE_collection_master(&scene->id);
 +      if (master_collection->scene_collections.first == NULL) {
 +              RNA_enum_set(op->ptr, "scene_collection", 0);
 +              return collection_link_exec(C, op);
 +      }
 +      else {
 +              return WM_enum_search_invoke(C, op, event);
 +      }
 +}
 +
 +static void collection_scene_collection_itemf_recursive(
 +        EnumPropertyItem *tmp, EnumPropertyItem **item, int *totitem, int *value, SceneCollection *sc)
 +{
 +      tmp->value = *value;
 +      tmp->icon = ICON_COLLAPSEMENU;
 +      tmp->identifier = sc->name;
 +      tmp->name = sc->name;
 +      RNA_enum_item_add(item, totitem, tmp);
 +
 +      (*value)++;
 +
 +      for (SceneCollection *ncs = sc->scene_collections.first; ncs; ncs = ncs->next) {
 +              collection_scene_collection_itemf_recursive(tmp, item, totitem, value, ncs);
 +      }
 +}
 +
 +static const EnumPropertyItem *collection_scene_collection_itemf(
 +        bContext *C, PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop), bool *r_free)
 +{
 +      EnumPropertyItem tmp = {0, "", 0, "", ""};
 +      EnumPropertyItem *item = NULL;
 +      int value = 0, totitem = 0;
 +
 +      Scene *scene = CTX_data_scene(C);
 +      SceneCollection *sc = BKE_collection_master(&scene->id);
 +
 +      collection_scene_collection_itemf_recursive(&tmp, &item, &totitem, &value, sc);
 +      RNA_enum_item_end(&item, &totitem);
 +      *r_free = true;
 +
 +      return item;
 +}
 +
 +void OUTLINER_OT_collection_link(wmOperatorType *ot)
 +{
 +      PropertyRNA *prop;
 +
 +      /* identifiers */
 +      ot->name = "Link Collection";
 +      ot->idname = "OUTLINER_OT_collection_link";
 +      ot->description = "Link a new collection to the active layer";
 +
 +      /* api callbacks */
 +      ot->exec = collection_link_exec;
 +      ot->invoke = collection_link_invoke;
 +      ot->poll = view_layer_editor_poll;
 +
 +      /* flags */
 +      ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
 +
 +      prop = RNA_def_enum(ot->srna, "scene_collection", DummyRNA_NULL_items, 0, "Scene Collection", "");
 +      RNA_def_enum_funcs(prop, collection_scene_collection_itemf);
 +      RNA_def_property_flag(prop, PROP_ENUM_NO_TRANSLATE);
 +      ot->prop = prop;
 +}
 +
 +/**
 + * Returns true if selected element is a collection directly
 + * linked to the active ViewLayer (not a nested collection)
 + */
 +static int collection_unlink_poll(bContext *C)
 +{
 +      if (view_layer_editor_poll(C) == 0) {
 +              return 0;
 +      }
 +
 +      LayerCollection *lc = outliner_collection_active(C);
 +
 +      if (lc == NULL) {
 +              return 0;
 +      }
 +
 +      ViewLayer *view_layer = CTX_data_view_layer(C);
 +      return BLI_findindex(&view_layer->layer_collections, lc) != -1 ? 1 : 0;
 +}
 +
 +static int collection_unlink_exec(bContext *C, wmOperator *op)
 +{
 +      LayerCollection *lc = outliner_collection_active(C);
 +      SpaceOops *soops = CTX_wm_space_outliner(C);
 +
 +      if (lc == NULL) {
 +              BKE_report(op->reports, RPT_ERROR, "Active element is not a collection");
 +              return OPERATOR_CANCELLED;
 +      }
 +
 +      ViewLayer *view_layer = CTX_data_view_layer(C);
 +      BKE_collection_unlink(view_layer, lc);
 +
 +      if (soops) {
 +              outliner_cleanup_tree(soops);
 +      }
 +
 +      DEG_relations_tag_update(CTX_data_main(C));
 +
 +      /* TODO(sergey): Use proper flag for tagging here. */
 +      DEG_id_tag_update(&CTX_data_scene(C)->id, 0);
 +
 +      WM_main_add_notifier(NC_SCENE | ND_LAYER, NULL);
 +      return OPERATOR_FINISHED;
 +}
 +
 +void OUTLINER_OT_collection_unlink(wmOperatorType *ot)
 +{
 +      /* identifiers */
 +      ot->name = "Unlink Collection";
 +      ot->idname = "OUTLINER_OT_collection_unlink";
 +      ot->description = "Unlink collection from the active layer";
 +
 +      /* api callbacks */
 +      ot->exec = collection_unlink_exec;
 +      ot->poll = collection_unlink_poll;
 +
 +      /* flags */
 +      ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
 +}
 +
 +/**********************************************************************************/
 +/* Add new collection. */
 +
 +static int collection_new_exec(bContext *C, wmOperator *UNUSED(op))
 +{
 +      SpaceOops *soops = CTX_wm_space_outliner(C);
 +      Main *bmain = CTX_data_main(C);
 +      Scene *scene = CTX_data_scene(C);
 +      ViewLayer *view_layer = CTX_data_view_layer(C);
 +      SceneCollection *scene_collection = BKE_collection_add(&scene->id, NULL, COLLECTION_TYPE_NONE, NULL);
 +      BKE_collection_link(view_layer, scene_collection);
 +
 +      outliner_cleanup_tree(soops);
 +      DEG_relations_tag_update(bmain);
 +      WM_main_add_notifier(NC_SCENE | ND_LAYER, NULL);
 +      return OPERATOR_FINISHED;
 +}
 +
 +void OUTLINER_OT_collection_new(wmOperatorType *ot)
 +{
 +      /* identifiers */
 +      ot->name = "New Collection";
 +      ot->idname = "OUTLINER_OT_collection_new";
 +      ot->description = "Add a new collection to the scene";
 +
 +      /* api callbacks */
 +      ot->exec = collection_new_exec;
 +
 +      /* flags */
 +      ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
 +}
 +
 +/**********************************************************************************/
 +/* Add new nested collection. */
 +
 +struct CollectionNewData
 +{
 +      bool error;
 +      SceneCollection *scene_collection;
 +};
 +
 +static TreeTraversalAction collection_find_selected_to_add(TreeElement *te, void *customdata)
 +{
 +      struct CollectionNewData *data = customdata;
 +      SceneCollection *scene_collection = outliner_scene_collection_from_tree_element(te);
 +
 +      if (!scene_collection) {
 +              return TRAVERSE_SKIP_CHILDS;
 +      }
 +
 +      if (data->scene_collection != NULL) {
 +              data->error = true;
 +              return TRAVERSE_BREAK;
 +      }
 +
 +      data->scene_collection = scene_collection;
 +      return TRAVERSE_CONTINUE;
 +}
 +
 +static int collection_nested_new_exec(bContext *C, wmOperator *op)
 +{
 +      SpaceOops *soops = CTX_wm_space_outliner(C);
 +      Main *bmain = CTX_data_main(C);
 +      Scene *scene = CTX_data_scene(C);
 +
 +      struct CollectionNewData data = {
 +              .error = false,
 +              .scene_collection = NULL,
 +      };
 +
 +      outliner_tree_traverse(soops, &soops->tree, 0, TSE_SELECTED, collection_find_selected_to_add, &data);
 +
 +      if (data.error) {
 +              BKE_report(op->reports, RPT_ERROR, "More than one collection is selected");
 +              return OPERATOR_CANCELLED;
 +      }
 +
 +      BKE_collection_add(
 +                  &scene->id,
 +                  data.scene_collection,
 +                  COLLECTION_TYPE_NONE,
 +                  NULL);
 +
 +      outliner_cleanup_tree(soops);
 +      DEG_relations_tag_update(bmain);
 +      WM_main_add_notifier(NC_SCENE | ND_LAYER, NULL);
 +      return OPERATOR_FINISHED;
 +}
 +
 +void OUTLINER_OT_collection_nested_new(wmOperatorType *ot)
 +{
 +      /* identifiers */
 +      ot->name = "New Nested Collection";
 +      ot->idname = "OUTLINER_OT_collection_nested_new";
 +      ot->description = "Add a new collection inside selected collection";
 +
 +      /* api callbacks */
 +      ot->exec = collection_nested_new_exec;
 +      ot->poll = collections_editor_poll;
 +
 +      /* flags */
 +      ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
 +}
 +
 +/**********************************************************************************/
 +/* Delete selected collection. */
 +
 +void OUTLINER_OT_collection_delete_selected(wmOperatorType *ot)
 +{
 +      /* identifiers */
 +      ot->name = "Delete Selected Collections";
 +      ot->idname = "OUTLINER_OT_collection_delete_selected";
 +      ot->description = "Delete all the selected collections";
 +
 +      /* api callbacks */
 +      ot->exec = collection_delete_exec;
 +      ot->poll = collections_editor_poll;
 +
 +      /* flags */
 +      ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
 +}
 +
 +/**********************************************************************************/
 +/* Add new selected objects. */
 +
 +struct SceneCollectionSelectedData {
 +      ListBase scene_collections_array;
 +};
 +
 +static TreeTraversalAction collection_find_selected_scene_collections(TreeElement *te, void *customdata)
 +{
 +      struct SceneCollectionSelectedData *data = customdata;
 +      SceneCollection *scene_collection = outliner_scene_collection_from_tree_element(te);
 +
 +      if (!scene_collection) {
 +              return TRAVERSE_SKIP_CHILDS;
 +      }
 +
 +      BLI_addtail(&data->scene_collections_array, BLI_genericNodeN(scene_collection));
 +      return TRAVERSE_CONTINUE;
 +}
 +
 +static int collection_objects_add_exec(bContext *C, wmOperator *op)
 +{
 +      SpaceOops *soops = CTX_wm_space_outliner(C);
 +      Main *bmain = CTX_data_main(C);
 +      Scene *scene = CTX_data_scene(C);
 +
 +      struct SceneCollectionSelectedData data = {
 +              .scene_collections_array = {NULL, NULL},
 +      };
 +
 +      outliner_tree_traverse(soops, &soops->tree, 0, TSE_SELECTED, collection_find_selected_scene_collections, &data);
 +
 +      if (BLI_listbase_is_empty(&data.scene_collections_array)) {
 +              BKE_report(op->reports, RPT_ERROR, "No collection is selected");
 +              return OPERATOR_CANCELLED;
 +      }
 +
 +      CTX_DATA_BEGIN (C, struct Object *, ob, selected_objects)
 +      {
-               LINKLIST_FOREACH(LinkData *, link, &data.scene_collections_array) {
++              BLI_LISTBASE_FOREACH (LinkData *, link, &data.scene_collections_array) {
 +                      SceneCollection *scene_collection = link->data;
 +                      BKE_collection_object_add(
 +                                  &scene->id,
 +                                  scene_collection,
 +                                  ob);
 +              }
 +      }
 +      CTX_DATA_END;
 +      BLI_freelistN(&data.scene_collections_array);
 +
 +      outliner_cleanup_tree(soops);
 +      DEG_relations_tag_update(bmain);
 +      WM_main_add_notifier(NC_SCENE | ND_LAYER, NULL);
 +      return OPERATOR_FINISHED;
 +}
 +
 +void OUTLINER_OT_collection_objects_add(wmOperatorType *ot)
 +{
 +      /* identifiers */
 +      ot->name = "Add Objects";
 +      ot->idname = "OUTLINER_OT_collection_objects_add";
 +      ot->description = "Add selected objects to collection";
 +
 +      /* api callbacks */
 +      ot->exec = collection_objects_add_exec;
 +      ot->poll = collections_editor_poll;
 +
 +      /* flags */
 +      ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
 +}
 +
 +/**********************************************************************************/
 +/* Remove selected objects. */
 +
 +
 +static int collection_objects_remove_exec(bContext *C, wmOperator *op)
 +{
 +      SpaceOops *soops = CTX_wm_space_outliner(C);
 +      Main *bmain = CTX_data_main(C);
 +      Scene *scene = CTX_data_scene(C);
 +
 +      struct SceneCollectionSelectedData data = {
 +              .scene_collections_array = {NULL, NULL},
 +      };
 +
 +      outliner_tree_traverse(soops, &soops->tree, 0, TSE_SELECTED, collection_find_selected_scene_collections, &data);
 +
 +      if (BLI_listbase_is_empty(&data.scene_collections_array)) {
 +              BKE_report(op->reports, RPT_ERROR, "No collection is selected");
 +              return OPERATOR_CANCELLED;
 +      }
 +
 +      CTX_DATA_BEGIN (C, struct Object *, ob, selected_objects)
 +      {
++              BLI_LISTBASE_FOREACH (LinkData *, link, &data.scene_collections_array) {
 +                      SceneCollection *scene_collection = link->data;
 +                      BKE_collection_object_remove(
 +                                  bmain,
 +                                  &scene->id,
 +                                  scene_collection,
 +                                  ob,
 +                                  true);
 +              }
 +      }
 +      CTX_DATA_END;
 +      BLI_freelistN(&data.scene_collections_array);
 +
 +      outliner_cleanup_tree(soops);
 +      DEG_relations_tag_update(bmain);
 +      WM_main_add_notifier(NC_SCENE | ND_LAYER, NULL);
 +      return OPERATOR_FINISHED;
 +}
 +
 +void OUTLINER_OT_collection_objects_remove(wmOperatorType *ot)
 +{
 +      /* identifiers */
 +      ot->name = "Remove Objects";
 +      ot->idname = "OUTLINER_OT_collection_objects_remove";
 +      ot->description = "Remove selected objects from collection";
 +
 +      /* api callbacks */
 +      ot->exec = collection_objects_remove_exec;
 +      ot->poll = collections_editor_poll;
 +
 +      /* flags */
 +      ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
 +}
 +
 +/**********************************************************************************/
 +
 +/**
 + * Returns true is selected element is a collection
 + */
 +static int collection_override_new_poll(bContext *(C))
 +{
 +#ifdef TODO_LAYER_OVERRIDE
 +      /* disable for now, since it's not implemented */
 +      (void) C;
 +      return 0;
 +#else
 +      return outliner_collection_active(C) ? 1 : 0;
 +#endif
 +}
 +
 +static int collection_override_new_invoke(bContext *UNUSED(C), wmOperator *op, const wmEvent *UNUSED(event))
 +{
 +      TODO_LAYER_OPERATORS;
 +      TODO_LAYER_OVERRIDE;
 +      BKE_report(op->reports, RPT_ERROR, "OUTLINER_OT_collections_override_new not implemented yet");
 +      return OPERATOR_CANCELLED;
 +}
 +
 +/* in the middle of renames remove s */
 +void OUTLINER_OT_collection_override_new(wmOperatorType *ot)
 +{
 +      /* identifiers */
 +      ot->name = "New Override";
 +      ot->idname = "OUTLINER_OT_collection_override_new";
 +      ot->description = "Add a new override to the active collection";
 +
 +      /* api callbacks */
 +      ot->invoke = collection_override_new_invoke;
 +      ot->poll = collection_override_new_poll;
 +
 +      /* flags */
 +      ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
 +}
 +
 +struct CollectionDeleteData {
 +      Scene *scene;
 +      SpaceOops *soops;
 +      GSet *collections_to_delete;
 +};
 +
 +static TreeTraversalAction collection_find_data_to_delete(TreeElement *te, void *customdata)
 +{
 +      struct CollectionDeleteData *data = customdata;
 +      SceneCollection *scene_collection = outliner_scene_collection_from_tree_element(te);
 +
 +      if (!scene_collection) {
 +              return TRAVERSE_SKIP_CHILDS;
 +      }
 +
 +      if (scene_collection == BKE_collection_master(&data->scene->id)) {
 +              /* skip - showing warning/error message might be missleading
 +               * when deleting multiple collections, so just do nothing */
 +      }
 +      else {
 +              BLI_gset_add(data->collections_to_delete, scene_collection);
 +              return TRAVERSE_SKIP_CHILDS; /* Childs will be gone anyway, no need to recurse deeper. */
 +      }
 +
 +      return TRAVERSE_CONTINUE;
 +}
 +
 +static TreeTraversalAction collection_delete_elements_from_collection(TreeElement *te, void *customdata)
 +{
 +      struct CollectionDeleteData *data = customdata;
 +      SceneCollection *scene_collection = outliner_scene_collection_from_tree_element(te);
 +
 +      if (!scene_collection) {
 +              return TRAVERSE_SKIP_CHILDS;
 +      }
 +
 +      const bool will_be_deleted = BLI_gset_haskey(data->collections_to_delete, scene_collection);
 +      if (will_be_deleted) {
 +              outliner_free_tree_element(te, te->parent ? &te->parent->subtree : &data->soops->tree);
 +              /* Childs are freed now, so don't recurse into them. */
 +              return TRAVERSE_SKIP_CHILDS;
 +      }
 +
 +      return TRAVERSE_CONTINUE;
 +}
 +
 +static int collection_delete_exec(bContext *C, wmOperator *UNUSED(op))
 +{
 +      Scene *scene = CTX_data_scene(C);
 +      SpaceOops *soops = CTX_wm_space_outliner(C);
 +      struct CollectionDeleteData data = {.scene = scene, .soops = soops};
 +
 +      data.collections_to_delete = BLI_gset_ptr_new(__func__);
 +
 +      TODO_LAYER_OVERRIDE; /* handle overrides */
 +
 +      /* We first walk over and find the SceneCollections we actually want to delete (ignoring duplicates). */
 +      outliner_tree_traverse(soops, &soops->tree, 0, TSE_SELECTED, collection_find_data_to_delete, &data);
 +
 +      /* Now, delete all tree elements representing a collection that will be deleted. We'll look for a
 +       * new element to select in a few lines, so we can't wait until the tree is recreated on redraw. */
 +      outliner_tree_traverse(soops, &soops->tree, 0, 0, collection_delete_elements_from_collection, &data);
 +
 +      /* Effectively delete the collections. */
 +      GSetIterator collections_to_delete_iter;
 +      GSET_ITER(collections_to_delete_iter, data.collections_to_delete) {
 +              SceneCollection *sc = BLI_gsetIterator_getKey(&collections_to_delete_iter);
 +              BKE_collection_remove(&data.scene->id, sc);
 +      }
 +
 +      BLI_gset_free(data.collections_to_delete, NULL);
 +
 +      TreeElement *select_te = outliner_tree_element_from_layer_collection_index(soops, CTX_data_view_layer(C), 0);
 +      if (select_te) {
 +              outliner_item_select(soops, select_te, false, false);
 +      }
 +
 +      DEG_relations_tag_update(CTX_data_main(C));
 +
 +      /* TODO(sergey): Use proper flag for tagging here. */
 +      DEG_id_tag_update(&scene->id, 0);
 +
 +      soops->storeflag |= SO_TREESTORE_REDRAW;
 +      WM_main_add_notifier(NC_SCENE | ND_LAYER, NULL);
 +
 +      return OPERATOR_FINISHED;
 +}
 +
 +void OUTLINER_OT_collections_delete(wmOperatorType *ot)
 +{
 +      /* identifiers */
 +      ot->name = "Delete";
 +      ot->idname = "OUTLINER_OT_collections_delete";
 +      ot->description = "Delete selected overrides or collections";
 +
 +      /* api callbacks */
 +      ot->exec = collection_delete_exec;
 +
 +      /* flags */
 +      ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
 +}
 +
 +static int collection_select_exec(bContext *C, wmOperator *op)
 +{
 +      ViewLayer *view_layer = CTX_data_view_layer(C);
 +      const int collection_index = RNA_int_get(op->ptr, "collection_index");
 +      view_layer->active_collection = collection_index;
 +      WM_main_add_notifier(NC_SCENE | ND_LAYER, NULL);
 +      return OPERATOR_FINISHED;
 +}
 +
 +void OUTLINER_OT_collection_select(wmOperatorType *ot)
 +{
 +      /* identifiers */
 +      ot->name = "Select";
 +      ot->idname = "OUTLINER_OT_collection_select";
 +      ot->description = "Change active collection or override";
 +
 +      /* api callbacks */
 +      ot->exec = collection_select_exec;
 +
 +      /* flags */
 +      ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
 +
 +      RNA_def_int(ot->srna, "collection_index", 0, 0, INT_MAX, "Index",
 +                  "Index of collection to select", 0, INT_MAX);
 +}
 +
 +#define ACTION_DISABLE 0
 +#define ACTION_ENABLE 1
 +#define ACTION_TOGGLE 2
 +
 +static int collection_toggle_exec(bContext *C, wmOperator *op)
 +{
 +      Main *bmain = CTX_data_main(C);
 +      Scene *scene = CTX_data_scene(C);
 +      int action = RNA_enum_get(op->ptr, "action");
 +      LayerCollection *layer_collection = CTX_data_layer_collection(C);
 +
 +      if (layer_collection->flag & COLLECTION_DISABLED) {
 +              if (ELEM(action, ACTION_TOGGLE, ACTION_ENABLE)) {
 +                      layer_collection->flag &= ~COLLECTION_DISABLED;
 +              }
 +              else { /* ACTION_DISABLE */
 +                      BKE_reportf(op->reports, RPT_ERROR, "Layer collection %s already disabled",
 +                                  layer_collection->scene_collection->name);
 +                      return OPERATOR_CANCELLED;
 +              }
 +      }
 +      else {
 +              if (ELEM(action, ACTION_TOGGLE, ACTION_DISABLE)) {
 +                      layer_collection->flag |= COLLECTION_DISABLED;
 +              }
 +              else { /* ACTION_ENABLE */
 +                      BKE_reportf(op->reports, RPT_ERROR, "Layer collection %s already enabled",
 +                                  layer_collection->scene_collection->name);
 +                      return OPERATOR_CANCELLED;
 +              }
 +      }
 +
 +      DEG_relations_tag_update(bmain);
 +      /* TODO(sergey): Use proper flag for tagging here. */
 +      DEG_id_tag_update(&scene->id, 0);
 +
 +      WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene);
 +      WM_event_add_notifier(C, NC_SCENE | ND_LAYER_CONTENT, scene);
 +
 +      return OPERATOR_FINISHED;
 +}
 +
 +void OUTLINER_OT_collection_toggle(wmOperatorType *ot)
 +{
 +      PropertyRNA *prop;
 +
 +      static EnumPropertyItem actions_items[] = {
 +              {ACTION_DISABLE, "DISABLE", 0, "Disable", "Disable selected markers"},
 +              {ACTION_ENABLE, "ENABLE", 0, "Enable", "Enable selected markers"},
 +              {ACTION_TOGGLE, "TOGGLE", 0, "Toggle", "Toggle disabled flag for selected markers"},
 +              {0, NULL, 0, NULL, NULL}
 +      };
 +
 +      /* identifiers */
 +      ot->name = "Toggle Collection";
 +      ot->idname = "OUTLINER_OT_collection_toggle";
 +      ot->description = "Deselect collection objects";
 +
 +      /* api callbacks */
 +      ot->exec = collection_toggle_exec;
 +
 +      /* flags */
 +      ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
 +
 +      /* properties */
 +      prop = RNA_def_int(ot->srna, "collection_index", -1, -1, INT_MAX, "Collection Index", "Index of collection to toggle", 0, INT_MAX);
 +      RNA_def_property_flag(prop, PROP_SKIP_SAVE);
 +      prop = RNA_def_enum(ot->srna, "action", actions_items, ACTION_TOGGLE, "Action", "Selection action to execute");
 +      RNA_def_property_flag(prop, PROP_SKIP_SAVE);
 +}
 +
 +#undef ACTION_TOGGLE
 +#undef ACTION_ENABLE
 +#undef ACTION_DISABLE
 +
 +/* -------------------------------------------------------------------- */
 +
 +static int stubs_invoke(bContext *UNUSED(C), wmOperator *op, const wmEvent *UNUSED(event))
 +{
 +      TODO_LAYER_OPERATORS;
 +      BKE_report(op->reports, RPT_ERROR, "Operator not implemented yet");
 +      return OPERATOR_CANCELLED;
 +}
 +
 +void OUTLINER_OT_collection_objects_select(wmOperatorType *ot)
 +{
 +      /* identifiers */
 +      ot->name = "Select Objects";
 +      ot->idname = "OUTLINER_OT_collection_objects_select";
 +      ot->description = "Select collection objects";
 +
 +      /* api callbacks */
 +      ot->invoke = stubs_invoke;
 +
 +      /* flags */
 +      ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
 +}
 +
 +void OUTLINER_OT_collection_objects_deselect(wmOperatorType *ot)
 +{
 +      /* identifiers */
 +      ot->name = "Deselect Objects";
 +      ot->idname = "OUTLINER_OT_collection_objects_deselect";
 +      ot->description = "Deselect collection objects";
 +
 +      /* api callbacks */
 +      ot->invoke = stubs_invoke;
 +
 +      /* flags */
 +      ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
 +}
index 3fd044afe48699978a723d7e3d9398948d8003b3,cf77afa32c40d5238ec32f1205f2a645ac745420..c8f38e5282b174bab7ac4c2f505d8b124cae14dc
@@@ -402,96 -483,6 +402,96 @@@ static void outliner_add_scene_contents
  #endif
  }
  
-       LINKLIST_FOREACH(LinkData *, link, &data.objects_selected_array) {
 +struct ObjectsSelectedData {
 +      ListBase objects_selected_array;
 +};
 +
 +static TreeTraversalAction outliner_find_selected_objects(TreeElement *te, void *customdata)
 +{
 +      struct ObjectsSelectedData *data = customdata;
 +      TreeStoreElem *tselem = TREESTORE(te);
 +
 +      if (ELEM(tselem->type, TSE_LAYER_COLLECTION, TSE_SCENE_COLLECTION)) {
 +              return TRAVERSE_CONTINUE;
 +      }
 +
 +      if (tselem->type || (tselem->id == NULL) || (GS(tselem->id->name) != ID_OB)) {
 +              return TRAVERSE_SKIP_CHILDS;
 +      }
 +
 +      BLI_addtail(&data->objects_selected_array, BLI_genericNodeN(te));
 +
 +      return TRAVERSE_CONTINUE;
 +}
 +
 +/**
 + * Move objects from a collection to another.
 + * We ignore the original object being inserted, we used it for polling only.
 + * Instead we move all the selected objects around.
 + */
 +static void outliner_object_reorder(
 +        Main *bmain, SpaceOops *soops,
 +        TreeElement *insert_element,
 +        TreeElement *insert_handle, TreeElementInsertType action)
 +{
 +      SceneCollection *sc = outliner_scene_collection_from_tree_element(insert_handle);
 +      SceneCollection *sc_ob_parent = NULL;
 +      ID *id = insert_handle->store_elem->id;
 +
 +      BLI_assert(action == TE_INSERT_INTO);
 +      UNUSED_VARS_NDEBUG(action);
 +
 +      struct ObjectsSelectedData data = {
 +              .objects_selected_array  = {NULL, NULL},
 +      };
 +
 +      /* Make sure we include the originally inserted element as well. */
 +      TREESTORE(insert_element)->flag |= TSE_SELECTED;
 +
 +      outliner_tree_traverse(soops, &soops->tree, 0, TSE_SELECTED, outliner_find_selected_objects, &data);
++      BLI_LISTBASE_FOREACH (LinkData *, link, &data.objects_selected_array) {
 +              TreeElement *ten_selected = (TreeElement *)link->data;
 +              /* Find parent scene-collection of object. */
 +              if (ten_selected->parent) {
 +                      for (TreeElement *te_ob_parent = ten_selected->parent; te_ob_parent; te_ob_parent = te_ob_parent->parent) {
 +                              if (ELEM(TREESTORE(te_ob_parent)->type, TSE_SCENE_COLLECTION, TSE_LAYER_COLLECTION)) {
 +                                      sc_ob_parent = outliner_scene_collection_from_tree_element(te_ob_parent);
 +                                      break;
 +                              }
 +                      }
 +              }
 +              else {
 +                      sc_ob_parent = BKE_collection_master(id);
 +              }
 +              Object *ob = (Object *)TREESTORE(ten_selected)->id;
 +              BKE_collection_object_move(id, sc, sc_ob_parent, ob);
 +      }
 +
 +      BLI_freelistN(&data.objects_selected_array);
 +
 +      DEG_relations_tag_update(bmain);
 +
 +      /* TODO(sergey): Use proper flag for tagging here. */
 +      DEG_id_tag_update(id, 0);
 +
 +      WM_main_add_notifier(NC_SCENE | ND_LAYER, NULL);
 +}
 +
 +static bool outliner_object_reorder_poll(
 +        const TreeElement *insert_element,
 +        TreeElement **io_insert_handle, TreeElementInsertType *io_action)
 +{
 +      TreeStoreElem *tselem_handle = TREESTORE(*io_insert_handle);
 +      if (ELEM(tselem_handle->type, TSE_SCENE_COLLECTION, TSE_LAYER_COLLECTION) &&
 +          (insert_element->parent != *io_insert_handle))
 +      {
 +              *io_action = TE_INSERT_INTO;
 +              return true;
 +      }
 +
 +      return false;
 +}
 +
  // can be inlined if necessary
  static void outliner_add_object_contents(SpaceOops *soops, TreeElement *te, TreeStoreElem *tselem, Object *ob)
  {