Blender V4.3
light_linking.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2001-2023 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
5#include "BKE_light_linking.h"
6
7#include <string>
8
9#include "MEM_guardedalloc.h"
10
11#include "DNA_ID.h"
13#include "DNA_object_types.h"
14#include "DNA_scene_types.h"
15
16#include "BLI_assert.h"
17#include "BLI_string.h"
18
19#include "BKE_collection.hh"
20#include "BKE_layer.hh"
21#include "BKE_lib_id.hh"
22#include "BKE_report.hh"
23
24#include "BLT_translation.hh"
25
26#include "DEG_depsgraph.hh"
28
30{
31 if (object->light_linking->receiver_collection == nullptr &&
32 object->light_linking->blocker_collection == nullptr)
33 {
34 MEM_SAFE_FREE(object->light_linking);
35 }
36}
37
39 const LightLinkingType link_type)
40{
41 if (!object->light_linking) {
42 return nullptr;
43 }
44
45 switch (link_type) {
47 return object->light_linking->receiver_collection;
49 return object->light_linking->blocker_collection;
50 }
51
52 return nullptr;
53}
54
55static std::string get_default_collection_name(const Object *object,
56 const LightLinkingType link_type)
57{
58 const char *format;
59
60 switch (link_type) {
62 format = DATA_("Light Linking for %s");
63 break;
65 format = DATA_("Shadow Linking for %s");
66 break;
67 }
68
69 char name[MAX_ID_NAME];
70 SNPRINTF(name, format, object->id.name + 2);
71
72 return name;
73}
74
76 Object *object,
77 const LightLinkingType link_type)
78{
79 const std::string collection_name = get_default_collection_name(object, link_type);
80
81 Collection *new_collection = BKE_collection_add(bmain, nullptr, collection_name.c_str());
82
83 BKE_light_linking_collection_assign(bmain, object, new_collection, link_type);
84
85 return new_collection;
86}
87
89 Collection *new_collection,
90 const LightLinkingType link_type)
91{
92 /* Remove user from old collection. */
93 Collection *old_collection = BKE_light_linking_collection_get(object, link_type);
94 if (old_collection) {
95 id_us_min(&old_collection->id);
96 }
97
98 /* Allocate light linking on demand. */
99 if (new_collection && !object->light_linking) {
100 object->light_linking = MEM_cnew<LightLinking>(__func__);
101 }
102
103 if (object->light_linking) {
104 /* Assign and increment user of new collection. */
105 switch (link_type) {
107 object->light_linking->receiver_collection = new_collection;
108 break;
110 object->light_linking->blocker_collection = new_collection;
111 break;
112 default:
114 break;
115 }
116
117 if (new_collection) {
118 id_us_plus(&new_collection->id);
119 }
120
122 }
123}
124
126 Object *object,
127 Collection *new_collection,
128 const LightLinkingType link_type)
129{
130 BKE_light_linking_collection_assign_only(object, new_collection, link_type);
131
134}
135
136static CollectionObject *find_collection_object(const Collection *collection, const Object *object)
137{
138 LISTBASE_FOREACH (CollectionObject *, collection_object, &collection->gobject) {
139 if (collection_object->ob == object) {
140 return collection_object;
141 }
142 }
143
144 return nullptr;
145}
146
148 const Collection *child)
149{
150 LISTBASE_FOREACH (CollectionChild *, collection_child, &collection->children) {
151 if (collection_child->collection == child) {
152 return collection_child;
153 }
154 }
155
156 return nullptr;
157}
158
159/* Add object to the light linking collection and return corresponding CollectionLightLinking
160 * settings.
161 *
162 * If the object is already in the collection then the content of the collection is not modified,
163 * and the existing light linking settings are returned. */
165 Collection *collection,
166 Object *object)
167{
168 BKE_collection_object_add(bmain, collection, object);
169
170 CollectionObject *collection_object = find_collection_object(collection, object);
171
172 if (!collection_object) {
173 BLI_assert_msg(0, "Object was not found after added to the light linking collection");
174 return nullptr;
175 }
176
177 return &collection_object->light_linking;
178}
179
180/* Add child collection to the light linking collection and return corresponding
181 * CollectionLightLinking settings.
182 *
183 * If the child collection is already in the collection then the content of the collection is
184 * not modified, and the existing light linking settings are returned. */
186 Collection *collection,
187 Collection *child)
188{
189 BKE_collection_child_add(bmain, collection, child);
190
191 CollectionChild *collection_child = find_collection_child(collection, child);
192
193 if (!collection_child) {
194 BLI_assert_msg(0, "Collection was not found after added to the light linking collection");
195 return nullptr;
196 }
197
198 return &collection_child->light_linking;
199}
200
202 Collection *collection,
203 ID *receiver,
204 const eCollectionLightLinkingState link_state)
205{
206 const ID_Type id_type = GS(receiver->name);
207
208 CollectionLightLinking *collection_light_linking = nullptr;
209
210 if (id_type == ID_OB) {
211 Object *object = reinterpret_cast<Object *>(receiver);
212 if (!OB_TYPE_IS_GEOMETRY(object->type)) {
213 return;
214 }
215 collection_light_linking = light_linking_collection_add_object(bmain, collection, object);
216 }
217 else if (id_type == ID_GR) {
218 collection_light_linking = light_linking_collection_add_collection(
219 bmain, collection, reinterpret_cast<Collection *>(receiver));
220 }
221 else {
222 return;
223 }
224
225 if (!collection_light_linking) {
226 return;
227 }
228
229 collection_light_linking->link_state = link_state;
230
231 DEG_id_tag_update(&collection->id, ID_RECALC_HIERARCHY);
233
235}
236
238 Collection *receiver,
239 const ID *before)
240{
241 CollectionChild *receiver_collection_child = find_collection_child(collection, receiver);
242 if (!receiver_collection_child) {
243 BLI_assert_msg(0, "Receiver child was not found after adding collection to light linking");
244 return;
245 }
246
247 const ID_Type before_id_type = GS(before->name);
248
249 if (before_id_type != ID_GR) {
250 /* Adding before object: move the collection to the very bottom.
251 * This is as far to the bottom as the receiver can be in the flattened list of the collection.
252 */
253 BLI_remlink(&collection->children, receiver_collection_child);
254 BLI_addtail(&collection->children, receiver_collection_child);
255 return;
256 }
257
258 CollectionChild *before_collection_child = find_collection_child(
259 collection, reinterpret_cast<const Collection *>(before));
260 if (!before_collection_child) {
261 BLI_assert_msg(0, "Before child was not found");
262 return;
263 }
264
265 BLI_remlink(&collection->children, receiver_collection_child);
266 BLI_insertlinkbefore(&collection->children, before_collection_child, receiver_collection_child);
267}
268
270 Collection *receiver,
271 const ID *after)
272{
273 CollectionChild *receiver_collection_child = find_collection_child(collection, receiver);
274 if (!receiver_collection_child) {
275 BLI_assert_msg(0, "Receiver child was not found after adding collection to light linking");
276 return;
277 }
278
279 const ID_Type after_id_type = GS(after->name);
280
281 if (after_id_type != ID_GR) {
282 /* Adding before object: move the collection to the very bottom.
283 * This is as far to the bottom as the receiver can be in the flattened list of the collection.
284 */
285 BLI_remlink(&collection->children, receiver_collection_child);
286 BLI_addtail(&collection->children, receiver_collection_child);
287 return;
288 }
289
290 CollectionChild *after_collection_child = find_collection_child(
291 collection, reinterpret_cast<const Collection *>(after));
292 if (!after_collection_child) {
293 BLI_assert_msg(0, "After child was not found");
294 return;
295 }
296
297 BLI_remlink(&collection->children, receiver_collection_child);
298 BLI_insertlinkafter(&collection->children, after_collection_child, receiver_collection_child);
299}
300
302 Object *receiver,
303 const ID *before)
304{
305 CollectionObject *receiver_collection_object = find_collection_object(collection, receiver);
306 if (!receiver_collection_object) {
308 0, "Receiver collection object was not found after adding collection to light linking");
309 return;
310 }
311
312 const ID_Type before_id_type = GS(before->name);
313
314 if (before_id_type != ID_OB) {
315 /* Adding before collection: move the receiver to the very beginning of the child objects list.
316 * This is as close to the top of the flattened list of the collection content the object can
317 * possibly be. */
318 BLI_remlink(&collection->gobject, receiver_collection_object);
319 BLI_addhead(&collection->gobject, receiver_collection_object);
320 return;
321 }
322
323 CollectionObject *before_collection_object = find_collection_object(
324 collection, reinterpret_cast<const Object *>(before));
325 if (!before_collection_object) {
326 BLI_assert_msg(0, "Before collection object was not found");
327 return;
328 }
329
330 BLI_remlink(&collection->gobject, receiver_collection_object);
331 BLI_insertlinkbefore(&collection->gobject, before_collection_object, receiver_collection_object);
332}
333
334static void order_object_receiver_after(Collection *collection, Object *receiver, const ID *after)
335{
336 CollectionObject *receiver_collection_object = find_collection_object(collection, receiver);
337 if (!receiver_collection_object) {
339 0, "Receiver collection object was not found after adding collection to light linking");
340 return;
341 }
342
343 const ID_Type after_id_type = GS(after->name);
344
345 if (after_id_type != ID_OB) {
346 /* Adding after collection: move the receiver to the very beginning of the child objects list.
347 * This is as close to the top of the flattened list of the collection content the object can
348 * possibly be. */
349 BLI_remlink(&collection->gobject, receiver_collection_object);
350 BLI_addhead(&collection->gobject, receiver_collection_object);
351 return;
352 }
353
354 CollectionObject *after_collection_object = find_collection_object(
355 collection, reinterpret_cast<const Object *>(after));
356 if (!after_collection_object) {
357 BLI_assert_msg(0, "After collection object was not found");
358 return;
359 }
360
361 BLI_remlink(&collection->gobject, receiver_collection_object);
362 BLI_insertlinkafter(&collection->gobject, after_collection_object, receiver_collection_object);
363}
364
366 Main *bmain,
367 Collection *collection,
368 ID *receiver,
369 const ID *before,
370 const eCollectionLightLinkingState link_state)
371{
372 BLI_assert(before);
373
374 BKE_light_linking_add_receiver_to_collection(bmain, collection, receiver, link_state);
375
376 if (!before) {
377 return;
378 }
379
380 const ID_Type id_type = GS(receiver->name);
381 if (id_type == ID_OB) {
382 order_object_receiver_before(collection, reinterpret_cast<Object *>(receiver), before);
383 }
384 else if (id_type == ID_GR) {
385 order_collection_receiver_before(collection, reinterpret_cast<Collection *>(receiver), before);
386 }
387}
388
390 Main *bmain,
391 Collection *collection,
392 ID *receiver,
393 const ID *after,
394 const eCollectionLightLinkingState link_state)
395{
396 BLI_assert(after);
397
398 BKE_light_linking_add_receiver_to_collection(bmain, collection, receiver, link_state);
399
400 if (!after) {
401 return;
402 }
403
404 const ID_Type id_type = GS(receiver->name);
405 if (id_type == ID_OB) {
406 order_object_receiver_after(collection, reinterpret_cast<Object *>(receiver), after);
407 }
408 else if (id_type == ID_GR) {
409 order_collection_receiver_after(collection, reinterpret_cast<Collection *>(receiver), after);
410 }
411}
412
414 Collection *collection,
415 ID *id,
416 ReportList *reports)
417{
418 const ID_Type id_type = GS(id->name);
419
420 if (id_type == ID_OB) {
421 BKE_collection_object_remove(bmain, collection, reinterpret_cast<Object *>(id), false);
422 }
423 else if (id_type == ID_GR) {
424 BKE_collection_child_remove(bmain, collection, reinterpret_cast<Collection *>(id));
425 }
426 else {
427 BKE_reportf(reports,
428 RPT_ERROR,
429 "Cannot unlink unsupported '%s' from light linking collection '%s'",
430 id->name + 2,
431 collection->id.name + 2);
432 return false;
433 }
434
435 DEG_id_tag_update(&collection->id, ID_RECALC_HIERARCHY);
436 if (id_type == ID_OB) {
438 }
439
441
442 return true;
443}
444
446 Object *emitter,
447 Object *receiver,
448 const LightLinkingType link_type,
449 const eCollectionLightLinkingState link_state)
450{
451 if (!OB_TYPE_IS_GEOMETRY(receiver->type)) {
452 return;
453 }
454
455 Collection *collection = BKE_light_linking_collection_get(emitter, link_type);
456
457 if (!collection) {
458 collection = BKE_light_linking_collection_new(bmain, emitter, link_type);
459 }
460
461 BKE_light_linking_add_receiver_to_collection(bmain, collection, &receiver->id, link_state);
462}
463
465 ViewLayer *view_layer,
466 Object *emitter,
467 const LightLinkingType link_type)
468{
469 Collection *collection = BKE_light_linking_collection_get(emitter, link_type);
470 if (!collection) {
471 return;
472 }
473
474 BKE_view_layer_synced_ensure(scene, view_layer);
475
476 /* Deselect all currently selected objects in the view layer, but keep the emitter selected.
477 * This is because the operation is called from the emitter being active, and it will be
478 * confusing to deselect it but keep active. */
480 if (base->object == emitter) {
481 continue;
482 }
483 base->flag &= ~BASE_SELECTED;
484 }
485
486 /* Select objects which are reachable via the receiver collection hierarchy. */
487 LISTBASE_FOREACH (CollectionObject *, cob, &collection->gobject) {
488 Base *base = BKE_view_layer_base_find(view_layer, cob->ob);
489 if (!base) {
490 continue;
491 }
492
493 /* TODO(sergey): Check whether the object is configured to receive light. */
494
495 base->flag |= BASE_SELECTED;
496 }
497
499}
bool BKE_collection_object_remove(Main *bmain, Collection *collection, Object *ob, bool free_us)
bool BKE_collection_child_remove(Main *bmain, Collection *parent, Collection *child)
Collection * BKE_collection_add(Main *bmain, Collection *collection_parent, const char *name_custom)
bool BKE_collection_child_add(Main *bmain, Collection *parent, Collection *child)
bool BKE_collection_object_add(Main *bmain, Collection *collection, Object *ob)
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 id_us_plus(ID *id)
Definition lib_id.cc:351
void id_us_min(ID *id)
Definition lib_id.cc:359
LightLinkingType
@ LIGHT_LINKING_BLOCKER
@ LIGHT_LINKING_RECEIVER
void BKE_reportf(ReportList *reports, eReportType type, const char *format,...) ATTR_PRINTF_FORMAT(3
#define BLI_assert_unreachable()
Definition BLI_assert.h:97
#define BLI_assert(a)
Definition BLI_assert.h:50
#define BLI_assert_msg(a, msg)
Definition BLI_assert.h:57
void BLI_addhead(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition listbase.cc:90
#define LISTBASE_FOREACH(type, var, list)
void BLI_insertlinkafter(struct ListBase *listbase, void *vprevlink, void *vnewlink) ATTR_NONNULL(1)
Definition listbase.cc:331
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
void BLI_insertlinkbefore(struct ListBase *listbase, void *vnextlink, void *vnewlink) ATTR_NONNULL(1)
Definition listbase.cc:370
#define SNPRINTF(dst, format,...)
Definition BLI_string.h:597
#define DATA_(msgid)
void DEG_id_tag_update(ID *id, unsigned int flags)
void DEG_relations_tag_update(Main *bmain)
ID and Library types, which are fundamental for SDNA.
@ ID_RECALC_SHADING
Definition DNA_ID.h:1061
@ ID_RECALC_SELECT
Definition DNA_ID.h:1068
@ ID_RECALC_HIERARCHY
Definition DNA_ID.h:1125
@ ID_RECALC_SYNC_TO_EVAL
Definition DNA_ID.h:1085
#define MAX_ID_NAME
Definition DNA_ID.h:377
ID_Type
@ ID_GR
@ ID_OB
Object groups, one object can be in many groups at once.
eCollectionLightLinkingState
Object is a sort of wrapper for general info.
#define OB_TYPE_IS_GEOMETRY(_type)
#define BASE_SELECTED(v3d, base)
Read Guarded memory(de)allocation.
#define MEM_SAFE_FREE(v)
#define GS(x)
Definition iris.cc:202
void BKE_light_linking_add_receiver_to_collection_before(Main *bmain, Collection *collection, ID *receiver, const ID *before, const eCollectionLightLinkingState link_state)
static CollectionObject * find_collection_object(const Collection *collection, const Object *object)
Collection * BKE_light_linking_collection_get(const Object *object, const LightLinkingType link_type)
static CollectionLightLinking * light_linking_collection_add_collection(Main *bmain, Collection *collection, Collection *child)
void BKE_light_linking_collection_assign_only(Object *object, Collection *new_collection, const LightLinkingType link_type)
void BKE_light_linking_free_if_empty(Object *object)
bool BKE_light_linking_unlink_id_from_collection(Main *bmain, Collection *collection, ID *id, ReportList *reports)
void BKE_light_linking_add_receiver_to_collection_after(Main *bmain, Collection *collection, ID *receiver, const ID *after, const eCollectionLightLinkingState link_state)
static void order_collection_receiver_before(Collection *collection, Collection *receiver, const ID *before)
static CollectionChild * find_collection_child(const Collection *collection, const Collection *child)
Collection * BKE_light_linking_collection_new(Main *bmain, Object *object, const LightLinkingType link_type)
static CollectionLightLinking * light_linking_collection_add_object(Main *bmain, Collection *collection, Object *object)
void BKE_light_linking_add_receiver_to_collection(Main *bmain, Collection *collection, ID *receiver, const eCollectionLightLinkingState link_state)
void BKE_light_linking_select_receivers_of_emitter(Scene *scene, ViewLayer *view_layer, Object *emitter, const LightLinkingType link_type)
static std::string get_default_collection_name(const Object *object, const LightLinkingType link_type)
static void order_object_receiver_before(Collection *collection, Object *receiver, const ID *before)
void BKE_light_linking_collection_assign(Main *bmain, Object *object, Collection *new_collection, const LightLinkingType link_type)
static void order_object_receiver_after(Collection *collection, Object *receiver, const ID *after)
static void order_collection_receiver_after(Collection *collection, Collection *receiver, const ID *after)
void BKE_light_linking_link_receiver_to_emitter(Main *bmain, Object *emitter, Object *receiver, const LightLinkingType link_type, const eCollectionLightLinkingState link_state)
format
short flag
CollectionLightLinking light_linking
CollectionLightLinking light_linking
Definition DNA_ID.h:413
char name[66]
Definition DNA_ID.h:425