2
* ***** BEGIN GPL LICENSE BLOCK *****
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.
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.
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.
18
* The Original Code is Copyright (C) 2011 Blender Foundation.
19
* All rights reserved.
21
* The Original Code is: all of this file.
23
* Contributor(s): Peter Larabell.
25
* ***** END GPL LICENSE BLOCK *****
28
/** \file blender/nodes/composite/nodes/node_composite_doubleEdgeMask.c
31
#include "node_composite_util.h"
32
/* **************** Double Edge Mask ******************** */
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
40
static bNodeSocketTemplate cmp_node_doubleedgemask_out[]= {
41
{ SOCK_FLOAT, 0, "Mask"}, // output socket definition
42
{ -1, 0, "" } // output socket array terminator
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)
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 */
54
// test if inner mask is filled
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
63
res[x]=1.0f; // pixel is just part of inner mask, and it's not an edge
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
70
/* upper right corner */
72
// test if inner mask is filled
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
81
res[x]=1.0f; // pixel is just part of inner mask, and it's not an edge
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
88
/* lower left corner */
90
// test if inner mask is filled
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
99
res[x]=1.0f; // pixel is just part of inner mask, and it's not an edge
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
106
/* lower right corner */
108
// test if inner mask is filled
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
117
res[x]=1.0f; // pixel is just part of inner mask, and it's not an edge
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
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
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
136
res[x]=1.0f; // pixel is just part of inner mask, and it's not an edge
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
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
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
156
res[x]=1.0f; // pixel is just part of inner mask, and it's not an edge
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
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
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
175
res[x]=1.0f; // pixel is just part of inner mask, and it's not an edge
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
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
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
195
res[x]=1.0f; // pixel is just part of inner mask, and it's not an edge
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
204
rsize[0]=isz; // fill in our return sizes for edges + fill
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)
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 */
218
// test if inner mask is filled
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
227
res[x]=1.0f; // pixel is just part of inner mask, and it's not an edge
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
236
gsz++; // increment the gradient pixel count
237
lres[x]=2; // flag pixel as gradient
240
/* upper right corner */
242
// test if inner mask is filled
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
251
res[x]=1.0f; // pixel is just part of inner mask, and it's not an edge
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
260
gsz++; // increment the gradient pixel count
261
lres[x]=2; // flag pixel as gradient
264
/* lower left corner */
266
// test if inner mask is filled
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
275
res[x]=1.0f; // pixel is just part of inner mask, and it's not an edge
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
284
gsz++; // increment the gradient pixel count
285
lres[x]=2; // flag pixel as gradient
288
/* lower right corner */
290
// test if inner mask is filled
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
299
res[x]=1.0f; // pixel is just part of inner mask, and it's not an edge
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
308
gsz++; // increment the gradient pixel count
309
lres[x]=2; // flag pixel as gradient
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
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
323
res[x]=1.0f; // pixel is just part of inner mask, and it's not an edge
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
332
gsz++; // increment the gradient pixel count
333
lres[x]=2; // flag pixel as gradient
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
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
349
res[x]=1.0f; // pixel is just part of inner mask, and it's not an edge
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
358
gsz++; // increment the gradient pixel count
359
lres[x]=2; // flag pixel as gradient
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
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
374
res[x]=1.0f; // pixel is just part of inner mask, and it's not an edge
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
383
gsz++; // increment the gradient pixel count
384
lres[x]=2; // flag pixel as gradient
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
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
400
res[x]=1.0f; // pixel is just part of inner mask, and it's not an edge
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
409
gsz++; // increment the gradient pixel count
410
lres[x]=2; // flag pixel as gradient
415
rsize[0]=isz; // fill in our return sizes for edges + fill
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)
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 */
429
// test if inner mask is filled
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
437
res[x]=1.0f; // pixel is just part of inner mask, and it's not an edge
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
444
/* upper right corner */
446
// test if inner mask is filled
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
454
res[x]=1.0f; // pixel is just part of inner mask, and it's not an edge
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
461
/* lower left corner */
463
// test if inner mask is filled
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
471
res[x]=1.0f; // pixel is just part of inner mask, and it's not an edge
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
478
/* lower right corner */
480
// test if inner mask is filled
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
488
res[x]=1.0f; // pixel is just part of inner mask, and it's not an edge
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
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
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
506
res[x]=1.0f; // pixel is just part of inner mask, and it's not an edge
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
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
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
525
res[x]=1.0f; // pixel is just part of inner mask, and it's not an edge
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
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
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
543
res[x]=1.0f; // pixel is just part of inner mask, and it's not an edge
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
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
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
562
res[x]=1.0f; // pixel is just part of inner mask, and it's not an edge
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
571
rsize[0]=isz; // fill in our return sizes for edges + fill
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)
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 */
585
// test if inner mask is filled
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
593
res[x]=1.0f; // pixel is just part of inner mask, and it's not an edge
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
602
gsz++; // increment the gradient pixel count
603
lres[x]=2; // flag pixel as gradient
606
/* upper right corner */
608
// test if inner mask is filled
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
616
res[x]=1.0f; // pixel is just part of inner mask, and it's not an edge
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
625
gsz++; // increment the gradient pixel count
626
lres[x]=2; // flag pixel as gradient
629
/* lower left corner */
631
// test if inner mask is filled
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
639
res[x]=1.0f; // pixel is just part of inner mask, and it's not an edge
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
648
gsz++; // increment the gradient pixel count
649
lres[x]=2; // flag pixel as gradient
652
/* lower right corner */
654
// test if inner mask is filled
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
662
res[x]=1.0f; // pixel is just part of inner mask, and it's not an edge
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
671
gsz++; // increment the gradient pixel count
672
lres[x]=2; // flag pixel as gradient
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
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
685
res[x]=1.0f; // pixel is just part of inner mask, and it's not an edge
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
694
gsz++; // increment the gradient pixel count
695
lres[x]=2; // flag pixel as gradient
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
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
710
res[x]=1.0f; // pixel is just part of inner mask, and it's not an edge
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
719
gsz++; // increment the gradient pixel count
720
lres[x]=2; // flag pixel as gradient
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
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
734
res[x]=1.0f; // pixel is just part of inner mask, and it's not an edge
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
743
gsz++; // increment the gradient pixel count
744
lres[x]=2; // flag pixel as gradient
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
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
759
res[x]=1.0f; // pixel is just part of inner mask, and it's not an edge
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
768
gsz++; // increment the gradient pixel count
769
lres[x]=2; // flag pixel as gradient
774
rsize[0]=isz; // fill in our return sizes for edges + fill
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)
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) {
796
if (!limask[a]) { // if the inner mask is empty
797
if (lomask[a]) { // if the outer mask is full
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.
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]))
809
in_osz++; // increment the outer boundary pixel count
810
lres[a]=3; // flag pixel as part of outer edge
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
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
825
res[a]=1.0f; // pixel is part of inner mask, but not at an edge
836
rsize[0]=in_isz; // fill in our return sizes for edges + fill
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)
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) {
858
if (!limask[a]) { // if the inner mask is empty
859
if (lomask[a]) { // if the outer mask is full
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.
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]))
871
in_osz++; // increment the outer boundary pixel count
872
lres[a]=3; // flag pixel as part of outer edge
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
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]))
887
in_isz++; // increment the inner boundary pixel count
888
lres[a]=4; // flag pixel as part of inner edge
891
res[a]=1.0f; // pixel is part of inner mask, but not at an edge
895
pix_prevRow--; // advance all four "surrounding" pixel pointers
902
rsize[0]=in_isz; // fill in our return sizes for edges + fill
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)
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
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
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,
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.
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
933
* In general, the buffer on-screen:
935
* Example: 9 by 9 pixel block
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
944
* ......... <----- pixel #80
952
* pixel #00 -----> .........
954
* gsz = 18 (18 "g" pixels above)
955
* isz = 4 (4 "i" pixels above)
956
* osz = 18 (18 "o" pixels above)
959
* The memory in gbuf[] after filling will look like this:
961
* gradientFillOffset (0 pixels) innerEdgeOffset (18 pixels) outerEdgeOffset (22 pixels)
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
972
* +---------- gradientAccum (18) ---------+ +--- innerAccum (22) ---+ +--- outerAccum (40) ---+
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.
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++) {
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
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
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
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)
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
1027
unsigned int gradientFillOffset;
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)
1036
* The general algorithm used to color each gradient pixel is:
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
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
1053
* ...............................
1054
* ...............+++++++++++.....
1055
* ...+O++++++..++++++++++++++....
1056
* ..+++\++++++++++++++++++++.....
1057
* .+++++G+++++++++*******+++.....
1058
* .+++++|+++++++*********+++.....
1059
* .++***I****************+++.....
1060
* .++*******************+++......
1061
* .+++*****************+++.......
1062
* ..+++***************+++........
1063
* ....+++**********+++...........
1064
* ......++++++++++++.............
1065
* ...............................
1067
* O = outside edge pixel
1069
* G = gradient pixel
1071
* I = inside edge pixel
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
1079
* d.) Pixel color is assigned as |GO| / ( |GI| + |GO| )
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.
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
1091
* Loop through all gradient pixels.
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
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
1108
odist=(float)(dmin); // cast outer min to a float
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
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
1124
idist=(float)(dmin); // cast inner min to a float
1126
rsl=*(unsigned int*)&idist; //
1127
rsl=0x5f3759df-(rsl>>1); // see notes above
1128
idist=*(float*)&rsl; //
1129
idist=idist*(rsopf-(rsf*idist*idist)); //
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.
1137
* Here we reconstruct the pixel's memory location in the CompBuf by
1138
* Pixel Index = Pixel Column + ( Pixel Row * Row Width )
1140
res[gbuf[gradientFillOffset+1]+(gbuf[gradientFillOffset]*rw)]=(idist/(idist+odist)); //set intensity
1146
static void node_composit_exec_doubleedgemask(void *UNUSED(data), bNode *node, bNodeStack **in, bNodeStack **out)
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
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)
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
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
1168
unsigned short *gbuf; // gradient/inner/outer pixel location index buffer
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
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
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
1185
t=(cbuf->x*cbuf->y)-1; // determine size of the frame
1187
stackbuf= alloc_compbuf(cbuf->x, cbuf->y, CB_VAL, 1); // allocate the output buffer
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
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.
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
1209
* 1.) Inner Edge -> Adjacent Only
1210
* Buffer Edge -> Keep Inside
1212
* 2.) Inner Edge -> Adjacent Only
1213
* Buffer Edge -> Bleed Out
1215
* 3.) Inner Edge -> All
1216
* Buffer Edge -> Keep Inside
1218
* 4.) Inner Edge -> All
1219
* Buffer Edge -> Bleed Out
1221
* Each version has slightly different criteria for detecting an edge pixel.
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);
1227
else { // "bleed out" buffer edge mode is turned on
1228
do_adjacentBleedBorders(t,rw,limask,lomask,lres,res,rsize);
1230
isz=rsize[0]; // set up inner edge, outer edge, and gradient buffer sizes after border pass
1233
// detect edges in all non-border pixels in the buffer
1234
do_adjacentEdgeDetection(t,rw,limask,lomask,lres,res,rsize,isz,osz,gsz);
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);
1240
else { // "bleed out" buffer edge mode is turned on
1241
do_allBleedBorders(t,rw,limask,lomask,lres,res,rsize);
1243
isz=rsize[0]; // set up inner edge, outer edge, and gradient buffer sizes after border pass
1246
// detect edges in all non-border pixels in the buffer
1247
do_allEdgeDetection(t,rw,limask,lomask,lres,res,rsize,isz,osz,gsz);
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.
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
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
1266
do_createEdgeLocationBuffer(t,rw,lres,res,gbuf,&innerEdgeOffset,&outerEdgeOffset,isz,gsz);
1267
do_fillGradientBuffer(rw,res,gbuf,isz,osz,gsz,innerEdgeOffset,outerEdgeOffset);
1269
MEM_freeN(gbuf); // free the gradient index buffer
1270
out[0]->data= stackbuf; // point the node output buffer to our filled buffer
1274
void register_node_type_cmp_doubleedgemask(bNodeTreeType *ttype)
1276
static bNodeType ntype; // allocate a node type data structure
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);
1283
nodeRegisterType(ttype, &ntype);