Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJeroen Bakker <jeroen@blender.org>2020-12-14 18:14:21 +0300
committerJeroen Bakker <jeroen@blender.org>2020-12-14 18:14:38 +0300
commitf4df036bc497b134789b624efd9008c6f4b9c6c8 (patch)
treefd9537758878f679087ff6854b1913b129b3ded8
parent07ce9910f7ccaa48ae28c35049dec598b6214b36 (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.
-rw-r--r--source/blender/blenkernel/BKE_cryptomatte.h10
-rw-r--r--source/blender/blenkernel/CMakeLists.txt2
-rw-r--r--source/blender/blenkernel/intern/cryptomatte.c87
-rw-r--r--source/blender/blenkernel/intern/cryptomatte.cc190
-rw-r--r--source/blender/blenloader/intern/versioning_290.c20
-rw-r--r--source/blender/compositor/nodes/COM_CryptomatteNode.cpp53
-rw-r--r--source/blender/makesdna/DNA_node_types.h12
-rw-r--r--source/blender/makesrna/RNA_access.h1
-rw-r--r--source/blender/makesrna/intern/rna_nodetree.c44
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_cryptomatte.c178
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;
}