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