Blender V5.0
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#include "BLI_string_utf8.h"
27
28#include "RE_pipeline.h"
29
30#include "MEM_guardedalloc.h"
31
32#include <cctype>
33#include <cstring>
34#include <iomanip>
35#include <sstream>
36#include <string>
37
40 /* Layer names in order of creation. */
42
43 CryptomatteSession() = default;
44 CryptomatteSession(const Main *bmain);
45 CryptomatteSession(StampData *stamp_data);
46 CryptomatteSession(const ViewLayer *view_layer);
47 CryptomatteSession(const Scene *scene, bool build_meta_data = false);
48 void init(const ViewLayer *view_layer, bool build_meta_data = false);
49
51 std::optional<std::string> operator[](float encoded_hash) const;
52
53 MEM_CXX_CLASS_ALLOC_FUNCS("cryptomatte:CryptomatteSession")
54};
55
57{
58 if (!BLI_listbase_is_empty(&bmain->objects)) {
61 LISTBASE_FOREACH (ID *, id, &bmain->objects) {
62 objects.add_ID(*id);
63 }
64
66 LISTBASE_FOREACH (ID *, id, &bmain->objects) {
67 const Object *asset_object = reinterpret_cast<Object *>(id);
68 while (asset_object->parent != nullptr) {
69 asset_object = asset_object->parent;
70 }
71 assets.add_ID(asset_object->id);
72 }
73 }
74 if (!BLI_listbase_is_empty(&bmain->materials)) {
77 LISTBASE_FOREACH (ID *, id, &bmain->materials) {
78 materials.add_ID(*id);
79 }
80 }
81}
82
98
100{
101 init(view_layer);
102}
103
104CryptomatteSession::CryptomatteSession(const Scene *scene, bool build_meta_data)
105{
106
107 if (build_meta_data) {
109 }
110
111 LISTBASE_FOREACH (const ViewLayer *, view_layer, &scene->view_layers) {
112 init(view_layer, build_meta_data);
113 }
114}
115
116void CryptomatteSession::init(const ViewLayer *view_layer, bool build_meta_data)
117{
120 if (cryptoflags == 0) {
121 cryptoflags = VIEW_LAYER_CRYPTOMATTE_ALL;
122 }
123
124 ListBase *object_bases = build_meta_data ? BKE_view_layer_object_bases_get(
125 const_cast<ViewLayer *>(view_layer)) :
126 nullptr;
127
128 if (cryptoflags & VIEW_LAYER_CRYPTOMATTE_OBJECT) {
131
132 if (build_meta_data) {
133 LISTBASE_FOREACH (Base *, base, object_bases) {
134 objects.add_ID(base->object->id);
135 }
136 }
137 }
138
139 if (cryptoflags & VIEW_LAYER_CRYPTOMATTE_ASSET) {
142
143 if (build_meta_data) {
144 LISTBASE_FOREACH (Base *, base, object_bases) {
145 const Object *asset_object = base->object;
146 while (asset_object->parent != nullptr) {
147 asset_object = asset_object->parent;
148 }
149 assets.add_ID(asset_object->id);
150 }
151 }
152 }
153
154 if (cryptoflags & VIEW_LAYER_CRYPTOMATTE_MATERIAL) {
157
158 if (build_meta_data) {
159 LISTBASE_FOREACH (Base *, base, object_bases) {
160 for (int i = 0; i < base->object->totcol; i++) {
161 Material *material = BKE_object_material_get(base->object, i + 1);
162 if (material) {
163 materials.add_ID(material->id);
164 }
165 }
166 }
167 }
168 }
169}
170
172{
173 if (!layer_names.contains(layer_name)) {
174 layer_names.append(layer_name);
175 }
176 return layers.lookup_or_add_default(layer_name);
177}
178
179std::optional<std::string> CryptomatteSession::operator[](float encoded_hash) const
180{
181 for (const blender::bke::cryptomatte::CryptomatteLayer &layer : layers.values()) {
182 std::optional<std::string> result = layer[encoded_hash];
183 if (result) {
184 return result;
185 }
186 }
187 return std::nullopt;
188}
189
191{
192 CryptomatteSession *session = new CryptomatteSession();
193 return session;
194}
195
197{
198 CryptomatteSession *session = new CryptomatteSession(render_result->stamp_data);
199 return session;
200}
201
202CryptomatteSession *BKE_cryptomatte_init_from_scene(const Scene *scene, bool build_meta_data)
203{
204 CryptomatteSession *session = new CryptomatteSession(scene, build_meta_data);
205 return session;
206}
207
209{
210 CryptomatteSession *session = new CryptomatteSession(view_layer);
211 return session;
212}
213
214void BKE_cryptomatte_add_layer(CryptomatteSession *session, const char *layer_name)
215{
216 session->add_layer(layer_name);
217}
218
220{
221 BLI_assert(session != nullptr);
222 delete session;
223}
224
225uint32_t BKE_cryptomatte_hash(const char *name, const int name_len)
226{
228 return hash.hash;
229}
230
232 const char *layer_name,
233 const Object *object)
234{
236 BLI_assert(layer);
237 return layer->add_ID(object->id);
238}
239
241 const char *layer_name,
242 const Material *material)
243{
244 if (material == nullptr) {
245 return 0.0f;
246 }
248 BLI_assert(layer);
249 return layer->add_ID(material->id);
250}
251
253 const char *layer_name,
254 const Object *object)
255{
256 const Object *asset_object = object;
257 while (asset_object->parent != nullptr) {
258 asset_object = asset_object->parent;
259 }
260 return BKE_cryptomatte_object_hash(session, layer_name, asset_object);
261}
262
263float BKE_cryptomatte_hash_to_float(uint32_t cryptomatte_hash)
264{
266}
267
269 const float encoded_hash,
270 char *r_name,
271 int name_maxncpy)
272{
273 std::optional<std::string> name = (*session)[encoded_hash];
274 if (!name) {
275 return false;
276 }
277
278 BLI_strncpy_utf8(r_name, name->c_str(), name_maxncpy);
279 return true;
280}
281
283{
284 DynStr *matte_id = BLI_dynstr_new();
285 bool first = true;
286 LISTBASE_FOREACH (CryptomatteEntry *, entry, &node_storage->entries) {
287 if (!first) {
288 BLI_dynstr_append(matte_id, ",");
289 }
290 if (entry->name[0] != '\0') {
291 BLI_dynstr_nappend(matte_id, entry->name, sizeof(entry->name));
292 }
293 else {
294 BLI_dynstr_appendf(matte_id, "<%.9g>", entry->encoded_hash);
295 }
296 first = false;
297 }
298 char *result = BLI_dynstr_get_cstring(matte_id);
299 BLI_dynstr_free(matte_id);
300 return result;
301}
302
303void BKE_cryptomatte_matte_id_to_entries(NodeCryptomatte *node_storage, const char *matte_id)
304{
305 BLI_freelistN(&node_storage->entries);
306
307 if (matte_id == nullptr) {
308 MEM_SAFE_FREE(node_storage->matte_id);
309 return;
310 }
311 /* Update the matte_id so the files can be opened in versions that don't
312 * use `CryptomatteEntry`. */
313 if (matte_id != node_storage->matte_id && node_storage->matte_id &&
314 STREQ(node_storage->matte_id, matte_id))
315 {
316 MEM_SAFE_FREE(node_storage->matte_id);
317 node_storage->matte_id = static_cast<char *>(MEM_dupallocN(matte_id));
318 }
319
320 std::istringstream ss(matte_id);
321 while (ss.good()) {
322 CryptomatteEntry *entry = nullptr;
323 std::string token;
324 getline(ss, token, ',');
325 /* Ignore empty tokens. */
326 if (token.length() > 0) {
327 size_t first = token.find_first_not_of(' ');
328 size_t last = token.find_last_not_of(' ');
329 if (first == std::string::npos || last == std::string::npos) {
330 break;
331 }
332 token = token.substr(first, (last - first + 1));
333 if (*token.begin() == '<' && *(--token.end()) == '>') {
334 float encoded_hash = atof(token.substr(1, token.length() - 2).c_str());
335 entry = MEM_callocN<CryptomatteEntry>(__func__);
336 entry->encoded_hash = encoded_hash;
337 }
338 else {
339 const char *name = token.c_str();
340 int name_len = token.length();
341 entry = MEM_callocN<CryptomatteEntry>(__func__);
342 STRNCPY(entry->name, name);
343 uint32_t hash = BKE_cryptomatte_hash(name, name_len);
345 }
346 }
347 if (entry != nullptr) {
348 BLI_addtail(&node_storage->entries, entry);
349 }
350 }
351}
352
354{
355 return BLI_hash_mm3(reinterpret_cast<const uchar *>(name.data()), name.size(), 0);
356}
357
358static void add_render_result_meta_data(RenderResult *render_result,
359 const blender::StringRef layer_name,
360 const blender::StringRefNull key_name,
361 const blender::StringRefNull value)
362{
364 render_result,
366 value.data());
367}
368
370{
372 session->layers.items())
373 {
374 const blender::StringRefNull layer_name(item.key);
375 const blender::bke::cryptomatte::CryptomatteLayer &layer = item.value;
376
377 const std::string manifest = layer.manifest();
378
379 add_render_result_meta_data(render_result, layer_name, "name", layer_name);
380 add_render_result_meta_data(render_result, layer_name, "hash", "MurmurHash3_32");
381 add_render_result_meta_data(render_result, layer_name, "conversion", "uint32_to_float32");
382 add_render_result_meta_data(render_result, layer_name, "manifest", manifest);
383 }
384}
385
387namespace manifest {
388constexpr StringRef WHITESPACES = " \t\n\v\f\r";
389
391{
392 size_t skip = ref.find_first_not_of(WHITESPACES);
393 if (skip == blender::StringRef::not_found) {
394 return ref;
395 }
396 return ref.drop_prefix(skip);
397}
398
399static constexpr int quoted_string_len_(blender::StringRef ref)
400{
401 int len = 1;
402 bool skip_next = false;
403 while (len < ref.size()) {
404 char current_char = ref[len];
405 if (skip_next) {
406 skip_next = false;
407 }
408 else {
409 if (current_char == '\\') {
410 skip_next = true;
411 }
412 if (current_char == '\"') {
413 len += 1;
414 break;
415 }
416 }
417 len += 1;
418 }
419 return len;
420}
421
422static std::string unquote_(const blender::StringRef ref)
423{
424 std::ostringstream stream;
425 for (char c : ref) {
426 if (c != '\\') {
427 stream << c;
428 }
429 }
430 return stream.str();
431}
432
434{
435 StringRef ref = manifest;
436 ref = skip_whitespaces_(ref);
437 if (ref.is_empty() || ref.front() != '{') {
438 return false;
439 }
440 ref = ref.drop_prefix(1);
441 while (!ref.is_empty()) {
442 char front = ref.front();
443
444 if (front == '\"') {
445 const int quoted_name_len = quoted_string_len_(ref);
446 const int name_len = quoted_name_len - 2;
447 std::string name = unquote_(ref.substr(1, name_len));
448 ref = ref.drop_prefix(quoted_name_len);
449 ref = skip_whitespaces_(ref);
450
451 if (ref.is_empty()) {
452 return false;
453 }
454 char colon = ref.front();
455 if (colon != ':') {
456 return false;
457 }
458 ref = ref.drop_prefix(1);
459 ref = skip_whitespaces_(ref);
460
461 if (ref.is_empty() || ref.front() != '\"') {
462 return false;
463 }
464
465 const int quoted_hash_len = quoted_string_len_(ref);
466 if (quoted_hash_len < 2) {
467 return false;
468 }
469 const int hash_len = quoted_hash_len - 2;
471 ref = ref.drop_prefix(quoted_hash_len);
472 layer.add_hash(name, hash);
473 }
474 else if (front == ',') {
475 ref = ref.drop_prefix(1);
476 }
477 else if (front == '}') {
478 ref = ref.drop_prefix(1);
479 ref = skip_whitespaces_(ref);
480 break;
481 }
482 ref = skip_whitespaces_(ref);
483 }
484
485 if (!ref.is_empty()) {
486 return false;
487 }
488
489 return true;
490}
491
492static std::string to_manifest(const CryptomatteLayer *layer)
493{
494 std::stringstream manifest;
495
496 bool is_first = true;
497 const blender::Map<std::string, CryptomatteHash> &const_map = layer->hashes;
498 manifest << "{";
500 if (is_first) {
501 is_first = false;
502 }
503 else {
504 manifest << ",";
505 }
506 manifest << quoted(item.key) << ":\"" << item.value.hex_encoded() << "\"";
507 }
508 manifest << "}";
509 return manifest.str();
510}
511
512} // namespace manifest
513
514/* Return the hash of the given cryptomatte layer name.
515 *
516 * The cryptomatte specification limits the hash to 7 characters.
517 * The 7 position limitation solves issues when using cryptomatte together with OpenEXR.
518 * The specification suggests to use the first 7 chars of the hashed layer_name.
519 */
520static std::string cryptomatte_layer_name_hash(const StringRef layer_name)
521{
522 std::stringstream stream;
523 const uint32_t render_pass_identifier = cryptomatte_determine_identifier(layer_name);
524 stream << std::setfill('0') << std::setw(sizeof(uint32_t) * 2) << std::hex
525 << render_pass_identifier;
526 return stream.str().substr(0, 7);
527}
528
529std::string BKE_cryptomatte_meta_data_key(const StringRef layer_name, const StringRefNull key_name)
530{
531 return "cryptomatte/" + cryptomatte_layer_name_hash(layer_name) + "/" + key_name;
532}
533
535{
536 int64_t last_token = render_pass_name.size();
537 while (last_token > 0 && std::isdigit(render_pass_name[last_token - 1])) {
538 last_token -= 1;
539 }
540 return render_pass_name.substr(0, last_token);
541}
542
544
546{
548 std::istringstream(hex_encoded) >> std::hex >> result.hash;
549 return result;
550}
551
553{
554 std::stringstream encoded;
555 encoded << std::setfill('0') << std::setw(sizeof(uint32_t) * 2) << std::hex << hash;
556 return encoded.str();
557}
558
559std::unique_ptr<CryptomatteLayer> CryptomatteLayer::read_from_manifest(
561{
562 std::unique_ptr<CryptomatteLayer> layer = std::make_unique<CryptomatteLayer>();
564 return layer;
565}
566
567uint32_t CryptomatteLayer::add_ID(const ID &id)
568{
569 const char *name = &id.name[2];
570 const int name_len = BLI_strnlen(name, MAX_NAME - 2);
571 uint32_t cryptohash_int = BKE_cryptomatte_hash(name, name_len);
572
573 add_hash(blender::StringRef(name, name_len), cryptohash_int);
574
575 return cryptohash_int;
576}
577
578void CryptomatteLayer::add_hash(blender::StringRef name, CryptomatteHash cryptomatte_hash)
579{
580 hashes.add_overwrite(name, cryptomatte_hash);
581}
582
583std::optional<std::string> CryptomatteLayer::operator[](float encoded_hash) const
584{
587 if (BKE_cryptomatte_hash_to_float(item.value.hash) == encoded_hash) {
588 return std::make_optional(item.key);
589 }
590 }
591 return std::nullopt;
592}
593
594std::string CryptomatteLayer::manifest() const
595{
597}
598
600{
601 BLI_assert(key.startswith("cryptomatte/"));
602
603 size_t start_index = key.find_first_of('/');
604 size_t end_index = key.find_last_of('/');
605 if (start_index == blender::StringRef::not_found) {
606 return "";
607 }
608 if (end_index == blender::StringRef::not_found) {
609 return "";
610 }
611 if (end_index <= start_index) {
612 return "";
613 }
614 return key.substr(start_index + 1, end_index - start_index - 1);
615}
616
618 const char *propname,
619 char *propvalue,
620 int /*propvalue_maxncpy*/)
621{
623
624 blender::StringRefNull key(propname);
625 if (!key.startswith("cryptomatte/")) {
626 return;
627 }
628 if (!key.endswith("/name")) {
629 return;
630 }
631 blender::StringRef layer_hash = extract_layer_hash(key);
632 data->hash_to_layer_name.add(layer_hash, propvalue);
633}
634
636 const char *propname,
637 char *propvalue,
638 int /*propvalue_maxncpy*/)
639{
641
642 blender::StringRefNull key(propname);
643 if (!key.startswith("cryptomatte/")) {
644 return;
645 }
646 if (!key.endswith("/manifest")) {
647 return;
648 }
649 blender::StringRef layer_hash = extract_layer_hash(key);
650 if (!data->hash_to_layer_name.contains(layer_hash)) {
651 return;
652 }
653
654 blender::StringRef layer_name = data->hash_to_layer_name.lookup(layer_hash);
655 blender::bke::cryptomatte::CryptomatteLayer &layer = data->session->add_layer(layer_name);
657}
658
660 const CryptomatteSession &session)
661{
662 return session.layer_names;
663}
664
666{
667 return session.layers.lookup_ptr(layer_name);
668}
669
670} // 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:75
DynStr * BLI_dynstr_new(void) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT
Definition BLI_dynstr.cc:37
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:56
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:913
char * STRNCPY(char(&dst)[N], const char *src)
Definition BLI_string.h:693
char * BLI_strncpy_utf8(char *__restrict dst, const char *__restrict src, size_t dst_maxncpy) ATTR_NONNULL(1
unsigned char uchar
#define STREQ(a, b)
#define MAX_NAME
Definition DNA_defs.h:50
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.
#define MEM_SAFE_FREE(v)
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)
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
const char * name
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:414
ListBase materials
Definition BKE_main.hh:284
ListBase objects
Definition BKE_main.hh:280
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