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