Blender V4.3
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
9#include <iostream>
10
12#include "DNA_scene_types.h"
13#include "DNA_space_types.h"
14
15#include "BKE_layer.hh"
16
17#include "BLI_listbase.h"
19#include "BLI_map.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
33
34 SpaceOutliner &outliner_;
35 ObjectTreeElementsMap object_tree_elements_map_;
36
37 public:
40
41 void operator()(TreeElement &collection_tree_elem);
42
43 private:
44 void object_tree_elements_lookup_create_recursive(TreeElement *te_parent);
45 void make_object_parent_hierarchy_collections();
46};
47
48/* -------------------------------------------------------------------- */
56
58{
59 return true;
60}
61
63{
64 ListBase tree = {nullptr};
65 Scene *scene = source_data.scene;
66 scene_ = scene;
67 show_objects_ = !(space_outliner_.filter & SO_FILTER_NO_OBJECT);
68
69 for (auto *view_layer : ListBaseWrapper<ViewLayer>(scene->view_layers)) {
70 view_layer_ = view_layer;
71
73 if (view_layer != source_data.view_layer) {
74 continue;
75 }
76
77 add_view_layer(*scene, tree, (TreeElement *)nullptr);
78 }
79 else {
80 TreeElement &te_view_layer = *add_element(
81 &tree, reinterpret_cast<ID *>(scene), &view_layer, nullptr, TSE_R_LAYER, 0);
82
83 TreeStoreElem *tselem = TREESTORE(&te_view_layer);
84
85 if (!tselem->used) {
86 tselem->flag &= ~TSE_CLOSED;
87 }
88
89 te_view_layer.name = view_layer->name;
90 te_view_layer.directdata = view_layer;
91
92 add_view_layer(*scene, te_view_layer.subtree, &te_view_layer);
93 }
94 }
95
96 return tree;
97}
98
99void TreeDisplayViewLayer::add_view_layer(Scene &scene, ListBase &tree, TreeElement *parent)
100{
101 const bool show_children = (space_outliner_.filter & SO_FILTER_NO_CHILDREN) == 0;
102
104 /* Show objects in the view layer. */
105 BKE_view_layer_synced_ensure(&scene, view_layer_);
106 for (Base *base : List<Base>(*BKE_view_layer_object_bases_get(view_layer_))) {
107 TreeElement *te_object = add_element(
108 &tree, reinterpret_cast<ID *>(base->object), nullptr, parent, TSE_SOME_ID, 0);
109 te_object->directdata = base;
110 }
111
112 if (show_children) {
114 }
115 }
116 else {
117 /* Show collections in the view layer. */
118 TreeElement &ten = *AbstractTreeDisplay::add_element(
119 &space_outliner_, &tree, &scene.id, nullptr, parent, TSE_VIEW_COLLECTION_BASE, 0);
120 TREESTORE(&ten)->flag &= ~TSE_CLOSED;
121
122 /* First layer collection is for master collection, don't show it. */
123 LayerCollection *lc = static_cast<LayerCollection *>(view_layer_->layer_collections.first);
124 if (lc == nullptr) {
125 return;
126 }
127
128 add_layer_collections_recursive(ten.subtree, lc->layer_collections, ten);
129 if (show_objects_) {
130 add_layer_collection_objects(ten.subtree, *lc, ten);
131 }
132 if (show_children) {
133 add_layer_collection_objects_children(ten);
134 }
135 }
136}
137
138void TreeDisplayViewLayer::add_layer_collections_recursive(ListBase &tree,
139 ListBase &layer_collections,
140 TreeElement &parent_ten)
141{
142 for (LayerCollection *lc : List<LayerCollection>(layer_collections)) {
143 const bool exclude = (lc->flag & LAYER_COLLECTION_EXCLUDE) != 0;
144 TreeElement *ten;
145
146 if (exclude && ((space_outliner_.show_restrict_flags & SO_RESTRICT_ENABLE) == 0)) {
147 ten = &parent_ten;
148 }
149 else {
150 ID *id = &lc->collection->id;
151 ten = add_element(&tree, id, lc, &parent_ten, TSE_LAYER_COLLECTION, 0);
152
153 /* Open by default, except linked collections, which may contain many elements. */
154 TreeStoreElem *tselem = TREESTORE(ten);
155 if (!(tselem->used || !ID_IS_EDITABLE(id) || ID_IS_OVERRIDE_LIBRARY(id))) {
156 tselem->flag &= ~TSE_CLOSED;
157 }
158 }
159
160 add_layer_collections_recursive(ten->subtree, lc->layer_collections, *ten);
161 if (!exclude && show_objects_) {
162 add_layer_collection_objects(ten->subtree, *lc, *ten);
163 }
164 }
165}
166
167void TreeDisplayViewLayer::add_layer_collection_objects(ListBase &tree,
168 LayerCollection &lc,
169 TreeElement &ten)
170{
171 BKE_view_layer_synced_ensure(scene_, view_layer_);
172 for (CollectionObject *cob : List<CollectionObject>(lc.collection->gobject)) {
173 Base *base = BKE_view_layer_base_find(view_layer_, cob->ob);
174 TreeElement *te_object = add_element(
175 &tree, reinterpret_cast<ID *>(base->object), nullptr, &ten, TSE_SOME_ID, 0);
176 te_object->directdata = base;
177 }
178}
179
180void TreeDisplayViewLayer::add_layer_collection_objects_children(TreeElement &collection_tree_elem)
181{
182 /* Call helper to add children. */
183 ObjectsChildrenBuilder child_builder{space_outliner_};
184 child_builder(collection_tree_elem);
185}
186
189/* -------------------------------------------------------------------- */
198 : outliner_(space_outliner)
199{
200}
201
203{
204 object_tree_elements_lookup_create_recursive(&collection_tree_elem);
205 make_object_parent_hierarchy_collections();
206}
207
211void ObjectsChildrenBuilder::object_tree_elements_lookup_create_recursive(TreeElement *te_parent)
212{
213 for (TreeElement *te : List<TreeElement>(te_parent->subtree)) {
214 TreeStoreElem *tselem = TREESTORE(te);
215
216 if (tselem->type == TSE_LAYER_COLLECTION) {
217 object_tree_elements_lookup_create_recursive(te);
218 continue;
219 }
220
221 if ((tselem->type == TSE_SOME_ID) && (te->idcode == ID_OB)) {
222 Object *ob = (Object *)tselem->id;
223 /* Lookup children or add new, empty children vector. */
224 Vector<TreeElement *> &tree_elements = object_tree_elements_map_.lookup_or_add(ob, {});
225
226 tree_elements.append(te);
227 object_tree_elements_lookup_create_recursive(te);
228 }
229 }
230}
231
236void ObjectsChildrenBuilder::make_object_parent_hierarchy_collections()
237{
238 for (ObjectTreeElementsMap::MutableItem item : object_tree_elements_map_.items()) {
239 Object *child = item.key;
240
241 if (child->parent == nullptr) {
242 continue;
243 }
244
245 Vector<TreeElement *> &child_ob_tree_elements = item.value;
246 Vector<TreeElement *> *parent_ob_tree_elements = object_tree_elements_map_.lookup_ptr(
247 child->parent);
248 if (parent_ob_tree_elements == nullptr) {
249 continue;
250 }
251
252 for (TreeElement *parent_ob_tree_element : *parent_ob_tree_elements) {
253 TreeElement *parent_ob_collection_tree_element = nullptr;
254 bool found = false;
255
256 /* We always want to remove the child from the direct collection its parent is nested under.
257 * This is particularly important when dealing with multi-level nesting (grandchildren). */
258 parent_ob_collection_tree_element = parent_ob_tree_element->parent;
259 while (!ELEM(TREESTORE(parent_ob_collection_tree_element)->type,
262 {
263 parent_ob_collection_tree_element = parent_ob_collection_tree_element->parent;
264 }
265
266 for (TreeElement *child_ob_tree_element : child_ob_tree_elements) {
267 if (child_ob_tree_element->parent == parent_ob_collection_tree_element) {
268 /* Move from the collection subtree into the parent object subtree. */
269 BLI_remlink(&parent_ob_collection_tree_element->subtree, child_ob_tree_element);
270 BLI_addtail(&parent_ob_tree_element->subtree, child_ob_tree_element);
271 child_ob_tree_element->parent = parent_ob_tree_element;
272 found = true;
273 break;
274 }
275 }
276
277 if (!found) {
278 /* We add the child in the tree even if it is not in the collection.
279 * We don't expand its sub-tree though, to make it less prominent. */
280 TreeElement *child_ob_tree_element = AbstractTreeDisplay::add_element(
281 &outliner_,
282 &parent_ob_tree_element->subtree,
283 reinterpret_cast<ID *>(child),
284 nullptr,
285 parent_ob_tree_element,
287 0,
288 false);
289 child_ob_tree_element->flag |= TE_CHILD_NOT_IN_COLLECTION;
290 child_ob_tree_elements.append(child_ob_tree_element);
291 }
292 }
293 }
294}
295
298} // 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(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition listbase.cc:110
void BLI_remlink(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition listbase.cc:130
#define ELEM(...)
#define ID_IS_EDITABLE(_id)
Definition DNA_ID.h:658
#define ID_IS_OVERRIDE_LIBRARY(_id)
Definition DNA_ID.h:683
@ ID_OB
Object groups, one object can be in many groups at once.
@ LAYER_COLLECTION_EXCLUDE
@ TSE_VIEW_COLLECTION_BASE
@ TSE_LAYER_COLLECTION
@ TSE_SOME_ID
@ TSE_R_LAYER
@ SO_RESTRICT_ENABLE
@ SO_FILTER_NO_CHILDREN
@ SO_FILTER_NO_OBJECT
@ SO_FILTER_NO_VIEW_LAYERS
@ SO_FILTER_NO_COLLECTION
const Value * lookup_ptr(const Key &key) const
Definition BLI_map.hh:484
MutableMapItem< Object *, TreeChildren > MutableItem
Definition BLI_map.hh:133
Value & lookup_or_add(const Key &key, const Value &value)
Definition BLI_map.hh:551
void append(const T &value)
Base Class For Tree-Displays.
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::VEC2, "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:413
ListBase layer_collections
struct Collection * collection
void * first
struct Object * parent
ListBase layer_collections
The data to build the tree from.
Establish and manage Outliner trees for different display modes.