Blender V4.5
cryptomatte.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2020 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
8
9#include "BKE_cryptomatte.h"
10#include "BKE_cryptomatte.hh"
11#include "BKE_image.hh"
12#include "BKE_layer.hh"
13#include "BKE_main.hh"
14#include "BKE_material.hh"
15
16#include "DNA_layer_types.h"
17#include "DNA_material_types.h"
18#include "DNA_node_types.h"
19#include "DNA_object_types.h"
20#include "DNA_scene_types.h"
21
22#include "BLI_dynstr.h"
23#include "BLI_hash_mm3.hh"
24#include "BLI_listbase.h"
25#include "BLI_string.h"
26
27#include "RE_pipeline.h"
28
29#include "MEM_guardedalloc.h"
30
31#include <cctype>
32#include <cstring>
33#include <iomanip>
34#include <sstream>
35#include <string>
36
39 /* Layer names in order of creation. */
41
42 CryptomatteSession() = default;
43 CryptomatteSession(const Main *bmain);
44 CryptomatteSession(StampData *stamp_data);
45 CryptomatteSession(const ViewLayer *view_layer);
46 CryptomatteSession(const Scene *scene, bool build_meta_data = false);
47 void init(const ViewLayer *view_layer, bool build_meta_data = false);
48
50 std::optional<std::string> operator[](float encoded_hash) const;
51
52 MEM_CXX_CLASS_ALLOC_FUNCS("cryptomatte:CryptomatteSession")
53};
54
56{
57 if (!BLI_listbase_is_empty(&bmain->objects)) {
60 LISTBASE_FOREACH (ID *, id, &bmain->objects) {
61 objects.add_ID(*id);
62 }
63
65 LISTBASE_FOREACH (ID *, id, &bmain->objects) {
66 const Object *asset_object = reinterpret_cast<Object *>(id);
67 while (asset_object->parent != nullptr) {
68 asset_object = asset_object->parent;
69 }
70 assets.add_ID(asset_object->id);
71 }
72 }
73 if (!BLI_listbase_is_empty(&bmain->materials)) {
76 LISTBASE_FOREACH (ID *, id, &bmain->materials) {
77 materials.add_ID(*id);
78 }
79 }
80}
81
97
99{
100 init(view_layer);
101}
102
103CryptomatteSession::CryptomatteSession(const Scene *scene, bool build_meta_data)
104{
105
106 if (build_meta_data) {
108 }
109
110 LISTBASE_FOREACH (const ViewLayer *, view_layer, &scene->view_layers) {
111 init(view_layer, build_meta_data);
112 }
113}
114
115void CryptomatteSession::init(const ViewLayer *view_layer, bool build_meta_data)
116{
119 if (cryptoflags == 0) {
120 cryptoflags = VIEW_LAYER_CRYPTOMATTE_ALL;
121 }
122
123 ListBase *object_bases = BKE_view_layer_object_bases_get(const_cast<ViewLayer *>(view_layer));
124
125 if (cryptoflags & VIEW_LAYER_CRYPTOMATTE_OBJECT) {
128
129 if (build_meta_data) {
130 LISTBASE_FOREACH (Base *, base, object_bases) {
131 objects.add_ID(base->object->id);
132 }
133 }
134 }
135
136 if (cryptoflags & VIEW_LAYER_CRYPTOMATTE_ASSET) {
139
140 if (build_meta_data) {
141 LISTBASE_FOREACH (Base *, base, object_bases) {
142 const Object *asset_object = base->object;
143 while (asset_object->parent != nullptr) {
144 asset_object = asset_object->parent;
145 }
146 assets.add_ID(asset_object->id);
147 }
148 }
149 }
150
151 if (cryptoflags & VIEW_LAYER_CRYPTOMATTE_MATERIAL) {
154
155 if (build_meta_data) {
156 LISTBASE_FOREACH (Base *, base, object_bases) {
157 for (int i = 0; i < base->object->totcol; i++) {
158 Material *material = BKE_object_material_get(base->object, i + 1);
159 if (material) {
160 materials.add_ID(material->id);
161 }
162 }
163 }
164 }
165 }
166}
167
169{
170 if (!layer_names.contains(layer_name)) {
171 layer_names.append(layer_name);
172 }
173 return layers.lookup_or_add_default(layer_name);
174}
175
176std::optional<std::string> CryptomatteSession::operator[](float encoded_hash) const
177{
178 for (const blender::bke::cryptomatte::CryptomatteLayer &layer : layers.values()) {
179 std::optional<std::string> result = layer[encoded_hash];
180 if (result) {
181 return result;
182 }
183 }
184 return std::nullopt;
185}
186
188{
189 CryptomatteSession *session = new CryptomatteSession();
190 return session;
191}
192
194{
195 CryptomatteSession *session = new CryptomatteSession(render_result->stamp_data);
196 return session;
197}
198
199CryptomatteSession *BKE_cryptomatte_init_from_scene(const Scene *scene, bool build_meta_data)
200{
201 CryptomatteSession *session = new CryptomatteSession(scene, build_meta_data);
202 return session;
203}
204
206{
207 CryptomatteSession *session = new CryptomatteSession(view_layer);
208 return session;
209}
210
211void BKE_cryptomatte_add_layer(CryptomatteSession *session, const char *layer_name)
212{
213 session->add_layer(layer_name);
214}
215
217{
218 BLI_assert(session != nullptr);
219 delete session;
220}
221
222uint32_t BKE_cryptomatte_hash(const char *name, const int name_len)
223{
225 return hash.hash;
226}
227
229 const char *layer_name,
230 const Object *object)
231{
233 BLI_assert(layer);
234 return layer->add_ID(object->id);
235}
236
238 const char *layer_name,
239 const Material *material)
240{
241 if (material == nullptr) {
242 return 0.0f;
243 }
245 BLI_assert(layer);
246 return layer->add_ID(material->id);
247}
248
250 const char *layer_name,
251 const Object *object)
252{
253 const Object *asset_object = object;
254 while (asset_object->parent != nullptr) {
255 asset_object = asset_object->parent;
256 }
257 return BKE_cryptomatte_object_hash(session, layer_name, asset_object);
258}
259
260float BKE_cryptomatte_hash_to_float(uint32_t cryptomatte_hash)
261{
263}
264
266 const float encoded_hash,
267 char *r_name,
268 int name_maxncpy)
269{
270 std::optional<std::string> name = (*session)[encoded_hash];
271 if (!name) {
272 return false;
273 }
274
275 BLI_strncpy(r_name, name->c_str(), name_maxncpy);
276 return true;
277}
278
280{
281 DynStr *matte_id = BLI_dynstr_new();
282 bool first = true;
283 LISTBASE_FOREACH (CryptomatteEntry *, entry, &node_storage->entries) {
284 if (!first) {
285 BLI_dynstr_append(matte_id, ",");
286 }
287 if (STRNLEN(entry->name) != 0) {
288 BLI_dynstr_nappend(matte_id, entry->name, sizeof(entry->name));
289 }
290 else {
291 BLI_dynstr_appendf(matte_id, "<%.9g>", entry->encoded_hash);
292 }
293 first = false;
294 }
295 char *result = BLI_dynstr_get_cstring(matte_id);
296 BLI_dynstr_free(matte_id);
297 return result;
298}
299
300void BKE_cryptomatte_matte_id_to_entries(NodeCryptomatte *node_storage, const char *matte_id)
301{
302 BLI_freelistN(&node_storage->entries);
303
304 if (matte_id == nullptr) {
305 MEM_SAFE_FREE(node_storage->matte_id);
306 return;
307 }
308 /* Update the matte_id so the files can be opened in versions that don't
309 * use `CryptomatteEntry`. */
310 if (matte_id != node_storage->matte_id && node_storage->matte_id &&
311 STREQ(node_storage->matte_id, matte_id))
312 {
313 MEM_SAFE_FREE(node_storage->matte_id);
314 node_storage->matte_id = static_cast<char *>(MEM_dupallocN(matte_id));
315 }
316
317 std::istringstream ss(matte_id);
318 while (ss.good()) {
319 CryptomatteEntry *entry = nullptr;
320 std::string token;
321 getline(ss, token, ',');
322 /* Ignore empty tokens. */
323 if (token.length() > 0) {
324 size_t first = token.find_first_not_of(' ');
325 size_t last = token.find_last_not_of(' ');
326 if (first == std::string::npos || last == std::string::npos) {
327 break;
328 }
329 token = token.substr(first, (last - first + 1));
330 if (*token.begin() == '<' && *(--token.end()) == '>') {
331 float encoded_hash = atof(token.substr(1, token.length() - 2).c_str());
332 entry = MEM_callocN<CryptomatteEntry>(__func__);
333 entry->encoded_hash = encoded_hash;
334 }
335 else {
336 const char *name = token.c_str();
337 int name_len = token.length();
338 entry = MEM_callocN<CryptomatteEntry>(__func__);
339 STRNCPY(entry->name, name);
340 uint32_t hash = BKE_cryptomatte_hash(name, name_len);
342 }
343 }
344 if (entry != nullptr) {
345 BLI_addtail(&node_storage->entries, entry);
346 }
347 }
348}
349
351{
352 return BLI_hash_mm3(reinterpret_cast<const uchar *>(name.data()), name.size(), 0);
353}
354
355static void add_render_result_meta_data(RenderResult *render_result,
356 const blender::StringRef layer_name,
357 const blender::StringRefNull key_name,
358 const blender::StringRefNull value)
359{
361 render_result,
363 value.data());
364}
365
367{
369 session->layers.items())
370 {
371 const blender::StringRefNull layer_name(item.key);
372 const blender::bke::cryptomatte::CryptomatteLayer &layer = item.value;
373
374 const std::string manifest = layer.manifest();
375
376 add_render_result_meta_data(render_result, layer_name, "name", layer_name);
377 add_render_result_meta_data(render_result, layer_name, "hash", "MurmurHash3_32");
378 add_render_result_meta_data(render_result, layer_name, "conversion", "uint32_to_float32");
379 add_render_result_meta_data(render_result, layer_name, "manifest", manifest);
380 }
381}
382
384namespace manifest {
385constexpr StringRef WHITESPACES = " \t\n\v\f\r";
386
388{
389 size_t skip = ref.find_first_not_of(WHITESPACES);
390 if (skip == blender::StringRef::not_found) {
391 return ref;
392 }
393 return ref.drop_prefix(skip);
394}
395
396static constexpr int quoted_string_len_(blender::StringRef ref)
397{
398 int len = 1;
399 bool skip_next = false;
400 while (len < ref.size()) {
401 char current_char = ref[len];
402 if (skip_next) {
403 skip_next = false;
404 }
405 else {
406 if (current_char == '\\') {
407 skip_next = true;
408 }
409 if (current_char == '\"') {
410 len += 1;
411 break;
412 }
413 }
414 len += 1;
415 }
416 return len;
417}
418
419static std::string unquote_(const blender::StringRef ref)
420{
421 std::ostringstream stream;
422 for (char c : ref) {
423 if (c != '\\') {
424 stream << c;
425 }
426 }
427 return stream.str();
428}
429
431{
432 StringRef ref = manifest;
433 ref = skip_whitespaces_(ref);
434 if (ref.is_empty() || ref.front() != '{') {
435 return false;
436 }
437 ref = ref.drop_prefix(1);
438 while (!ref.is_empty()) {
439 char front = ref.front();
440
441 if (front == '\"') {
442 const int quoted_name_len = quoted_string_len_(ref);
443 const int name_len = quoted_name_len - 2;
444 std::string name = unquote_(ref.substr(1, name_len));
445 ref = ref.drop_prefix(quoted_name_len);
446 ref = skip_whitespaces_(ref);
447
448 if (ref.is_empty()) {
449 return false;
450 }
451 char colon = ref.front();
452 if (colon != ':') {
453 return false;
454 }
455 ref = ref.drop_prefix(1);
456 ref = skip_whitespaces_(ref);
457
458 if (ref.is_empty() || ref.front() != '\"') {
459 return false;
460 }
461
462 const int quoted_hash_len = quoted_string_len_(ref);
463 if (quoted_hash_len < 2) {
464 return false;
465 }
466 const int hash_len = quoted_hash_len - 2;
468 ref = ref.drop_prefix(quoted_hash_len);
469 layer.add_hash(name, hash);
470 }
471 else if (front == ',') {
472 ref = ref.drop_prefix(1);
473 }
474 else if (front == '}') {
475 ref = ref.drop_prefix(1);
476 ref = skip_whitespaces_(ref);
477 break;
478 }
479 ref = skip_whitespaces_(ref);
480 }
481
482 if (!ref.is_empty()) {
483 return false;
484 }
485
486 return true;
487}
488
489static std::string to_manifest(const CryptomatteLayer *layer)
490{
491 std::stringstream manifest;
492
493 bool is_first = true;
494 const blender::Map<std::string, CryptomatteHash> &const_map = layer->hashes;
495 manifest << "{";
497 if (is_first) {
498 is_first = false;
499 }
500 else {
501 manifest << ",";
502 }
503 manifest << quoted(item.key) << ":\"" << item.value.hex_encoded() << "\"";
504 }
505 manifest << "}";
506 return manifest.str();
507}
508
509} // namespace manifest
510
511/* Return the hash of the given cryptomatte layer name.
512 *
513 * The cryptomatte specification limits the hash to 7 characters.
514 * The 7 position limitation solves issues when using cryptomatte together with OpenEXR.
515 * The specification suggests to use the first 7 chars of the hashed layer_name.
516 */
517static std::string cryptomatte_layer_name_hash(const StringRef layer_name)
518{
519 std::stringstream stream;
520 const uint32_t render_pass_identifier = cryptomatte_determine_identifier(layer_name);
521 stream << std::setfill('0') << std::setw(sizeof(uint32_t) * 2) << std::hex
522 << render_pass_identifier;
523 return stream.str().substr(0, 7);
524}
525
526std::string BKE_cryptomatte_meta_data_key(const StringRef layer_name, const StringRefNull key_name)
527{
528 return "cryptomatte/" + cryptomatte_layer_name_hash(layer_name) + "/" + key_name;
529}
530
532{
533 int64_t last_token = render_pass_name.size();
534 while (last_token > 0 && std::isdigit(render_pass_name[last_token - 1])) {
535 last_token -= 1;
536 }
537 return render_pass_name.substr(0, last_token);
538}
539
541
543{
545 std::istringstream(hex_encoded) >> std::hex >> result.hash;
546 return result;
547}
548
550{
551 std::stringstream encoded;
552 encoded << std::setfill('0') << std::setw(sizeof(uint32_t) * 2) << std::hex << hash;
553 return encoded.str();
554}
555
556std::unique_ptr<CryptomatteLayer> CryptomatteLayer::read_from_manifest(
558{
559 std::unique_ptr<CryptomatteLayer> layer = std::make_unique<CryptomatteLayer>();
561 return layer;
562}
563
564uint32_t CryptomatteLayer::add_ID(const ID &id)
565{
566 const char *name = &id.name[2];
567 const int name_len = BLI_strnlen(name, MAX_NAME - 2);
568 uint32_t cryptohash_int = BKE_cryptomatte_hash(name, name_len);
569
570 add_hash(blender::StringRef(name, name_len), cryptohash_int);
571
572 return cryptohash_int;
573}
574
575void CryptomatteLayer::add_hash(blender::StringRef name, CryptomatteHash cryptomatte_hash)
576{
577 hashes.add_overwrite(name, cryptomatte_hash);
578}
579
580std::optional<std::string> CryptomatteLayer::operator[](float encoded_hash) const
581{
584 if (BKE_cryptomatte_hash_to_float(item.value.hash) == encoded_hash) {
585 return std::make_optional(item.key);
586 }
587 }
588 return std::nullopt;
589}
590
591std::string CryptomatteLayer::manifest() const
592{
594}
595
597{
598 BLI_assert(key.startswith("cryptomatte/"));
599
600 size_t start_index = key.find_first_of('/');
601 size_t end_index = key.find_last_of('/');
602 if (start_index == blender::StringRef::not_found) {
603 return "";
604 }
605 if (end_index == blender::StringRef::not_found) {
606 return "";
607 }
608 if (end_index <= start_index) {
609 return "";
610 }
611 return key.substr(start_index + 1, end_index - start_index - 1);
612}
613
615 const char *propname,
616 char *propvalue,
617 int /*propvalue_maxncpy*/)
618{
620
621 blender::StringRefNull key(propname);
622 if (!key.startswith("cryptomatte/")) {
623 return;
624 }
625 if (!key.endswith("/name")) {
626 return;
627 }
628 blender::StringRef layer_hash = extract_layer_hash(key);
629 data->hash_to_layer_name.add(layer_hash, propvalue);
630}
631
633 const char *propname,
634 char *propvalue,
635 int /*propvalue_maxncpy*/)
636{
638
639 blender::StringRefNull key(propname);
640 if (!key.startswith("cryptomatte/")) {
641 return;
642 }
643 if (!key.endswith("/manifest")) {
644 return;
645 }
646 blender::StringRef layer_hash = extract_layer_hash(key);
647 if (!data->hash_to_layer_name.contains(layer_hash)) {
648 return;
649 }
650
651 blender::StringRef layer_name = data->hash_to_layer_name.lookup(layer_hash);
652 blender::bke::cryptomatte::CryptomatteLayer &layer = data->session->add_layer(layer_name);
654}
655
657 const CryptomatteSession &session)
658{
659 return session.layer_names;
660}
661
663{
664 return session.layers.lookup_ptr(layer_name);
665}
666
667} // namespace blender::bke::cryptomatte
float BKE_cryptomatte_hash_to_float(uint32_t cryptomatte_hash)
uint32_t BKE_cryptomatte_hash(const char *name, int name_len)
void BKE_stamp_info_callback(void *data, StampData *stamp_data, StampCallback callback, bool noskip)
void BKE_render_result_stamp_data(RenderResult *rr, const char *key, const char *value)
void BKE_scene_view_layers_synced_ensure(const Scene *scene)
ListBase * BKE_view_layer_object_bases_get(ViewLayer *view_layer)
General operations, lookup, etc. for materials.
Material * BKE_object_material_get(Object *ob, short act)
#define BLI_assert(a)
Definition BLI_assert.h:46
A dynamically sized string ADT.
char * BLI_dynstr_get_cstring(const DynStr *ds) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
void BLI_dynstr_nappend(DynStr *__restrict ds, const char *cstr, int len) ATTR_NONNULL()
Definition BLI_dynstr.cc:74
DynStr * BLI_dynstr_new(void) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT
Definition BLI_dynstr.cc:36
void BLI_dynstr_free(DynStr *ds) ATTR_NONNULL()
void BLI_dynstr_appendf(DynStr *__restrict ds, const char *__restrict format,...) ATTR_PRINTF_FORMAT(2
void BLI_dynstr_append(DynStr *__restrict ds, const char *cstr) ATTR_NONNULL()
Definition BLI_dynstr.cc:55
uint32_t BLI_hash_mm3(const unsigned char *data, size_t len, uint32_t seed)
Definition hash_mm3.cc:73
#define LISTBASE_FOREACH(type, var, list)
BLI_INLINE bool BLI_listbase_is_empty(const ListBase *lb)
void void BLI_freelistN(ListBase *listbase) ATTR_NONNULL(1)
Definition listbase.cc:497
void BLI_addtail(ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition listbase.cc:111
int char char int int int int size_t BLI_strnlen(const char *str, size_t maxlen) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
Definition string.cc:923
#define STRNLEN(str)
Definition BLI_string.h:608
char * STRNCPY(char(&dst)[N], const char *src)
Definition BLI_string.h:688
char * BLI_strncpy(char *__restrict dst, const char *__restrict src, size_t dst_maxncpy) ATTR_NONNULL(1
unsigned char uchar
#define STREQ(a, b)
eViewLayerCryptomatteFlags
@ VIEW_LAYER_CRYPTOMATTE_MATERIAL
@ VIEW_LAYER_CRYPTOMATTE_ASSET
@ VIEW_LAYER_CRYPTOMATTE_OBJECT
#define VIEW_LAYER_CRYPTOMATTE_ALL
Object is a sort of wrapper for general info.
#define RE_PASSNAME_CRYPTOMATTE_MATERIAL
#define RE_PASSNAME_CRYPTOMATTE_ASSET
#define RE_PASSNAME_CRYPTOMATTE_OBJECT
Read Guarded memory(de)allocation.
BMesh const char void * data
void init()
long long int int64_t
const Value * lookup_ptr(const Key &key) const
Definition BLI_map.hh:508
ItemIterator items() const &
Definition BLI_map.hh:902
ItemIterator items() const &
Definition BLI_map.hh:902
constexpr const char & front() const
static constexpr int64_t not_found
constexpr int64_t find_last_of(StringRef chars, int64_t pos=INT64_MAX) const
constexpr int64_t find_first_not_of(StringRef chars, int64_t pos=0) const
constexpr bool is_empty() const
constexpr StringRef substr(int64_t start, int64_t size) const
constexpr bool startswith(StringRef prefix) const
constexpr bool endswith(StringRef suffix) const
constexpr int64_t find_first_of(StringRef chars, int64_t pos=0) const
constexpr int64_t size() const
constexpr const char * data() const
constexpr StringRef drop_prefix(int64_t n) const
CryptomatteSession * BKE_cryptomatte_init_from_render_result(const RenderResult *render_result)
uint32_t BKE_cryptomatte_hash(const char *name, const int name_len)
void BKE_cryptomatte_store_metadata(const CryptomatteSession *session, RenderResult *render_result)
static void add_render_result_meta_data(RenderResult *render_result, const blender::StringRef layer_name, const blender::StringRefNull key_name, const blender::StringRefNull value)
bool BKE_cryptomatte_find_name(const CryptomatteSession *session, const float encoded_hash, char *r_name, int name_maxncpy)
CryptomatteSession * BKE_cryptomatte_init()
void BKE_cryptomatte_free(CryptomatteSession *session)
CryptomatteSession * BKE_cryptomatte_init_from_scene(const Scene *scene, bool build_meta_data)
void BKE_cryptomatte_add_layer(CryptomatteSession *session, const char *layer_name)
float BKE_cryptomatte_hash_to_float(uint32_t cryptomatte_hash)
uint32_t BKE_cryptomatte_asset_hash(CryptomatteSession *session, const char *layer_name, const Object *object)
static uint32_t cryptomatte_determine_identifier(const blender::StringRef name)
CryptomatteSession * BKE_cryptomatte_init_from_view_layer(const ViewLayer *view_layer)
void BKE_cryptomatte_matte_id_to_entries(NodeCryptomatte *node_storage, const char *matte_id)
char * BKE_cryptomatte_entries_to_matte_id(NodeCryptomatte *node_storage)
uint32_t BKE_cryptomatte_object_hash(CryptomatteSession *session, const char *layer_name, const Object *object)
uint32_t BKE_cryptomatte_material_hash(CryptomatteSession *session, const char *layer_name, const Material *material)
#define MEM_SAFE_FREE(v)
#define MAX_NAME
void * MEM_callocN(size_t len, const char *str)
Definition mallocn.cc:118
void * MEM_dupallocN(const void *vmemh)
Definition mallocn.cc:143
static bool from_manifest(CryptomatteLayer &layer, blender::StringRefNull manifest)
static constexpr int quoted_string_len_(blender::StringRef ref)
static std::string unquote_(const blender::StringRef ref)
static constexpr blender::StringRef skip_whitespaces_(blender::StringRef ref)
static std::string to_manifest(const CryptomatteLayer *layer)
StringRef BKE_cryptomatte_extract_layer_name(StringRef render_pass_name)
CryptomatteLayer * BKE_cryptomatte_layer_get(CryptomatteSession &session, StringRef layer_name)
static std::string cryptomatte_layer_name_hash(const StringRef layer_name)
std::string BKE_cryptomatte_meta_data_key(StringRef layer_name, StringRefNull key_name)
const blender::Vector< std::string > & BKE_cryptomatte_layer_names_get(const CryptomatteSession &session)
#define hash
Definition noise_c.cc:154
CryptomatteSession()=default
blender::Map< std::string, blender::bke::cryptomatte::CryptomatteLayer > layers
std::optional< std::string > operator[](float encoded_hash) const
void init(const ViewLayer *view_layer, bool build_meta_data=false)
blender::bke::cryptomatte::CryptomatteLayer & add_layer(std::string layer_name)
blender::Vector< std::string > layer_names
Definition DNA_ID.h:404
ListBase materials
Definition BKE_main.hh:251
ListBase objects
Definition BKE_main.hh:247
struct Object * parent
struct StampData * stamp_data
ListBase view_layers
short cryptomatte_flag
char name[64]
static CryptomatteHash from_hex_encoded(blender::StringRef hex_encoded)
void add_hash(blender::StringRef name, CryptomatteHash cryptomatte_hash)
blender::Map< std::string, CryptomatteHash > hashes
static void extract_layer_manifest(void *_data, const char *propname, char *propvalue, int propvalue_maxncpy)
static blender::StringRef extract_layer_hash(blender::StringRefNull key)
static void extract_layer_names(void *_data, const char *propname, char *propvalue, int propvalue_maxncpy)
i
Definition text_draw.cc:230
uint len