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