Blender V2.61 - r43446

node_composite_doubleEdgeMask.c

Go to the documentation of this file.
00001 /*
00002  * ***** BEGIN GPL LICENSE BLOCK *****
00003  *
00004  * This program is free software; you can redistribute it and/or
00005  * modify it under the terms of the GNU General Public License
00006  * as published by the Free Software Foundation; either version 2
00007  * of the License, or (at your option) any later version.
00008  *
00009  * This program is distributed in the hope that it will be useful,
00010  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012  * GNU General Public License for more details.
00013  *
00014  * You should have received a copy of the GNU General Public License
00015  * along with this program; if not, write to the Free Software Foundation,
00016  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00017  *
00018  * The Original Code is Copyright (C) 2011 Blender Foundation.
00019  * All rights reserved.
00020  *
00021  * The Original Code is: all of this file.
00022  *
00023  * Contributor(s): Peter Larabell.
00024  *
00025  * ***** END GPL LICENSE BLOCK *****
00026  */
00027 
00031 #include "node_composite_util.h"
00032 /* **************** Double Edge Mask ******************** */
00033 
00034 
00035 static bNodeSocketTemplate cmp_node_doubleedgemask_in[]= {
00036     { SOCK_FLOAT, 1, "Inner Mask", 0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f, PROP_NONE},  // inner mask socket definition
00037     { SOCK_FLOAT, 1, "Outer Mask", 0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f, PROP_NONE},  // outer mask socket definition
00038     { -1, 0, "" }                                                                   // input socket array terminator
00039 };
00040 static bNodeSocketTemplate cmp_node_doubleedgemask_out[]= {
00041     { SOCK_FLOAT, 0, "Mask"},          // output socket definition
00042     { -1, 0, "" }                      // output socket array terminator
00043 };
00044 
00045 static void do_adjacentKeepBorders(unsigned int t, unsigned int rw, unsigned int *limask, unsigned int *lomask, unsigned int *lres, float *res, unsigned int *rsize){
00046     int x;
00047     unsigned int isz=0; // inner edge size
00048     unsigned int osz=0; // outer edge size
00049     unsigned int gsz=0; // gradient fill area size
00050     /* Test the four corners */
00051     /* upper left corner */
00052     x=t-rw+1;
00053     // test if inner mask is filled
00054     if(limask[x]){
00055         // test if pixel underneath, or to the right, are empty in the inner mask,
00056         // but filled in the outer mask
00057         if((!limask[x-rw] && lomask[x-rw]) || (!limask[x+1] && lomask[x+1])){
00058             isz++;                               // increment inner edge size
00059             lres[x]=4;                           // flag pixel as inner edge
00060         } else {
00061             res[x]=1.0f;                         // pixel is just part of inner mask, and it's not an edge
00062         }
00063     } else if(lomask[x]){                        // inner mask was empty, test if outer mask is filled
00064         osz++;                                   // increment outer edge size
00065         lres[x]=3;                               // flag pixel as outer edge
00066     }
00067     /* upper right corner */
00068     x=t;
00069     // test if inner mask is filled
00070     if(limask[x]){
00071         // test if pixel underneath, or to the left, are empty in the inner mask,
00072         // but filled in the outer mask
00073         if((!limask[x-rw] && lomask[x-rw]) || (!limask[x-1] && lomask[x-1])){
00074             isz++;                               // increment inner edge size
00075             lres[x]=4;                           // flag pixel as inner edge
00076         } else {
00077             res[x]=1.0f;                         // pixel is just part of inner mask, and it's not an edge
00078         }
00079     } else if(lomask[x]){                        // inner mask was empty, test if outer mask is filled
00080         osz++;                                   // increment outer edge size
00081         lres[x]=3;                               // flag pixel as outer edge
00082     }
00083     /* lower left corner */
00084     x=0;
00085     // test if inner mask is filled
00086     if(limask[x]){
00087         // test if pixel above, or to the right, are empty in the inner mask,
00088         // but filled in the outer mask
00089         if((!limask[x+rw] && lomask[x+rw]) || (!limask[x+1] && lomask[x+1])){
00090             isz++;                               // increment inner edge size
00091             lres[x]=4;                           // flag pixel as inner edge
00092         } else {
00093             res[x]=1.0f;                         // pixel is just part of inner mask, and it's not an edge
00094         }
00095     } else if(lomask[x]){                        // inner mask was empty, test if outer mask is filled
00096         osz++;                                   // increment outer edge size
00097         lres[x]=3;                               // flag pixel as outer edge
00098     }
00099     /* lower right corner */
00100     x=rw-1;
00101     // test if inner mask is filled
00102     if(limask[x]){
00103         // test if pixel above, or to the left, are empty in the inner mask,
00104         // but filled in the outer mask
00105         if((!limask[x+rw] && lomask[x+rw]) || (!limask[x-1] && lomask[x-1])){
00106             isz++;                               // increment inner edge size
00107             lres[x]=4;                           // flag pixel as inner edge
00108         } else {
00109             res[x]=1.0f;                         // pixel is just part of inner mask, and it's not an edge
00110         }
00111     } else if(lomask[x]){                        // inner mask was empty, test if outer mask is filled
00112         osz++;                                   // increment outer edge size
00113         lres[x]=3;                               // flag pixel as outer edge
00114     }
00115 
00116     /* Test the TOP row of pixels in buffer, except corners */
00117     for(x= t-1; x>=(t-rw)+2; x--) {
00118         // test if inner mask is filled
00119         if(limask[x]) {
00120             // test if pixel to the right, or to the left, are empty in the inner mask,
00121             // but filled in the outer mask
00122             if((!limask[x-1] && lomask[x-1]) || (!limask[x+1] && lomask[x+1])) {
00123                 isz++;                           // increment inner edge size
00124                 lres[x]=4;                       // flag pixel as inner edge
00125             } else {
00126                 res[x]=1.0f;                     // pixel is just part of inner mask, and it's not an edge
00127             }
00128         } else if(lomask[x]) {                   // inner mask was empty, test if outer mask is filled
00129             osz++;                               // increment outer edge size
00130             lres[x]=3;                           // flag pixel as outer edge
00131         }
00132     }
00133 
00134     /* Test the BOTTOM row of pixels in buffer, except corners */
00135     for(x= rw-2; x; x--) {
00136         // test if inner mask is filled
00137         if(limask[x]) {
00138             // test if pixel to the right, or to the left, are empty in the inner mask,
00139             // but filled in the outer mask
00140             if((!limask[x-1] && lomask[x-1]) || (!limask[x+1] && lomask[x+1])) {
00141                 isz++;                           // increment inner edge size
00142                 lres[x]=4;                       // flag pixel as inner edge
00143             } else {
00144                 res[x]=1.0f;                     // pixel is just part of inner mask, and it's not an edge
00145             }
00146         } else if(lomask[x]) {                   // inner mask was empty, test if outer mask is filled
00147             osz++;                               // increment outer edge size
00148             lres[x]=3;                           // flag pixel as outer edge
00149         }
00150     }
00151     /* Test the LEFT edge of pixels in buffer, except corners */
00152     for(x= t-(rw<<1)+1; x>=rw; x-=rw) {
00153         // test if inner mask is filled
00154         if(limask[x]) {
00155             // test if pixel underneath, or above, are empty in the inner mask,
00156             // but filled in the outer mask
00157             if((!limask[x-rw] && lomask[x-rw]) || (!limask[x+rw] && lomask[x+rw])) {
00158                 isz++;                           // increment inner edge size
00159                 lres[x]=4;                       // flag pixel as inner edge
00160             } else {
00161                 res[x]=1.0f;                     // pixel is just part of inner mask, and it's not an edge
00162             }
00163         } else if(lomask[x]) {                   // inner mask was empty, test if outer mask is filled
00164             osz++;                               // increment outer edge size
00165             lres[x]=3;                           // flag pixel as outer edge
00166         }
00167     }
00168 
00169     /* Test the RIGHT edge of pixels in buffer, except corners */
00170     for(x= t-rw; x>rw; x-=rw) {
00171         // test if inner mask is filled
00172         if(limask[x]) {
00173             // test if pixel underneath, or above, are empty in the inner mask,
00174             // but filled in the outer mask
00175             if((!limask[x-rw] && lomask[x-rw]) || (!limask[x+rw] && lomask[x+rw])) {
00176                 isz++;                           // increment inner edge size
00177                 lres[x]=4;                       // flag pixel as inner edge
00178             } else {
00179                 res[x]=1.0f;                     // pixel is just part of inner mask, and it's not an edge
00180             }
00181         } else if(lomask[x]) {                   // inner mask was empty, test if outer mask is filled
00182             osz++;                               // increment outer edge size
00183             lres[x]=3;                           // flag pixel as outer edge
00184         }
00185     }
00186 
00187     rsize[0]=isz;  // fill in our return sizes for edges + fill
00188     rsize[1]=osz;
00189     rsize[2]=gsz;
00190 }
00191 
00192 static void do_adjacentBleedBorders(unsigned int t, unsigned int rw, unsigned int *limask, unsigned int *lomask, unsigned int *lres, float *res, unsigned int *rsize){
00193     int x;
00194     unsigned int isz=0; // inner edge size
00195     unsigned int osz=0; // outer edge size
00196     unsigned int gsz=0; // gradient fill area size
00197     /* Test the four corners */
00198     /* upper left corner */
00199     x=t-rw+1;
00200     // test if inner mask is filled
00201     if(limask[x]){
00202         // test if pixel underneath, or to the right, are empty in the inner mask,
00203         // but filled in the outer mask
00204         if((!limask[x-rw] && lomask[x-rw]) || (!limask[x+1] && lomask[x+1])){
00205             isz++;                               // increment inner edge size
00206             lres[x]=4;                           // flag pixel as inner edge
00207         } else {
00208             res[x]=1.0f;                         // pixel is just part of inner mask, and it's not an edge
00209         }
00210     } else if(lomask[x]){                        // inner mask was empty, test if outer mask is filled
00211         if(!lomask[x-rw] || !lomask[x+1]) {      // test if outer mask is empty underneath or to the right
00212             osz++;                               // increment outer edge size
00213             lres[x]=3;                           // flag pixel as outer edge
00214         } else {
00215             gsz++;                               // increment the gradient pixel count
00216             lres[x]=2;                           // flag pixel as gradient
00217         }
00218     }
00219     /* upper right corner */
00220     x=t;
00221     // test if inner mask is filled
00222     if(limask[x]){
00223         // test if pixel underneath, or to the left, are empty in the inner mask,
00224         // but filled in the outer mask
00225         if((!limask[x-rw] && lomask[x-rw]) || (!limask[x-1] && lomask[x-1])){
00226             isz++;                               // increment inner edge size
00227             lres[x]=4;                           // flag pixel as inner edge
00228         } else {
00229             res[x]=1.0f;                         // pixel is just part of inner mask, and it's not an edge
00230         }
00231     } else if(lomask[x]){                        // inner mask was empty, test if outer mask is filled
00232         if(!lomask[x-rw] || !lomask[x-1]) {      // test if outer mask is empty underneath or to the left
00233             osz++;                               // increment outer edge size
00234             lres[x]=3;                           // flag pixel as outer edge
00235         } else {
00236             gsz++;                               // increment the gradient pixel count
00237             lres[x]=2;                           // flag pixel as gradient
00238         }
00239     }
00240     /* lower left corner */
00241     x=0;
00242     // test if inner mask is filled
00243     if(limask[x]){
00244         // test if pixel above, or to the right, are empty in the inner mask,
00245         // but filled in the outer mask
00246         if((!limask[x+rw] && lomask[x+rw]) || (!limask[x+1] && lomask[x+1])){
00247             isz++;                               // increment inner edge size
00248             lres[x]=4;                           // flag pixel as inner edge
00249         } else {
00250             res[x]=1.0f;                         // pixel is just part of inner mask, and it's not an edge
00251         }
00252     } else if(lomask[x]){                        // inner mask was empty, test if outer mask is filled
00253         if(!lomask[x+rw] || !lomask[x+1]) {      // test if outer mask is empty above or to the right
00254             osz++;                               // increment outer edge size
00255             lres[x]=3;                           // flag pixel as outer edge
00256         } else {
00257             gsz++;                               // increment the gradient pixel count
00258             lres[x]=2;                           // flag pixel as gradient
00259         }
00260     }
00261     /* lower right corner */
00262     x=rw-1;
00263     // test if inner mask is filled
00264     if(limask[x]){
00265         // test if pixel above, or to the left, are empty in the inner mask,
00266         // but filled in the outer mask
00267         if((!limask[x+rw] && lomask[x+rw]) || (!limask[x-1] && lomask[x-1])){
00268             isz++;                               // increment inner edge size
00269             lres[x]=4;                           // flag pixel as inner edge
00270         } else {
00271             res[x]=1.0f;                         // pixel is just part of inner mask, and it's not an edge
00272         }
00273     } else if(lomask[x]){                        // inner mask was empty, test if outer mask is filled
00274         if(!lomask[x+rw] || !lomask[x-1]) {      // test if outer mask is empty above or to the left
00275             osz++;                               // increment outer edge size
00276             lres[x]=3;                           // flag pixel as outer edge
00277         } else {
00278             gsz++;                               // increment the gradient pixel count
00279             lres[x]=2;                           // flag pixel as gradient
00280         }
00281     }
00282     /* Test the TOP row of pixels in buffer, except corners */
00283     for(x= t-1; x>=(t-rw)+2; x--) {
00284         // test if inner mask is filled
00285         if(limask[x]) {
00286             // test if pixel to the left, or to the right, are empty in the inner mask,
00287             // but filled in the outer mask
00288             if((!limask[x-1] && lomask[x-1]) || (!limask[x+1] && lomask[x+1])) {
00289                 isz++;                           // increment inner edge size
00290                 lres[x]=4;                       // flag pixel as inner edge
00291             } else {
00292                 res[x]=1.0f;                     // pixel is just part of inner mask, and it's not an edge
00293             }
00294         } else if(lomask[x]) {                   // inner mask was empty, test if outer mask is filled
00295             if(!lomask[x-1] || !lomask[x+1]) {   // test if outer mask is empty to the left or to the right
00296                 osz++;                           // increment outer edge size
00297                 lres[x]=3;                       // flag pixel as outer edge
00298             } else {
00299                 gsz++;                           // increment the gradient pixel count
00300                 lres[x]=2;                       // flag pixel as gradient
00301             }
00302         }
00303     }
00304 
00305     /* Test the BOTTOM row of pixels in buffer, except corners */
00306     for(x= rw-2; x; x--) {
00307         // test if inner mask is filled
00308         if(limask[x]) {
00309             // test if pixel to the left, or to the right, are empty in the inner mask,
00310             // but filled in the outer mask
00311             if((!limask[x-1] && lomask[x-1]) || (!limask[x+1] && lomask[x+1])) {
00312                 isz++;                           // increment inner edge size
00313                 lres[x]=4;                       // flag pixel as inner edge
00314             } else {
00315                 res[x]=1.0f;                     // pixel is just part of inner mask, and it's not an edge
00316             }
00317         } else if(lomask[x]) {                   // inner mask was empty, test if outer mask is filled
00318             if(!lomask[x-1] || !lomask[x+1]) {   // test if outer mask is empty to the left or to the right
00319                 osz++;                           // increment outer edge size
00320                 lres[x]=3;                       // flag pixel as outer edge
00321             } else {
00322                 gsz++;                           // increment the gradient pixel count
00323                 lres[x]=2;                       // flag pixel as gradient
00324             }
00325         }
00326     }
00327     /* Test the LEFT edge of pixels in buffer, except corners */
00328     for(x= t-(rw<<1)+1; x>=rw; x-=rw) {
00329         // test if inner mask is filled
00330         if(limask[x]) {
00331             // test if pixel underneath, or above, are empty in the inner mask,
00332             // but filled in the outer mask
00333             if((!limask[x-rw] && lomask[x-rw]) || (!limask[x+rw] && lomask[x+rw])) {
00334                 isz++;                           // increment inner edge size
00335                 lres[x]=4;                       // flag pixel as inner edge
00336             } else {
00337                 res[x]=1.0f;                     // pixel is just part of inner mask, and it's not an edge
00338             }
00339         } else if(lomask[x]) {                   // inner mask was empty, test if outer mask is filled
00340             if(!lomask[x-rw] || !lomask[x+rw]) { // test if outer mask is empty underneath or above
00341                 osz++;                           // increment outer edge size
00342                 lres[x]=3;                       // flag pixel as outer edge
00343             } else {
00344                 gsz++;                           // increment the gradient pixel count
00345                 lres[x]=2;                       // flag pixel as gradient
00346             }
00347         }
00348     }
00349 
00350     /* Test the RIGHT edge of pixels in buffer, except corners */
00351     for(x= t-rw; x>rw; x-=rw) {
00352         // test if inner mask is filled
00353         if(limask[x]) {
00354             // test if pixel underneath, or above, are empty in the inner mask,
00355             // but filled in the outer mask
00356             if((!limask[x-rw] && lomask[x-rw]) || (!limask[x+rw] && lomask[x+rw])) {
00357                 isz++;                           // increment inner edge size
00358                 lres[x]=4;                       // flag pixel as inner edge
00359             } else {
00360                 res[x]=1.0f;                     // pixel is just part of inner mask, and it's not an edge
00361             }
00362         } else if(lomask[x]) {                   // inner mask was empty, test if outer mask is filled
00363             if(!lomask[x-rw] || !lomask[x+rw]) { // test if outer mask is empty underneath or above
00364                 osz++;                           // increment outer edge size
00365                 lres[x]=3;                       // flag pixel as outer edge
00366             } else {
00367                 gsz++;                           // increment the gradient pixel count
00368                 lres[x]=2;                       // flag pixel as gradient
00369             }
00370         }
00371     }
00372 
00373     rsize[0]=isz;  // fill in our return sizes for edges + fill
00374     rsize[1]=osz;
00375     rsize[2]=gsz;
00376 }
00377 
00378 static void do_allKeepBorders(unsigned int t, unsigned int rw, unsigned int *limask, unsigned int *lomask, unsigned int *lres, float *res, unsigned int *rsize){
00379     int x;
00380     unsigned int isz=0; // inner edge size
00381     unsigned int osz=0; // outer edge size
00382     unsigned int gsz=0; // gradient fill area size
00383     /* Test the four corners */
00384     /* upper left corner */
00385     x=t-rw+1;
00386     // test if inner mask is filled
00387     if(limask[x]){
00388         // test if the inner mask is empty underneath or to the right
00389         if(!limask[x-rw] || !limask[x+1]){
00390             isz++;                               // increment inner edge size
00391             lres[x]=4;                           // flag pixel as inner edge
00392         } else {
00393             res[x]=1.0f;                         // pixel is just part of inner mask, and it's not an edge
00394         }
00395     } else if(lomask[x]){                        // inner mask was empty, test if outer mask is filled
00396         osz++;                                   // increment outer edge size
00397         lres[x]=3;                               // flag pixel as outer edge
00398     }
00399     /* upper right corner */
00400     x=t;
00401     // test if inner mask is filled
00402     if(limask[x]){
00403         // test if the inner mask is empty underneath or to the left
00404         if(!limask[x-rw] || !limask[x-1]){
00405             isz++;                               // increment inner edge size
00406             lres[x]=4;                           // flag pixel as inner edge
00407         } else {
00408             res[x]=1.0f;                         // pixel is just part of inner mask, and it's not an edge
00409         }
00410     } else if(lomask[x]){                        // inner mask was empty, test if outer mask is filled
00411         osz++;                                   // increment outer edge size
00412         lres[x]=3;                               // flag pixel as outer edge
00413     }
00414     /* lower left corner */
00415     x=0;
00416     // test if inner mask is filled
00417     if(limask[x]){
00418         // test if inner mask is empty above or to the right
00419         if(!limask[x+rw] || !limask[x+1]){
00420             isz++;                               // increment inner edge size
00421             lres[x]=4;                           // flag pixel as inner edge
00422         } else {
00423             res[x]=1.0f;                         // pixel is just part of inner mask, and it's not an edge
00424         }
00425     } else if(lomask[x]){                        // inner mask was empty, test if outer mask is filled
00426         osz++;                                   // increment outer edge size
00427         lres[x]=3;                               // flag pixel as outer edge
00428     }
00429     /* lower right corner */
00430     x=rw-1;
00431     // test if inner mask is filled
00432     if(limask[x]){
00433         // test if inner mask is empty above or to the left
00434         if(!limask[x+rw] || !limask[x-1]){
00435             isz++;                               // increment inner edge size
00436             lres[x]=4;                           // flag pixel as inner edge
00437         } else {
00438             res[x]=1.0f;                         // pixel is just part of inner mask, and it's not an edge
00439         }
00440     } else if(lomask[x]){                        // inner mask was empty, test if outer mask is filled
00441         osz++;                                   // increment outer edge size
00442         lres[x]=3;                               // flag pixel as outer edge
00443     }
00444 
00445     /* Test the TOP row of pixels in buffer, except corners */
00446     for(x= t-1; x>=(t-rw)+2; x--) {
00447         // test if inner mask is filled
00448         if(limask[x]) {
00449             // test if inner mask is empty to the left or to the right
00450             if(!limask[x-1] || !limask[x+1]) {
00451                 isz++;                           // increment inner edge size
00452                 lres[x]=4;                       // flag pixel as inner edge
00453             } else {
00454                 res[x]=1.0f;                     // pixel is just part of inner mask, and it's not an edge
00455             }
00456         } else if(lomask[x]) {                   // inner mask was empty, test if outer mask is filled
00457             osz++;                               // increment outer edge size
00458             lres[x]=3;                           // flag pixel as outer edge
00459         }
00460     }
00461 
00462     /* Test the BOTTOM row of pixels in buffer, except corners */
00463     for(x= rw-2; x; x--) {
00464         // test if inner mask is filled
00465         if(limask[x]) {
00466             // test if inner mask is empty to the left or to the right
00467             if(!limask[x-1] || !limask[x+1]) {
00468                 isz++;                           // increment inner edge size
00469                 lres[x]=4;                       // flag pixel as inner edge
00470             } else {
00471                 res[x]=1.0f;                     // pixel is just part of inner mask, and it's not an edge
00472             }
00473         } else if(lomask[x]) {                   // inner mask was empty, test if outer mask is filled
00474             osz++;                               // increment outer edge size
00475             lres[x]=3;                           // flag pixel as outer edge
00476         }
00477     }
00478     /* Test the LEFT edge of pixels in buffer, except corners */
00479     for(x= t-(rw<<1)+1; x>=rw; x-=rw) {
00480         // test if inner mask is filled
00481         if(limask[x]) {
00482             // test if inner mask is empty underneath or above
00483             if(!limask[x-rw] || !limask[x+rw]) {
00484                 isz++;                           // increment inner edge size
00485                 lres[x]=4;                       // flag pixel as inner edge
00486             } else {
00487                 res[x]=1.0f;                     // pixel is just part of inner mask, and it's not an edge
00488             }
00489         } else if(lomask[x]) {                   // inner mask was empty, test if outer mask is filled
00490             osz++;                               // increment outer edge size
00491             lres[x]=3;                           // flag pixel as outer edge
00492         }
00493     }
00494 
00495     /* Test the RIGHT edge of pixels in buffer, except corners */
00496     for(x= t-rw; x>rw; x-=rw) {
00497         // test if inner mask is filled
00498         if(limask[x]) {
00499             // test if inner mask is empty underneath or above
00500             if(!limask[x-rw] || !limask[x+rw]) {
00501                 isz++;                           // increment inner edge size
00502                 lres[x]=4;                       // flag pixel as inner edge
00503             } else {
00504                 res[x]=1.0f;                     // pixel is just part of inner mask, and it's not an edge
00505             }
00506         } else if(lomask[x]) {                   // inner mask was empty, test if outer mask is filled
00507             osz++;                               // increment outer edge size
00508             lres[x]=3;                           // flag pixel as outer edge
00509         }
00510     }
00511 
00512     rsize[0]=isz;  // fill in our return sizes for edges + fill
00513     rsize[1]=osz;
00514     rsize[2]=gsz;
00515 }
00516 
00517 static void do_allBleedBorders(unsigned int t, unsigned int rw, unsigned int *limask, unsigned int *lomask, unsigned int *lres, float *res, unsigned int *rsize){
00518     int x;
00519     unsigned int isz=0; // inner edge size
00520     unsigned int osz=0; // outer edge size
00521     unsigned int gsz=0; // gradient fill area size
00522     /* Test the four corners */
00523     /* upper left corner */
00524     x=t-rw+1;
00525     // test if inner mask is filled
00526     if(limask[x]){
00527         // test if the inner mask is empty underneath or to the right
00528         if(!limask[x-rw] || !limask[x+1]){
00529             isz++;                               // increment inner edge size
00530             lres[x]=4;                           // flag pixel as inner edge
00531         } else {
00532             res[x]=1.0f;                         // pixel is just part of inner mask, and it's not an edge
00533         }
00534     } else if(lomask[x]){                        // inner mask was empty, test if outer mask is filled
00535         if(!lomask[x-rw] || !lomask[x+1]) {      // test if outer mask is empty underneath or to the right
00536             osz++;                               // increment outer edge size
00537             lres[x]=3;                           // flag pixel as outer edge
00538         } else {
00539             gsz++;                               // increment the gradient pixel count
00540             lres[x]=2;                           // flag pixel as gradient
00541         }
00542     }
00543     /* upper right corner */
00544     x=t;
00545     // test if inner mask is filled
00546     if(limask[x]){
00547         // test if the inner mask is empty underneath or to the left
00548         if(!limask[x-rw] || !limask[x-1]){
00549             isz++;                               // increment inner edge size
00550             lres[x]=4;                           // flag pixel as inner edge
00551         } else {
00552             res[x]=1.0f;                         // pixel is just part of inner mask, and it's not an edge
00553         }
00554     } else if(lomask[x]){                        // inner mask was empty, test if outer mask is filled
00555         if(!lomask[x-rw] || !lomask[x-1]) {      // test if outer mask is empty above or to the left
00556             osz++;                               // increment outer edge size
00557             lres[x]=3;                           // flag pixel as outer edge
00558         } else {
00559             gsz++;                               // increment the gradient pixel count
00560             lres[x]=2;                           // flag pixel as gradient
00561         }
00562     }
00563     /* lower left corner */
00564     x=0;
00565     // test if inner mask is filled
00566     if(limask[x]){
00567         // test if inner mask is empty above or to the right
00568         if(!limask[x+rw] || !limask[x+1]){
00569             isz++;                               // increment inner edge size
00570             lres[x]=4;                           // flag pixel as inner edge
00571         } else {
00572             res[x]=1.0f;                         // pixel is just part of inner mask, and it's not an edge
00573         }
00574     } else if(lomask[x]){                        // inner mask was empty, test if outer mask is filled
00575         if(!lomask[x+rw] || !lomask[x+1]) {      // test if outer mask is empty underneath or to the right
00576             osz++;                               // increment outer edge size
00577             lres[x]=3;                           // flag pixel as outer edge
00578         } else {
00579             gsz++;                               // increment the gradient pixel count
00580             lres[x]=2;                           // flag pixel as gradient
00581         }
00582     }
00583     /* lower right corner */
00584     x=rw-1;
00585     // test if inner mask is filled
00586     if(limask[x]){
00587         // test if inner mask is empty above or to the left
00588         if(!limask[x+rw] || !limask[x-1]){
00589             isz++;                               // increment inner edge size
00590             lres[x]=4;                           // flag pixel as inner edge
00591         } else {
00592             res[x]=1.0f;                         // pixel is just part of inner mask, and it's not an edge
00593         }
00594     } else if(lomask[x]){                        // inner mask was empty, test if outer mask is filled
00595         if(!lomask[x+rw] || !lomask[x-1]) {      // test if outer mask is empty underneath or to the left
00596             osz++;                               // increment outer edge size
00597             lres[x]=3;                           // flag pixel as outer edge
00598         } else {
00599             gsz++;                               // increment the gradient pixel count
00600             lres[x]=2;                           // flag pixel as gradient
00601         }
00602     }
00603     /* Test the TOP row of pixels in buffer, except corners */
00604     for(x= t-1; x>=(t-rw)+2; x--) {
00605         // test if inner mask is filled
00606         if(limask[x]) {
00607             // test if inner mask is empty to the left or to the right
00608             if(!limask[x-1] || !limask[x+1]) {
00609                 isz++;                           // increment inner edge size
00610                 lres[x]=4;                       // flag pixel as inner edge
00611             } else {
00612                 res[x]=1.0f;                     // pixel is just part of inner mask, and it's not an edge
00613             }
00614         } else if(lomask[x]) {                   // inner mask was empty, test if outer mask is filled
00615             if(!lomask[x-1] || !lomask[x+1]) {   // test if outer mask is empty to the left or to the right
00616                 osz++;                           // increment outer edge size
00617                 lres[x]=3;                       // flag pixel as outer edge
00618             } else {
00619                 gsz++;                           // increment the gradient pixel count
00620                 lres[x]=2;                       // flag pixel as gradient
00621             }
00622         }
00623     }
00624 
00625     /* Test the BOTTOM row of pixels in buffer, except corners */
00626     for(x= rw-2; x; x--) {
00627         // test if inner mask is filled
00628         if(limask[x]) {
00629             // test if inner mask is empty to the left or to the right
00630             if(!limask[x-1] || !limask[x+1]) {
00631                 isz++;                           // increment inner edge size
00632                 lres[x]=4;                       // flag pixel as inner edge
00633             } else {
00634                 res[x]=1.0f;                     // pixel is just part of inner mask, and it's not an edge
00635             }
00636         } else if(lomask[x]) {                   // inner mask was empty, test if outer mask is filled
00637             if(!lomask[x-1] || !lomask[x+1]) {   // test if outer mask is empty to the left or to the right
00638                 osz++;                           // increment outer edge size
00639                 lres[x]=3;                       // flag pixel as outer edge
00640             } else {
00641                 gsz++;                           // increment the gradient pixel count
00642                 lres[x]=2;                       // flag pixel as gradient
00643             }
00644         }
00645     }
00646     /* Test the LEFT edge of pixels in buffer, except corners */
00647     for(x= t-(rw<<1)+1; x>=rw; x-=rw) {
00648         // test if inner mask is filled
00649         if(limask[x]) {
00650             // test if inner mask is empty underneath or above
00651             if(!limask[x-rw] || !limask[x+rw]) {
00652                 isz++;                           // increment inner edge size
00653                 lres[x]=4;                       // flag pixel as inner edge
00654             } else {
00655                 res[x]=1.0f;                     // pixel is just part of inner mask, and it's not an edge
00656             }
00657         } else if(lomask[x]) {                   // inner mask was empty, test if outer mask is filled
00658             if(!lomask[x-rw] || !lomask[x+rw]) { // test if outer mask is empty underneath or above
00659                 osz++;                           // increment outer edge size
00660                 lres[x]=3;                       // flag pixel as outer edge
00661             } else {
00662                 gsz++;                           // increment the gradient pixel count
00663                 lres[x]=2;                       // flag pixel as gradient
00664             }
00665         }
00666     }
00667 
00668     /* Test the RIGHT edge of pixels in buffer, except corners */
00669     for(x= t-rw; x>rw; x-=rw) {
00670         // test if inner mask is filled
00671         if(limask[x]) {
00672             // test if inner mask is empty underneath or above
00673             if(!limask[x-rw] || !limask[x+rw]) {
00674                 isz++;                           // increment inner edge size
00675                 lres[x]=4;                       // flag pixel as inner edge
00676             } else {
00677                 res[x]=1.0f;                     // pixel is just part of inner mask, and it's not an edge
00678             }
00679         } else if(lomask[x]) {                   // inner mask was empty, test if outer mask is filled
00680             if(!lomask[x-rw] || !lomask[x+rw]) { // test if outer mask is empty underneath or above
00681                 osz++;                           // increment outer edge size
00682                 lres[x]=3;                       // flag pixel as outer edge
00683             } else {
00684                 gsz++;                           // increment the gradient pixel count
00685                 lres[x]=2;                       // flag pixel as gradient
00686             }
00687         }
00688     }
00689 
00690     rsize[0]=isz;  // fill in our return sizes for edges + fill
00691     rsize[1]=osz;
00692     rsize[2]=gsz;
00693 }
00694 
00695 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){
00696     int x;                             // x = pixel loop counter
00697     int a;                             // a = pixel loop counter
00698     int dx;                            // dx = delta x
00699     int pix_prevRow;                   // pix_prevRow = pixel one row behind the one we are testing in a loop
00700     int pix_nextRow;                   // pix_nextRow = pixel one row in front of the one we are testing in a loop
00701     int pix_prevCol;                   // pix_prevCol = pixel one column behind the one we are testing in a loop
00702     int pix_nextCol;                   // pix_nextCol = pixel one column in front of the one we are testing in a loop
00703     /* Test all rows between the FIRST and LAST rows, excluding left and right edges */
00704     for(x= (t-rw)+1, dx=x-(rw-2); dx>rw; x-=rw,dx-=rw) {
00705         a=x-2;
00706         pix_prevRow=a+rw;
00707         pix_nextRow=a-rw;
00708         pix_prevCol=a+1;
00709         pix_nextCol=a-1;
00710         while(a>dx-2) {
00711             if(!limask[a]) {             // if the inner mask is empty
00712                 if(lomask[a]) {          // if the outer mask is full
00713                     /*
00714                       Next we test all 4 directions around the current pixel: next/prev/up/down
00715                       The test ensures that the outer mask is empty and that the inner mask
00716                       is also empty. If both conditions are true for any one of the 4 adjacent pixels
00717                       then the current pixel is counted as being a true outer edge pixel.
00718                      */
00719                     if((!lomask[pix_nextCol] && !limask[pix_nextCol]) ||
00720                        (!lomask[pix_prevCol] && !limask[pix_prevCol]) ||
00721                        (!lomask[pix_nextRow] && !limask[pix_nextRow]) ||
00722                        (!lomask[pix_prevRow] && !limask[pix_prevRow]))
00723                     {
00724                         in_osz++;           // increment the outer boundary pixel count
00725                         lres[a]=3;       // flag pixel as part of outer edge
00726                     } else {             // it's not a boundary pixel, but it is a gradient pixel
00727                         in_gsz++;           // increment the gradient pixel count
00728                         lres[a]=2;       // flag pixel as gradient
00729                     }
00730                 }
00731 
00732             } else {
00733                 if(!limask[pix_nextCol] || !limask[pix_prevCol] || !limask[pix_nextRow] || !limask[pix_prevRow]) {
00734                     in_isz++;               // increment the inner boundary pixel count
00735                     lres[a]=4;           // flag pixel as part of inner edge
00736                 } else {
00737                     res[a]=1.0f;         // pixel is part of inner mask, but not at an edge
00738                 }
00739             }
00740             a--;
00741             pix_prevRow--;
00742             pix_nextRow--;
00743             pix_prevCol--;
00744             pix_nextCol--;
00745         }
00746     }
00747 
00748     rsize[0]=in_isz;  // fill in our return sizes for edges + fill
00749     rsize[1]=in_osz;
00750     rsize[2]=in_gsz;
00751 }
00752 
00753 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){
00754     int x;                             // x = pixel loop counter
00755     int a;                             // a = pixel loop counter
00756     int dx;                            // dx = delta x
00757     int pix_prevRow;                   // pix_prevRow = pixel one row behind the one we are testing in a loop
00758     int pix_nextRow;                   // pix_nextRow = pixel one row in front of the one we are testing in a loop
00759     int pix_prevCol;                   // pix_prevCol = pixel one column behind the one we are testing in a loop
00760     int pix_nextCol;                   // pix_nextCol = pixel one column in front of the one we are testing in a loop
00761     /* Test all rows between the FIRST and LAST rows, excluding left and right edges */
00762     for(x= (t-rw)+1, dx=x-(rw-2); dx>rw; x-=rw,dx-=rw) {
00763         a=x-2;
00764         pix_prevRow=a+rw;
00765         pix_nextRow=a-rw;
00766         pix_prevCol=a+1;
00767         pix_nextCol=a-1;
00768         while(a>dx-2) {
00769             if(!limask[a]) {             // if the inner mask is empty
00770                 if(lomask[a]) {          // if the outer mask is full
00771                     /*
00772                       Next we test all 4 directions around the current pixel: next/prev/up/down
00773                       The test ensures that the outer mask is empty and that the inner mask
00774                       is also empty. If both conditions are true for any one of the 4 adjacent pixels
00775                       then the current pixel is counted as being a true outer edge pixel.
00776                      */
00777                     if((!lomask[pix_nextCol] && !limask[pix_nextCol]) ||
00778                        (!lomask[pix_prevCol] && !limask[pix_prevCol]) ||
00779                        (!lomask[pix_nextRow] && !limask[pix_nextRow]) ||
00780                        (!lomask[pix_prevRow] && !limask[pix_prevRow]))
00781                     {
00782                         in_osz++;           // increment the outer boundary pixel count
00783                         lres[a]=3;       // flag pixel as part of outer edge
00784                     } else {             // it's not a boundary pixel, but it is a gradient pixel
00785                         in_gsz++;           // increment the gradient pixel count
00786                         lres[a]=2;       // flag pixel as gradient
00787                     }
00788                 }
00789 
00790             } else {
00791                 if((!limask[pix_nextCol] && lomask[pix_nextCol]) ||
00792                    (!limask[pix_prevCol] && lomask[pix_prevCol]) ||
00793                    (!limask[pix_nextRow] && lomask[pix_nextRow]) ||
00794                    (!limask[pix_prevRow] && lomask[pix_prevRow]))
00795                 {
00796                     in_isz++;               // increment the inner boundary pixel count
00797                     lres[a]=4;           // flag pixel as part of inner edge
00798                 } else {
00799                     res[a]=1.0f;         // pixel is part of inner mask, but not at an edge
00800                 }
00801             }
00802             a--;
00803             pix_prevRow--;              // advance all four "surrounding" pixel pointers
00804             pix_nextRow--;
00805             pix_prevCol--;
00806             pix_nextCol--;
00807         }
00808     }
00809 
00810     rsize[0]=in_isz;  // fill in our return sizes for edges + fill
00811     rsize[1]=in_osz;
00812     rsize[2]=in_gsz;
00813 }
00814 
00815 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){
00816     int x;                             // x = pixel loop counter
00817     int a;                             // a = temporary pixel index buffer loop counter
00818     unsigned int ud;                   // ud = unscaled edge distance
00819     unsigned int dmin;                 // dmin = minimun edge distance
00820 
00821     unsigned int rsl;                  // long used for finding fast 1.0/sqrt
00822     unsigned int gradientFillOffset;
00823     unsigned int innerAccum=0;         // for looping inner edge pixel indexes, represents current position from offset
00824     unsigned int outerAccum=0;         // for looping outer edge pixel indexes, represents current position from offset
00825     unsigned int gradientAccum=0;      // for looping gradient pixel indexes, represents current position from offset
00826     /*
00827     Here we compute the size of buffer needed to hold (row,col) coordinates
00828     for each pixel previously determined to be either gradient, inner edge,
00829     or outer edge.
00830 
00831     Allocation is done by requesting 4 bytes "sizeof(int)" per pixel, even
00832     though gbuf[] is declared as unsigned short* (2 bytes) because we don't
00833     store the pixel indexes, we only store x,y location of pixel in buffer.
00834 
00835     This does make the assumption that x and y can fit in 16 unsigned bits
00836     so if Blender starts doing renders greater than 65536 in either direction
00837     this will need to allocate gbuf[] as unsigned int* and allocate 8 bytes
00838     per flagged pixel.
00839 
00840     In general, the buffer on-screen:
00841 
00842     Example:  9 by 9 pixel block
00843 
00844     . = pixel non-white in both outer and inner mask
00845     o = pixel white in outer, but not inner mask, adjacent to "." pixel
00846     g = pixel white in outer, but not inner mask, not adjacent to "." pixel
00847     i = pixel white in inner mask, adjacent to "g" or "." pixel
00848     F = pixel white in inner mask, only adjacent to other pixels white in the inner mask
00849 
00850 
00851                      .........   <----- pixel #80
00852                      ..oooo...
00853                      .oggggo..
00854                      .oggiggo.
00855                      .ogiFigo.
00856                      .oggiggo.
00857                      .oggggo..
00858                      ..oooo...
00859     pixel #00 -----> .........
00860 
00861     gsz = 18   (18 "g" pixels above)
00862     isz = 4    (4 "i" pixels above)
00863     osz = 18   (18 "o" pixels above)
00864 
00865 
00866     The memory in gbuf[] after filling will look like this:
00867 
00868      gradientFillOffset (0 pixels)                   innerEdgeOffset (18 pixels)    outerEdgeOffset (22 pixels)
00869     /                                               /                              /
00870     /                                               /                              /
00871     |X   Y   X   Y   X   Y   X   Y   >     <X   Y   X   Y   >     <X   Y   X   Y   X   Y   >     <X   Y   X   Y   | <- (x,y)
00872     +-------------------------------->     <---------------->     <------------------------>     <----------------+
00873     |0   2   4   6   8   10  12  14  > ... <68  70  72  74  > ... <80  82  84  86  88  90  > ... <152 154 156 158 | <- bytes
00874     +-------------------------------->     <---------------->     <------------------------>     <----------------+
00875     |g0  g0  g1  g1  g2  g2  g3  g3  >     <g17 g17 i0  i0  >     <i2  i2  i3  i3  o0  o0  >     <o16 o16 o17 o17 | <- pixel
00876                                                  /                              /                              /
00877                                                 /                              /                              /
00878                                                /                              /                              /
00879       +---------- gradientAccum (18) ---------+      +--- innerAccum (22) ---+      +--- outerAccum (40) ---+
00880 
00881 
00882     Ultimately we do need the pixel's memory buffer index to set the output
00883     pixel color, but it's faster to reconstruct the memory buffer location
00884     each iteration of the final gradient calculation than it is to deconstruct
00885     a memory location into x,y pairs each round.
00886 */
00887 
00888 
00889     gradientFillOffset=0;                              // since there are likely "more" of these, put it first. :)
00890     *innerEdgeOffset=gradientFillOffset+gsz;           // set start of inner edge indexes
00891     *outerEdgeOffset=(*innerEdgeOffset)+isz;           // set start of outer edge indexes
00892     /* set the accumulators to correct positions */    // set up some accumulator variables for loops
00893     gradientAccum = gradientFillOffset;                // each accumulator variable starts at its respective
00894     innerAccum = *innerEdgeOffset;                     // section's offset so when we start filling, each
00895     outerAccum = *outerEdgeOffset;                     // section fills up it's allocated space in gbuf
00896     //uses dmin=row, rsl=col
00897     for(x=0,dmin=0; x<t; x+=rw,dmin++) {
00898         for(rsl=0; rsl<rw; rsl++) {
00899             a=x+rsl;
00900             if(lres[a]==2) {           // it is a gradient pixel flagged by 2
00901                 ud=gradientAccum<<1;   // double the index to reach correct unsigned short location
00902                 gbuf[ud]=dmin;         // insert pixel's row into gradient pixel location buffer
00903                 gbuf[ud+1]=rsl;        // insert pixel's column into gradient pixel location buffer
00904                 gradientAccum++;       // increment gradient index buffer pointer
00905             } else if(lres[a]==3) {    // it is an outer edge pixel flagged by 3
00906                 ud=outerAccum<<1;      // double the index to reach correct unsigned short location
00907                 gbuf[ud]=dmin;         // insert pixel's row into outer edge pixel location buffer
00908                 gbuf[ud+1]=rsl;        // insert pixel's column into outer edge pixel location buffer
00909                 outerAccum++;          // increment outer edge index buffer pointer
00910                 res[a]=0.0f;           // set output pixel intensity now since it won't change later
00911             } else if(lres[a]==4) {    // it is an inner edge pixel flagged by 4
00912                 ud=innerAccum<<1;      // double int index to reach correct unsigned short location
00913                 gbuf[ud]=dmin;         // insert pixel's row into inner edge pixel location buffer
00914                 gbuf[ud+1]=rsl;        // insert pixel's column into inner edge pixel location buffer
00915                 innerAccum++;          // increment inner edge index buffer pointer
00916                 res[a]=1.0f;           // set output pixel intensity now since it won't change later
00917             }
00918         }
00919     }
00920 
00921 }
00922 
00923 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){
00924     int x;                             // x = pixel loop counter
00925     int a;                             // a = temporary pixel index buffer loop counter
00926     int fsz;                           // size of the frame
00927     unsigned int rsl;                  // long used for finding fast 1.0/sqrt
00928     float rsf;                         // float used for finding fast 1.0/sqrt
00929     const float rsopf = 1.5f;          // constant float used for finding fast 1.0/sqrt
00930 
00931     unsigned int gradientFillOffset;
00932     unsigned int t;
00933     unsigned int ud;                   // ud = unscaled edge distance
00934     unsigned int dmin;                 // dmin = minimun edge distance
00935     float odist;                       // odist = current outer edge distance
00936     float idist;                       // idist = current inner edge distance
00937     int dx;                            // dx = X-delta (used for distance proportion calculation)
00938     int dy;                            // dy = Y-delta (used for distance proportion calculation)
00939 
00940     /*
00941      The general algorithm used to color each gradient pixel is:
00942 
00943      1.) Loop through all gradient pixels.
00944         A.) For each gradient pixel:
00945             a.) Loop though all outside edge pixels, looking for closest one
00946                 to the gradient pixel we are in.
00947             b.) Loop through all inside edge pixels, looking for closest one
00948                 to the gradient pixel we are in.
00949             c.) Find proportion of distance from gradient pixel to inside edge
00950                 pixel compared to sum of distance to inside edge and distance to
00951                 outside edge.
00952 
00953                 In an image where:
00954                 . = blank (black) pixels, not covered by inner mask or outer mask
00955                 + = desired gradient pixels, covered only by outer mask
00956                 * = white full mask pixels, covered by at least inner mask
00957 
00958                 ...............................
00959                 ...............+++++++++++.....
00960                 ...+O++++++..++++++++++++++....
00961                 ..+++\++++++++++++++++++++.....
00962                 .+++++G+++++++++*******+++.....
00963                 .+++++|+++++++*********+++.....
00964                 .++***I****************+++.....
00965                 .++*******************+++......
00966                 .+++*****************+++.......
00967                 ..+++***************+++........
00968                 ....+++**********+++...........
00969                 ......++++++++++++.............
00970                 ...............................
00971 
00972                     O = outside edge pixel
00973                      \
00974                       G = gradient pixel
00975                       |
00976                       I = inside edge pixel
00977 
00978                                  __
00979                       *note that IO does not need to be a straight line, in fact
00980                        many cases can arise where straight lines do not work
00981                        correctly.
00982 
00983                                             __       __     __
00984             d.) Pixel color is assigned as |GO| / ( |GI| + |GO| )
00985 
00986      The implementation does not compute distance, but the reciprocal of the
00987      distance. This is done to avoid having to compute a square root, as a
00988      reciprocal square root can be computed faster. Therefore, the code computes
00989      pixel color as |GI| / (|GI| + |GO|). Since these are reciprocals, GI serves the
00990      purpose of GO for the proportion calculation.
00991 
00992      For the purposes of the minimun distance comparisons, we only check
00993      the sums-of-squares against eachother, since they are in the same
00994      mathematical sort-order as if we did go ahead and take square roots
00995 
00996      Loop through all gradient pixels.
00997      */
00998 
00999     for(x= gsz-1; x>=0; x--) {
01000         gradientFillOffset=x<<1;
01001         t=gbuf[gradientFillOffset];         // calculate column of pixel indexed by gbuf[x]
01002         fsz=gbuf[gradientFillOffset+1];     // calculate row of pixel indexed by gbuf[x]
01003         dmin=0xffffffff;                    // reset min distance to edge pixel
01004         for(a=outerEdgeOffset+osz-1; a>=outerEdgeOffset; a--) {   // loop through all outer edge buffer pixels
01005             ud=a<<1;
01006             dy=t-gbuf[ud];                  // set dx to gradient pixel column - outer edge pixel row
01007             dx=fsz-gbuf[ud+1];              // set dy to gradient pixel row - outer edge pixel column
01008             ud=dx*dx+dy*dy;                 // compute sum of squares
01009             if(ud<dmin) {                   // if our new sum of squares is less than the current minimum
01010                 dmin=ud;                    // set a new minimum equal to the new lower value
01011             }
01012         }
01013         odist=(float)(dmin);                     // cast outer min to a float
01014         rsf=odist*0.5f;                          //
01015         rsl=*(unsigned int*)&odist;              // use some peculiar properties of the way bits are stored
01016         rsl=0x5f3759df-(rsl>>1);                 // in floats vs. unsigned ints to compute an approximate
01017         odist=*(float*)&rsl;                     // reciprocal square root
01018         odist=odist*(rsopf-(rsf*odist*odist));   // -- ** this line can be iterated for more accuracy ** --
01019         dmin=0xffffffff;                         // reset min distance to edge pixel
01020         for(a= innerEdgeOffset+isz-1; a>=innerEdgeOffset; a--) {   // loop through all inside edge pixels
01021             ud=a<<1;
01022             dy=t-gbuf[ud];         // compute delta in Y from gradient pixel to inside edge pixel
01023             dx=fsz-gbuf[ud+1];     // compute delta in X from gradient pixel to inside edge pixel
01024             ud=dx*dx+dy*dy;        // compute sum of squares
01025             if(ud<dmin) {          // if our new sum of squares is less than the current minimum we've found
01026                 dmin=ud;           // set a new minimum equal to the new lower value
01027             }
01028         }
01029         idist=(float)(dmin);                     // cast inner min to a float
01030         rsf=idist*0.5f;                          //
01031         rsl=*(unsigned int*)&idist;              //
01032         rsl=0x5f3759df-(rsl>>1);                 // see notes above
01033         idist=*(float*)&rsl;                     //
01034         idist=idist*(rsopf-(rsf*idist*idist));   //
01035         /*
01036          Note once again that since we are using reciprocals of distance values our
01037          proportion is already the correct intensity, and does not need to be
01038          subracted from 1.0 like it would have if we used real distances.
01039          */
01040 
01041         /*
01042          Here we reconstruct the pixel's memory location in the CompBuf by
01043          Pixel Index = Pixel Column + ( Pixel Row * Row Width )
01044          */
01045         res[gbuf[gradientFillOffset+1]+(gbuf[gradientFillOffset]*rw)]=(idist/(idist+odist));    //set intensity
01046     }
01047 
01048 }
01049 
01050 
01051 static void node_composit_exec_doubleedgemask(void *UNUSED(data), bNode *node, bNodeStack **in, bNodeStack **out) {
01052 
01053     float *imask;                      // imask = pointer to inner mask pixel buffer
01054     float *omask;                      // omask = pointer to outer mask pixel buffer
01055     float *res;                        // res = pointer to output mask
01056 
01057     unsigned int *lres;                // lres = unsigned int pointer to output pixel buffer (for bit operations)
01058     unsigned int *limask;              // limask = unsigned int pointer to inner mask (for bit operations)
01059     unsigned int *lomask;              // lomask = unsigned int pointer to outer mask (for bit operations)
01060 
01061     int rw;                            // rw = pixel row width
01062     int t;                             // t = total number of pixels in buffer - 1 (used for loop starts)
01063     int fsz;                           // size of the frame
01064 
01065     unsigned int isz=0;                // size (in pixels) of inside edge pixel index buffer
01066     unsigned int osz=0;                // size (in pixels) of outside edge pixel index buffer
01067     unsigned int gsz=0;                // size (in pixels) of gradient pixel index buffer
01068     unsigned int rsize[3];             // size storage to pass to helper functions
01069     unsigned int innerEdgeOffset=0;    // offset into final buffer where inner edge pixel indexes start
01070     unsigned int outerEdgeOffset=0;    // offset into final buffer where outer edge pixel indexes start
01071 
01072     unsigned short *gbuf;              // gradient/inner/outer pixel location index buffer
01073 
01074     CompBuf *cbuf;                     // pointer, will be set to inner mask data
01075     CompBuf *dbuf;                     // pointer, will be set to outer mask data
01076     CompBuf *stackbuf;                 // pointer, will get allocated as output buffer
01077 
01078     if(out[0]->hasoutput==0) {         // if the node's output socket is not connected to anything...
01079         return;                        //     do not execute any further, just exit the node immediately
01080     }
01081 
01082     if(in[0]->data && in[1]->data) {                    // if both input sockets have some data coming in...
01083         cbuf= in[0]->data;                              //     get a pointer to the inner mask data
01084         dbuf= in[1]->data;                              //     get a pointer to the outer mask data
01085         if(cbuf->type!=CB_VAL || dbuf->type!=CB_VAL) {  // if either input socket has an incorrect data type coming in
01086             return;                                     //     exit the node immediately
01087         }
01088 
01089         t=(cbuf->x*cbuf->y)-1;                                // determine size of the frame
01090 
01091         stackbuf= alloc_compbuf(cbuf->x, cbuf->y, CB_VAL, 1); // allocate the output buffer
01092 
01093         imask= cbuf->rect;             // set the inner mask
01094         omask= dbuf->rect;             // set the outer mask
01095         res= stackbuf->rect;           // set output pointer
01096         lres= (unsigned int*)res;      // unsigned int pointer to output buffer (for bit level ops)
01097         limask=(unsigned int*)imask;   // unsigned int pointer to input mask (for bit level ops)
01098         lomask=(unsigned int*)omask;   // unsigned int pointer to output mask (for bit level ops)
01099         rw= cbuf->x;                   // width of a row of pixels
01100 
01101 
01102         /*
01103          The whole buffer is broken up into 4 parts. The four CORNERS, the FIRST and LAST rows, the
01104          LEFT and RIGHT edges (excluding the corner pixels), and all OTHER rows.
01105          This allows for quick computation of outer edge pixels where
01106          a screen edge pixel is marked to be gradient.
01107 
01108          The pixel type (gradient vs inner-edge vs outer-edge) tests change
01109          depending on the user selected "Inner Edge Mode" and the user selected
01110          "Buffer Edge Mode" on the node's GUI. There are 4 sets of basically the
01111          same algorithm:
01112 
01113          1.) Inner Edge -> Adjacent Only
01114              Buffer Edge -> Keep Inside
01115 
01116          2.) Inner Edge -> Adjacent Only
01117              Buffer Edge -> Bleed Out
01118 
01119          3.) Inner Edge -> All
01120              Buffer Edge -> Keep Inside
01121 
01122          4.) Inner Edge -> All
01123              Buffer Edge -> Bleed Out
01124 
01125          Each version has slightly different criteria for detecting an edge pixel.
01126          */
01127         if(node->custom2) {            // if "adjacent only" inner edge mode is turned on
01128             if(node->custom1) {        // if "keep inside" buffer edge mode is turned on
01129                 do_adjacentKeepBorders(t,rw,limask,lomask,lres,res,rsize);
01130             }else{                     // "bleed out" buffer edge mode is turned on
01131                 do_adjacentBleedBorders(t,rw,limask,lomask,lres,res,rsize);
01132             }
01133             isz=rsize[0];              // set up inner edge, outer edge, and gradient buffer sizes after border pass
01134             osz=rsize[1];
01135             gsz=rsize[2];
01136             // detect edges in all non-border pixels in the buffer
01137             do_adjacentEdgeDetection(t,rw,limask,lomask,lres,res,rsize,isz,osz,gsz);
01138         }else{                         // "all" inner edge mode is turned on
01139             if(node->custom1) {        // if "keep inside" buffer edge mode is turned on
01140                 do_allKeepBorders(t,rw,limask,lomask,lres,res,rsize);
01141             }else{                     // "bleed out" buffer edge mode is turned on
01142                 do_allBleedBorders(t,rw,limask,lomask,lres,res,rsize);
01143             }
01144             isz=rsize[0];              // set up inner edge, outer edge, and gradient buffer sizes after border pass
01145             osz=rsize[1];
01146             gsz=rsize[2];
01147             // detect edges in all non-border pixels in the buffer
01148             do_allEdgeDetection(t,rw,limask,lomask,lres,res,rsize,isz,osz,gsz);
01149         }
01150 
01151         isz=rsize[0];                  // set edge and gradient buffer sizes once again...
01152         osz=rsize[1];                  // the sizes in rsize[] may have been modified
01153         gsz=rsize[2];                  // by the do_*EdgeDetection() function.
01154 
01155         // quick check for existance of edges in the buffer...
01156         // if we don't have any one of the three sizes, the other two make no difference visually,
01157         // so we can just pass the inner input buffer back as output.
01158         if(!gsz || !isz || !osz) {
01159             out[0]->data= stackbuf;    // point the node output buffer to our filled buffer
01160             return;
01161         }
01162 
01163 
01164         fsz=gsz+isz+osz;                                   // calculate size of pixel index buffer needed
01165         gbuf= MEM_mallocN(fsz*sizeof(int), "grd buf");     // allocate edge/gradient pixel index buffer
01166 
01167         do_createEdgeLocationBuffer(t,rw,lres,res,gbuf,&innerEdgeOffset,&outerEdgeOffset,isz,gsz);
01168         do_fillGradientBuffer(rw,res,gbuf,isz,osz,gsz,innerEdgeOffset,outerEdgeOffset);
01169 
01170         MEM_freeN(gbuf);          // free the gradient index buffer
01171         out[0]->data= stackbuf;   // point the node output buffer to our filled buffer
01172     }
01173 }
01174 
01175 void register_node_type_cmp_doubleedgemask(bNodeTreeType *ttype) {
01176     static bNodeType ntype;      // allocate a node type data structure
01177 
01178     node_type_base(ttype, &ntype, CMP_NODE_DOUBLEEDGEMASK, "Double Edge Mask", NODE_CLASS_MATTE, NODE_OPTIONS);
01179     node_type_socket_templates(&ntype, cmp_node_doubleedgemask_in, cmp_node_doubleedgemask_out);
01180     node_type_size(&ntype, 210, 210, 210);
01181     node_type_exec(&ntype, node_composit_exec_doubleedgemask);
01182 
01183     nodeRegisterType(ttype, &ntype);
01184 }