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