Blender V2.61 - r43446
|
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 }