diff options
author | Jeroen Bakker <jeroen@blender.org> | 2020-12-14 18:14:21 +0300 |
---|---|---|
committer | Jeroen Bakker <jeroen@blender.org> | 2020-12-14 18:14:38 +0300 |
commit | f4df036bc497b134789b624efd9008c6f4b9c6c8 (patch) | |
tree | fd9537758878f679087ff6854b1913b129b3ded8 /source | |
parent | 07ce9910f7ccaa48ae28c35049dec598b6214b36 (diff) |
Cryptomatte: Data structure in compositor node
This changes the way how the mattes are stored in the compositor node. This used to
be a single string what was decoded/encoded when needed. The new data structure
stores all entries in `CryptomatteEntry` and is converted to the old `matte_id`
property on the fly.
This is done for some future changes in the workflow where a more structured
approach leads to less confusing and easier to read code.
Diffstat (limited to 'source')
-rw-r--r-- | source/blender/blenkernel/BKE_cryptomatte.h | 10 | ||||
-rw-r--r-- | source/blender/blenkernel/CMakeLists.txt | 2 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/cryptomatte.c | 87 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/cryptomatte.cc | 190 | ||||
-rw-r--r-- | source/blender/blenloader/intern/versioning_290.c | 20 | ||||
-rw-r--r-- | source/blender/compositor/nodes/COM_CryptomatteNode.cpp | 53 | ||||
-rw-r--r-- | source/blender/makesdna/DNA_node_types.h | 12 | ||||
-rw-r--r-- | source/blender/makesrna/RNA_access.h | 1 | ||||
-rw-r--r-- | source/blender/makesrna/intern/rna_nodetree.c | 44 | ||||
-rw-r--r-- | source/blender/nodes/composite/nodes/node_composite_cryptomatte.c | 178 |
10 files changed, 288 insertions, 309 deletions
diff --git a/source/blender/blenkernel/BKE_cryptomatte.h b/source/blender/blenkernel/BKE_cryptomatte.h index 929266d1b89..c3c17f72cae 100644 --- a/source/blender/blenkernel/BKE_cryptomatte.h +++ b/source/blender/blenkernel/BKE_cryptomatte.h @@ -25,18 +25,28 @@ #include "BLI_sys_types.h" +#include "DNA_layer_types.h" + #ifdef __cplusplus extern "C" { #endif struct Object; struct Material; +struct ID; +struct Main; +uint32_t BKE_cryptomatte_hash(const char *name, int name_len); uint32_t BKE_cryptomatte_object_hash(const struct Object *object); uint32_t BKE_cryptomatte_material_hash(const struct Material *material); uint32_t BKE_cryptomatte_asset_hash(const struct Object *object); float BKE_cryptomatte_hash_to_float(uint32_t cryptomatte_hash); +char *BKE_cryptomatte_entries_to_matte_id(struct NodeCryptomatte *node_storage); +void BKE_cryptomatte_matte_id_to_entries(const struct Main *bmain, + struct NodeCryptomatte *node_storage, + const char *matte_id); + #ifdef __cplusplus } #endif diff --git a/source/blender/blenkernel/CMakeLists.txt b/source/blender/blenkernel/CMakeLists.txt index 5b10f734d71..d440d3e4d64 100644 --- a/source/blender/blenkernel/CMakeLists.txt +++ b/source/blender/blenkernel/CMakeLists.txt @@ -101,7 +101,7 @@ set(SRC intern/constraint.c intern/context.c intern/crazyspace.c - intern/cryptomatte.c + intern/cryptomatte.cc intern/curve.c intern/curve_bevel.c intern/curve_decimate.c diff --git a/source/blender/blenkernel/intern/cryptomatte.c b/source/blender/blenkernel/intern/cryptomatte.c deleted file mode 100644 index 6570ffce920..00000000000 --- a/source/blender/blenkernel/intern/cryptomatte.c +++ /dev/null @@ -1,87 +0,0 @@ -/* - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * The Original Code is Copyright (C) 2008 Blender Foundation. - * All rights reserved. - */ - -/** \file - * \ingroup bke - */ - -#include "BKE_cryptomatte.h" - -#include "DNA_material_types.h" -#include "DNA_object_types.h" - -#include "BLI_compiler_attrs.h" -#include "BLI_hash_mm3.h" -#include "BLI_string.h" -#include <string.h> - -static uint32_t cryptomatte_hash(const ID *id) -{ - const char *name = &id->name[2]; - const int len = BLI_strnlen(name, MAX_NAME - 2); - uint32_t cryptohash_int = BLI_hash_mm3((const unsigned char *)name, len, 0); - return cryptohash_int; -} - -uint32_t BKE_cryptomatte_object_hash(const Object *object) -{ - return cryptomatte_hash(&object->id); -} - -uint32_t BKE_cryptomatte_material_hash(const Material *material) -{ - if (material == NULL) { - return 0.0f; - } - return cryptomatte_hash(&material->id); -} - -uint32_t BKE_cryptomatte_asset_hash(const Object *object) -{ - const Object *asset_object = object; - while (asset_object->parent != NULL) { - asset_object = asset_object->parent; - } - return cryptomatte_hash(&asset_object->id); -} - -/* Convert a cryptomatte hash to a float. - * - * Cryptomatte hashes are stored in float textures and images. The conversion is taken from the - * cryptomatte specification. See Floating point conversion section in - * https://github.com/Psyop/Cryptomatte/blob/master/specification/cryptomatte_specification.pdf. - * - * The conversion uses as many 32 bit floating point values as possible to minimize hash - * collisions. Unfortunately not all 32 bits can be as NaN and Inf can be problematic. - * - * Note that this conversion assumes to be running on a L-endian system. */ -float BKE_cryptomatte_hash_to_float(uint32_t cryptomatte_hash) -{ - uint32_t mantissa = cryptomatte_hash & ((1 << 23) - 1); - uint32_t exponent = (cryptomatte_hash >> 23) & ((1 << 8) - 1); - exponent = MAX2(exponent, (uint32_t)1); - exponent = MIN2(exponent, (uint32_t)254); - exponent = exponent << 23; - uint32_t sign = (cryptomatte_hash >> 31); - sign = sign << 31; - uint32_t float_bits = sign | exponent | mantissa; - float f; - memcpy(&f, &float_bits, sizeof(uint32_t)); - return f; -} diff --git a/source/blender/blenkernel/intern/cryptomatte.cc b/source/blender/blenkernel/intern/cryptomatte.cc new file mode 100644 index 00000000000..4bbeb088628 --- /dev/null +++ b/source/blender/blenkernel/intern/cryptomatte.cc @@ -0,0 +1,190 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2020 Blender Foundation. + * All rights reserved. + */ + +/** \file + * \ingroup bke + */ + +#include "BKE_cryptomatte.h" +#include "BKE_main.h" + +#include "DNA_material_types.h" +#include "DNA_node_types.h" +#include "DNA_object_types.h" + +#include "BLI_compiler_attrs.h" +#include "BLI_dynstr.h" +#include "BLI_hash_mm3.h" +#include "BLI_listbase.h" +#include "BLI_string.h" + +#include "MEM_guardedalloc.h" + +#include <cstring> +#include <sstream> +#include <string> + +static uint32_t cryptomatte_hash(const ID *id) +{ + const char *name = &id->name[2]; + const int name_len = BLI_strnlen(name, MAX_NAME); + uint32_t cryptohash_int = BKE_cryptomatte_hash(name, name_len); + return cryptohash_int; +} + +uint32_t BKE_cryptomatte_hash(const char *name, int name_len) +{ + uint32_t cryptohash_int = BLI_hash_mm3((const unsigned char *)name, name_len, 0); + return cryptohash_int; +} + +uint32_t BKE_cryptomatte_object_hash(const Object *object) +{ + return cryptomatte_hash(&object->id); +} + +uint32_t BKE_cryptomatte_material_hash(const Material *material) +{ + if (material == nullptr) { + return 0.0f; + } + return cryptomatte_hash(&material->id); +} + +uint32_t BKE_cryptomatte_asset_hash(const Object *object) +{ + const Object *asset_object = object; + while (asset_object->parent != nullptr) { + asset_object = asset_object->parent; + } + return cryptomatte_hash(&asset_object->id); +} + +/* Convert a cryptomatte hash to a float. + * + * Cryptomatte hashes are stored in float textures and images. The conversion is taken from the + * cryptomatte specification. See Floating point conversion section in + * https://github.com/Psyop/Cryptomatte/blob/master/specification/cryptomatte_specification.pdf. + * + * The conversion uses as many 32 bit floating point values as possible to minimize hash + * collisions. Unfortunately not all 32 bits can be as NaN and Inf can be problematic. + * + * Note that this conversion assumes to be running on a L-endian system. */ +float BKE_cryptomatte_hash_to_float(uint32_t cryptomatte_hash) +{ + uint32_t mantissa = cryptomatte_hash & ((1 << 23) - 1); + uint32_t exponent = (cryptomatte_hash >> 23) & ((1 << 8) - 1); + exponent = MAX2(exponent, (uint32_t)1); + exponent = MIN2(exponent, (uint32_t)254); + exponent = exponent << 23; + uint32_t sign = (cryptomatte_hash >> 31); + sign = sign << 31; + uint32_t float_bits = sign | exponent | mantissa; + float f; + memcpy(&f, &float_bits, sizeof(uint32_t)); + return f; +} + +static ID *cryptomatte_find_id(const ListBase *ids, const float encoded_hash) +{ + LISTBASE_FOREACH (ID *, id, ids) { + uint32_t hash = BKE_cryptomatte_hash((id->name + 2), BLI_strnlen(id->name + 2, MAX_NAME)); + if (BKE_cryptomatte_hash_to_float(hash) == encoded_hash) { + return id; + } + } + return nullptr; +} + +/* Find an ID in the given main that matches the given encoded float. */ +static struct ID *BKE_cryptomatte_find_id(const Main *bmain, const float encoded_hash) +{ + ID *result; + result = cryptomatte_find_id(&bmain->objects, encoded_hash); + if (result == nullptr) { + result = cryptomatte_find_id(&bmain->materials, encoded_hash); + } + return result; +} + +char *BKE_cryptomatte_entries_to_matte_id(NodeCryptomatte *node_storage) +{ + DynStr *matte_id = BLI_dynstr_new(); + bool first = true; + LISTBASE_FOREACH (CryptomatteEntry *, entry, &node_storage->entries) { + if (!first) { + BLI_dynstr_append(matte_id, ","); + } + if (BLI_strnlen(entry->name, sizeof(entry->name)) != 0) { + BLI_dynstr_nappend(matte_id, entry->name, sizeof(entry->name)); + } + else { + BLI_dynstr_appendf(matte_id, "<%.9g>", entry->encoded_hash); + } + first = false; + } + char *result = BLI_dynstr_get_cstring(matte_id); + BLI_dynstr_free(matte_id); + return result; +} + +void BKE_cryptomatte_matte_id_to_entries(const Main *bmain, + NodeCryptomatte *node_storage, + const char *matte_id) +{ + BLI_freelistN(&node_storage->entries); + + std::istringstream ss(matte_id); + while (ss.good()) { + CryptomatteEntry *entry = nullptr; + std::string token; + getline(ss, token, ','); + /* Ignore empty tokens. */ + if (token.length() > 0) { + size_t first = token.find_first_not_of(' '); + size_t last = token.find_last_not_of(' '); + if (first == std::string::npos || last == std::string::npos) { + break; + } + token = token.substr(first, (last - first + 1)); + if (*token.begin() == '<' && *(--token.end()) == '>') { + float encoded_hash = atof(token.substr(1, token.length() - 2).c_str()); + entry = (CryptomatteEntry *)MEM_callocN(sizeof(CryptomatteEntry), __func__); + entry->encoded_hash = encoded_hash; + if (bmain) { + ID *id = BKE_cryptomatte_find_id(bmain, encoded_hash); + if (id != nullptr) { + BLI_strncpy(entry->name, id->name + 2, sizeof(entry->name)); + } + } + } + else { + const char *name = token.c_str(); + int name_len = token.length(); + entry = (CryptomatteEntry *)MEM_callocN(sizeof(CryptomatteEntry), __func__); + BLI_strncpy(entry->name, name, sizeof(entry->name)); + uint32_t hash = BKE_cryptomatte_hash(name, name_len); + entry->encoded_hash = BKE_cryptomatte_hash_to_float(hash); + } + } + if (entry != nullptr) { + BLI_addtail(&node_storage->entries, entry); + } + } +}
\ No newline at end of file diff --git a/source/blender/blenloader/intern/versioning_290.c b/source/blender/blenloader/intern/versioning_290.c index 4e642258899..6f055186702 100644 --- a/source/blender/blenloader/intern/versioning_290.c +++ b/source/blender/blenloader/intern/versioning_290.c @@ -52,6 +52,7 @@ #include "BKE_armature.h" #include "BKE_collection.h" #include "BKE_colortools.h" +#include "BKE_cryptomatte.h" #include "BKE_fcurve.h" #include "BKE_gpencil.h" #include "BKE_lib_id.h" @@ -1280,5 +1281,24 @@ void blo_do_versions_290(FileData *fd, Library *UNUSED(lib), Main *bmain) } } } + + /* Convert `NodeCryptomatte->storage->matte_id` to `NodeCryptomatte->storage->entries` */ + if (!DNA_struct_find(fd->filesdna, "CryptomatteEntry")) { + LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) { + if (scene->nodetree) { + LISTBASE_FOREACH (bNode *, node, &scene->nodetree->nodes) { + if (node->type == CMP_NODE_CRYPTOMATTE) { + NodeCryptomatte *storage = (NodeCryptomatte *)node->storage; + char *matte_id = storage->matte_id; + if (matte_id == NULL || strlen(storage->matte_id) == 0) { + continue; + } + BKE_cryptomatte_matte_id_to_entries(NULL, storage, storage->matte_id); + MEM_SAFE_FREE(storage->matte_id); + } + } + } + } + } } } diff --git a/source/blender/compositor/nodes/COM_CryptomatteNode.cpp b/source/blender/compositor/nodes/COM_CryptomatteNode.cpp index 8cc6b933759..7ca4e1f76fc 100644 --- a/source/blender/compositor/nodes/COM_CryptomatteNode.cpp +++ b/source/blender/compositor/nodes/COM_CryptomatteNode.cpp @@ -17,12 +17,15 @@ */ #include "COM_CryptomatteNode.h" -#include "BLI_assert.h" -#include "BLI_hash_mm3.h" -#include "BLI_string.h" #include "COM_ConvertOperation.h" #include "COM_CryptomatteOperation.h" #include "COM_SetAlphaOperation.h" + +#include "BLI_assert.h" +#include "BLI_hash_mm3.h" +#include "BLI_listbase.h" +#include "BLI_string.h" + #include <iterator> CryptomatteNode::CryptomatteNode(bNode *editorNode) : Node(editorNode) @@ -30,24 +33,6 @@ CryptomatteNode::CryptomatteNode(bNode *editorNode) : Node(editorNode) /* pass */ } -/* This is taken from the Cryptomatte specification 1.0. */ -static inline float hash_to_float(uint32_t hash) -{ - uint32_t mantissa = hash & ((1 << 23) - 1); - uint32_t exponent = (hash >> 23) & ((1 << 8) - 1); - exponent = max(exponent, (uint32_t)1); - exponent = min(exponent, (uint32_t)254); - exponent = exponent << 23; - uint32_t sign = (hash >> 31); - sign = sign << 31; - uint32_t float_bits = sign | exponent | mantissa; - float f; - /* Bit casting relies on equal size for both types. */ - BLI_STATIC_ASSERT(sizeof(float) == sizeof(uint32_t), "float and uint32_t are not the same size") - ::memcpy(&f, &float_bits, sizeof(float)); - return f; -} - void CryptomatteNode::convertToOperations(NodeConverter &converter, const CompositorContext & /*context*/) const { @@ -61,30 +46,8 @@ void CryptomatteNode::convertToOperations(NodeConverter &converter, CryptomatteOperation *operation = new CryptomatteOperation(getNumberOfInputSockets() - 1); if (cryptoMatteSettings) { - if (cryptoMatteSettings->matte_id) { - /* Split the string by commas, ignoring white space. */ - std::string input = cryptoMatteSettings->matte_id; - std::istringstream ss(input); - while (ss.good()) { - std::string token; - getline(ss, token, ','); - /* Ignore empty tokens. */ - if (token.length() > 0) { - size_t first = token.find_first_not_of(' '); - size_t last = token.find_last_not_of(' '); - if (first == std::string::npos || last == std::string::npos) { - break; - } - token = token.substr(first, (last - first + 1)); - if (*token.begin() == '<' && *(--token.end()) == '>') { - operation->addObjectIndex(atof(token.substr(1, token.length() - 2).c_str())); - } - else { - uint32_t hash = BLI_hash_mm3((const unsigned char *)token.c_str(), token.length(), 0); - operation->addObjectIndex(hash_to_float(hash)); - } - } - } + LISTBASE_FOREACH (CryptomatteEntry *, cryptomatte_entry, &cryptoMatteSettings->entries) { + operation->addObjectIndex(cryptomatte_entry->encoded_hash); } } diff --git a/source/blender/makesdna/DNA_node_types.h b/source/blender/makesdna/DNA_node_types.h index 8e463a8b406..f6ceb2b8e6a 100644 --- a/source/blender/makesdna/DNA_node_types.h +++ b/source/blender/makesdna/DNA_node_types.h @@ -1052,10 +1052,20 @@ typedef struct NodeSunBeams { float ray_length; } NodeSunBeams; +typedef struct CryptomatteEntry { + struct CryptomatteEntry *next, *prev; + float encoded_hash; + /** MAX_NAME. */ + char name[64]; + char _pad[4]; +} CryptomatteEntry; + typedef struct NodeCryptomatte { float add[3]; float remove[3]; - char *matte_id; + char *matte_id DNA_DEPRECATED; + /* Contains `CryptomatteEntry`. */ + ListBase entries; int num_inputs; char _pad[4]; } NodeCryptomatte; diff --git a/source/blender/makesrna/RNA_access.h b/source/blender/makesrna/RNA_access.h index a581edcb04b..4aeb9b9e5f7 100644 --- a/source/blender/makesrna/RNA_access.h +++ b/source/blender/makesrna/RNA_access.h @@ -202,6 +202,7 @@ extern StructRNA RNA_CopyRotationConstraint; extern StructRNA RNA_CopyScaleConstraint; extern StructRNA RNA_CopyTransformsConstraint; extern StructRNA RNA_CorrectiveSmoothModifier; +extern StructRNA RNA_CryptomatteEntry; extern StructRNA RNA_Curve; extern StructRNA RNA_CurveMap; extern StructRNA RNA_CurveMapPoint; diff --git a/source/blender/makesrna/intern/rna_nodetree.c b/source/blender/makesrna/intern/rna_nodetree.c index 4fc486eadac..153e2aebd22 100644 --- a/source/blender/makesrna/intern/rna_nodetree.c +++ b/source/blender/makesrna/intern/rna_nodetree.c @@ -37,6 +37,7 @@ #include "BKE_animsys.h" #include "BKE_attribute.h" +#include "BKE_cryptomatte.h" #include "BKE_image.h" #include "BKE_node.h" #include "BKE_texture.h" @@ -3626,33 +3627,26 @@ static void rna_NodeCryptomatte_matte_get(PointerRNA *ptr, char *value) { bNode *node = (bNode *)ptr->data; NodeCryptomatte *nc = node->storage; - - strcpy(value, (nc->matte_id) ? nc->matte_id : ""); + char *matte_id = BKE_cryptomatte_entries_to_matte_id(nc); + strcpy(value, matte_id); + MEM_freeN(matte_id); } static int rna_NodeCryptomatte_matte_length(PointerRNA *ptr) { bNode *node = (bNode *)ptr->data; NodeCryptomatte *nc = node->storage; - - return (nc->matte_id) ? strlen(nc->matte_id) : 0; + char *matte_id = BKE_cryptomatte_entries_to_matte_id(nc); + int result = strlen(matte_id); + MEM_freeN(matte_id); + return result; } static void rna_NodeCryptomatte_matte_set(PointerRNA *ptr, const char *value) { bNode *node = (bNode *)ptr->data; NodeCryptomatte *nc = node->storage; - - if (nc->matte_id) { - MEM_freeN(nc->matte_id); - } - - if (value && value[0]) { - nc->matte_id = BLI_strdup(value); - } - else { - nc->matte_id = NULL; - } + BKE_cryptomatte_matte_id_to_entries(NULL, nc, value); } static void rna_NodeCryptomatte_update_add(Main *bmain, Scene *scene, PointerRNA *ptr) @@ -8205,6 +8199,24 @@ static void def_cmp_sunbeams(StructRNA *srna) RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); } +static void def_cmp_cryptomatte_entry(BlenderRNA *brna) +{ + StructRNA *srna; + PropertyRNA *prop; + + srna = RNA_def_struct(brna, "CryptomatteEntry", NULL); + RNA_def_struct_sdna(srna, "CryptomatteEntry"); + + prop = RNA_def_property(srna, "encoded_hash", PROP_FLOAT, PROP_NONE); + RNA_def_property_clear_flag(prop, PROP_EDITABLE); + RNA_def_property_float_sdna(prop, NULL, "encoded_hash"); + + prop = RNA_def_property(srna, "name", PROP_STRING, PROP_NONE); + RNA_def_property_clear_flag(prop, PROP_EDITABLE); + RNA_def_property_ui_text(prop, "Name", ""); + RNA_def_struct_name_property(srna, prop); +} + static void def_cmp_cryptomatte(StructRNA *srna) { PropertyRNA *prop; @@ -8494,6 +8506,8 @@ static void rna_def_compositor_node(BlenderRNA *brna) /* compositor node need_exec flag */ func = RNA_def_function(srna, "tag_need_exec", "rna_CompositorNode_tag_need_exec"); RNA_def_function_ui_description(func, "Tag the node for compositor update"); + + def_cmp_cryptomatte_entry(brna); } static void rna_def_texture_node(BlenderRNA *brna) diff --git a/source/blender/nodes/composite/nodes/node_composite_cryptomatte.c b/source/blender/nodes/composite/nodes/node_composite_cryptomatte.c index c8d2d993e75..f5308fe2671 100644 --- a/source/blender/nodes/composite/nodes/node_composite_cryptomatte.c +++ b/source/blender/nodes/composite/nodes/node_composite_cryptomatte.c @@ -27,172 +27,36 @@ #include "BLI_utildefines.h" #include "node_composite_util.h" -/* this is taken from the cryptomatte specification 1.0 */ - -BLI_INLINE float hash_to_float(uint32_t hash) +static CryptomatteEntry *cryptomatte_find(NodeCryptomatte *n, float encoded_hash) { - uint32_t mantissa = hash & ((1 << 23) - 1); - uint32_t exponent = (hash >> 23) & ((1 << 8) - 1); - exponent = MAX2(exponent, (uint32_t)1); - exponent = MIN2(exponent, (uint32_t)254); - exponent = exponent << 23; - uint32_t sign = (hash >> 31); - sign = sign << 31; - uint32_t float_bits = sign | exponent | mantissa; - float f; - /* Bit casting relies on equal size for both types. */ - BLI_STATIC_ASSERT(sizeof(float) == sizeof(uint32_t), "float and uint32_t are not the same size") - memcpy(&f, &float_bits, sizeof(float)); - return f; + LISTBASE_FOREACH (CryptomatteEntry *, entry, &n->entries) { + if (entry->encoded_hash == encoded_hash) { + return entry; + } + } + return NULL; } static void cryptomatte_add(NodeCryptomatte *n, float f) { - /* Turn the number into a string. */ - char number[32]; - BLI_snprintf(number, sizeof(number), "<%.9g>", f); - - /* Search if we already have the number. */ - if (n->matte_id && strlen(n->matte_id) != 0) { - size_t start = 0; - const size_t end = strlen(n->matte_id); - size_t token_len = 0; - while (start < end) { - /* Ignore leading whitespace. */ - while (start < end && n->matte_id[start] == ' ') { - start++; - } - - /* Find the next separator. */ - char *token_end = strchr(n->matte_id + start, ','); - if (ELEM(token_end, NULL, n->matte_id + start)) { - token_end = n->matte_id + end; - } - /* Be aware that token_len still contains any trailing white space. */ - token_len = token_end - (n->matte_id + start); - - /* If this has a leading bracket, - * assume a raw floating point number and look for the closing bracket. */ - if (n->matte_id[start] == '<') { - if (strncmp(n->matte_id + start, number, strlen(number)) == 0) { - /* This number is already there, so continue. */ - return; - } - } - else { - /* Remove trailing white space */ - size_t name_len = token_len; - while (n->matte_id[start + name_len] == ' ' && name_len > 0) { - name_len--; - } - /* Calculate the hash of the token and compare. */ - uint32_t hash = BLI_hash_mm3((const unsigned char *)(n->matte_id + start), name_len, 0); - if (f == hash_to_float(hash)) { - return; - } - } - start += token_len + 1; - } - } - - DynStr *new_matte = BLI_dynstr_new(); - if (!new_matte) { + /* Check if entry already exist. */ + if (cryptomatte_find(n, f) != NULL) { return; } - - if (n->matte_id) { - BLI_dynstr_append(new_matte, n->matte_id); - MEM_freeN(n->matte_id); - } - - if (BLI_dynstr_get_len(new_matte) > 0) { - BLI_dynstr_append(new_matte, ","); - } - BLI_dynstr_append(new_matte, number); - n->matte_id = BLI_dynstr_get_cstring(new_matte); - BLI_dynstr_free(new_matte); + CryptomatteEntry *entry = MEM_callocN(sizeof(CryptomatteEntry), __func__); + entry->encoded_hash = f; + BLI_addtail(&n->entries, entry); } static void cryptomatte_remove(NodeCryptomatte *n, float f) { - if (n->matte_id == NULL || strlen(n->matte_id) == 0) { - /* Empty string, nothing to remove. */ + CryptomatteEntry *entry = cryptomatte_find(n, f); + if (entry == NULL) { return; } - /* This will be the new string without the removed key. */ - DynStr *new_matte = BLI_dynstr_new(); - if (!new_matte) { - return; - } - - /* Turn the number into a string. */ - static char number[32]; - BLI_snprintf(number, sizeof(number), "<%.9g>", f); - - /* Search if we already have the number. */ - size_t start = 0; - const size_t end = strlen(n->matte_id); - size_t token_len = 0; - bool is_first = true; - while (start < end) { - bool skip = false; - /* Ignore leading whitespace or commas. */ - while (start < end && ((n->matte_id[start] == ' ') || (n->matte_id[start] == ','))) { - start++; - } - - /* Find the next separator. */ - char *token_end = strchr(n->matte_id + start + 1, ','); - if (ELEM(token_end, NULL, n->matte_id + start)) { - token_end = n->matte_id + end; - } - /* Be aware that token_len still contains any trailing white space. */ - token_len = token_end - (n->matte_id + start); - - if (token_len == 1) { - skip = true; - } - /* If this has a leading bracket, - * assume a raw floating point number and look for the closing bracket. */ - else if (n->matte_id[start] == '<') { - if (strncmp(n->matte_id + start, number, strlen(number)) == 0) { - /* This number is already there, so skip it. */ - skip = true; - } - } - else { - /* Remove trailing white space */ - size_t name_len = token_len; - while (n->matte_id[start + name_len] == ' ' && name_len > 0) { - name_len--; - } - /* Calculate the hash of the token and compare. */ - uint32_t hash = BLI_hash_mm3((const unsigned char *)(n->matte_id + start), name_len, 0); - if (f == hash_to_float(hash)) { - skip = true; - } - } - if (!skip) { - if (is_first) { - is_first = false; - } - else { - BLI_dynstr_append(new_matte, ", "); - } - BLI_dynstr_nappend(new_matte, n->matte_id + start, token_len); - } - start += token_len + 1; - } - - if (n->matte_id) { - MEM_freeN(n->matte_id); - n->matte_id = NULL; - } - if (BLI_dynstr_get_len(new_matte) > 0) { - n->matte_id = BLI_dynstr_get_cstring(new_matte); - } - BLI_dynstr_free(new_matte); + BLI_remlink(&n->entries, entry); + MEM_freeN(entry); } static bNodeSocketTemplate outputs[] = { @@ -265,10 +129,7 @@ static void node_free_cryptomatte(bNode *node) NodeCryptomatte *nc = node->storage; if (nc) { - if (nc->matte_id) { - MEM_freeN(nc->matte_id); - } - + BLI_freelistN(&nc->entries); MEM_freeN(nc); } } @@ -280,10 +141,7 @@ static void node_copy_cryptomatte(bNodeTree *UNUSED(dest_ntree), NodeCryptomatte *src_nc = src_node->storage; NodeCryptomatte *dest_nc = MEM_dupallocN(src_nc); - if (src_nc->matte_id) { - dest_nc->matte_id = MEM_dupallocN(src_nc->matte_id); - } - + BLI_duplicatelist(&dest_nc->entries, &src_nc->entries); dest_node->storage = dest_nc; } |