~siretart/ubuntu/utopic/blender/libav10

« back to all changes in this revision

Viewing changes to source/blender/nodes/composite/nodes/node_composite_doubleEdgeMask.c

  • Committer: Package Import Robot
  • Author(s): Matteo F. Vescovi
  • Date: 2012-07-23 08:54:18 UTC
  • mfrom: (14.2.16 sid)
  • mto: (14.2.19 sid)
  • mto: This revision was merged to the branch mainline in revision 42.
  • Revision ID: package-import@ubuntu.com-20120723085418-9foz30v6afaf5ffs
Tags: 2.63a-2
* debian/: Cycles support added (Closes: #658075)
  For now, this top feature has been enabled only
  on [any-amd64 any-i386] architectures because
  of OpenImageIO failing on all others
* debian/: scripts installation path changed
  from /usr/lib to /usr/share:
  + debian/patches/: patchset re-worked for path changing
  + debian/control: "Breaks" field added on yafaray-exporter

Show diffs side-by-side

added added

removed removed

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