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