|
|
|
|
@@ -0,0 +1,1183 @@
|
|
|
|
|
/*
|
|
|
|
|
* $Id: node_composite_doubleEdgeMask.c 35237 2012-01-01 03:06:22Z xgl.asyliax $
|
|
|
|
|
*
|
|
|
|
|
* ***** BEGIN GPL LICENSE BLOCK *****
|
|
|
|
|
*
|
|
|
|
|
* This program is free software; you can redistribute it and/or
|
|
|
|
|
* modify it under the terms of the GNU General Public License
|
|
|
|
|
* as published by the Free Software Foundation; either version 2
|
|
|
|
|
* of the License, or (at your option) any later version.
|
|
|
|
|
*
|
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
|
*
|
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
|
* along with this program; if not, write to the Free Software Foundation,
|
|
|
|
|
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
|
|
|
*
|
|
|
|
|
* The Original Code is Copyright (C) 2011 Blender Foundation.
|
|
|
|
|
* All rights reserved.
|
|
|
|
|
*
|
|
|
|
|
* The Original Code is: all of this file.
|
|
|
|
|
*
|
|
|
|
|
* Contributor(s): Peter Larabell.
|
|
|
|
|
*
|
|
|
|
|
* ***** END GPL LICENSE BLOCK *****
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
/** \file blender/nodes/composite/nodes/node_composite_doubleEdgeMask.c
|
|
|
|
|
* \ingroup cmpnodes
|
|
|
|
|
*/
|
|
|
|
|
#include "node_composite_util.h"
|
|
|
|
|
/* **************** DblEdgMatte ******************** */
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static bNodeSocketTemplate cmp_node_doubleedgemask_in[]= {
|
|
|
|
|
{ SOCK_FLOAT, 1, "Inner Mask", 0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f, PROP_NONE}, // inner mask socket definition
|
|
|
|
|
{ SOCK_FLOAT, 1, "Outer Mask", 0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f, PROP_NONE}, // outer mask socket definition
|
|
|
|
|
{ -1, 0, "" } // input socket array terminator
|
|
|
|
|
};
|
|
|
|
|
static bNodeSocketTemplate cmp_node_doubleedgemask_out[]= {
|
|
|
|
|
{ SOCK_FLOAT, 0, "Mask"}, // output socket definition
|
|
|
|
|
{ -1, 0, "" } // output socket array terminator
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static void do_adjacentKeepBorders(unsigned int t, unsigned int rw, unsigned int *limask, unsigned int *lomask, unsigned int *lres, float *res, unsigned int *rsize){
|
|
|
|
|
int x;
|
|
|
|
|
unsigned int isz=0; // inner edge size
|
|
|
|
|
unsigned int osz=0; // outer edge size
|
|
|
|
|
unsigned int gsz=0; // gradient fill area size
|
|
|
|
|
/* Test the four corners */
|
|
|
|
|
/* upper left corner */
|
|
|
|
|
x=t-rw+1;
|
|
|
|
|
// test if inner mask is filled
|
|
|
|
|
if(limask[x]){
|
|
|
|
|
// test if pixel underneath, or to the right, are empty in the inner mask,
|
|
|
|
|
// but filled in the outer mask
|
|
|
|
|
if((!limask[x-rw] && lomask[x-rw]) || (!limask[x+1] && lomask[x+1])){
|
|
|
|
|
isz++; // increment inner edge size
|
|
|
|
|
lres[x]=4; // flag pixel as inner edge
|
|
|
|
|
} else {
|
|
|
|
|
res[x]=1.0f; // pixel is just part of inner mask, and it's not an edge
|
|
|
|
|
}
|
|
|
|
|
} else if(lomask[x]){ // inner mask was empty, test if outer mask is filled
|
|
|
|
|
osz++; // increment outer edge size
|
|
|
|
|
lres[x]=3; // flag pixel as outer edge
|
|
|
|
|
}
|
|
|
|
|
/* upper right corner */
|
|
|
|
|
x=t;
|
|
|
|
|
// test if inner mask is filled
|
|
|
|
|
if(limask[x]){
|
|
|
|
|
// test if pixel underneath, or to the left, are empty in the inner mask,
|
|
|
|
|
// but filled in the outer mask
|
|
|
|
|
if((!limask[x-rw] && lomask[x-rw]) || (!limask[x-1] && lomask[x-1])){
|
|
|
|
|
isz++; // increment inner edge size
|
|
|
|
|
lres[x]=4; // flag pixel as inner edge
|
|
|
|
|
} else {
|
|
|
|
|
res[x]=1.0f; // pixel is just part of inner mask, and it's not an edge
|
|
|
|
|
}
|
|
|
|
|
} else if(lomask[x]){ // inner mask was empty, test if outer mask is filled
|
|
|
|
|
osz++; // increment outer edge size
|
|
|
|
|
lres[x]=3; // flag pixel as outer edge
|
|
|
|
|
}
|
|
|
|
|
/* lower left corner */
|
|
|
|
|
x=0;
|
|
|
|
|
// test if inner mask is filled
|
|
|
|
|
if(limask[x]){
|
|
|
|
|
// test if pixel above, or to the right, are empty in the inner mask,
|
|
|
|
|
// but filled in the outer mask
|
|
|
|
|
if((!limask[x+rw] && lomask[x+rw]) || (!limask[x+1] && lomask[x+1])){
|
|
|
|
|
isz++; // increment inner edge size
|
|
|
|
|
lres[x]=4; // flag pixel as inner edge
|
|
|
|
|
} else {
|
|
|
|
|
res[x]=1.0f; // pixel is just part of inner mask, and it's not an edge
|
|
|
|
|
}
|
|
|
|
|
} else if(lomask[x]){ // inner mask was empty, test if outer mask is filled
|
|
|
|
|
osz++; // increment outer edge size
|
|
|
|
|
lres[x]=3; // flag pixel as outer edge
|
|
|
|
|
}
|
|
|
|
|
/* lower right corner */
|
|
|
|
|
x=rw-1;
|
|
|
|
|
// test if inner mask is filled
|
|
|
|
|
if(limask[x]){
|
|
|
|
|
// test if pixel above, or to the left, are empty in the inner mask,
|
|
|
|
|
// but filled in the outer mask
|
|
|
|
|
if((!limask[x+rw] && lomask[x+rw]) || (!limask[x-1] && lomask[x-1])){
|
|
|
|
|
isz++; // increment inner edge size
|
|
|
|
|
lres[x]=4; // flag pixel as inner edge
|
|
|
|
|
} else {
|
|
|
|
|
res[x]=1.0f; // pixel is just part of inner mask, and it's not an edge
|
|
|
|
|
}
|
|
|
|
|
} else if(lomask[x]){ // inner mask was empty, test if outer mask is filled
|
|
|
|
|
osz++; // increment outer edge size
|
|
|
|
|
lres[x]=3; // flag pixel as outer edge
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Test the TOP row of pixels in buffer, except corners */
|
|
|
|
|
for(x= t-1; x>=(t-rw)+2; x--) {
|
|
|
|
|
// test if inner mask is filled
|
|
|
|
|
if(limask[x]) {
|
|
|
|
|
// test if pixel to the right, or to the left, are empty in the inner mask,
|
|
|
|
|
// but filled in the outer mask
|
|
|
|
|
if((!limask[x-1] && lomask[x-1]) || (!limask[x+1] && lomask[x+1])) {
|
|
|
|
|
isz++; // increment inner edge size
|
|
|
|
|
lres[x]=4; // flag pixel as inner edge
|
|
|
|
|
} else {
|
|
|
|
|
res[x]=1.0f; // pixel is just part of inner mask, and it's not an edge
|
|
|
|
|
}
|
|
|
|
|
} else if(lomask[x]) { // inner mask was empty, test if outer mask is filled
|
|
|
|
|
osz++; // increment outer edge size
|
|
|
|
|
lres[x]=3; // flag pixel as outer edge
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Test the BOTTOM row of pixels in buffer, except corners */
|
|
|
|
|
for(x= rw-2; x; x--) {
|
|
|
|
|
// test if inner mask is filled
|
|
|
|
|
if(limask[x]) {
|
|
|
|
|
// test if pixel to the right, or to the left, are empty in the inner mask,
|
|
|
|
|
// but filled in the outer mask
|
|
|
|
|
if((!limask[x-1] && lomask[x-1]) || (!limask[x+1] && lomask[x+1])) {
|
|
|
|
|
isz++; // increment inner edge size
|
|
|
|
|
lres[x]=4; // flag pixel as inner edge
|
|
|
|
|
} else {
|
|
|
|
|
res[x]=1.0f; // pixel is just part of inner mask, and it's not an edge
|
|
|
|
|
}
|
|
|
|
|
} else if(lomask[x]) { // inner mask was empty, test if outer mask is filled
|
|
|
|
|
osz++; // increment outer edge size
|
|
|
|
|
lres[x]=3; // flag pixel as outer edge
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
/* Test the LEFT edge of pixels in buffer, except corners */
|
|
|
|
|
for(x= t-(rw<<1)+1; x>=rw; x-=rw) {
|
|
|
|
|
// test if inner mask is filled
|
|
|
|
|
if(limask[x]) {
|
|
|
|
|
// test if pixel underneath, or above, are empty in the inner mask,
|
|
|
|
|
// but filled in the outer mask
|
|
|
|
|
if((!limask[x-rw] && lomask[x-rw]) || (!limask[x+rw] && lomask[x+rw])) {
|
|
|
|
|
isz++; // increment inner edge size
|
|
|
|
|
lres[x]=4; // flag pixel as inner edge
|
|
|
|
|
} else {
|
|
|
|
|
res[x]=1.0f; // pixel is just part of inner mask, and it's not an edge
|
|
|
|
|
}
|
|
|
|
|
} else if(lomask[x]) { // inner mask was empty, test if outer mask is filled
|
|
|
|
|
osz++; // increment outer edge size
|
|
|
|
|
lres[x]=3; // flag pixel as outer edge
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Test the RIGHT edge of pixels in buffer, except corners */
|
|
|
|
|
for(x= t-rw; x>rw; x-=rw) {
|
|
|
|
|
// test if inner mask is filled
|
|
|
|
|
if(limask[x]) {
|
|
|
|
|
// test if pixel underneath, or above, are empty in the inner mask,
|
|
|
|
|
// but filled in the outer mask
|
|
|
|
|
if((!limask[x-rw] && lomask[x-rw]) || (!limask[x+rw] && lomask[x+rw])) {
|
|
|
|
|
isz++; // increment inner edge size
|
|
|
|
|
lres[x]=4; // flag pixel as inner edge
|
|
|
|
|
} else {
|
|
|
|
|
res[x]=1.0f; // pixel is just part of inner mask, and it's not an edge
|
|
|
|
|
}
|
|
|
|
|
} else if(lomask[x]) { // inner mask was empty, test if outer mask is filled
|
|
|
|
|
osz++; // increment outer edge size
|
|
|
|
|
lres[x]=3; // flag pixel as outer edge
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
rsize[0]=isz; // fill in our return sizes for edges + fill
|
|
|
|
|
rsize[1]=osz;
|
|
|
|
|
rsize[2]=gsz;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void do_adjacentBleedBorders(unsigned int t, unsigned int rw, unsigned int *limask, unsigned int *lomask, unsigned int *lres, float *res, unsigned int *rsize){
|
|
|
|
|
int x;
|
|
|
|
|
unsigned int isz=0; // inner edge size
|
|
|
|
|
unsigned int osz=0; // outer edge size
|
|
|
|
|
unsigned int gsz=0; // gradient fill area size
|
|
|
|
|
/* Test the four corners */
|
|
|
|
|
/* upper left corner */
|
|
|
|
|
x=t-rw+1;
|
|
|
|
|
// test if inner mask is filled
|
|
|
|
|
if(limask[x]){
|
|
|
|
|
// test if pixel underneath, or to the right, are empty in the inner mask,
|
|
|
|
|
// but filled in the outer mask
|
|
|
|
|
if((!limask[x-rw] && lomask[x-rw]) || (!limask[x+1] && lomask[x+1])){
|
|
|
|
|
isz++; // increment inner edge size
|
|
|
|
|
lres[x]=4; // flag pixel as inner edge
|
|
|
|
|
} else {
|
|
|
|
|
res[x]=1.0f; // pixel is just part of inner mask, and it's not an edge
|
|
|
|
|
}
|
|
|
|
|
} else if(lomask[x]){ // inner mask was empty, test if outer mask is filled
|
|
|
|
|
if(!lomask[x-rw] || !lomask[x+1]) { // test if outer mask is empty underneath or to the right
|
|
|
|
|
osz++; // increment outer edge size
|
|
|
|
|
lres[x]=3; // flag pixel as outer edge
|
|
|
|
|
} else {
|
|
|
|
|
gsz++; // increment the gradient pixel count
|
|
|
|
|
lres[x]=2; // flag pixel as gradient
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
/* upper right corner */
|
|
|
|
|
x=t;
|
|
|
|
|
// test if inner mask is filled
|
|
|
|
|
if(limask[x]){
|
|
|
|
|
// test if pixel underneath, or to the left, are empty in the inner mask,
|
|
|
|
|
// but filled in the outer mask
|
|
|
|
|
if((!limask[x-rw] && lomask[x-rw]) || (!limask[x-1] && lomask[x-1])){
|
|
|
|
|
isz++; // increment inner edge size
|
|
|
|
|
lres[x]=4; // flag pixel as inner edge
|
|
|
|
|
} else {
|
|
|
|
|
res[x]=1.0f; // pixel is just part of inner mask, and it's not an edge
|
|
|
|
|
}
|
|
|
|
|
} else if(lomask[x]){ // inner mask was empty, test if outer mask is filled
|
|
|
|
|
if(!lomask[x-rw] || !lomask[x-1]) { // test if outer mask is empty underneath or to the left
|
|
|
|
|
osz++; // increment outer edge size
|
|
|
|
|
lres[x]=3; // flag pixel as outer edge
|
|
|
|
|
} else {
|
|
|
|
|
gsz++; // increment the gradient pixel count
|
|
|
|
|
lres[x]=2; // flag pixel as gradient
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
/* lower left corner */
|
|
|
|
|
x=0;
|
|
|
|
|
// test if inner mask is filled
|
|
|
|
|
if(limask[x]){
|
|
|
|
|
// test if pixel above, or to the right, are empty in the inner mask,
|
|
|
|
|
// but filled in the outer mask
|
|
|
|
|
if((!limask[x+rw] && lomask[x+rw]) || (!limask[x+1] && lomask[x+1])){
|
|
|
|
|
isz++; // increment inner edge size
|
|
|
|
|
lres[x]=4; // flag pixel as inner edge
|
|
|
|
|
} else {
|
|
|
|
|
res[x]=1.0f; // pixel is just part of inner mask, and it's not an edge
|
|
|
|
|
}
|
|
|
|
|
} else if(lomask[x]){ // inner mask was empty, test if outer mask is filled
|
|
|
|
|
if(!lomask[x+rw] || !lomask[x+1]) { // test if outer mask is empty above or to the right
|
|
|
|
|
osz++; // increment outer edge size
|
|
|
|
|
lres[x]=3; // flag pixel as outer edge
|
|
|
|
|
} else {
|
|
|
|
|
gsz++; // increment the gradient pixel count
|
|
|
|
|
lres[x]=2; // flag pixel as gradient
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
/* lower right corner */
|
|
|
|
|
x=rw-1;
|
|
|
|
|
// test if inner mask is filled
|
|
|
|
|
if(limask[x]){
|
|
|
|
|
// test if pixel above, or to the left, are empty in the inner mask,
|
|
|
|
|
// but filled in the outer mask
|
|
|
|
|
if((!limask[x+rw] && lomask[x+rw]) || (!limask[x-1] && lomask[x-1])){
|
|
|
|
|
isz++; // increment inner edge size
|
|
|
|
|
lres[x]=4; // flag pixel as inner edge
|
|
|
|
|
} else {
|
|
|
|
|
res[x]=1.0f; // pixel is just part of inner mask, and it's not an edge
|
|
|
|
|
}
|
|
|
|
|
} else if(lomask[x]){ // inner mask was empty, test if outer mask is filled
|
|
|
|
|
if(!lomask[x+rw] || !lomask[x-1]) { // test if outer mask is empty above or to the left
|
|
|
|
|
osz++; // increment outer edge size
|
|
|
|
|
lres[x]=3; // flag pixel as outer edge
|
|
|
|
|
} else {
|
|
|
|
|
gsz++; // increment the gradient pixel count
|
|
|
|
|
lres[x]=2; // flag pixel as gradient
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
/* Test the TOP row of pixels in buffer, except corners */
|
|
|
|
|
for(x= t-1; x>=(t-rw)+2; x--) {
|
|
|
|
|
// test if inner mask is filled
|
|
|
|
|
if(limask[x]) {
|
|
|
|
|
// test if pixel to the left, or to the right, are empty in the inner mask,
|
|
|
|
|
// but filled in the outer mask
|
|
|
|
|
if((!limask[x-1] && lomask[x-1]) || (!limask[x+1] && lomask[x+1])) {
|
|
|
|
|
isz++; // increment inner edge size
|
|
|
|
|
lres[x]=4; // flag pixel as inner edge
|
|
|
|
|
} else {
|
|
|
|
|
res[x]=1.0f; // pixel is just part of inner mask, and it's not an edge
|
|
|
|
|
}
|
|
|
|
|
} else if(lomask[x]) { // inner mask was empty, test if outer mask is filled
|
|
|
|
|
if(!lomask[x-1] || !lomask[x+1]) { // test if outer mask is empty to the left or to the right
|
|
|
|
|
osz++; // increment outer edge size
|
|
|
|
|
lres[x]=3; // flag pixel as outer edge
|
|
|
|
|
} else {
|
|
|
|
|
gsz++; // increment the gradient pixel count
|
|
|
|
|
lres[x]=2; // flag pixel as gradient
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Test the BOTTOM row of pixels in buffer, except corners */
|
|
|
|
|
for(x= rw-2; x; x--) {
|
|
|
|
|
// test if inner mask is filled
|
|
|
|
|
if(limask[x]) {
|
|
|
|
|
// test if pixel to the left, or to the right, are empty in the inner mask,
|
|
|
|
|
// but filled in the outer mask
|
|
|
|
|
if((!limask[x-1] && lomask[x-1]) || (!limask[x+1] && lomask[x+1])) {
|
|
|
|
|
isz++; // increment inner edge size
|
|
|
|
|
lres[x]=4; // flag pixel as inner edge
|
|
|
|
|
} else {
|
|
|
|
|
res[x]=1.0f; // pixel is just part of inner mask, and it's not an edge
|
|
|
|
|
}
|
|
|
|
|
} else if(lomask[x]) { // inner mask was empty, test if outer mask is filled
|
|
|
|
|
if(!lomask[x-1] || !lomask[x+1]) { // test if outer mask is empty to the left or to the right
|
|
|
|
|
osz++; // increment outer edge size
|
|
|
|
|
lres[x]=3; // flag pixel as outer edge
|
|
|
|
|
} else {
|
|
|
|
|
gsz++; // increment the gradient pixel count
|
|
|
|
|
lres[x]=2; // flag pixel as gradient
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
/* Test the LEFT edge of pixels in buffer, except corners */
|
|
|
|
|
for(x= t-(rw<<1)+1; x>=rw; x-=rw) {
|
|
|
|
|
// test if inner mask is filled
|
|
|
|
|
if(limask[x]) {
|
|
|
|
|
// test if pixel underneath, or above, are empty in the inner mask,
|
|
|
|
|
// but filled in the outer mask
|
|
|
|
|
if((!limask[x-rw] && lomask[x-rw]) || (!limask[x+rw] && lomask[x+rw])) {
|
|
|
|
|
isz++; // increment inner edge size
|
|
|
|
|
lres[x]=4; // flag pixel as inner edge
|
|
|
|
|
} else {
|
|
|
|
|
res[x]=1.0f; // pixel is just part of inner mask, and it's not an edge
|
|
|
|
|
}
|
|
|
|
|
} else if(lomask[x]) { // inner mask was empty, test if outer mask is filled
|
|
|
|
|
if(!lomask[x-rw] || !lomask[x+rw]) { // test if outer mask is empty underneath or above
|
|
|
|
|
osz++; // increment outer edge size
|
|
|
|
|
lres[x]=3; // flag pixel as outer edge
|
|
|
|
|
} else {
|
|
|
|
|
gsz++; // increment the gradient pixel count
|
|
|
|
|
lres[x]=2; // flag pixel as gradient
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Test the RIGHT edge of pixels in buffer, except corners */
|
|
|
|
|
for(x= t-rw; x>rw; x-=rw) {
|
|
|
|
|
// test if inner mask is filled
|
|
|
|
|
if(limask[x]) {
|
|
|
|
|
// test if pixel underneath, or above, are empty in the inner mask,
|
|
|
|
|
// but filled in the outer mask
|
|
|
|
|
if((!limask[x-rw] && lomask[x-rw]) || (!limask[x+rw] && lomask[x+rw])) {
|
|
|
|
|
isz++; // increment inner edge size
|
|
|
|
|
lres[x]=4; // flag pixel as inner edge
|
|
|
|
|
} else {
|
|
|
|
|
res[x]=1.0f; // pixel is just part of inner mask, and it's not an edge
|
|
|
|
|
}
|
|
|
|
|
} else if(lomask[x]) { // inner mask was empty, test if outer mask is filled
|
|
|
|
|
if(!lomask[x-rw] || !lomask[x+rw]) { // test if outer mask is empty underneath or above
|
|
|
|
|
osz++; // increment outer edge size
|
|
|
|
|
lres[x]=3; // flag pixel as outer edge
|
|
|
|
|
} else {
|
|
|
|
|
gsz++; // increment the gradient pixel count
|
|
|
|
|
lres[x]=2; // flag pixel as gradient
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
rsize[0]=isz; // fill in our return sizes for edges + fill
|
|
|
|
|
rsize[1]=osz;
|
|
|
|
|
rsize[2]=gsz;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void do_allKeepBorders(unsigned int t, unsigned int rw, unsigned int *limask, unsigned int *lomask, unsigned int *lres, float *res, unsigned int *rsize){
|
|
|
|
|
int x;
|
|
|
|
|
unsigned int isz=0; // inner edge size
|
|
|
|
|
unsigned int osz=0; // outer edge size
|
|
|
|
|
unsigned int gsz=0; // gradient fill area size
|
|
|
|
|
/* Test the four corners */
|
|
|
|
|
/* upper left corner */
|
|
|
|
|
x=t-rw+1;
|
|
|
|
|
// test if inner mask is filled
|
|
|
|
|
if(limask[x]){
|
|
|
|
|
// test if the inner mask is empty underneath or to the right
|
|
|
|
|
if(!limask[x-rw] || !limask[x+1]){
|
|
|
|
|
isz++; // increment inner edge size
|
|
|
|
|
lres[x]=4; // flag pixel as inner edge
|
|
|
|
|
} else {
|
|
|
|
|
res[x]=1.0f; // pixel is just part of inner mask, and it's not an edge
|
|
|
|
|
}
|
|
|
|
|
} else if(lomask[x]){ // inner mask was empty, test if outer mask is filled
|
|
|
|
|
osz++; // increment outer edge size
|
|
|
|
|
lres[x]=3; // flag pixel as outer edge
|
|
|
|
|
}
|
|
|
|
|
/* upper right corner */
|
|
|
|
|
x=t;
|
|
|
|
|
// test if inner mask is filled
|
|
|
|
|
if(limask[x]){
|
|
|
|
|
// test if the inner mask is empty underneath or to the left
|
|
|
|
|
if(!limask[x-rw] || !limask[x-1]){
|
|
|
|
|
isz++; // increment inner edge size
|
|
|
|
|
lres[x]=4; // flag pixel as inner edge
|
|
|
|
|
} else {
|
|
|
|
|
res[x]=1.0f; // pixel is just part of inner mask, and it's not an edge
|
|
|
|
|
}
|
|
|
|
|
} else if(lomask[x]){ // inner mask was empty, test if outer mask is filled
|
|
|
|
|
osz++; // increment outer edge size
|
|
|
|
|
lres[x]=3; // flag pixel as outer edge
|
|
|
|
|
}
|
|
|
|
|
/* lower left corner */
|
|
|
|
|
x=0;
|
|
|
|
|
// test if inner mask is filled
|
|
|
|
|
if(limask[x]){
|
|
|
|
|
// test if inner mask is empty above or to the right
|
|
|
|
|
if(!limask[x+rw] || !limask[x+1]){
|
|
|
|
|
isz++; // increment inner edge size
|
|
|
|
|
lres[x]=4; // flag pixel as inner edge
|
|
|
|
|
} else {
|
|
|
|
|
res[x]=1.0f; // pixel is just part of inner mask, and it's not an edge
|
|
|
|
|
}
|
|
|
|
|
} else if(lomask[x]){ // inner mask was empty, test if outer mask is filled
|
|
|
|
|
osz++; // increment outer edge size
|
|
|
|
|
lres[x]=3; // flag pixel as outer edge
|
|
|
|
|
}
|
|
|
|
|
/* lower right corner */
|
|
|
|
|
x=rw-1;
|
|
|
|
|
// test if inner mask is filled
|
|
|
|
|
if(limask[x]){
|
|
|
|
|
// test if inner mask is empty above or to the left
|
|
|
|
|
if(!limask[x+rw] || !limask[x-1]){
|
|
|
|
|
isz++; // increment inner edge size
|
|
|
|
|
lres[x]=4; // flag pixel as inner edge
|
|
|
|
|
} else {
|
|
|
|
|
res[x]=1.0f; // pixel is just part of inner mask, and it's not an edge
|
|
|
|
|
}
|
|
|
|
|
} else if(lomask[x]){ // inner mask was empty, test if outer mask is filled
|
|
|
|
|
osz++; // increment outer edge size
|
|
|
|
|
lres[x]=3; // flag pixel as outer edge
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Test the TOP row of pixels in buffer, except corners */
|
|
|
|
|
for(x= t-1; x>=(t-rw)+2; x--) {
|
|
|
|
|
// test if inner mask is filled
|
|
|
|
|
if(limask[x]) {
|
|
|
|
|
// test if inner mask is empty to the left or to the right
|
|
|
|
|
if(!limask[x-1] || !limask[x+1]) {
|
|
|
|
|
isz++; // increment inner edge size
|
|
|
|
|
lres[x]=4; // flag pixel as inner edge
|
|
|
|
|
} else {
|
|
|
|
|
res[x]=1.0f; // pixel is just part of inner mask, and it's not an edge
|
|
|
|
|
}
|
|
|
|
|
} else if(lomask[x]) { // inner mask was empty, test if outer mask is filled
|
|
|
|
|
osz++; // increment outer edge size
|
|
|
|
|
lres[x]=3; // flag pixel as outer edge
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Test the BOTTOM row of pixels in buffer, except corners */
|
|
|
|
|
for(x= rw-2; x; x--) {
|
|
|
|
|
// test if inner mask is filled
|
|
|
|
|
if(limask[x]) {
|
|
|
|
|
// test if inner mask is empty to the left or to the right
|
|
|
|
|
if(!limask[x-1] || !limask[x+1]) {
|
|
|
|
|
isz++; // increment inner edge size
|
|
|
|
|
lres[x]=4; // flag pixel as inner edge
|
|
|
|
|
} else {
|
|
|
|
|
res[x]=1.0f; // pixel is just part of inner mask, and it's not an edge
|
|
|
|
|
}
|
|
|
|
|
} else if(lomask[x]) { // inner mask was empty, test if outer mask is filled
|
|
|
|
|
osz++; // increment outer edge size
|
|
|
|
|
lres[x]=3; // flag pixel as outer edge
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
/* Test the LEFT edge of pixels in buffer, except corners */
|
|
|
|
|
for(x= t-(rw<<1)+1; x>=rw; x-=rw) {
|
|
|
|
|
// test if inner mask is filled
|
|
|
|
|
if(limask[x]) {
|
|
|
|
|
// test if inner mask is empty underneath or above
|
|
|
|
|
if(!limask[x-rw] || !limask[x+rw]) {
|
|
|
|
|
isz++; // increment inner edge size
|
|
|
|
|
lres[x]=4; // flag pixel as inner edge
|
|
|
|
|
} else {
|
|
|
|
|
res[x]=1.0f; // pixel is just part of inner mask, and it's not an edge
|
|
|
|
|
}
|
|
|
|
|
} else if(lomask[x]) { // inner mask was empty, test if outer mask is filled
|
|
|
|
|
osz++; // increment outer edge size
|
|
|
|
|
lres[x]=3; // flag pixel as outer edge
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Test the RIGHT edge of pixels in buffer, except corners */
|
|
|
|
|
for(x= t-rw; x>rw; x-=rw) {
|
|
|
|
|
// test if inner mask is filled
|
|
|
|
|
if(limask[x]) {
|
|
|
|
|
// test if inner mask is empty underneath or above
|
|
|
|
|
if(!limask[x-rw] || !limask[x+rw]) {
|
|
|
|
|
isz++; // increment inner edge size
|
|
|
|
|
lres[x]=4; // flag pixel as inner edge
|
|
|
|
|
} else {
|
|
|
|
|
res[x]=1.0f; // pixel is just part of inner mask, and it's not an edge
|
|
|
|
|
}
|
|
|
|
|
} else if(lomask[x]) { // inner mask was empty, test if outer mask is filled
|
|
|
|
|
osz++; // increment outer edge size
|
|
|
|
|
lres[x]=3; // flag pixel as outer edge
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
rsize[0]=isz; // fill in our return sizes for edges + fill
|
|
|
|
|
rsize[1]=osz;
|
|
|
|
|
rsize[2]=gsz;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void do_allBleedBorders(unsigned int t, unsigned int rw, unsigned int *limask, unsigned int *lomask, unsigned int *lres, float *res, unsigned int *rsize){
|
|
|
|
|
int x;
|
|
|
|
|
unsigned int isz=0; // inner edge size
|
|
|
|
|
unsigned int osz=0; // outer edge size
|
|
|
|
|
unsigned int gsz=0; // gradient fill area size
|
|
|
|
|
/* Test the four corners */
|
|
|
|
|
/* upper left corner */
|
|
|
|
|
x=t-rw+1;
|
|
|
|
|
// test if inner mask is filled
|
|
|
|
|
if(limask[x]){
|
|
|
|
|
// test if the inner mask is empty underneath or to the right
|
|
|
|
|
if(!limask[x-rw] || !limask[x+1]){
|
|
|
|
|
isz++; // increment inner edge size
|
|
|
|
|
lres[x]=4; // flag pixel as inner edge
|
|
|
|
|
} else {
|
|
|
|
|
res[x]=1.0f; // pixel is just part of inner mask, and it's not an edge
|
|
|
|
|
}
|
|
|
|
|
} else if(lomask[x]){ // inner mask was empty, test if outer mask is filled
|
|
|
|
|
if(!lomask[x-rw] || !lomask[x+1]) { // test if outer mask is empty underneath or to the right
|
|
|
|
|
osz++; // increment outer edge size
|
|
|
|
|
lres[x]=3; // flag pixel as outer edge
|
|
|
|
|
} else {
|
|
|
|
|
gsz++; // increment the gradient pixel count
|
|
|
|
|
lres[x]=2; // flag pixel as gradient
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
/* upper right corner */
|
|
|
|
|
x=t;
|
|
|
|
|
// test if inner mask is filled
|
|
|
|
|
if(limask[x]){
|
|
|
|
|
// test if the inner mask is empty underneath or to the left
|
|
|
|
|
if(!limask[x-rw] || !limask[x-1]){
|
|
|
|
|
isz++; // increment inner edge size
|
|
|
|
|
lres[x]=4; // flag pixel as inner edge
|
|
|
|
|
} else {
|
|
|
|
|
res[x]=1.0f; // pixel is just part of inner mask, and it's not an edge
|
|
|
|
|
}
|
|
|
|
|
} else if(lomask[x]){ // inner mask was empty, test if outer mask is filled
|
|
|
|
|
if(!lomask[x-rw] || !lomask[x-1]) { // test if outer mask is empty above or to the left
|
|
|
|
|
osz++; // increment outer edge size
|
|
|
|
|
lres[x]=3; // flag pixel as outer edge
|
|
|
|
|
} else {
|
|
|
|
|
gsz++; // increment the gradient pixel count
|
|
|
|
|
lres[x]=2; // flag pixel as gradient
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
/* lower left corner */
|
|
|
|
|
x=0;
|
|
|
|
|
// test if inner mask is filled
|
|
|
|
|
if(limask[x]){
|
|
|
|
|
// test if inner mask is empty above or to the right
|
|
|
|
|
if(!limask[x+rw] || !limask[x+1]){
|
|
|
|
|
isz++; // increment inner edge size
|
|
|
|
|
lres[x]=4; // flag pixel as inner edge
|
|
|
|
|
} else {
|
|
|
|
|
res[x]=1.0f; // pixel is just part of inner mask, and it's not an edge
|
|
|
|
|
}
|
|
|
|
|
} else if(lomask[x]){ // inner mask was empty, test if outer mask is filled
|
|
|
|
|
if(!lomask[x+rw] || !lomask[x+1]) { // test if outer mask is empty underneath or to the right
|
|
|
|
|
osz++; // increment outer edge size
|
|
|
|
|
lres[x]=3; // flag pixel as outer edge
|
|
|
|
|
} else {
|
|
|
|
|
gsz++; // increment the gradient pixel count
|
|
|
|
|
lres[x]=2; // flag pixel as gradient
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
/* lower right corner */
|
|
|
|
|
x=rw-1;
|
|
|
|
|
// test if inner mask is filled
|
|
|
|
|
if(limask[x]){
|
|
|
|
|
// test if inner mask is empty above or to the left
|
|
|
|
|
if(!limask[x+rw] || !limask[x-1]){
|
|
|
|
|
isz++; // increment inner edge size
|
|
|
|
|
lres[x]=4; // flag pixel as inner edge
|
|
|
|
|
} else {
|
|
|
|
|
res[x]=1.0f; // pixel is just part of inner mask, and it's not an edge
|
|
|
|
|
}
|
|
|
|
|
} else if(lomask[x]){ // inner mask was empty, test if outer mask is filled
|
|
|
|
|
if(!lomask[x+rw] || !lomask[x-1]) { // test if outer mask is empty underneath or to the left
|
|
|
|
|
osz++; // increment outer edge size
|
|
|
|
|
lres[x]=3; // flag pixel as outer edge
|
|
|
|
|
} else {
|
|
|
|
|
gsz++; // increment the gradient pixel count
|
|
|
|
|
lres[x]=2; // flag pixel as gradient
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
/* Test the TOP row of pixels in buffer, except corners */
|
|
|
|
|
for(x= t-1; x>=(t-rw)+2; x--) {
|
|
|
|
|
// test if inner mask is filled
|
|
|
|
|
if(limask[x]) {
|
|
|
|
|
// test if inner mask is empty to the left or to the right
|
|
|
|
|
if(!limask[x-1] || !limask[x+1]) {
|
|
|
|
|
isz++; // increment inner edge size
|
|
|
|
|
lres[x]=4; // flag pixel as inner edge
|
|
|
|
|
} else {
|
|
|
|
|
res[x]=1.0f; // pixel is just part of inner mask, and it's not an edge
|
|
|
|
|
}
|
|
|
|
|
} else if(lomask[x]) { // inner mask was empty, test if outer mask is filled
|
|
|
|
|
if(!lomask[x-1] || !lomask[x+1]) { // test if outer mask is empty to the left or to the right
|
|
|
|
|
osz++; // increment outer edge size
|
|
|
|
|
lres[x]=3; // flag pixel as outer edge
|
|
|
|
|
} else {
|
|
|
|
|
gsz++; // increment the gradient pixel count
|
|
|
|
|
lres[x]=2; // flag pixel as gradient
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Test the BOTTOM row of pixels in buffer, except corners */
|
|
|
|
|
for(x= rw-2; x; x--) {
|
|
|
|
|
// test if inner mask is filled
|
|
|
|
|
if(limask[x]) {
|
|
|
|
|
// test if inner mask is empty to the left or to the right
|
|
|
|
|
if(!limask[x-1] || !limask[x+1]) {
|
|
|
|
|
isz++; // increment inner edge size
|
|
|
|
|
lres[x]=4; // flag pixel as inner edge
|
|
|
|
|
} else {
|
|
|
|
|
res[x]=1.0f; // pixel is just part of inner mask, and it's not an edge
|
|
|
|
|
}
|
|
|
|
|
} else if(lomask[x]) { // inner mask was empty, test if outer mask is filled
|
|
|
|
|
if(!lomask[x-1] || !lomask[x+1]) { // test if outer mask is empty to the left or to the right
|
|
|
|
|
osz++; // increment outer edge size
|
|
|
|
|
lres[x]=3; // flag pixel as outer edge
|
|
|
|
|
} else {
|
|
|
|
|
gsz++; // increment the gradient pixel count
|
|
|
|
|
lres[x]=2; // flag pixel as gradient
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
/* Test the LEFT edge of pixels in buffer, except corners */
|
|
|
|
|
for(x= t-(rw<<1)+1; x>=rw; x-=rw) {
|
|
|
|
|
// test if inner mask is filled
|
|
|
|
|
if(limask[x]) {
|
|
|
|
|
// test if inner mask is empty underneath or above
|
|
|
|
|
if(!limask[x-rw] || !limask[x+rw]) {
|
|
|
|
|
isz++; // increment inner edge size
|
|
|
|
|
lres[x]=4; // flag pixel as inner edge
|
|
|
|
|
} else {
|
|
|
|
|
res[x]=1.0f; // pixel is just part of inner mask, and it's not an edge
|
|
|
|
|
}
|
|
|
|
|
} else if(lomask[x]) { // inner mask was empty, test if outer mask is filled
|
|
|
|
|
if(!lomask[x-rw] || !lomask[x+rw]) { // test if outer mask is empty underneath or above
|
|
|
|
|
osz++; // increment outer edge size
|
|
|
|
|
lres[x]=3; // flag pixel as outer edge
|
|
|
|
|
} else {
|
|
|
|
|
gsz++; // increment the gradient pixel count
|
|
|
|
|
lres[x]=2; // flag pixel as gradient
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Test the RIGHT edge of pixels in buffer, except corners */
|
|
|
|
|
for(x= t-rw; x>rw; x-=rw) {
|
|
|
|
|
// test if inner mask is filled
|
|
|
|
|
if(limask[x]) {
|
|
|
|
|
// test if inner mask is empty underneath or above
|
|
|
|
|
if(!limask[x-rw] || !limask[x+rw]) {
|
|
|
|
|
isz++; // increment inner edge size
|
|
|
|
|
lres[x]=4; // flag pixel as inner edge
|
|
|
|
|
} else {
|
|
|
|
|
res[x]=1.0f; // pixel is just part of inner mask, and it's not an edge
|
|
|
|
|
}
|
|
|
|
|
} else if(lomask[x]) { // inner mask was empty, test if outer mask is filled
|
|
|
|
|
if(!lomask[x-rw] || !lomask[x+rw]) { // test if outer mask is empty underneath or above
|
|
|
|
|
osz++; // increment outer edge size
|
|
|
|
|
lres[x]=3; // flag pixel as outer edge
|
|
|
|
|
} else {
|
|
|
|
|
gsz++; // increment the gradient pixel count
|
|
|
|
|
lres[x]=2; // flag pixel as gradient
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
rsize[0]=isz; // fill in our return sizes for edges + fill
|
|
|
|
|
rsize[1]=osz;
|
|
|
|
|
rsize[2]=gsz;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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){
|
|
|
|
|
int x; // x = pixel loop counter
|
|
|
|
|
int a; // a = pixel loop counter
|
|
|
|
|
int dx; // dx = delta x
|
|
|
|
|
int pix_prevRow; // pix_prevRow = pixel one row behind the one we are testing in a loop
|
|
|
|
|
int pix_nextRow; // pix_nextRow = pixel one row in front of the one we are testing in a loop
|
|
|
|
|
int pix_prevCol; // pix_prevCol = pixel one column behind the one we are testing in a loop
|
|
|
|
|
int pix_nextCol; // pix_nextCol = pixel one column in front of the one we are testing in a loop
|
|
|
|
|
/* Test all rows between the FIRST and LAST rows, excluding left and right edges */
|
|
|
|
|
for(x= (t-rw)+1, dx=x-(rw-2); dx>rw; x-=rw,dx-=rw) {
|
|
|
|
|
a=x-2;
|
|
|
|
|
pix_prevRow=a+rw;
|
|
|
|
|
pix_nextRow=a-rw;
|
|
|
|
|
pix_prevCol=a+1;
|
|
|
|
|
pix_nextCol=a-1;
|
|
|
|
|
while(a>dx-2) {
|
|
|
|
|
if(!limask[a]) { // if the inner mask is empty
|
|
|
|
|
if(lomask[a]) { // if the outer mask is full
|
|
|
|
|
/*
|
|
|
|
|
Next we test all 4 directions around the current pixel: next/prev/up/down
|
|
|
|
|
The test ensures that the outer mask is empty and that the inner mask
|
|
|
|
|
is also empty. If both conditions are true for any one of the 4 adjacent pixels
|
|
|
|
|
then the current pixel is counted as being a true outer edge pixel.
|
|
|
|
|
*/
|
|
|
|
|
if((!lomask[pix_nextCol] && !limask[pix_nextCol]) || \
|
|
|
|
|
(!lomask[pix_prevCol] && !limask[pix_prevCol]) || \
|
|
|
|
|
(!lomask[pix_nextRow] && !limask[pix_nextRow]) || \
|
|
|
|
|
(!lomask[pix_prevRow] && !limask[pix_prevRow])) {
|
|
|
|
|
in_osz++; // increment the outer boundary pixel count
|
|
|
|
|
lres[a]=3; // flag pixel as part of outer edge
|
|
|
|
|
} else { // it's not a boundary pixel, but it is a gradient pixel
|
|
|
|
|
in_gsz++; // increment the gradient pixel count
|
|
|
|
|
lres[a]=2; // flag pixel as gradient
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
if(!limask[pix_nextCol] || !limask[pix_prevCol] || !limask[pix_nextRow] || !limask[pix_prevRow]) {
|
|
|
|
|
in_isz++; // increment the inner boundary pixel count
|
|
|
|
|
lres[a]=4; // flag pixel as part of inner edge
|
|
|
|
|
} else {
|
|
|
|
|
res[a]=1.0f; // pixel is part of inner mask, but not at an edge
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
a--;
|
|
|
|
|
pix_prevRow--;
|
|
|
|
|
pix_nextRow--;
|
|
|
|
|
pix_prevCol--;
|
|
|
|
|
pix_nextCol--;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
rsize[0]=in_isz; // fill in our return sizes for edges + fill
|
|
|
|
|
rsize[1]=in_osz;
|
|
|
|
|
rsize[2]=in_gsz;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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){
|
|
|
|
|
int x; // x = pixel loop counter
|
|
|
|
|
int a; // a = pixel loop counter
|
|
|
|
|
int dx; // dx = delta x
|
|
|
|
|
int pix_prevRow; // pix_prevRow = pixel one row behind the one we are testing in a loop
|
|
|
|
|
int pix_nextRow; // pix_nextRow = pixel one row in front of the one we are testing in a loop
|
|
|
|
|
int pix_prevCol; // pix_prevCol = pixel one column behind the one we are testing in a loop
|
|
|
|
|
int pix_nextCol; // pix_nextCol = pixel one column in front of the one we are testing in a loop
|
|
|
|
|
/* Test all rows between the FIRST and LAST rows, excluding left and right edges */
|
|
|
|
|
for(x= (t-rw)+1, dx=x-(rw-2); dx>rw; x-=rw,dx-=rw) {
|
|
|
|
|
a=x-2;
|
|
|
|
|
pix_prevRow=a+rw;
|
|
|
|
|
pix_nextRow=a-rw;
|
|
|
|
|
pix_prevCol=a+1;
|
|
|
|
|
pix_nextCol=a-1;
|
|
|
|
|
while(a>dx-2) {
|
|
|
|
|
if(!limask[a]) { // if the inner mask is empty
|
|
|
|
|
if(lomask[a]) { // if the outer mask is full
|
|
|
|
|
/*
|
|
|
|
|
Next we test all 4 directions around the current pixel: next/prev/up/down
|
|
|
|
|
The test ensures that the outer mask is empty and that the inner mask
|
|
|
|
|
is also empty. If both conditions are true for any one of the 4 adjacent pixels
|
|
|
|
|
then the current pixel is counted as being a true outer edge pixel.
|
|
|
|
|
*/
|
|
|
|
|
if((!lomask[pix_nextCol] && !limask[pix_nextCol]) || \
|
|
|
|
|
(!lomask[pix_prevCol] && !limask[pix_prevCol]) || \
|
|
|
|
|
(!lomask[pix_nextRow] && !limask[pix_nextRow]) || \
|
|
|
|
|
(!lomask[pix_prevRow] && !limask[pix_prevRow])) {
|
|
|
|
|
in_osz++; // increment the outer boundary pixel count
|
|
|
|
|
lres[a]=3; // flag pixel as part of outer edge
|
|
|
|
|
} else { // it's not a boundary pixel, but it is a gradient pixel
|
|
|
|
|
in_gsz++; // increment the gradient pixel count
|
|
|
|
|
lres[a]=2; // flag pixel as gradient
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
if((!limask[pix_nextCol] && lomask[pix_nextCol]) || \
|
|
|
|
|
(!limask[pix_prevCol] && lomask[pix_prevCol]) || \
|
|
|
|
|
(!limask[pix_nextRow] && lomask[pix_nextRow]) || \
|
|
|
|
|
(!limask[pix_prevRow] && lomask[pix_prevRow])) {
|
|
|
|
|
in_isz++; // increment the inner boundary pixel count
|
|
|
|
|
lres[a]=4; // flag pixel as part of inner edge
|
|
|
|
|
} else {
|
|
|
|
|
res[a]=1.0f; // pixel is part of inner mask, but not at an edge
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
a--;
|
|
|
|
|
pix_prevRow--; // advance all four "surrounding" pixel pointers
|
|
|
|
|
pix_nextRow--;
|
|
|
|
|
pix_prevCol--;
|
|
|
|
|
pix_nextCol--;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
rsize[0]=in_isz; // fill in our return sizes for edges + fill
|
|
|
|
|
rsize[1]=in_osz;
|
|
|
|
|
rsize[2]=in_gsz;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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){
|
|
|
|
|
int x; // x = pixel loop counter
|
|
|
|
|
int a; // a = temporary pixel index buffer loop counter
|
|
|
|
|
unsigned int ud; // ud = unscaled edge distance
|
|
|
|
|
unsigned int dmin; // dmin = minimun edge distance
|
|
|
|
|
|
|
|
|
|
unsigned int rsl; // long used for finding fast 1.0/sqrt
|
|
|
|
|
unsigned int gradientFillOffset;
|
|
|
|
|
unsigned int innerAccum=0; // for looping inner edge pixel indexes, represents current position from offset
|
|
|
|
|
unsigned int outerAccum=0; // for looping outer edge pixel indexes, represents current position from offset
|
|
|
|
|
unsigned int gradientAccum=0; // for looping gradient pixel indexes, represents current position from offset
|
|
|
|
|
/*
|
|
|
|
|
Here we compute the size of buffer needed to hold (row,col) coordinates
|
|
|
|
|
for each pixel previously determined to be either gradient, inner edge,
|
|
|
|
|
or outer edge.
|
|
|
|
|
|
|
|
|
|
Allocation is done by requesting 4 bytes "sizeof(int)" per pixel, even
|
|
|
|
|
though gbuf[] is declared as unsigned short* (2 bytes) because we don't
|
|
|
|
|
store the pixel indexes, we only store x,y location of pixel in buffer.
|
|
|
|
|
|
|
|
|
|
This does make the assumption that x and y can fit in 16 unsigned bits
|
|
|
|
|
so if Blender starts doing renders greater than 65536 in either direction
|
|
|
|
|
this will need to allocate gbuf[] as unsigned int* and allocate 8 bytes
|
|
|
|
|
per flagged pixel.
|
|
|
|
|
|
|
|
|
|
In general, the buffer on-screen:
|
|
|
|
|
|
|
|
|
|
Example: 9 by 9 pixel block
|
|
|
|
|
|
|
|
|
|
. = pixel non-white in both outer and inner mask
|
|
|
|
|
o = pixel white in outer, but not inner mask, adjacent to "." pixel
|
|
|
|
|
g = pixel white in outer, but not inner mask, not adjacent to "." pixel
|
|
|
|
|
i = pixel white in inner mask, adjacent to "g" or "." pixel
|
|
|
|
|
F = pixel white in inner mask, only adjacent to other pixels white in the inner mask
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
......... <----- pixel #80
|
|
|
|
|
..oooo...
|
|
|
|
|
.oggggo..
|
|
|
|
|
.oggiggo.
|
|
|
|
|
.ogiFigo.
|
|
|
|
|
.oggiggo.
|
|
|
|
|
.oggggo..
|
|
|
|
|
..oooo...
|
|
|
|
|
pixel #00 -----> .........
|
|
|
|
|
|
|
|
|
|
gsz = 18 (18 "g" pixels above)
|
|
|
|
|
isz = 4 (4 "i" pixels above)
|
|
|
|
|
osz = 18 (18 "o" pixels above)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
The memory in gbuf[] after filling will look like this:
|
|
|
|
|
|
|
|
|
|
gradientFillOffset (0 pixels) innerEdgeOffset (18 pixels) outerEdgeOffset (22 pixels)
|
|
|
|
|
/ / /
|
|
|
|
|
/ / /
|
|
|
|
|
|X Y X Y X Y X Y > <X Y X Y > <X Y X Y X Y > <X Y X Y | <- (x,y)
|
|
|
|
|
+--------------------------------> <----------------> <------------------------> <----------------+
|
|
|
|
|
|0 2 4 6 8 10 12 14 > ... <68 70 72 74 > ... <80 82 84 86 88 90 > ... <152 154 156 158 | <- bytes
|
|
|
|
|
+--------------------------------> <----------------> <------------------------> <----------------+
|
|
|
|
|
|g0 g0 g1 g1 g2 g2 g3 g3 > <g17 g17 i0 i0 > <i2 i2 i3 i3 o0 o0 > <o16 o16 o17 o17 | <- pixel
|
|
|
|
|
/ / /
|
|
|
|
|
/ / /
|
|
|
|
|
/ / /
|
|
|
|
|
+---------- gradientAccum (18) ---------+ +--- innerAccum (22) ---+ +--- outerAccum (40) ---+
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Ultimately we do need the pixel's memory buffer index to set the output
|
|
|
|
|
pixel color, but it's faster to reconstruct the memory buffer location
|
|
|
|
|
each iteration of the final gradient calculation than it is to deconstruct
|
|
|
|
|
a memory location into x,y pairs each round.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
gradientFillOffset=0; // since there are likely "more" of these, put it first. :)
|
|
|
|
|
*innerEdgeOffset=gradientFillOffset+gsz; // set start of inner edge indexes
|
|
|
|
|
*outerEdgeOffset=(*innerEdgeOffset)+isz; // set start of outer edge indexes
|
|
|
|
|
/* set the accumulators to correct positions */ // set up some accumulator variables for loops
|
|
|
|
|
gradientAccum = gradientFillOffset; // each accumulator variable starts at its respective
|
|
|
|
|
innerAccum = *innerEdgeOffset; // section's offset so when we start filling, each
|
|
|
|
|
outerAccum = *outerEdgeOffset; // section fills up it's allocated space in gbuf
|
|
|
|
|
//uses dmin=row, rsl=col
|
|
|
|
|
for(x=0,dmin=0; x<t; x+=rw,dmin++) {
|
|
|
|
|
for(rsl=0; rsl<rw; rsl++) {
|
|
|
|
|
a=x+rsl;
|
|
|
|
|
if(lres[a]==2) { // it is a gradient pixel flagged by 2
|
|
|
|
|
ud=gradientAccum<<1; // double the index to reach correct unsigned short location
|
|
|
|
|
gbuf[ud]=dmin; // insert pixel's row into gradient pixel location buffer
|
|
|
|
|
gbuf[ud+1]=rsl; // insert pixel's column into gradient pixel location buffer
|
|
|
|
|
gradientAccum++; // increment gradient index buffer pointer
|
|
|
|
|
} else if(lres[a]==3) { // it is an outer edge pixel flagged by 3
|
|
|
|
|
ud=outerAccum<<1; // double the index to reach correct unsigned short location
|
|
|
|
|
gbuf[ud]=dmin; // insert pixel's row into outer edge pixel location buffer
|
|
|
|
|
gbuf[ud+1]=rsl; // insert pixel's column into outer edge pixel location buffer
|
|
|
|
|
outerAccum++; // increment outer edge index buffer pointer
|
|
|
|
|
res[a]=0.0f; // set output pixel intensity now since it won't change later
|
|
|
|
|
} else if(lres[a]==4) { // it is an inner edge pixel flagged by 4
|
|
|
|
|
ud=innerAccum<<1; // double int index to reach correct unsigned short location
|
|
|
|
|
gbuf[ud]=dmin; // insert pixel's row into inner edge pixel location buffer
|
|
|
|
|
gbuf[ud+1]=rsl; // insert pixel's column into inner edge pixel location buffer
|
|
|
|
|
innerAccum++; // increment inner edge index buffer pointer
|
|
|
|
|
res[a]=1.0f; // set output pixel intensity now since it won't change later
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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){
|
|
|
|
|
int x; // x = pixel loop counter
|
|
|
|
|
int a; // a = temporary pixel index buffer loop counter
|
|
|
|
|
int fsz; // size of the frame
|
|
|
|
|
unsigned int rsl; // long used for finding fast 1.0/sqrt
|
|
|
|
|
float rsf; // float used for finding fast 1.0/sqrt
|
|
|
|
|
const float rsopf = 1.5f; // constant float used for finding fast 1.0/sqrt
|
|
|
|
|
|
|
|
|
|
unsigned int gradientFillOffset;
|
|
|
|
|
unsigned int t;
|
|
|
|
|
unsigned int ud; // ud = unscaled edge distance
|
|
|
|
|
unsigned int dmin; // dmin = minimun edge distance
|
|
|
|
|
float odist; // odist = current outer edge distance
|
|
|
|
|
float idist; // idist = current inner edge distance
|
|
|
|
|
int dx; // dx = X-delta (used for distance proportion calculation)
|
|
|
|
|
int dy; // dy = Y-delta (used for distance proportion calculation)
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
The general algorithm used to color each gradient pixel is:
|
|
|
|
|
|
|
|
|
|
1.) Loop through all gradient pixels.
|
|
|
|
|
A.) For each gradient pixel:
|
|
|
|
|
a.) Loop though all outside edge pixels, looking for closest one
|
|
|
|
|
to the gradient pixel we are in.
|
|
|
|
|
b.) Loop through all inside edge pixels, looking for closest one
|
|
|
|
|
to the gradient pixel we are in.
|
|
|
|
|
c.) Find proportion of distance from gradient pixel to inside edge
|
|
|
|
|
pixel compared to sum of distance to inside edge and distance to
|
|
|
|
|
outside edge.
|
|
|
|
|
|
|
|
|
|
In an image where:
|
|
|
|
|
. = blank (black) pixels, not covered by inner mask or outer mask
|
|
|
|
|
+ = desired gradient pixels, covered only by outer mask
|
|
|
|
|
* = white full mask pixels, covered by at least inner mask
|
|
|
|
|
|
|
|
|
|
...............................
|
|
|
|
|
...............+++++++++++.....
|
|
|
|
|
...+O++++++..++++++++++++++....
|
|
|
|
|
..+++\++++++++++++++++++++.....
|
|
|
|
|
.+++++G+++++++++*******+++.....
|
|
|
|
|
.+++++|+++++++*********+++.....
|
|
|
|
|
.++***I****************+++.....
|
|
|
|
|
.++*******************+++......
|
|
|
|
|
.+++*****************+++.......
|
|
|
|
|
..+++***************+++........
|
|
|
|
|
....+++**********+++...........
|
|
|
|
|
......++++++++++++.............
|
|
|
|
|
...............................
|
|
|
|
|
|
|
|
|
|
O = outside edge pixel
|
|
|
|
|
\
|
|
|
|
|
G = gradient pixel
|
|
|
|
|
|
|
|
|
|
|
I = inside edge pixel
|
|
|
|
|
|
|
|
|
|
__
|
|
|
|
|
*note that IO does not need to be a straight line, in fact
|
|
|
|
|
many cases can arise where straight lines do not work
|
|
|
|
|
correctly.
|
|
|
|
|
|
|
|
|
|
__ __ __
|
|
|
|
|
d.) Pixel color is assigned as |GO| / ( |GI| + |GO| )
|
|
|
|
|
|
|
|
|
|
The implementation does not compute distance, but the reciprocal of the
|
|
|
|
|
distance. This is done to avoid having to compute a square root, as a
|
|
|
|
|
reciprocal square root can be computed faster. Therefore, the code computes
|
|
|
|
|
pixel color as |GI| / (|GI| + |GO|). Since these are reciprocals, GI serves the
|
|
|
|
|
purpose of GO for the proportion calculation.
|
|
|
|
|
|
|
|
|
|
For the purposes of the minimun distance comparisons, we only check
|
|
|
|
|
the sums-of-squares against eachother, since they are in the same
|
|
|
|
|
mathematical sort-order as if we did go ahead and take square roots
|
|
|
|
|
|
|
|
|
|
Loop through all gradient pixels.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
for(x= gsz-1; x>=0; x--) {
|
|
|
|
|
gradientFillOffset=x<<1;
|
|
|
|
|
t=gbuf[gradientFillOffset]; // calculate column of pixel indexed by gbuf[x]
|
|
|
|
|
fsz=gbuf[gradientFillOffset+1]; // calculate row of pixel indexed by gbuf[x]
|
|
|
|
|
dmin=0xffffffff; // reset min distance to edge pixel
|
|
|
|
|
for(a=outerEdgeOffset+osz-1; a>=outerEdgeOffset; a--) { // loop through all outer edge buffer pixels
|
|
|
|
|
ud=a<<1;
|
|
|
|
|
dy=t-gbuf[ud]; // set dx to gradient pixel column - outer edge pixel row
|
|
|
|
|
dx=fsz-gbuf[ud+1]; // set dy to gradient pixel row - outer edge pixel column
|
|
|
|
|
ud=dx*dx+dy*dy; // compute sum of squares
|
|
|
|
|
if(ud<dmin) { // if our new sum of squares is less than the current minimum
|
|
|
|
|
dmin=ud; // set a new minimum equal to the new lower value
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
odist=(float)(dmin); // cast outer min to a float
|
|
|
|
|
rsf=odist*0.5f; //
|
|
|
|
|
rsl=*(unsigned int*)&odist; // use some peculiar properties of the way bits are stored
|
|
|
|
|
rsl=0x5f3759df-(rsl>>1); // in floats vs. unsigned ints to compute an approximate
|
|
|
|
|
odist=*(float*)&rsl; // reciprocal square root
|
|
|
|
|
odist=odist*(rsopf-(rsf*odist*odist)); // -- ** this line can be iterated for more accuracy ** --
|
|
|
|
|
dmin=0xffffffff; // reset min distance to edge pixel
|
|
|
|
|
for(a= innerEdgeOffset+isz-1; a>=innerEdgeOffset; a--) { // loop through all inside edge pixels
|
|
|
|
|
ud=a<<1;
|
|
|
|
|
dy=t-gbuf[ud]; // compute delta in Y from gradient pixel to inside edge pixel
|
|
|
|
|
dx=fsz-gbuf[ud+1]; // compute delta in X from gradient pixel to inside edge pixel
|
|
|
|
|
ud=dx*dx+dy*dy; // compute sum of squares
|
|
|
|
|
if(ud<dmin) { // if our new sum of squares is less than the current minimum we've found
|
|
|
|
|
dmin=ud; // set a new minimum equal to the new lower value
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
idist=(float)(dmin); // cast inner min to a float
|
|
|
|
|
rsf=idist*0.5f; //
|
|
|
|
|
rsl=*(unsigned int*)&idist; //
|
|
|
|
|
rsl=0x5f3759df-(rsl>>1); // see notes above
|
|
|
|
|
idist=*(float*)&rsl; //
|
|
|
|
|
idist=idist*(rsopf-(rsf*idist*idist)); //
|
|
|
|
|
/*
|
|
|
|
|
Note once again that since we are using reciprocals of distance values our
|
|
|
|
|
proportion is already the correct intensity, and does not need to be
|
|
|
|
|
subracted from 1.0 like it would have if we used real distances.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
Here we reconstruct the pixel's memory location in the CompBuf by
|
|
|
|
|
Pixel Index = Pixel Column + ( Pixel Row * Row Width )
|
|
|
|
|
*/
|
|
|
|
|
res[gbuf[gradientFillOffset+1]+(gbuf[gradientFillOffset]*rw)]=(idist/(idist+odist)); //set intensity
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void node_composit_exec_doubleedgemask(void *UNUSED(data), bNode *node, bNodeStack **in, bNodeStack **out) {
|
|
|
|
|
|
|
|
|
|
float *imask; // imask = pointer to inner mask pixel buffer
|
|
|
|
|
float *omask; // omask = pointer to outer mask pixel buffer
|
|
|
|
|
float *res; // res = pointer to output mask
|
|
|
|
|
|
|
|
|
|
unsigned int *lres; // lres = unsigned int pointer to output pixel buffer (for bit operations)
|
|
|
|
|
unsigned int *limask; // limask = unsigned int pointer to inner mask (for bit operations)
|
|
|
|
|
unsigned int *lomask; // lomask = unsigned int pointer to outer mask (for bit operations)
|
|
|
|
|
|
|
|
|
|
int rw; // rw = pixel row width
|
|
|
|
|
int t; // t = total number of pixels in buffer - 1 (used for loop starts)
|
|
|
|
|
int fsz; // size of the frame
|
|
|
|
|
|
|
|
|
|
unsigned int isz=0; // size (in pixels) of inside edge pixel index buffer
|
|
|
|
|
unsigned int osz=0; // size (in pixels) of outside edge pixel index buffer
|
|
|
|
|
unsigned int gsz=0; // size (in pixels) of gradient pixel index buffer
|
|
|
|
|
unsigned int rsize[3]; // size storage to pass to helper functions
|
|
|
|
|
unsigned int innerEdgeOffset=0; // offset into final buffer where inner edge pixel indexes start
|
|
|
|
|
unsigned int outerEdgeOffset=0; // offset into final buffer where outer edge pixel indexes start
|
|
|
|
|
|
|
|
|
|
unsigned short *gbuf; // gradient/inner/outer pixel location index buffer
|
|
|
|
|
|
|
|
|
|
CompBuf *cbuf; // pointer, will be set to inner mask data
|
|
|
|
|
CompBuf *dbuf; // pointer, will be set to outer mask data
|
|
|
|
|
CompBuf *stackbuf; // pointer, will get allocated as output buffer
|
|
|
|
|
|
|
|
|
|
if(out[0]->hasoutput==0) { // if the node's output socket is not connected to anything...
|
|
|
|
|
return; // do not execute any further, just exit the node immediately
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if(in[0]->data && in[1]->data) { // if both input sockets have some data coming in...
|
|
|
|
|
cbuf= in[0]->data; // get a pointer to the inner mask data
|
|
|
|
|
dbuf= in[1]->data; // get a pointer to the outer mask data
|
|
|
|
|
if(cbuf->type!=CB_VAL || dbuf->type!=CB_VAL) { // if either input socket has an incorrect data type coming in
|
|
|
|
|
return; // exit the node immediately
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
t=(cbuf->x*cbuf->y)-1; // determine size of the frame
|
|
|
|
|
|
|
|
|
|
stackbuf= alloc_compbuf(cbuf->x, cbuf->y, CB_VAL, 1); // allocate the output buffer
|
|
|
|
|
|
|
|
|
|
imask= cbuf->rect; // set the inner mask
|
|
|
|
|
omask= dbuf->rect; // set the outer mask
|
|
|
|
|
res= stackbuf->rect; // set output pointer
|
|
|
|
|
lres= (unsigned int*)res; // unsigned int pointer to output buffer (for bit level ops)
|
|
|
|
|
limask=(unsigned int*)imask; // unsigned int pointer to input mask (for bit level ops)
|
|
|
|
|
lomask=(unsigned int*)omask; // unsigned int pointer to output mask (for bit level ops)
|
|
|
|
|
rw= cbuf->x; // width of a row of pixels
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
The whole buffer is broken up into 4 parts. The four CORNERS, the FIRST and LAST rows, the
|
|
|
|
|
LEFT and RIGHT edges (excluding the corner pixels), and all OTHER rows.
|
|
|
|
|
This allows for quick computation of outer edge pixels where
|
|
|
|
|
a screen edge pixel is marked to be gradient.
|
|
|
|
|
|
|
|
|
|
The pixel type (gradient vs inner-edge vs outer-edge) tests change
|
|
|
|
|
depending on the user selected "Inner Edge Mode" and the user selected
|
|
|
|
|
"Buffer Edge Mode" on the node's GUI. There are 4 sets of basically the
|
|
|
|
|
same algorithm:
|
|
|
|
|
|
|
|
|
|
1.) Inner Edge -> Adjacent Only
|
|
|
|
|
Buffer Edge -> Keep Inside
|
|
|
|
|
|
|
|
|
|
2.) Inner Edge -> Adjacent Only
|
|
|
|
|
Buffer Edge -> Bleed Out
|
|
|
|
|
|
|
|
|
|
3.) Inner Edge -> All
|
|
|
|
|
Buffer Edge -> Keep Inside
|
|
|
|
|
|
|
|
|
|
4.) Inner Edge -> All
|
|
|
|
|
Buffer Edge -> Bleed Out
|
|
|
|
|
|
|
|
|
|
Each version has slightly different criteria for detecting an edge pixel.
|
|
|
|
|
*/
|
|
|
|
|
if(node->custom2) { // if "adjacent only" inner edge mode is turned on
|
|
|
|
|
if(node->custom1) { // if "keep inside" buffer edge mode is turned on
|
|
|
|
|
do_adjacentKeepBorders(t,rw,limask,lomask,lres,res,rsize);
|
|
|
|
|
}else{ // "bleed out" buffer edge mode is turned on
|
|
|
|
|
do_adjacentBleedBorders(t,rw,limask,lomask,lres,res,rsize);
|
|
|
|
|
}
|
|
|
|
|
isz=rsize[0]; // set up inner edge, outer edge, and gradient buffer sizes after border pass
|
|
|
|
|
osz=rsize[1];
|
|
|
|
|
gsz=rsize[2];
|
|
|
|
|
// detect edges in all non-border pixels in the buffer
|
|
|
|
|
do_adjacentEdgeDetection(t,rw,limask,lomask,lres,res,rsize,isz,osz,gsz);
|
|
|
|
|
}else{ // "all" inner edge mode is turned on
|
|
|
|
|
if(node->custom1) { // if "keep inside" buffer edge mode is turned on
|
|
|
|
|
do_allKeepBorders(t,rw,limask,lomask,lres,res,rsize);
|
|
|
|
|
}else{ // "bleed out" buffer edge mode is turned on
|
|
|
|
|
do_allBleedBorders(t,rw,limask,lomask,lres,res,rsize);
|
|
|
|
|
}
|
|
|
|
|
isz=rsize[0]; // set up inner edge, outer edge, and gradient buffer sizes after border pass
|
|
|
|
|
osz=rsize[1];
|
|
|
|
|
gsz=rsize[2];
|
|
|
|
|
// detect edges in all non-border pixels in the buffer
|
|
|
|
|
do_allEdgeDetection(t,rw,limask,lomask,lres,res,rsize,isz,osz,gsz);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
isz=rsize[0]; // set edge and gradient buffer sizes once again...
|
|
|
|
|
osz=rsize[1]; // the sizes in rsize[] have been modified (always increased)
|
|
|
|
|
gsz=rsize[2]; // by the do_*EdgeDetection() function.
|
|
|
|
|
|
|
|
|
|
// quick check for existance of edges in the buffer...
|
|
|
|
|
// if we don't have any one of the three sizes, the other two make no difference visually,
|
|
|
|
|
// so we can just pass the inner input buffer back as output.
|
|
|
|
|
if(!gsz || !isz || !osz) {
|
|
|
|
|
out[0]->data= stackbuf; // point the node output buffer to our filled buffer
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
fsz=gsz+isz+osz; // calculate size of pixel index buffer needed
|
|
|
|
|
gbuf= MEM_mallocN(fsz*sizeof(int), "grd buf"); // allocate edge/gradient pixel index buffer
|
|
|
|
|
|
|
|
|
|
do_createEdgeLocationBuffer(t,rw,lres,res,gbuf,&innerEdgeOffset,&outerEdgeOffset,isz,gsz);
|
|
|
|
|
do_fillGradientBuffer(rw,res,gbuf,isz,osz,gsz,innerEdgeOffset,outerEdgeOffset);
|
|
|
|
|
|
|
|
|
|
MEM_freeN(gbuf); // free the gradient index buffer
|
|
|
|
|
out[0]->data= stackbuf; // point the node output buffer to our filled buffer
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void register_node_type_cmp_doubleedgemask(bNodeTreeType *ttype) {
|
|
|
|
|
static bNodeType ntype; // allocate a node type data structure
|
|
|
|
|
|
|
|
|
|
node_type_base(ttype, &ntype, CMP_NODE_DOUBLEEDGEMASK, "Double Edge Mask", NODE_CLASS_OP_FILTER, NODE_OPTIONS);
|
|
|
|
|
node_type_socket_templates(&ntype, cmp_node_doubleedgemask_in, cmp_node_doubleedgemask_out);
|
|
|
|
|
node_type_size(&ntype, 210, 210, 210);
|
|
|
|
|
node_type_exec(&ntype, node_composit_exec_doubleedgemask);
|
|
|
|
|
|
|
|
|
|
nodeRegisterType(ttype, &ntype);
|
|
|
|
|
}
|