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:
Diffstat (limited to 'source/blender/nodes/composite/nodes/node_composite_cryptomatte.c')
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_cryptomatte.c309
1 files changed, 309 insertions, 0 deletions
diff --git a/source/blender/nodes/composite/nodes/node_composite_cryptomatte.c b/source/blender/nodes/composite/nodes/node_composite_cryptomatte.c
new file mode 100644
index 00000000000..488dfa6756e
--- /dev/null
+++ b/source/blender/nodes/composite/nodes/node_composite_cryptomatte.c
@@ -0,0 +1,309 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * 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) 2018 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): Lukas Stockner, Stefan Werner
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/nodes/composite/nodes/node_composite_cryptomatte.c
+ * \ingroup cmpnodes
+ */
+
+#include "node_composite_util.h"
+#include "BLI_dynstr.h"
+#include "BLI_hash_mm3.h"
+#include "BLI_assert.h"
+
+#ifndef max
+ #define max(a,b) (((a) > (b)) ? (a) : (b))
+#endif
+
+#ifndef min
+ #define min(a,b) (((a) < (b)) ? (a) : (b))
+#endif
+
+/* 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;
+}
+
+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 seprator. */
+ char* token_end = strchr(n->matte_id+start, ',');
+ if (token_end == NULL || token_end == 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) {
+ 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);
+}
+
+static void cryptomatte_remove(NodeCryptomatte*n, float f)
+{
+ if (n->matte_id == NULL || strlen(n->matte_id) == 0) {
+ /* Empty string, nothing to remove. */
+ 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 seprator. */
+ char* token_end = strchr(n->matte_id+start+1, ',');
+ if (token_end == NULL || token_end == 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);
+}
+
+static bNodeSocketTemplate outputs[] = {
+ { SOCK_RGBA, 0, N_("Image")},
+ { SOCK_FLOAT, 0, N_("Matte")},
+ { SOCK_RGBA, 0, N_("Pick")},
+ { -1, 0, "" }
+};
+
+void ntreeCompositCryptomatteSyncFromAdd(bNodeTree *UNUSED(ntree), bNode *node)
+{
+ NodeCryptomatte *n = node->storage;
+ if (n->add[0] != 0.0f) {
+ cryptomatte_add(n, n->add[0]);
+ n->add[0] = 0.0f;
+ n->add[1] = 0.0f;
+ n->add[2] = 0.0f;
+ }
+}
+
+void ntreeCompositCryptomatteSyncFromRemove(bNodeTree *UNUSED(ntree), bNode *node)
+{
+ NodeCryptomatte *n = node->storage;
+ if (n->remove[0] != 0.0f) {
+ cryptomatte_remove(n, n->remove[0]);
+ n->remove[0] = 0.0f;
+ n->remove[1] = 0.0f;
+ n->remove[2] = 0.0f;
+ }
+}
+
+bNodeSocket *ntreeCompositCryptomatteAddSocket(bNodeTree *ntree, bNode *node)
+{
+ NodeCryptomatte *n = node->storage;
+ char sockname[32];
+ n->num_inputs++;
+ BLI_snprintf(sockname, sizeof(sockname), "Crypto %.2d", n->num_inputs-1);
+ bNodeSocket *sock = nodeAddStaticSocket(ntree, node, SOCK_IN, SOCK_RGBA, PROP_NONE, NULL, sockname);
+ return sock;
+}
+
+int ntreeCompositCryptomatteRemoveSocket(bNodeTree *ntree, bNode *node)
+{
+ NodeCryptomatte *n = node->storage;
+ if (n->num_inputs < 2) {
+ return 0;
+ }
+ bNodeSocket *sock = node->inputs.last;
+ nodeRemoveSocket(ntree, node, sock);
+ n->num_inputs--;
+ return 1;
+}
+
+static void init(bNodeTree *ntree, bNode *node)
+{
+ NodeCryptomatte *user = MEM_callocN(sizeof(NodeCryptomatte), "cryptomatte user");
+ node->storage = user;
+
+
+ nodeAddStaticSocket(ntree, node, SOCK_IN, SOCK_RGBA, PROP_NONE, "image", "Image");
+
+ /* Add three inputs by default, as recommended by the Cryptomatte specification. */
+ ntreeCompositCryptomatteAddSocket(ntree, node);
+ ntreeCompositCryptomatteAddSocket(ntree, node);
+ ntreeCompositCryptomatteAddSocket(ntree, node);
+}
+
+static void node_free_cryptomatte(bNode *node)
+{
+ NodeCryptomatte *nc = node->storage;
+
+ if (nc) {
+ if (nc->matte_id) {
+ MEM_freeN(nc->matte_id);
+ }
+
+ MEM_freeN(nc);
+ }
+}
+
+static void node_copy_cryptomatte(bNodeTree *UNUSED(dest_ntree), bNode *dest_node, bNode *src_node)
+{
+ 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);
+
+ dest_node->storage = dest_nc;
+}
+
+void register_node_type_cmp_cryptomatte(void)
+{
+ static bNodeType ntype;
+
+ cmp_node_type_base(&ntype, CMP_NODE_CRYPTOMATTE, "Cryptomatte", NODE_CLASS_CONVERTOR, 0);
+ node_type_socket_templates(&ntype, NULL, outputs);
+ node_type_init(&ntype, init);
+ node_type_storage(&ntype, "NodeCryptomatte", node_free_cryptomatte, node_copy_cryptomatte);
+ nodeRegisterType(&ntype);
+}