Blender V5.0
tree_display_view_layer.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2023 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
8
10#include "DNA_scene_types.h"
11#include "DNA_space_types.h"
12
13#include "BKE_layer.hh"
14#include "BKE_library.hh"
15
16#include "BLI_listbase.h"
18#include "BLI_map.hh"
19#include "BLI_set.hh"
20#include "BLI_vector.hh"
21
22#include "../outliner_intern.hh"
23#include "common.hh"
24#include "tree_display.hh"
25
26namespace blender::ed::outliner {
27
28template<typename T> using List = ListBaseWrapper<T>;
29
31 using TreeChildren = Vector<TreeElement *>;
32 using ObjectTreeElementsMap = Map<Object *, TreeChildren>;
33
34 SpaceOutliner &outliner_;
35 ObjectTreeElementsMap object_tree_elements_map_;
39 Vector<Object *> ordered_objects_;
43 Set<Object *> objects_in_ordered_objects_;
44
45 public:
48
49 void operator()(TreeElement &collection_tree_elem);
50
51 private:
52 void object_tree_elements_lookup_create_recursive(TreeElement *te_parent);
53 void make_object_parent_hierarchy_collections();
54 void add_object_and_parents_in_order(Object *ob);
55};
56
57/* -------------------------------------------------------------------- */
60
65
67{
68 return true;
69}
70
72{
73 ListBase tree = {nullptr};
74 Scene *scene = source_data.scene;
75 scene_ = scene;
76 show_objects_ = !(space_outliner_.filter & SO_FILTER_NO_OBJECT);
77
78 for (auto *view_layer : ListBaseWrapper<ViewLayer>(scene->view_layers)) {
79 view_layer_ = view_layer;
80
82 if (view_layer != source_data.view_layer) {
83 continue;
84 }
85
86 add_view_layer(*scene, tree, (TreeElement *)nullptr);
87 }
88 else {
89 TreeElement &te_view_layer = *add_element(
90 &tree, reinterpret_cast<ID *>(scene), &view_layer, nullptr, TSE_R_LAYER, 0);
91
92 TreeStoreElem *tselem = TREESTORE(&te_view_layer);
93
94 if (!tselem->used) {
95 tselem->flag &= ~TSE_CLOSED;
96 }
97
98 te_view_layer.name = view_layer->name;
99 te_view_layer.directdata = view_layer;
100
101 add_view_layer(*scene, te_view_layer.subtree, &te_view_layer);
102 }
103 }
104
105 return tree;
106}
107
108void TreeDisplayViewLayer::add_view_layer(Scene &scene, ListBase &tree, TreeElement *parent)
109{
110 const bool show_children = (space_outliner_.filter & SO_FILTER_NO_CHILDREN) == 0;
111
113 /* Show objects in the view layer. */
114 BKE_view_layer_synced_ensure(&scene, view_layer_);
115 for (Base *base : List<Base>(*BKE_view_layer_object_bases_get(view_layer_))) {
116 TreeElement *te_object = add_element(
117 &tree, reinterpret_cast<ID *>(base->object), nullptr, parent, TSE_SOME_ID, 0);
118 te_object->directdata = base;
119 }
120
121 if (show_children) {
123 }
124 }
125 else {
126 /* Show collections in the view layer. */
127 TreeElement &ten = *AbstractTreeDisplay::add_element(
128 &space_outliner_, &tree, &scene.id, nullptr, parent, TSE_VIEW_COLLECTION_BASE, 0);
129 TREESTORE(&ten)->flag &= ~TSE_CLOSED;
130
131 /* First layer collection is for master collection, don't show it. */
132 LayerCollection *lc = static_cast<LayerCollection *>(view_layer_->layer_collections.first);
133 if (lc == nullptr) {
134 return;
135 }
136
137 add_layer_collections_recursive(ten.subtree, lc->layer_collections, ten);
138 if (show_objects_) {
139 add_layer_collection_objects(ten.subtree, *lc, ten);
140 }
141 if (show_children) {
142 add_layer_collection_objects_children(ten);
143 }
144 }
145}
146
147void TreeDisplayViewLayer::add_layer_collections_recursive(ListBase &tree,
148 ListBase &layer_collections,
149 TreeElement &parent_ten)
150{
151 for (LayerCollection *lc : List<LayerCollection>(layer_collections)) {
152 const bool exclude = (lc->flag & LAYER_COLLECTION_EXCLUDE) != 0;
153 TreeElement *ten;
154
155 if (exclude && ((space_outliner_.show_restrict_flags & SO_RESTRICT_ENABLE) == 0)) {
156 ten = &parent_ten;
157 }
158 else {
159 ID *id = &lc->collection->id;
160 ten = add_element(&tree, id, lc, &parent_ten, TSE_LAYER_COLLECTION, 0);
161
162 /* Open by default, except linked collections, which may contain many elements. */
163 TreeStoreElem *tselem = TREESTORE(ten);
164 if (!(tselem->used || !ID_IS_EDITABLE(id) || ID_IS_OVERRIDE_LIBRARY(id))) {
165 tselem->flag &= ~TSE_CLOSED;
166 }
167 }
168
169 add_layer_collections_recursive(ten->subtree, lc->layer_collections, *ten);
170 if (!exclude && show_objects_) {
171 add_layer_collection_objects(ten->subtree, *lc, *ten);
172 }
173 }
174}
175
176void TreeDisplayViewLayer::add_layer_collection_objects(ListBase &tree,
177 LayerCollection &lc,
178 TreeElement &ten)
179{
180 BKE_view_layer_synced_ensure(scene_, view_layer_);
182 Base *base = BKE_view_layer_base_find(view_layer_, cob->ob);
183 TreeElement *te_object = add_element(
184 &tree, reinterpret_cast<ID *>(base->object), nullptr, &ten, TSE_SOME_ID, 0);
185 te_object->directdata = base;
186 }
187}
188
189void TreeDisplayViewLayer::add_layer_collection_objects_children(TreeElement &collection_tree_elem)
190{
191 /* Call helper to add children. */
192 ObjectsChildrenBuilder child_builder{space_outliner_};
193 child_builder(collection_tree_elem);
194}
195
197
198/* -------------------------------------------------------------------- */
205
207 : outliner_(space_outliner)
208{
209}
210
212{
213 object_tree_elements_lookup_create_recursive(&collection_tree_elem);
214 make_object_parent_hierarchy_collections();
215}
216
220void ObjectsChildrenBuilder::object_tree_elements_lookup_create_recursive(TreeElement *te_parent)
221{
222 for (TreeElement *te : List<TreeElement>(te_parent->subtree)) {
223 TreeStoreElem *tselem = TREESTORE(te);
224
225 if (tselem->type == TSE_LAYER_COLLECTION) {
226 object_tree_elements_lookup_create_recursive(te);
227 continue;
228 }
229
230 if ((tselem->type == TSE_SOME_ID) && (te->idcode == ID_OB)) {
231 Object *ob = (Object *)tselem->id;
232 /* Lookup children or add new, empty children vector. */
233 Vector<TreeElement *> &tree_elements = object_tree_elements_map_.lookup_or_add(ob, {});
234 add_object_and_parents_in_order(ob);
235 tree_elements.append(te);
236 object_tree_elements_lookup_create_recursive(te);
237 }
238 }
239}
240
245void ObjectsChildrenBuilder::make_object_parent_hierarchy_collections()
246{
247 /* Ordered list (parent before children) is important. Otherwise, it is easy to miss objects that
248 * are linked with another collection. For details, see: !136971. */
249 for (Object *ob : ordered_objects_) {
250 if (ob->parent == nullptr) {
251 continue;
252 }
253
254 Vector<TreeElement *> *parent_ob_tree_elements = object_tree_elements_map_.lookup_ptr(
255 ob->parent);
256 Vector<TreeElement *> *child_ob_tree_elements = object_tree_elements_map_.lookup_ptr(ob);
257
258 if (!parent_ob_tree_elements || !child_ob_tree_elements) {
259 continue;
260 }
261
262 for (TreeElement *parent_ob_tree_element : *parent_ob_tree_elements) {
263 TreeElement *parent_ob_collection_tree_element = nullptr;
264 bool found = false;
265
266 /* We always want to remove the child from the direct collection its parent is nested under.
267 * This is particularly important when dealing with multi-level nesting (grandchildren). */
268 parent_ob_collection_tree_element = parent_ob_tree_element->parent;
269 while (!ELEM(TREESTORE(parent_ob_collection_tree_element)->type,
272 {
273 parent_ob_collection_tree_element = parent_ob_collection_tree_element->parent;
274 }
275
276 for (TreeElement *child_ob_tree_element : *child_ob_tree_elements) {
277 if (child_ob_tree_element->parent == parent_ob_collection_tree_element) {
278 /* Move from the collection subtree into the parent object subtree. */
279 BLI_remlink(&parent_ob_collection_tree_element->subtree, child_ob_tree_element);
280 BLI_addtail(&parent_ob_tree_element->subtree, child_ob_tree_element);
281 child_ob_tree_element->parent = parent_ob_tree_element;
282 found = true;
283 break;
284 }
285 }
286
287 if (!found) {
288 /* We add the child in the tree even if it is not in the collection.
289 * We don't expand its sub-tree though, to make it less prominent. */
290 TreeElement *child_ob_tree_element = AbstractTreeDisplay::add_element(
291 &outliner_,
292 &parent_ob_tree_element->subtree,
293 reinterpret_cast<ID *>(ob),
294 nullptr,
295 parent_ob_tree_element,
297 0,
298 false);
299 child_ob_tree_element->flag |= TE_CHILD_NOT_IN_COLLECTION;
300 child_ob_tree_elements->append(child_ob_tree_element);
301 }
302 }
303 }
304}
305
306void ObjectsChildrenBuilder::add_object_and_parents_in_order(Object *ob)
307{
308 if (Object *parent = ob->parent) {
309 add_object_and_parents_in_order(parent);
310 }
311 if (objects_in_ordered_objects_.add(ob)) {
312 ordered_objects_.append(ob);
313 }
314}
315
317
318} // namespace blender::ed::outliner
void BKE_view_layer_synced_ensure(const Scene *scene, ViewLayer *view_layer)
Base * BKE_view_layer_base_find(ViewLayer *view_layer, Object *ob)
ListBase * BKE_view_layer_object_bases_get(ViewLayer *view_layer)
void BLI_addtail(ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition listbase.cc:111
void BLI_remlink(ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition listbase.cc:131
#define ELEM(...)
struct ID ID
#define ID_IS_EDITABLE(_id)
Definition DNA_ID.h:705
#define ID_IS_OVERRIDE_LIBRARY(_id)
Definition DNA_ID.h:730
@ ID_OB
Object groups, one object can be in many groups at once.
struct CollectionObject CollectionObject
@ LAYER_COLLECTION_EXCLUDE
struct Base Base
struct LayerCollection LayerCollection
struct ListBase ListBase
struct Object Object
@ TSE_VIEW_COLLECTION_BASE
@ TSE_LAYER_COLLECTION
@ TSE_SOME_ID
@ TSE_R_LAYER
@ TSE_CLOSED
struct TreeStoreElem TreeStoreElem
@ SO_RESTRICT_ENABLE
@ SO_FILTER_NO_CHILDREN
@ SO_FILTER_NO_OBJECT
@ SO_FILTER_NO_VIEW_LAYERS
@ SO_FILTER_NO_COLLECTION
Value & lookup_or_add(const Key &key, const Value &value)
Definition BLI_map.hh:588
void append(const T &value)
AbstractTreeDisplay(SpaceOutliner &space_outliner)
static TreeElement * add_element(SpaceOutliner *space_outliner, ListBase *lb, ID *owner_id, void *create_data, TreeElement *parent, short type, short index, const bool expand=true)
void operator()(TreeElement &collection_tree_elem)
ListBase build_tree(const TreeSourceData &source_data) override
GPU_SHADER_INTERFACE_INFO(depth_2d_update_iface).smooth(Type fragColor push_constant(Type::float2_t, "extent") .push_constant(Type source_data
KDTree_3d * tree
void outliner_make_object_parent_hierarchy(ListBase *lb)
Definition common.cc:40
ListBaseWrapperTemplate< ListBase, T > ListBaseWrapper
#define TREESTORE(a)
struct Object * object
Definition DNA_ID.h:414
ListBase layer_collections
struct Collection * collection
void * first
struct Object * parent
ListBase view_layers
ListBase layer_collections
The data to build the tree from.
Establish and manage Outliner trees for different display modes.