style cleanup: follow style guide for formatting of if/for/while loops, and else...
[blender.git] / source / blender / nodes / composite / nodes / node_composite_doubleEdgeMask.c
1 /*
2  * ***** BEGIN GPL LICENSE BLOCK *****
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software Foundation,
16  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  *
18  * The Original Code is Copyright (C) 2011 Blender Foundation.
19  * All rights reserved.
20  *
21  * The Original Code is: all of this file.
22  *
23  * Contributor(s): Peter Larabell.
24  *
25  * ***** END GPL LICENSE BLOCK *****
26  */
27
28 /** \file blender/nodes/composite/nodes/node_composite_doubleEdgeMask.c
29  *  \ingroup cmpnodes
30  */
31 #include "node_composite_util.h"
32 /* **************** Double Edge Mask ******************** */
33
34
35 static bNodeSocketTemplate cmp_node_doubleedgemask_in[]= {
36         { SOCK_FLOAT, 1, "Inner Mask", 0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f, PROP_NONE},  // inner mask socket definition
37         { SOCK_FLOAT, 1, "Outer Mask", 0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f, PROP_NONE},  // outer mask socket definition
38         { -1, 0, ""     }                                                                                                                                       // input socket array terminator
39 };
40 static bNodeSocketTemplate cmp_node_doubleedgemask_out[]= {
41         { SOCK_FLOAT, 0, "Mask"},               // output socket definition
42         { -1, 0, "" }                                   // output socket array terminator
43 };
44
45 static void do_adjacentKeepBorders(unsigned int t, unsigned int rw, unsigned int *limask, unsigned int *lomask, unsigned int *lres, float *res, unsigned int *rsize)
46 {
47         int x;
48         unsigned int isz=0; // inner edge size
49         unsigned int osz=0; // outer edge size
50         unsigned int gsz=0; // gradient fill area size
51         /* Test the four corners */
52         /* upper left corner */
53         x=t-rw+1;
54         // test if inner mask is filled
55         if (limask[x]) {
56                 // test if pixel underneath, or to the right, are empty in the inner mask,
57                 // but filled in the outer mask
58                 if ((!limask[x-rw] && lomask[x-rw]) || (!limask[x+1] && lomask[x+1])) {
59                         isz++;                                                          // increment inner edge size
60                         lres[x]=4;                                                      // flag pixel as inner edge
61                 }
62                 else {
63                         res[x]=1.0f;                                            // pixel is just part of inner mask, and it's not an edge
64                 }
65         }
66         else if (lomask[x]) {                                           // inner mask was empty, test if outer mask is filled
67                 osz++;                                                                  // increment outer edge size
68                 lres[x]=3;                                                              // flag pixel as outer edge
69         }
70         /* upper right corner */
71         x=t;
72         // test if inner mask is filled
73         if (limask[x]) {
74                 // test if pixel underneath, or to the left, are empty in the inner mask,
75                 // but filled in the outer mask
76                 if ((!limask[x-rw] && lomask[x-rw]) || (!limask[x-1] && lomask[x-1])) {
77                         isz++;                                                          // increment inner edge size
78                         lres[x]=4;                                                      // flag pixel as inner edge
79                 }
80                 else {
81                         res[x]=1.0f;                                            // pixel is just part of inner mask, and it's not an edge
82                 }
83         }
84         else if (lomask[x]) {                                           // inner mask was empty, test if outer mask is filled
85                 osz++;                                                                  // increment outer edge size
86                 lres[x]=3;                                                              // flag pixel as outer edge
87         }
88         /* lower left corner */
89         x=0;
90         // test if inner mask is filled
91         if (limask[x]) {
92                 // test if pixel above, or to the right, are empty in the inner mask,
93                 // but filled in the outer mask
94                 if ((!limask[x+rw] && lomask[x+rw]) || (!limask[x+1] && lomask[x+1])) {
95                         isz++;                                                          // increment inner edge size
96                         lres[x]=4;                                                      // flag pixel as inner edge
97                 }
98                 else {
99                         res[x]=1.0f;                                            // pixel is just part of inner mask, and it's not an edge
100                 }
101         }
102         else if (lomask[x]) {                                           // inner mask was empty, test if outer mask is filled
103                 osz++;                                                                  // increment outer edge size
104                 lres[x]=3;                                                              // flag pixel as outer edge
105         }
106         /* lower right corner */
107         x=rw-1;
108         // test if inner mask is filled
109         if (limask[x]) {
110                 // test if pixel above, or to the left, are empty in the inner mask,
111                 // but filled in the outer mask
112                 if ((!limask[x+rw] && lomask[x+rw]) || (!limask[x-1] && lomask[x-1])) {
113                         isz++;                                                          // increment inner edge size
114                         lres[x]=4;                                                      // flag pixel as inner edge
115                 }
116                 else {
117                         res[x]=1.0f;                                            // pixel is just part of inner mask, and it's not an edge
118                 }
119         }
120         else if (lomask[x]) {                                           // inner mask was empty, test if outer mask is filled
121                 osz++;                                                                  // increment outer edge size
122                 lres[x]=3;                                                              // flag pixel as outer edge
123         }
124
125         /* Test the TOP row of pixels in buffer, except corners */
126         for (x= t-1; x>=(t-rw)+2; x--) {
127                 // test if inner mask is filled
128                 if (limask[x]) {
129                         // test if pixel to the right, or to the left, are empty in the inner mask,
130                         // but filled in the outer mask
131                         if ((!limask[x-1] && lomask[x-1]) || (!limask[x+1] && lomask[x+1])) {
132                                 isz++;                                                  // increment inner edge size
133                                 lres[x]=4;                                              // flag pixel as inner edge
134                         }
135                         else {
136                                 res[x]=1.0f;                                    // pixel is just part of inner mask, and it's not an edge
137                         }
138                 }
139                 else if (lomask[x]) {                                   // inner mask was empty, test if outer mask is filled
140                         osz++;                                                          // increment outer edge size
141                         lres[x]=3;                                                      // flag pixel as outer edge
142                 }
143         }
144
145         /* Test the BOTTOM row of pixels in buffer, except corners */
146         for (x= rw-2; x; x--) {
147                 // test if inner mask is filled
148                 if (limask[x]) {
149                         // test if pixel to the right, or to the left, are empty in the inner mask,
150                         // but filled in the outer mask
151                         if ((!limask[x-1] && lomask[x-1]) || (!limask[x+1] && lomask[x+1])) {
152                                 isz++;                                                  // increment inner edge size
153                                 lres[x]=4;                                              // flag pixel as inner edge
154                         }
155                         else {
156                                 res[x]=1.0f;                                    // pixel is just part of inner mask, and it's not an edge
157                         }
158                 }
159                 else if (lomask[x]) {                                   // inner mask was empty, test if outer mask is filled
160                         osz++;                                                          // increment outer edge size
161                         lres[x]=3;                                                      // flag pixel as outer edge
162                 }
163         }
164         /* Test the LEFT edge of pixels in buffer, except corners */
165         for (x= t-(rw<<1)+1; x>=rw; x-=rw) {
166                 // test if inner mask is filled
167                 if (limask[x]) {
168                         // test if pixel underneath, or above, are empty in the inner mask,
169                         // but filled in the outer mask
170                         if ((!limask[x-rw] && lomask[x-rw]) || (!limask[x+rw] && lomask[x+rw])) {
171                                 isz++;                                                  // increment inner edge size
172                                 lres[x]=4;                                              // flag pixel as inner edge
173                         }
174                         else {
175                                 res[x]=1.0f;                                    // pixel is just part of inner mask, and it's not an edge
176                         }
177                 }
178                 else if (lomask[x]) {                                   // inner mask was empty, test if outer mask is filled
179                         osz++;                                                          // increment outer edge size
180                         lres[x]=3;                                                      // flag pixel as outer edge
181                 }
182         }
183
184         /* Test the RIGHT edge of pixels in buffer, except corners */
185         for (x= t-rw; x>rw; x-=rw) {
186                 // test if inner mask is filled
187                 if (limask[x]) {
188                         // test if pixel underneath, or above, are empty in the inner mask,
189                         // but filled in the outer mask
190                         if ((!limask[x-rw] && lomask[x-rw]) || (!limask[x+rw] && lomask[x+rw])) {
191                                 isz++;                                                  // increment inner edge size
192                                 lres[x]=4;                                              // flag pixel as inner edge
193                         }
194                         else {
195                                 res[x]=1.0f;                                    // pixel is just part of inner mask, and it's not an edge
196                         }
197                 }
198                 else if (lomask[x]) {                                   // inner mask was empty, test if outer mask is filled
199                         osz++;                                                          // increment outer edge size
200                         lres[x]=3;                                                      // flag pixel as outer edge
201                 }
202         }
203
204         rsize[0]=isz; // fill in our return sizes for edges + fill
205         rsize[1]=osz;
206         rsize[2]=gsz;
207 }
208
209 static void do_adjacentBleedBorders(unsigned int t, unsigned int rw, unsigned int *limask, unsigned int *lomask, unsigned int *lres, float *res, unsigned int *rsize)
210 {
211         int x;
212         unsigned int isz=0; // inner edge size
213         unsigned int osz=0; // outer edge size
214         unsigned int gsz=0; // gradient fill area size
215         /* Test the four corners */
216         /* upper left corner */
217         x=t-rw+1;
218         // test if inner mask is filled
219         if (limask[x]) {
220                 // test if pixel underneath, or to the right, are empty in the inner mask,
221                 // but filled in the outer mask
222                 if ((!limask[x-rw] && lomask[x-rw]) || (!limask[x+1] && lomask[x+1])) {
223                         isz++;                                                          // increment inner edge size
224                         lres[x]=4;                                                      // flag pixel as inner edge
225                 }
226                 else {
227                         res[x]=1.0f;                                            // pixel is just part of inner mask, and it's not an edge
228                 }
229         }
230         else if (lomask[x]) {                                           // inner mask was empty, test if outer mask is filled
231                 if (!lomask[x-rw] || !lomask[x+1]) {            // test if outer mask is empty underneath or to the right
232                         osz++;                                                          // increment outer edge size
233                         lres[x]=3;                                                      // flag pixel as outer edge
234                 }
235                 else {
236                         gsz++;                                                          // increment the gradient pixel count
237                         lres[x]=2;                                                      // flag pixel as gradient
238                 }
239         }
240         /* upper right corner */
241         x=t;
242         // test if inner mask is filled
243         if (limask[x]) {
244                 // test if pixel underneath, or to the left, are empty in the inner mask,
245                 // but filled in the outer mask
246                 if ((!limask[x-rw] && lomask[x-rw]) || (!limask[x-1] && lomask[x-1])) {
247                         isz++;                                                          // increment inner edge size
248                         lres[x]=4;                                                      // flag pixel as inner edge
249                 }
250                 else {
251                         res[x]=1.0f;                                            // pixel is just part of inner mask, and it's not an edge
252                 }
253         }
254         else if (lomask[x]) {                                           // inner mask was empty, test if outer mask is filled
255                 if (!lomask[x-rw] || !lomask[x-1]) {    // test if outer mask is empty underneath or to the left
256                         osz++;                                                          // increment outer edge size
257                         lres[x]=3;                                                      // flag pixel as outer edge
258                 }
259                 else {
260                         gsz++;                                                          // increment the gradient pixel count
261                         lres[x]=2;                                                      // flag pixel as gradient
262                 }
263         }
264         /* lower left corner */
265         x=0;
266         // test if inner mask is filled
267         if (limask[x]) {
268                 // test if pixel above, or to the right, are empty in the inner mask,
269                 // but filled in the outer mask
270                 if ((!limask[x+rw] && lomask[x+rw]) || (!limask[x+1] && lomask[x+1])) {
271                         isz++;                                                          // increment inner edge size
272                         lres[x]=4;                                                      // flag pixel as inner edge
273                 }
274                 else {
275                         res[x]=1.0f;                                            // pixel is just part of inner mask, and it's not an edge
276                 }
277         }
278         else if (lomask[x]) {                                           // inner mask was empty, test if outer mask is filled
279                 if (!lomask[x+rw] || !lomask[x+1]) {    // test if outer mask is empty above or to the right
280                         osz++;                                                          // increment outer edge size
281                         lres[x]=3;                                                      // flag pixel as outer edge
282                 }
283                 else {
284                         gsz++;                                                          // increment the gradient pixel count
285                         lres[x]=2;                                                      // flag pixel as gradient
286                 }
287         }
288         /* lower right corner */
289         x=rw-1;
290         // test if inner mask is filled
291         if (limask[x]) {
292                 // test if pixel above, or to the left, are empty in the inner mask,
293                 // but filled in the outer mask
294                 if ((!limask[x+rw] && lomask[x+rw]) || (!limask[x-1] && lomask[x-1])) {
295                         isz++;                                                          // increment inner edge size
296                         lres[x]=4;                                                      // flag pixel as inner edge
297                 }
298                 else {
299                         res[x]=1.0f;                                            // pixel is just part of inner mask, and it's not an edge
300                 }
301         }
302         else if (lomask[x]) {                                           // inner mask was empty, test if outer mask is filled
303                 if (!lomask[x+rw] || !lomask[x-1]) {    // test if outer mask is empty above or to the left
304                         osz++;                                                          // increment outer edge size
305                         lres[x]=3;                                                      // flag pixel as outer edge
306                 }
307                 else {
308                         gsz++;                                                          // increment the gradient pixel count
309                         lres[x]=2;                                                      // flag pixel as gradient
310                 }
311         }
312         /* Test the TOP row of pixels in buffer, except corners */
313         for (x= t-1; x>=(t-rw)+2; x--) {
314                 // test if inner mask is filled
315                 if (limask[x]) {
316                         // test if pixel to the left, or to the right, are empty in the inner mask,
317                         // but filled in the outer mask
318                         if ((!limask[x-1] && lomask[x-1]) || (!limask[x+1] && lomask[x+1])) {
319                                 isz++;                                                  // increment inner edge size
320                                 lres[x]=4;                                              // flag pixel as inner edge
321                         }
322                         else {
323                                 res[x]=1.0f;                                    // pixel is just part of inner mask, and it's not an edge
324                         }
325                 }
326                 else if (lomask[x]) {                                   // inner mask was empty, test if outer mask is filled
327                         if (!lomask[x-1] || !lomask[x+1]) {     // test if outer mask is empty to the left or to the right
328                                 osz++;                                                  // increment outer edge size
329                                 lres[x]=3;                                              // flag pixel as outer edge
330                         }
331                         else {
332                                 gsz++;                                                  // increment the gradient pixel count
333                                 lres[x]=2;                                              // flag pixel as gradient
334                         }
335                 }
336         }
337
338         /* Test the BOTTOM row of pixels in buffer, except corners */
339         for (x= rw-2; x; x--) {
340                 // test if inner mask is filled
341                 if (limask[x]) {
342                         // test if pixel to the left, or to the right, are empty in the inner mask,
343                         // but filled in the outer mask
344                         if ((!limask[x-1] && lomask[x-1]) || (!limask[x+1] && lomask[x+1])) {
345                                 isz++;                                                  // increment inner edge size
346                                 lres[x]=4;                                              // flag pixel as inner edge
347                         }
348                         else {
349                                 res[x]=1.0f;                                    // pixel is just part of inner mask, and it's not an edge
350                         }
351                 }
352                 else if (lomask[x]) {                                   // inner mask was empty, test if outer mask is filled
353                         if (!lomask[x-1] || !lomask[x+1]) {     // test if outer mask is empty to the left or to the right
354                                 osz++;                                                  // increment outer edge size
355                                 lres[x]=3;                                              // flag pixel as outer edge
356                         }
357                         else {
358                                 gsz++;                                                  // increment the gradient pixel count
359                                 lres[x]=2;                                              // flag pixel as gradient
360                         }
361                 }
362         }
363         /* Test the LEFT edge of pixels in buffer, except corners */
364         for (x= t-(rw<<1)+1; x>=rw; x-=rw) {
365                 // test if inner mask is filled
366                 if (limask[x]) {
367                         // test if pixel underneath, or above, are empty in the inner mask,
368                         // but filled in the outer mask
369                         if ((!limask[x-rw] && lomask[x-rw]) || (!limask[x+rw] && lomask[x+rw])) {
370                                 isz++;                                                  // increment inner edge size
371                                 lres[x]=4;                                              // flag pixel as inner edge
372                         }
373                         else {
374                                 res[x]=1.0f;                                    // pixel is just part of inner mask, and it's not an edge
375                         }
376                 }
377                 else if (lomask[x]) {                                           // inner mask was empty, test if outer mask is filled
378                         if (!lomask[x-rw] || !lomask[x+rw]) {   // test if outer mask is empty underneath or above
379                                 osz++;                                                          // increment outer edge size
380                                 lres[x]=3;                                                      // flag pixel as outer edge
381                         }
382                         else {
383                                 gsz++;                                                  // increment the gradient pixel count
384                                 lres[x]=2;                                              // flag pixel as gradient
385                         }
386                 }
387         }
388
389         /* Test the RIGHT edge of pixels in buffer, except corners */
390         for (x= t-rw; x>rw; x-=rw) {
391                 // test if inner mask is filled
392                 if (limask[x]) {
393                         // test if pixel underneath, or above, are empty in the inner mask,
394                         // but filled in the outer mask
395                         if ((!limask[x-rw] && lomask[x-rw]) || (!limask[x+rw] && lomask[x+rw])) {
396                                 isz++;                                                  // increment inner edge size
397                                 lres[x]=4;                                              // flag pixel as inner edge
398                         }
399                         else {
400                                 res[x]=1.0f;                                    // pixel is just part of inner mask, and it's not an edge
401                         }
402                 }
403                 else if (lomask[x]) {                                           // inner mask was empty, test if outer mask is filled
404                         if (!lomask[x-rw] || !lomask[x+rw]) {   // test if outer mask is empty underneath or above
405                                 osz++;                                                          // increment outer edge size
406                                 lres[x]=3;                                                      // flag pixel as outer edge
407                         }
408                         else {
409                                 gsz++;                                                  // increment the gradient pixel count
410                                 lres[x]=2;                                              // flag pixel as gradient
411                         }
412                 }
413         }
414
415         rsize[0]=isz;  // fill in our return sizes for edges + fill
416         rsize[1]=osz;
417         rsize[2]=gsz;
418 }
419
420 static void do_allKeepBorders(unsigned int t, unsigned int rw, unsigned int *limask, unsigned int *lomask, unsigned int *lres, float *res, unsigned int *rsize)
421 {
422         int x;
423         unsigned int isz=0; // inner edge size
424         unsigned int osz=0; // outer edge size
425         unsigned int gsz=0; // gradient fill area size
426         /* Test the four corners */
427         /* upper left corner */
428         x=t-rw+1;
429         // test if inner mask is filled
430         if (limask[x]) {
431                 // test if the inner mask is empty underneath or to the right
432                 if (!limask[x-rw] || !limask[x+1]) {
433                         isz++;                                                          // increment inner edge size
434                         lres[x]=4;                                                      // flag pixel as inner edge
435                 }
436                 else {
437                         res[x]=1.0f;                                            // pixel is just part of inner mask, and it's not an edge
438                 }
439         }
440         else if (lomask[x]) {                                           // inner mask was empty, test if outer mask is filled
441                 osz++;                                                                  // increment outer edge size
442                 lres[x]=3;                                                              // flag pixel as outer edge
443         }
444         /* upper right corner */
445         x=t;
446         // test if inner mask is filled
447         if (limask[x]) {
448                 // test if the inner mask is empty underneath or to the left
449                 if (!limask[x-rw] || !limask[x-1]) {
450                         isz++;                                                          // increment inner edge size
451                         lres[x]=4;                                                      // flag pixel as inner edge
452                 }
453                 else {
454                         res[x]=1.0f;                                            // pixel is just part of inner mask, and it's not an edge
455                 }
456         }
457         else if (lomask[x]) {                                           // inner mask was empty, test if outer mask is filled
458                 osz++;                                                                  // increment outer edge size
459                 lres[x]=3;                                                              // flag pixel as outer edge
460         }
461         /* lower left corner */
462         x=0;
463         // test if inner mask is filled
464         if (limask[x]) {
465                 // test if inner mask is empty above or to the right
466                 if (!limask[x+rw] || !limask[x+1]) {
467                         isz++;                                                          // increment inner edge size
468                         lres[x]=4;                                                      // flag pixel as inner edge
469                 }
470                 else {
471                         res[x]=1.0f;                                            // pixel is just part of inner mask, and it's not an edge
472                 }
473         }
474         else if (lomask[x]) {                                           // inner mask was empty, test if outer mask is filled
475                 osz++;                                                                  // increment outer edge size
476                 lres[x]=3;                                                              // flag pixel as outer edge
477         }
478         /* lower right corner */
479         x=rw-1;
480         // test if inner mask is filled
481         if (limask[x]) {
482                 // test if inner mask is empty above or to the left
483                 if (!limask[x+rw] || !limask[x-1]) {
484                         isz++;                                                          // increment inner edge size
485                         lres[x]=4;                                                      // flag pixel as inner edge
486                 }
487                 else {
488                         res[x]=1.0f;                                            // pixel is just part of inner mask, and it's not an edge
489                 }
490         }
491         else if (lomask[x]) {                                           // inner mask was empty, test if outer mask is filled
492                 osz++;                                                                  // increment outer edge size
493                 lres[x]=3;                                                              // flag pixel as outer edge
494         }
495
496         /* Test the TOP row of pixels in buffer, except corners */
497         for (x= t-1; x>=(t-rw)+2; x--) {
498                 // test if inner mask is filled
499                 if (limask[x]) {
500                         // test if inner mask is empty to the left or to the right
501                         if (!limask[x-1] || !limask[x+1]) {
502                                 isz++;                                                  // increment inner edge size
503                                 lres[x]=4;                                              // flag pixel as inner edge
504                         }
505                         else {
506                                 res[x]=1.0f;                                    // pixel is just part of inner mask, and it's not an edge
507                         }
508                 }
509                 else if (lomask[x]) {                                   // inner mask was empty, test if outer mask is filled
510                         osz++;                                                          // increment outer edge size
511                         lres[x]=3;                                                      // flag pixel as outer edge
512                 }
513         }
514
515         /* Test the BOTTOM row of pixels in buffer, except corners */
516         for (x= rw-2; x; x--) {
517                 // test if inner mask is filled
518                 if (limask[x]) {
519                         // test if inner mask is empty to the left or to the right
520                         if (!limask[x-1] || !limask[x+1]) {
521                                 isz++;                                                  // increment inner edge size
522                                 lres[x]=4;                                              // flag pixel as inner edge
523                         }
524                         else {
525                                 res[x]=1.0f;                                    // pixel is just part of inner mask, and it's not an edge
526                         }
527                 }
528                 else if (lomask[x]) {                                   // inner mask was empty, test if outer mask is filled
529                         osz++;                                                          // increment outer edge size
530                         lres[x]=3;                                                      // flag pixel as outer edge
531                 }
532         }
533         /* Test the LEFT edge of pixels in buffer, except corners */
534         for (x= t-(rw<<1)+1; x>=rw; x-=rw) {
535                 // test if inner mask is filled
536                 if (limask[x]) {
537                         // test if inner mask is empty underneath or above
538                         if (!limask[x-rw] || !limask[x+rw]) {
539                                 isz++;                                                  // increment inner edge size
540                                 lres[x]=4;                                              // flag pixel as inner edge
541                         }
542                         else {
543                                 res[x]=1.0f;                                    // pixel is just part of inner mask, and it's not an edge
544                         }
545                 }
546                 else if (lomask[x]) {                                   // inner mask was empty, test if outer mask is filled
547                         osz++;                                                          // increment outer edge size
548                         lres[x]=3;                                                      // flag pixel as outer edge
549                 }
550         }
551
552         /* Test the RIGHT edge of pixels in buffer, except corners */
553         for (x= t-rw; x>rw; x-=rw) {
554                 // test if inner mask is filled
555                 if (limask[x]) {
556                         // test if inner mask is empty underneath or above
557                         if (!limask[x-rw] || !limask[x+rw]) {
558                                 isz++;                                                  // increment inner edge size
559                                 lres[x]=4;                                              // flag pixel as inner edge
560                         }
561                         else {
562                                 res[x]=1.0f;                                    // pixel is just part of inner mask, and it's not an edge
563                         }
564                 }
565                 else if (lomask[x]) {                                   // inner mask was empty, test if outer mask is filled
566                         osz++;                                                          // increment outer edge size
567                         lres[x]=3;                                                      // flag pixel as outer edge
568                 }
569         }
570
571         rsize[0]=isz;  // fill in our return sizes for edges + fill
572         rsize[1]=osz;
573         rsize[2]=gsz;
574 }
575
576 static void do_allBleedBorders(unsigned int t, unsigned int rw, unsigned int *limask, unsigned int *lomask, unsigned int *lres, float *res, unsigned int *rsize)
577 {
578         int x;
579         unsigned int isz=0; // inner edge size
580         unsigned int osz=0; // outer edge size
581         unsigned int gsz=0; // gradient fill area size
582         /* Test the four corners */
583         /* upper left corner */
584         x=t-rw+1;
585         // test if inner mask is filled
586         if (limask[x]) {
587                 // test if the inner mask is empty underneath or to the right
588                 if (!limask[x-rw] || !limask[x+1]) {
589                         isz++;                                                          // increment inner edge size
590                         lres[x]=4;                                                      // flag pixel as inner edge
591                 }
592                 else {
593                         res[x]=1.0f;                                            // pixel is just part of inner mask, and it's not an edge
594                 }
595         }
596         else if (lomask[x]) {                                           // inner mask was empty, test if outer mask is filled
597                 if (!lomask[x-rw] || !lomask[x+1]) {    // test if outer mask is empty underneath or to the right
598                         osz++;                                                          // increment outer edge size
599                         lres[x]=3;                                                      // flag pixel as outer edge
600                 }
601                 else {
602                         gsz++;                                                          // increment the gradient pixel count
603                         lres[x]=2;                                                      // flag pixel as gradient
604                 }
605         }
606         /* upper right corner */
607         x=t;
608         // test if inner mask is filled
609         if (limask[x]) {
610                 // test if the inner mask is empty underneath or to the left
611                 if (!limask[x-rw] || !limask[x-1]) {
612                         isz++;                                                          // increment inner edge size
613                         lres[x]=4;                                                      // flag pixel as inner edge
614                 }
615                 else {
616                         res[x]=1.0f;                                            // pixel is just part of inner mask, and it's not an edge
617                 }
618         }
619         else if (lomask[x]) {                                           // inner mask was empty, test if outer mask is filled
620                 if (!lomask[x-rw] || !lomask[x-1]) {            // test if outer mask is empty above or to the left
621                         osz++;                                                          // increment outer edge size
622                         lres[x]=3;                                                      // flag pixel as outer edge
623                 }
624                 else {
625                         gsz++;                                                          // increment the gradient pixel count
626                         lres[x]=2;                                                      // flag pixel as gradient
627                 }
628         }
629         /* lower left corner */
630         x=0;
631         // test if inner mask is filled
632         if (limask[x]) {
633                 // test if inner mask is empty above or to the right
634                 if (!limask[x+rw] || !limask[x+1]) {
635                         isz++;                                                          // increment inner edge size
636                         lres[x]=4;                                                      // flag pixel as inner edge
637                 }
638                 else {
639                         res[x]=1.0f;                                            // pixel is just part of inner mask, and it's not an edge
640                 }
641         }
642         else if (lomask[x]) {                                           // inner mask was empty, test if outer mask is filled
643                 if (!lomask[x+rw] || !lomask[x+1]) {    // test if outer mask is empty underneath or to the right
644                         osz++;                                                          // increment outer edge size
645                         lres[x]=3;                                                      // flag pixel as outer edge
646                 }
647                 else {
648                         gsz++;                                                          // increment the gradient pixel count
649                         lres[x]=2;                                                      // flag pixel as gradient
650                 }
651         }
652         /* lower right corner */
653         x=rw-1;
654         // test if inner mask is filled
655         if (limask[x]) {
656                 // test if inner mask is empty above or to the left
657                 if (!limask[x+rw] || !limask[x-1]) {
658                         isz++;                                                          // increment inner edge size
659                         lres[x]=4;                                                      // flag pixel as inner edge
660                 }
661                 else {
662                         res[x]=1.0f;                                            // pixel is just part of inner mask, and it's not an edge
663                 }
664         }
665         else if (lomask[x]) {                                           // inner mask was empty, test if outer mask is filled
666                 if (!lomask[x+rw] || !lomask[x-1]) {    // test if outer mask is empty underneath or to the left
667                         osz++;                                                          // increment outer edge size
668                         lres[x]=3;                                                      // flag pixel as outer edge
669                 }
670                 else {
671                         gsz++;                                                          // increment the gradient pixel count
672                         lres[x]=2;                                                      // flag pixel as gradient
673                 }
674         }
675         /* Test the TOP row of pixels in buffer, except corners */
676         for (x= t-1; x>=(t-rw)+2; x--) {
677                 // test if inner mask is filled
678                 if (limask[x]) {
679                         // test if inner mask is empty to the left or to the right
680                         if (!limask[x-1] || !limask[x+1]) {
681                                 isz++;                                                  // increment inner edge size
682                                 lres[x]=4;                                              // flag pixel as inner edge
683                         }
684                         else {
685                                 res[x]=1.0f;                                    // pixel is just part of inner mask, and it's not an edge
686                         }
687                 }
688                 else if (lomask[x]) {                                   // inner mask was empty, test if outer mask is filled
689                         if (!lomask[x-1] || !lomask[x+1]) {     // test if outer mask is empty to the left or to the right
690                                 osz++;                                                  // increment outer edge size
691                                 lres[x]=3;                                              // flag pixel as outer edge
692                         }
693                         else {
694                                 gsz++;                                                  // increment the gradient pixel count
695                                 lres[x]=2;                                              // flag pixel as gradient
696                         }
697                 }
698         }
699
700         /* Test the BOTTOM row of pixels in buffer, except corners */
701         for (x= rw-2; x; x--) {
702                 // test if inner mask is filled
703                 if (limask[x]) {
704                         // test if inner mask is empty to the left or to the right
705                         if (!limask[x-1] || !limask[x+1]) {
706                                 isz++;                                                  // increment inner edge size
707                                 lres[x]=4;                                              // flag pixel as inner edge
708                         }
709                         else {
710                                 res[x]=1.0f;                                    // pixel is just part of inner mask, and it's not an edge
711                         }
712                 }
713                 else if (lomask[x]) {                                   // inner mask was empty, test if outer mask is filled
714                         if (!lomask[x-1] || !lomask[x+1]) {     // test if outer mask is empty to the left or to the right
715                                 osz++;                                                  // increment outer edge size
716                                 lres[x]=3;                                              // flag pixel as outer edge
717                         }
718                         else {
719                                 gsz++;                                                  // increment the gradient pixel count
720                                 lres[x]=2;                                              // flag pixel as gradient
721                         }
722                 }
723         }
724         /* Test the LEFT edge of pixels in buffer, except corners */
725         for (x= t-(rw<<1)+1; x>=rw; x-=rw) {
726                 // test if inner mask is filled
727                 if (limask[x]) {
728                         // test if inner mask is empty underneath or above
729                         if (!limask[x-rw] || !limask[x+rw]) {
730                                 isz++;                                                          // increment inner edge size
731                                 lres[x]=4;                                                      // flag pixel as inner edge
732                         }
733                         else {
734                                 res[x]=1.0f;                                            // pixel is just part of inner mask, and it's not an edge
735                         }
736                 }
737                 else if (lomask[x]) {                                           // inner mask was empty, test if outer mask is filled
738                         if (!lomask[x-rw] || !lomask[x+rw]) {   // test if outer mask is empty underneath or above
739                                 osz++;                                                          // increment outer edge size
740                                 lres[x]=3;                                                      // flag pixel as outer edge
741                         }
742                         else {
743                                 gsz++;                                                          // increment the gradient pixel count
744                                 lres[x]=2;                                                      // flag pixel as gradient
745                         }
746                 }
747         }
748
749         /* Test the RIGHT edge of pixels in buffer, except corners */
750         for (x= t-rw; x>rw; x-=rw) {
751                 // test if inner mask is filled
752                 if (limask[x]) {
753                         // test if inner mask is empty underneath or above
754                         if (!limask[x-rw] || !limask[x+rw]) {
755                                 isz++;                                                  // increment inner edge size
756                                 lres[x]=4;                                              // flag pixel as inner edge
757                         }
758                         else {
759                                 res[x]=1.0f;                                    // pixel is just part of inner mask, and it's not an edge
760                         }
761                 }
762                 else if (lomask[x]) {                                           // inner mask was empty, test if outer mask is filled
763                         if (!lomask[x-rw] || !lomask[x+rw]) {   // test if outer mask is empty underneath or above
764                                 osz++;                                                          // increment outer edge size
765                                 lres[x]=3;                                                      // flag pixel as outer edge
766                         }
767                         else {
768                                 gsz++;                                                  // increment the gradient pixel count
769                                 lres[x]=2;                                              // flag pixel as gradient
770                         }
771                 }
772         }
773
774         rsize[0]=isz;  // fill in our return sizes for edges + fill
775         rsize[1]=osz;
776         rsize[2]=gsz;
777 }
778
779 static void do_allEdgeDetection(unsigned int t, unsigned int rw, unsigned int *limask, unsigned int *lomask, unsigned int *lres, float *res, unsigned int *rsize, unsigned int in_isz, unsigned int in_osz, unsigned int in_gsz)
780 {
781         int x;                                                          // x = pixel loop counter
782         int a;                                                          // a = pixel loop counter
783         int dx;                                                         // dx = delta x
784         int pix_prevRow;                                        // pix_prevRow = pixel one row behind the one we are testing in a loop
785         int pix_nextRow;                                        // pix_nextRow = pixel one row in front of the one we are testing in a loop
786         int pix_prevCol;                                        // pix_prevCol = pixel one column behind the one we are testing in a loop
787         int pix_nextCol;                                        // pix_nextCol = pixel one column in front of the one we are testing in a loop
788         /* Test all rows between the FIRST and LAST rows, excluding left and right edges */
789         for (x= (t-rw)+1, dx=x-(rw-2); dx>rw; x-=rw,dx-=rw) {
790                 a=x-2;
791                 pix_prevRow=a+rw;
792                 pix_nextRow=a-rw;
793                 pix_prevCol=a+1;
794                 pix_nextCol=a-1;
795                 while (a>dx-2) {
796                         if (!limask[a]) {                       // if the inner mask is empty
797                                 if (lomask[a]) {                // if the outer mask is full
798                                         /*
799                                          * Next we test all 4 directions around the current pixel: next/prev/up/down
800                                          * The test ensures that the outer mask is empty and that the inner mask
801                                          * is also empty. If both conditions are true for any one of the 4 adjacent pixels
802                                          * then the current pixel is counted as being a true outer edge pixel.
803                                          */
804                                         if ((!lomask[pix_nextCol] && !limask[pix_nextCol]) ||
805                                             (!lomask[pix_prevCol] && !limask[pix_prevCol]) ||
806                                             (!lomask[pix_nextRow] && !limask[pix_nextRow]) ||
807                                             (!lomask[pix_prevRow] && !limask[pix_prevRow]))
808                                         {
809                                                 in_osz++;               // increment the outer boundary pixel count
810                                                 lres[a]=3;              // flag pixel as part of outer edge
811                                         }
812                                         else {                          // it's not a boundary pixel, but it is a gradient pixel
813                                                 in_gsz++;               // increment the gradient pixel count
814                                                 lres[a]=2;              // flag pixel as gradient
815                                         }
816                                 }
817
818                         }
819                         else {
820                                 if (!limask[pix_nextCol] || !limask[pix_prevCol] || !limask[pix_nextRow] || !limask[pix_prevRow]) {
821                                         in_isz++;                       // increment the inner boundary pixel count
822                                         lres[a]=4;                      // flag pixel as part of inner edge
823                                 }
824                                 else {
825                                         res[a]=1.0f;            // pixel is part of inner mask, but not at an edge
826                                 }
827                         }
828                         a--;
829                         pix_prevRow--;
830                         pix_nextRow--;
831                         pix_prevCol--;
832                         pix_nextCol--;
833                 }
834         }
835
836         rsize[0]=in_isz;  // fill in our return sizes for edges + fill
837         rsize[1]=in_osz;
838         rsize[2]=in_gsz;
839 }
840
841 static void do_adjacentEdgeDetection(unsigned int t, unsigned int rw, unsigned int *limask, unsigned int *lomask, unsigned int *lres, float *res, unsigned int *rsize, unsigned int in_isz, unsigned int in_osz, unsigned int in_gsz)
842 {
843         int x;                                                  // x = pixel loop counter
844         int a;                                                  // a = pixel loop counter
845         int dx;                                                 // dx = delta x
846         int pix_prevRow;                                // pix_prevRow = pixel one row behind the one we are testing in a loop
847         int pix_nextRow;                                // pix_nextRow = pixel one row in front of the one we are testing in a loop
848         int pix_prevCol;                                // pix_prevCol = pixel one column behind the one we are testing in a loop
849         int pix_nextCol;                                // pix_nextCol = pixel one column in front of the one we are testing in a loop
850         /* Test all rows between the FIRST and LAST rows, excluding left and right edges */
851         for (x= (t-rw)+1, dx=x-(rw-2); dx>rw; x-=rw,dx-=rw) {
852                 a=x-2;
853                 pix_prevRow=a+rw;
854                 pix_nextRow=a-rw;
855                 pix_prevCol=a+1;
856                 pix_nextCol=a-1;
857                 while (a>dx-2) {
858                         if (!limask[a]) {                       // if the inner mask is empty
859                                 if (lomask[a]) {                // if the outer mask is full
860                                         /*
861                                          * Next we test all 4 directions around the current pixel: next/prev/up/down
862                                          * The test ensures that the outer mask is empty and that the inner mask
863                                          * is also empty. If both conditions are true for any one of the 4 adjacent pixels
864                                          * then the current pixel is counted as being a true outer edge pixel.
865                                          */
866                                         if ((!lomask[pix_nextCol] && !limask[pix_nextCol]) ||
867                                             (!lomask[pix_prevCol] && !limask[pix_prevCol]) ||
868                                             (!lomask[pix_nextRow] && !limask[pix_nextRow]) ||
869                                             (!lomask[pix_prevRow] && !limask[pix_prevRow]))
870                                         {
871                                                 in_osz++;               // increment the outer boundary pixel count
872                                                 lres[a]=3;              // flag pixel as part of outer edge
873                                         }
874                                         else {                          // it's not a boundary pixel, but it is a gradient pixel
875                                                 in_gsz++;               // increment the gradient pixel count
876                                                 lres[a]=2;              // flag pixel as gradient
877                                         }
878                                 }
879
880                         }
881                         else {
882                                 if ((!limask[pix_nextCol] && lomask[pix_nextCol]) ||
883                                     (!limask[pix_prevCol] && lomask[pix_prevCol]) ||
884                                     (!limask[pix_nextRow] && lomask[pix_nextRow]) ||
885                                     (!limask[pix_prevRow] && lomask[pix_prevRow]))
886                                 {
887                                         in_isz++;                       // increment the inner boundary pixel count
888                                         lres[a]=4;                      // flag pixel as part of inner edge
889                                 }
890                                 else {
891                                         res[a]=1.0f;            // pixel is part of inner mask, but not at an edge
892                                 }
893                         }
894                         a--;
895                         pix_prevRow--;                          // advance all four "surrounding" pixel pointers
896                         pix_nextRow--;
897                         pix_prevCol--;
898                         pix_nextCol--;
899                 }
900         }
901
902         rsize[0]=in_isz;  // fill in our return sizes for edges + fill
903         rsize[1]=in_osz;
904         rsize[2]=in_gsz;
905 }
906
907 static void do_createEdgeLocationBuffer(unsigned int t, unsigned int rw, unsigned int *lres, float *res, unsigned short *gbuf, unsigned int *innerEdgeOffset, unsigned int *outerEdgeOffset, unsigned int isz, unsigned int gsz)
908 {
909         int x;                                                  // x = pixel loop counter
910         int a;                                                  // a = temporary pixel index buffer loop counter
911         unsigned int ud;                                // ud = unscaled edge distance
912         unsigned int dmin;                              // dmin = minimun edge distance
913
914         unsigned int rsl;                               // long used for finding fast 1.0/sqrt
915         unsigned int gradientFillOffset;
916         unsigned int innerAccum=0;              // for looping inner edge pixel indexes, represents current position from offset
917         unsigned int outerAccum=0;              // for looping outer edge pixel indexes, represents current position from offset
918         unsigned int gradientAccum=0;   // for looping gradient pixel indexes, represents current position from offset
919         /*
920          * Here we compute the size of buffer needed to hold (row,col) coordinates
921          * for each pixel previously determined to be either gradient, inner edge,
922          * or outer edge.
923          *
924          * Allocation is done by requesting 4 bytes "sizeof(int)" per pixel, even
925          * though gbuf[] is declared as unsigned short* (2 bytes) because we don't
926          * store the pixel indexes, we only store x,y location of pixel in buffer.
927          *
928          * This does make the assumption that x and y can fit in 16 unsigned bits
929          * so if Blender starts doing renders greater than 65536 in either direction
930          * this will need to allocate gbuf[] as unsigned int* and allocate 8 bytes
931          * per flagged pixel.
932          *
933          * In general, the buffer on-screen:
934          *
935          * Example:  9 by 9 pixel block
936          *
937          * . = pixel non-white in both outer and inner mask
938          * o = pixel white in outer, but not inner mask, adjacent to "." pixel
939          * g = pixel white in outer, but not inner mask, not adjacent to "." pixel
940          * i = pixel white in inner mask, adjacent to "g" or "." pixel
941          * F = pixel white in inner mask, only adjacent to other pixels white in the inner mask
942          *
943          *
944          *                  .........   <----- pixel #80
945          *                  ..oooo...
946          *                  .oggggo..
947          *                  .oggiggo.
948          *                  .ogiFigo.
949          *                  .oggiggo.
950          *                  .oggggo..
951          *                  ..oooo...
952          * pixel #00 -----> .........
953          *
954          * gsz = 18   (18 "g" pixels above)
955          * isz = 4    (4 "i" pixels above)
956          * osz = 18   (18 "o" pixels above)
957          *
958          *
959          * The memory in gbuf[] after filling will look like this:
960          *
961          *  gradientFillOffset (0 pixels)                   innerEdgeOffset (18 pixels)    outerEdgeOffset (22 pixels)
962          * /                                               /                              /
963          * /                                               /                              /
964          * |X   Y   X   Y   X   Y   X   Y   >     <X   Y   X   Y   >     <X   Y   X   Y   X   Y   >     <X   Y   X   Y   | <- (x,y)
965          * +-------------------------------->     <---------------->     <------------------------>     <----------------+
966          * |0   2   4   6   8   10  12  14  > ... <68  70  72  74  > ... <80  82  84  86  88  90  > ... <152 154 156 158 | <- bytes
967          * +-------------------------------->     <---------------->     <------------------------>     <----------------+
968          * |g0  g0  g1  g1  g2  g2  g3  g3  >     <g17 g17 i0  i0  >     <i2  i2  i3  i3  o0  o0  >     <o16 o16 o17 o17 | <- pixel
969          *                                              /                              /                              /
970          *                                             /                              /                              /
971          *                                            /                              /                              /
972          *   +---------- gradientAccum (18) ---------+      +--- innerAccum (22) ---+      +--- outerAccum (40) ---+
973          *
974          *
975          * Ultimately we do need the pixel's memory buffer index to set the output
976          * pixel color, but it's faster to reconstruct the memory buffer location
977          * each iteration of the final gradient calculation than it is to deconstruct
978          * a memory location into x,y pairs each round.
979          */
980
981
982         gradientFillOffset=0;                                                           // since there are likely "more" of these, put it first. :)
983         *innerEdgeOffset=gradientFillOffset+gsz;                        // set start of inner edge indexes
984         *outerEdgeOffset=(*innerEdgeOffset)+isz;                        // set start of outer edge indexes
985         /* set the accumulators to correct positions */         // set up some accumulator variables for loops
986         gradientAccum = gradientFillOffset;                                     // each accumulator variable starts at its respective
987         innerAccum = *innerEdgeOffset;                                          // section's offset so when we start filling, each
988         outerAccum = *outerEdgeOffset;                                          // section fills up it's allocated space in gbuf
989         //uses dmin=row, rsl=col
990         for (x=0,dmin=0; x<t; x+=rw,dmin++) {
991                 for (rsl=0; rsl<rw; rsl++) {
992                         a=x+rsl;
993                         if (lres[a]==2) {                       // it is a gradient pixel flagged by 2
994                                 ud=gradientAccum<<1;    // double the index to reach correct unsigned short location
995                                 gbuf[ud]=dmin;                  // insert pixel's row into gradient pixel location buffer
996                                 gbuf[ud+1]=rsl;                 // insert pixel's column into gradient pixel location buffer
997                                 gradientAccum++;                // increment gradient index buffer pointer
998                         }
999                         else if (lres[a]==3) {          // it is an outer edge pixel flagged by 3
1000                                 ud=outerAccum<<1;               // double the index to reach correct unsigned short location
1001                                 gbuf[ud]=dmin;                  // insert pixel's row into outer edge pixel location buffer
1002                                 gbuf[ud+1]=rsl;                 // insert pixel's column into outer edge pixel location buffer
1003                                 outerAccum++;                   // increment outer edge index buffer pointer
1004                                 res[a]=0.0f;                    // set output pixel intensity now since it won't change later
1005                         }
1006                         else if (lres[a]==4) {          // it is an inner edge pixel flagged by 4
1007                                 ud=innerAccum<<1;               // double int index to reach correct unsigned short location
1008                                 gbuf[ud]=dmin;                  // insert pixel's row into inner edge pixel location buffer
1009                                 gbuf[ud+1]=rsl;                 // insert pixel's column into inner edge pixel location buffer
1010                                 innerAccum++;                   // increment inner edge index buffer pointer
1011                                 res[a]=1.0f;                    // set output pixel intensity now since it won't change later
1012                         }
1013                 }
1014         }
1015
1016 }
1017
1018 static void do_fillGradientBuffer(unsigned int rw, float *res, unsigned short *gbuf, unsigned int isz, unsigned int osz, unsigned int gsz, unsigned int innerEdgeOffset, unsigned int outerEdgeOffset)
1019 {
1020         int x;                                                  // x = pixel loop counter
1021         int a;                                                  // a = temporary pixel index buffer loop counter
1022         int fsz;                                                // size of the frame
1023         unsigned int rsl;                               // long used for finding fast 1.0/sqrt
1024         float rsf;                                              // float used for finding fast 1.0/sqrt
1025         const float rsopf = 1.5f;               // constant float used for finding fast 1.0/sqrt
1026
1027         unsigned int gradientFillOffset;
1028         unsigned int t;
1029         unsigned int ud;                                // ud = unscaled edge distance
1030         unsigned int dmin;                              // dmin = minimun edge distance
1031         float odist;                                    // odist = current outer edge distance
1032         float idist;                                    // idist = current inner edge distance
1033         int dx;                                                 // dx = X-delta (used for distance proportion calculation)
1034         int dy;                                                 // dy = Y-delta (used for distance proportion calculation)
1035         /*
1036          * The general algorithm used to color each gradient pixel is:
1037          *
1038          * 1.) Loop through all gradient pixels.
1039          *    A.) For each gradient pixel:
1040          *        a.) Loop though all outside edge pixels, looking for closest one
1041          *            to the gradient pixel we are in.
1042          *        b.) Loop through all inside edge pixels, looking for closest one
1043          *            to the gradient pixel we are in.
1044          *        c.) Find proportion of distance from gradient pixel to inside edge
1045          *            pixel compared to sum of distance to inside edge and distance to
1046          *            outside edge.
1047          *
1048          *            In an image where:
1049          *            . = blank (black) pixels, not covered by inner mask or outer mask
1050          *            + = desired gradient pixels, covered only by outer mask
1051          *            * = white full mask pixels, covered by at least inner mask
1052          *
1053          *            ...............................
1054          *            ...............+++++++++++.....
1055          *            ...+O++++++..++++++++++++++....
1056          *            ..+++\++++++++++++++++++++.....
1057          *            .+++++G+++++++++*******+++.....
1058          *            .+++++|+++++++*********+++.....
1059          *            .++***I****************+++.....
1060          *            .++*******************+++......
1061          *            .+++*****************+++.......
1062          *            ..+++***************+++........
1063          *            ....+++**********+++...........
1064          *            ......++++++++++++.............
1065          *            ...............................
1066          *
1067          *                O = outside edge pixel
1068          *                 \
1069          *                  G = gradient pixel
1070          *                  |
1071          *                  I = inside edge pixel
1072          *
1073          *                             __
1074          *                  *note that IO does not need to be a straight line, in fact
1075          *                   many cases can arise where straight lines do not work
1076          *                   correctly.
1077          *
1078          *                                        __       __     __
1079          *        d.) Pixel color is assigned as |GO| / ( |GI| + |GO| )
1080          *
1081          * The implementation does not compute distance, but the reciprocal of the
1082          * distance. This is done to avoid having to compute a square root, as a
1083          * reciprocal square root can be computed faster. Therefore, the code computes
1084          * pixel color as |GI| / (|GI| + |GO|). Since these are reciprocals, GI serves the
1085          * purpose of GO for the proportion calculation.
1086          *
1087          * For the purposes of the minimun distance comparisons, we only check
1088          * the sums-of-squares against each other, since they are in the same
1089          * mathematical sort-order as if we did go ahead and take square roots
1090          *
1091          * Loop through all gradient pixels.
1092          */
1093
1094         for (x= gsz-1; x>=0; x--) {
1095                 gradientFillOffset=x<<1;
1096                 t=gbuf[gradientFillOffset];             // calculate column of pixel indexed by gbuf[x]
1097                 fsz=gbuf[gradientFillOffset+1]; // calculate row of pixel indexed by gbuf[x]
1098                 dmin=0xffffffff;                                        // reset min distance to edge pixel
1099                 for (a=outerEdgeOffset+osz-1; a>=outerEdgeOffset; a--) {        // loop through all outer edge buffer pixels
1100                         ud=a<<1;
1101                         dy=t-gbuf[ud];                                  // set dx to gradient pixel column - outer edge pixel row
1102                         dx=fsz-gbuf[ud+1];                              // set dy to gradient pixel row - outer edge pixel column
1103                         ud=dx*dx+dy*dy;                                 // compute sum of squares
1104                         if (ud<dmin) {                                  // if our new sum of squares is less than the current minimum
1105                                 dmin=ud;                                        // set a new minimum equal to the new lower value
1106                         }
1107                 }
1108                 odist=(float)(dmin);                                    // cast outer min to a float
1109                 rsf=odist*0.5f;                                                 //
1110                 rsl=*(unsigned int*)&odist;                             // use some peculiar properties of the way bits are stored
1111                 rsl=0x5f3759df-(rsl>>1);                                // in floats vs. unsigned ints to compute an approximate
1112                 odist=*(float*)&rsl;                                    // reciprocal square root
1113                 odist=odist*(rsopf-(rsf*odist*odist));  // -- ** this line can be iterated for more accuracy ** --
1114                 dmin=0xffffffff;                                                // reset min distance to edge pixel
1115                 for (a= innerEdgeOffset+isz-1; a>=innerEdgeOffset; a--) {       // loop through all inside edge pixels
1116                         ud=a<<1;
1117                         dy=t-gbuf[ud];                  // compute delta in Y from gradient pixel to inside edge pixel
1118                         dx=fsz-gbuf[ud+1];              // compute delta in X from gradient pixel to inside edge pixel
1119                         ud=dx*dx+dy*dy;                 // compute sum of squares
1120                         if (ud<dmin) {                  // if our new sum of squares is less than the current minimum we've found
1121                                 dmin=ud;                        // set a new minimum equal to the new lower value
1122                         }
1123                 }
1124                 idist=(float)(dmin);                                    // cast inner min to a float
1125                 rsf=idist*0.5f;                                                 //
1126                 rsl=*(unsigned int*)&idist;                             //
1127                 rsl=0x5f3759df-(rsl>>1);                                // see notes above
1128                 idist=*(float*)&rsl;                                    //
1129                 idist=idist*(rsopf-(rsf*idist*idist));  //
1130                 /*
1131                  * Note once again that since we are using reciprocals of distance values our
1132                  * proportion is already the correct intensity, and does not need to be
1133                  * subracted from 1.0 like it would have if we used real distances.
1134                  */
1135
1136                 /*
1137                  * Here we reconstruct the pixel's memory location in the CompBuf by
1138                  * Pixel Index = Pixel Column + ( Pixel Row * Row Width )
1139                  */
1140                 res[gbuf[gradientFillOffset+1]+(gbuf[gradientFillOffset]*rw)]=(idist/(idist+odist));    //set intensity
1141         }
1142
1143 }
1144
1145
1146 static void node_composit_exec_doubleedgemask(void *UNUSED(data), bNode *node, bNodeStack **in, bNodeStack **out)
1147 {
1148
1149         float *imask;                                   // imask = pointer to inner mask pixel buffer
1150         float *omask;                                   // omask = pointer to outer mask pixel buffer
1151         float *res;                                             // res = pointer to output mask
1152
1153         unsigned int *lres;                             // lres = unsigned int pointer to output pixel buffer (for bit operations)
1154         unsigned int *limask;                   // limask = unsigned int pointer to inner mask (for bit operations)
1155         unsigned int *lomask;                   // lomask = unsigned int pointer to outer mask (for bit operations)
1156
1157         int rw;                                                 // rw = pixel row width
1158         int t;                                                  // t = total number of pixels in buffer - 1 (used for loop starts)
1159         int fsz;                                                // size of the frame
1160
1161         unsigned int isz=0;                             // size (in pixels) of inside edge pixel index buffer
1162         unsigned int osz=0;                             // size (in pixels) of outside edge pixel index buffer
1163         unsigned int gsz=0;                             // size (in pixels) of gradient pixel index buffer
1164         unsigned int rsize[3];                  // size storage to pass to helper functions
1165         unsigned int innerEdgeOffset=0; // offset into final buffer where inner edge pixel indexes start
1166         unsigned int outerEdgeOffset=0; // offset into final buffer where outer edge pixel indexes start
1167
1168         unsigned short *gbuf;                   // gradient/inner/outer pixel location index buffer
1169
1170         CompBuf *cbuf;                                  // pointer, will be set to inner mask data
1171         CompBuf *dbuf;                                  // pointer, will be set to outer mask data
1172         CompBuf *stackbuf;                              // pointer, will get allocated as output buffer
1173
1174         if (out[0]->hasoutput==0) {             // if the node's output socket is not connected to anything...
1175                 return;                                         //     do not execute any further, just exit the node immediately
1176         }
1177
1178         if (in[0]->data && in[1]->data) {                                       // if both input sockets have some data coming in...
1179                 cbuf= in[0]->data;                                                              //     get a pointer to the inner mask data
1180                 dbuf= in[1]->data;                                                              //     get a pointer to the outer mask data
1181                 if (cbuf->type!=CB_VAL || dbuf->type!=CB_VAL) { // if either input socket has an incorrect data type coming in
1182                         return;                                                                         //     exit the node immediately
1183                 }
1184
1185                 t=(cbuf->x*cbuf->y)-1;                                                                  // determine size of the frame
1186
1187                 stackbuf= alloc_compbuf(cbuf->x, cbuf->y, CB_VAL, 1);   // allocate the output buffer
1188
1189                 imask= cbuf->rect;                              // set the inner mask
1190                 omask= dbuf->rect;                              // set the outer mask
1191                 res= stackbuf->rect;                    // set output pointer
1192                 lres= (unsigned int*)res;               // unsigned int pointer to output buffer (for bit level ops)
1193                 limask=(unsigned int*)imask;    // unsigned int pointer to input mask (for bit level ops)
1194                 lomask=(unsigned int*)omask;    // unsigned int pointer to output mask (for bit level ops)
1195                 rw= cbuf->x;                                    // width of a row of pixels
1196
1197
1198                 /*
1199                  * The whole buffer is broken up into 4 parts. The four CORNERS, the FIRST and LAST rows, the
1200                  * LEFT and RIGHT edges (excluding the corner pixels), and all OTHER rows.
1201                  * This allows for quick computation of outer edge pixels where
1202                  * a screen edge pixel is marked to be gradient.
1203                  *
1204                  * The pixel type (gradient vs inner-edge vs outer-edge) tests change
1205                  * depending on the user selected "Inner Edge Mode" and the user selected
1206                  * "Buffer Edge Mode" on the node's GUI. There are 4 sets of basically the
1207                  * same algorithm:
1208                  *
1209                  * 1.) Inner Edge -> Adjacent Only
1210                  *     Buffer Edge -> Keep Inside
1211                  *
1212                  * 2.) Inner Edge -> Adjacent Only
1213                  *     Buffer Edge -> Bleed Out
1214                  *
1215                  * 3.) Inner Edge -> All
1216                  *     Buffer Edge -> Keep Inside
1217                  *
1218                  * 4.) Inner Edge -> All
1219                  *     Buffer Edge -> Bleed Out
1220                  *
1221                  * Each version has slightly different criteria for detecting an edge pixel.
1222                  */
1223                 if (node->custom2) {            // if "adjacent only" inner edge mode is turned on
1224                         if (node->custom1) {    // if "keep inside" buffer edge mode is turned on
1225                                 do_adjacentKeepBorders(t,rw,limask,lomask,lres,res,rsize);
1226                         }
1227                         else {                                  // "bleed out" buffer edge mode is turned on
1228                                 do_adjacentBleedBorders(t,rw,limask,lomask,lres,res,rsize);
1229                         }
1230                         isz=rsize[0];                   // set up inner edge, outer edge, and gradient buffer sizes after border pass
1231                         osz=rsize[1];
1232                         gsz=rsize[2];
1233                         // detect edges in all non-border pixels in the buffer
1234                         do_adjacentEdgeDetection(t,rw,limask,lomask,lres,res,rsize,isz,osz,gsz);
1235                 }
1236                 else {                                          // "all" inner edge mode is turned on
1237                         if (node->custom1) {    // if "keep inside" buffer edge mode is turned on
1238                                 do_allKeepBorders(t,rw,limask,lomask,lres,res,rsize);
1239                         }
1240                         else {                                  // "bleed out" buffer edge mode is turned on
1241                                 do_allBleedBorders(t,rw,limask,lomask,lres,res,rsize);
1242                         }
1243                         isz=rsize[0];                   // set up inner edge, outer edge, and gradient buffer sizes after border pass
1244                         osz=rsize[1];
1245                         gsz=rsize[2];
1246                         // detect edges in all non-border pixels in the buffer
1247                         do_allEdgeDetection(t,rw,limask,lomask,lres,res,rsize,isz,osz,gsz);
1248                 }
1249
1250                 isz=rsize[0];                           // set edge and gradient buffer sizes once again...
1251                 osz=rsize[1];                           // the sizes in rsize[] may have been modified
1252                 gsz=rsize[2];                           // by the do_*EdgeDetection() function.
1253
1254                 // quick check for existance of edges in the buffer...
1255                 // if we don't have any one of the three sizes, the other two make no difference visually,
1256                 // so we can just pass the inner input buffer back as output.
1257                 if (!gsz || !isz || !osz) {
1258                         out[0]->data= stackbuf; // point the node output buffer to our filled buffer
1259                         return;
1260                 }
1261
1262
1263                 fsz=gsz+isz+osz;                                                                        // calculate size of pixel index buffer needed
1264                 gbuf= MEM_mallocN(fsz*sizeof(int), "grd buf");          // allocate edge/gradient pixel index buffer
1265
1266                 do_createEdgeLocationBuffer(t,rw,lres,res,gbuf,&innerEdgeOffset,&outerEdgeOffset,isz,gsz);
1267                 do_fillGradientBuffer(rw,res,gbuf,isz,osz,gsz,innerEdgeOffset,outerEdgeOffset);
1268
1269                 MEM_freeN(gbuf);                // free the gradient index buffer
1270                 out[0]->data= stackbuf; // point the node output buffer to our filled buffer
1271         }
1272 }
1273
1274 void register_node_type_cmp_doubleedgemask(bNodeTreeType *ttype)
1275 {
1276         static bNodeType ntype; // allocate a node type data structure
1277
1278         node_type_base(ttype, &ntype, CMP_NODE_DOUBLEEDGEMASK, "Double Edge Mask", NODE_CLASS_MATTE, NODE_OPTIONS);
1279         node_type_socket_templates(&ntype, cmp_node_doubleedgemask_in, cmp_node_doubleedgemask_out);
1280         node_type_size(&ntype, 210, 210, 210);
1281         node_type_exec(&ntype, node_composit_exec_doubleedgemask);
1282
1283         nodeRegisterType(ttype, &ntype);
1284 }