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