1 /*
2  * This program is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU General Public License
4  * as published by the Free Software Foundation; either version 2
5  * of the License, or (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software Foundation,
14  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15  *
16  * The Original Code is Copyright (C) 2018 Blender Foundation.
17  * All rights reserved.
18  */
19 
20 /** \file
21  * \ingroup cmpnodes
22  */
23 
24 #include "BLI_assert.h"
25 #include "BLI_dynstr.h"
26 #include "BLI_hash_mm3.h"
27 #include "BLI_utildefines.h"
28 #include "node_composite_util.h"
29 
30 /* this is taken from the cryptomatte specification 1.0 */
31 
hash_to_float(uint32_t hash)32 BLI_INLINE float hash_to_float(uint32_t hash)
33 {
34   uint32_t mantissa = hash & ((1 << 23) - 1);
35   uint32_t exponent = (hash >> 23) & ((1 << 8) - 1);
36   exponent = MAX2(exponent, (uint32_t)1);
37   exponent = MIN2(exponent, (uint32_t)254);
38   exponent = exponent << 23;
39   uint32_t sign = (hash >> 31);
40   sign = sign << 31;
41   uint32_t float_bits = sign | exponent | mantissa;
42   float f;
43   /* Bit casting relies on equal size for both types. */
44   BLI_STATIC_ASSERT(sizeof(float) == sizeof(uint32_t), "float and uint32_t are not the same size")
45   memcpy(&f, &float_bits, sizeof(float));
46   return f;
47 }
48 
cryptomatte_add(NodeCryptomatte * n,float f)49 static void cryptomatte_add(NodeCryptomatte *n, float f)
50 {
51   /* Turn the number into a string. */
52   char number[32];
53   BLI_snprintf(number, sizeof(number), "<%.9g>", f);
54 
55   /* Search if we already have the number. */
56   if (n->matte_id && strlen(n->matte_id) != 0) {
57     size_t start = 0;
58     const size_t end = strlen(n->matte_id);
59     size_t token_len = 0;
60     while (start < end) {
61       /* Ignore leading whitespace. */
62       while (start < end && n->matte_id[start] == ' ') {
63         start++;
64       }
65 
66       /* Find the next separator. */
67       char *token_end = strchr(n->matte_id + start, ',');
68       if (token_end == NULL || token_end == n->matte_id + start) {
69         token_end = n->matte_id + end;
70       }
71       /* Be aware that token_len still contains any trailing white space. */
72       token_len = token_end - (n->matte_id + start);
73 
74       /* If this has a leading bracket,
75        * assume a raw floating point number and look for the closing bracket. */
76       if (n->matte_id[start] == '<') {
77         if (strncmp(n->matte_id + start, number, strlen(number)) == 0) {
78           /* This number is already there, so continue. */
79           return;
80         }
81       }
82       else {
83         /* Remove trailing white space */
84         size_t name_len = token_len;
85         while (n->matte_id[start + name_len] == ' ' && name_len > 0) {
86           name_len--;
87         }
88         /* Calculate the hash of the token and compare. */
89         uint32_t hash = BLI_hash_mm3((const unsigned char *)(n->matte_id + start), name_len, 0);
90         if (f == hash_to_float(hash)) {
91           return;
92         }
93       }
94       start += token_len + 1;
95     }
96   }
97 
98   DynStr *new_matte = BLI_dynstr_new();
99   if (!new_matte) {
100     return;
101   }
102 
103   if (n->matte_id) {
104     BLI_dynstr_append(new_matte, n->matte_id);
105     MEM_freeN(n->matte_id);
106   }
107 
108   if (BLI_dynstr_get_len(new_matte) > 0) {
109     BLI_dynstr_append(new_matte, ",");
110   }
111   BLI_dynstr_append(new_matte, number);
112   n->matte_id = BLI_dynstr_get_cstring(new_matte);
113   BLI_dynstr_free(new_matte);
114 }
115 
cryptomatte_remove(NodeCryptomatte * n,float f)116 static void cryptomatte_remove(NodeCryptomatte *n, float f)
117 {
118   if (n->matte_id == NULL || strlen(n->matte_id) == 0) {
119     /* Empty string, nothing to remove. */
120     return;
121   }
122 
123   /* This will be the new string without the removed key. */
124   DynStr *new_matte = BLI_dynstr_new();
125   if (!new_matte) {
126     return;
127   }
128 
129   /* Turn the number into a string. */
130   static char number[32];
131   BLI_snprintf(number, sizeof(number), "<%.9g>", f);
132 
133   /* Search if we already have the number. */
134   size_t start = 0;
135   const size_t end = strlen(n->matte_id);
136   size_t token_len = 0;
137   bool is_first = true;
138   while (start < end) {
139     bool skip = false;
140     /* Ignore leading whitespace or commas. */
141     while (start < end && ((n->matte_id[start] == ' ') || (n->matte_id[start] == ','))) {
142       start++;
143     }
144 
145     /* Find the next separator. */
146     char *token_end = strchr(n->matte_id + start + 1, ',');
147     if (token_end == NULL || token_end == n->matte_id + start) {
148       token_end = n->matte_id + end;
149     }
150     /* Be aware that token_len still contains any trailing white space. */
151     token_len = token_end - (n->matte_id + start);
152 
153     if (token_len == 1) {
154       skip = true;
155     }
156     /* If this has a leading bracket,
157      * assume a raw floating point number and look for the closing bracket. */
158     else if (n->matte_id[start] == '<') {
159       if (strncmp(n->matte_id + start, number, strlen(number)) == 0) {
160         /* This number is already there, so skip it. */
161         skip = true;
162       }
163     }
164     else {
165       /* Remove trailing white space */
166       size_t name_len = token_len;
167       while (n->matte_id[start + name_len] == ' ' && name_len > 0) {
168         name_len--;
169       }
170       /* Calculate the hash of the token and compare. */
171       uint32_t hash = BLI_hash_mm3((const unsigned char *)(n->matte_id + start), name_len, 0);
172       if (f == hash_to_float(hash)) {
173         skip = true;
174       }
175     }
176     if (!skip) {
177       if (is_first) {
178         is_first = false;
179       }
180       else {
181         BLI_dynstr_append(new_matte, ", ");
182       }
183       BLI_dynstr_nappend(new_matte, n->matte_id + start, token_len);
184     }
185     start += token_len + 1;
186   }
187 
188   if (n->matte_id) {
189     MEM_freeN(n->matte_id);
190     n->matte_id = NULL;
191   }
192   if (BLI_dynstr_get_len(new_matte) > 0) {
193     n->matte_id = BLI_dynstr_get_cstring(new_matte);
194   }
195   BLI_dynstr_free(new_matte);
196 }
197 
198 static bNodeSocketTemplate outputs[] = {
199     {SOCK_RGBA, N_("Image")},
200     {SOCK_FLOAT, N_("Matte")},
201     {SOCK_RGBA, N_("Pick")},
202     {-1, ""},
203 };
204 
ntreeCompositCryptomatteSyncFromAdd(bNodeTree * UNUSED (ntree),bNode * node)205 void ntreeCompositCryptomatteSyncFromAdd(bNodeTree *UNUSED(ntree), bNode *node)
206 {
207   NodeCryptomatte *n = node->storage;
208   if (n->add[0] != 0.0f) {
209     cryptomatte_add(n, n->add[0]);
210     n->add[0] = 0.0f;
211     n->add[1] = 0.0f;
212     n->add[2] = 0.0f;
213   }
214 }
215 
ntreeCompositCryptomatteSyncFromRemove(bNodeTree * UNUSED (ntree),bNode * node)216 void ntreeCompositCryptomatteSyncFromRemove(bNodeTree *UNUSED(ntree), bNode *node)
217 {
218   NodeCryptomatte *n = node->storage;
219   if (n->remove[0] != 0.0f) {
220     cryptomatte_remove(n, n->remove[0]);
221     n->remove[0] = 0.0f;
222     n->remove[1] = 0.0f;
223     n->remove[2] = 0.0f;
224   }
225 }
226 
ntreeCompositCryptomatteAddSocket(bNodeTree * ntree,bNode * node)227 bNodeSocket *ntreeCompositCryptomatteAddSocket(bNodeTree *ntree, bNode *node)
228 {
229   NodeCryptomatte *n = node->storage;
230   char sockname[32];
231   n->num_inputs++;
232   BLI_snprintf(sockname, sizeof(sockname), "Crypto %.2d", n->num_inputs - 1);
233   bNodeSocket *sock = nodeAddStaticSocket(
234       ntree, node, SOCK_IN, SOCK_RGBA, PROP_NONE, NULL, sockname);
235   return sock;
236 }
237 
ntreeCompositCryptomatteRemoveSocket(bNodeTree * ntree,bNode * node)238 int ntreeCompositCryptomatteRemoveSocket(bNodeTree *ntree, bNode *node)
239 {
240   NodeCryptomatte *n = node->storage;
241   if (n->num_inputs < 2) {
242     return 0;
243   }
244   bNodeSocket *sock = node->inputs.last;
245   nodeRemoveSocket(ntree, node, sock);
246   n->num_inputs--;
247   return 1;
248 }
249 
init(bNodeTree * ntree,bNode * node)250 static void init(bNodeTree *ntree, bNode *node)
251 {
252   NodeCryptomatte *user = MEM_callocN(sizeof(NodeCryptomatte), "cryptomatte user");
253   node->storage = user;
254 
255   nodeAddStaticSocket(ntree, node, SOCK_IN, SOCK_RGBA, PROP_NONE, "image", "Image");
256 
257   /* Add three inputs by default, as recommended by the Cryptomatte specification. */
258   ntreeCompositCryptomatteAddSocket(ntree, node);
259   ntreeCompositCryptomatteAddSocket(ntree, node);
260   ntreeCompositCryptomatteAddSocket(ntree, node);
261 }
262 
node_free_cryptomatte(bNode * node)263 static void node_free_cryptomatte(bNode *node)
264 {
265   NodeCryptomatte *nc = node->storage;
266 
267   if (nc) {
268     if (nc->matte_id) {
269       MEM_freeN(nc->matte_id);
270     }
271 
272     MEM_freeN(nc);
273   }
274 }
275 
node_copy_cryptomatte(bNodeTree * UNUSED (dest_ntree),bNode * dest_node,const bNode * src_node)276 static void node_copy_cryptomatte(bNodeTree *UNUSED(dest_ntree),
277                                   bNode *dest_node,
278                                   const bNode *src_node)
279 {
280   NodeCryptomatte *src_nc = src_node->storage;
281   NodeCryptomatte *dest_nc = MEM_dupallocN(src_nc);
282 
283   if (src_nc->matte_id) {
284     dest_nc->matte_id = MEM_dupallocN(src_nc->matte_id);
285   }
286 
287   dest_node->storage = dest_nc;
288 }
289 
register_node_type_cmp_cryptomatte(void)290 void register_node_type_cmp_cryptomatte(void)
291 {
292   static bNodeType ntype;
293 
294   cmp_node_type_base(&ntype, CMP_NODE_CRYPTOMATTE, "Cryptomatte", NODE_CLASS_CONVERTOR, 0);
295   node_type_socket_templates(&ntype, NULL, outputs);
296   node_type_init(&ntype, init);
297   node_type_storage(&ntype, "NodeCryptomatte", node_free_cryptomatte, node_copy_cryptomatte);
298   nodeRegisterType(&ntype);
299 }
300