Page MenuHome

dem.patch

Authored By
Thomas Dinges (dingto)
Nov 13 2013, 4:06 PM
Size
44 KB
Subscribers
None

dem.patch

Index: source/blender/blenkernel/BKE_node.h
===================================================================
--- source/blender/blenkernel/BKE_node.h (revision 41530)
+++ source/blender/blenkernel/BKE_node.h (working copy)
@@ -567,6 +567,7 @@
#define CMP_NODE_COLOR_MATTE 259
#define CMP_NODE_COLORBALANCE 260
#define CMP_NODE_HUECORRECT 261
+#define CMP_NODE_DBLEDGMATTE 262
#define CMP_NODE_GLARE 301
#define CMP_NODE_TONEMAP 302
Index: source/blender/blenkernel/intern/node.c
===================================================================
--- source/blender/blenkernel/intern/node.c (revision 41530)
+++ source/blender/blenkernel/intern/node.c (working copy)
@@ -1820,6 +1820,7 @@
register_node_type_cmp_vecblur(ntypelist);
register_node_type_cmp_dilateerode(ntypelist);
register_node_type_cmp_defocus(ntypelist);
+ register_node_type_cmp_dbledgmatte(ntypelist);
register_node_type_cmp_valtorgb(ntypelist);
register_node_type_cmp_rgbtobw(ntypelist);
Index: source/blender/makesrna/intern/rna_nodetree_types.h
===================================================================
--- source/blender/makesrna/intern/rna_nodetree_types.h (revision 41530)
+++ source/blender/makesrna/intern/rna_nodetree_types.h (working copy)
@@ -96,6 +96,7 @@
DefNode( CompositorNode, CMP_NODE_SPLITVIEWER, def_cmp_splitviewer, "SPLITVIEWER", SplitViewer, "Split Viewer", "" )
DefNode( CompositorNode, CMP_NODE_MAP_UV, def_cmp_map_uv, "MAP_UV", MapUV, "Map UV", "" )
DefNode( CompositorNode, CMP_NODE_ID_MASK, def_cmp_id_mask, "ID_MASK", IDMask, "ID Mask", "" )
+DefNode( CompositorNode, CMP_NODE_DBLEDGMATTE, def_cmp_dbl_edg_matte, "DBLEDGMATTE", DblEdgMatte, "Double Edge Matte", "" )
DefNode( CompositorNode, CMP_NODE_DEFOCUS, def_cmp_defocus, "DEFOCUS", Defocus, "Defocus", "" )
DefNode( CompositorNode, CMP_NODE_DISPLACE, 0, "DISPLACE", Displace, "Displace", "" )
DefNode( CompositorNode, CMP_NODE_COMBHSVA, 0, "COMBHSVA", CombHSVA, "Combine HSVA", "" )
@@ -117,7 +118,7 @@
DefNode( CompositorNode, CMP_NODE_DIST_MATTE, def_cmp_distance_matte, "DISTANCE_MATTE", DistanceMatte, "Distance Matte", "" )
DefNode( CompositorNode, CMP_NODE_COLORBALANCE, def_cmp_colorbalance, "COLORBALANCE", ColorBalance, "Color Balance", "" )
DefNode( CompositorNode, CMP_NODE_HUECORRECT, def_cmp_huecorrect, "HUECORRECT", HueCorrect, "Hue Correct", "" )
-
+
DefNode( TextureNode, TEX_NODE_OUTPUT, def_tex_output, "OUTPUT", Output, "Output", "" )
DefNode( TextureNode, TEX_NODE_CHECKER, 0, "CHECKER", Checker, "Checker", "" )
DefNode( TextureNode, TEX_NODE_TEXTURE, def_texture, "TEXTURE", Texture, "Texture", "" )
Index: source/blender/makesrna/intern/rna_nodetree.c
===================================================================
--- source/blender/makesrna/intern/rna_nodetree.c (revision 41530)
+++ source/blender/makesrna/intern/rna_nodetree.c (working copy)
@@ -1868,7 +1868,7 @@
static void def_cmp_id_mask(StructRNA *srna)
{
PropertyRNA *prop;
-
+
prop = RNA_def_property(srna, "index", PROP_INT, PROP_NONE);
RNA_def_property_int_sdna(prop, NULL, "custom1");
RNA_def_property_range(prop, 0, 32767);
@@ -1881,6 +1881,35 @@
RNA_def_property_update(prop, NC_NODE|NA_EDITED, "rna_Node_update");
}
+static void def_cmp_dbl_edg_matte(StructRNA * srna)
+{
+ PropertyRNA *prop;
+
+ static EnumPropertyItem BufEdgeMode_items[] = {
+ {0, "BLEED", 0, "Bleed Out", "Allow mask pixels to bleed along edges"},
+ {1, "KEEP", 0, "Keep In", "Restrict mask pixels from touching edges"},
+ {0, NULL, 0, NULL, NULL}
+ };
+
+ static EnumPropertyItem InnerEdgeMode_items[] = {
+ {0, "ALL", 0, "All", "All pixels on inner mask edge are considered during mask calculation"},
+ {1, "ADJONL", 0, "Adjacent Only", "Only inner mask pixels adjacent to outer mask pixels are considerer during mask calculation"},
+ {0, NULL, 0, NULL, NULL}
+ };
+
+ prop = RNA_def_property(srna, "inner_mode", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "custom2");
+ RNA_def_property_enum_items(prop, InnerEdgeMode_items);
+ RNA_def_property_ui_text(prop, "Inner Edge Mode", "");
+ RNA_def_property_update(prop, NC_NODE|NA_EDITED, "rna_Node_update");
+
+ prop = RNA_def_property(srna, "edge_mode", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "custom1");
+ RNA_def_property_enum_items(prop, BufEdgeMode_items);
+ RNA_def_property_ui_text(prop, "Buffer Edge Mode", "");
+ RNA_def_property_update(prop, NC_NODE|NA_EDITED, "rna_Node_update");
+}
+
static void def_cmp_map_uv(StructRNA *srna)
{
PropertyRNA *prop;
Index: source/blender/makesrna/RNA_access.h
===================================================================
--- source/blender/makesrna/RNA_access.h (revision 41530)
+++ source/blender/makesrna/RNA_access.h (working copy)
@@ -136,6 +136,7 @@
extern StructRNA RNA_CompositorNodeGlare;
extern StructRNA RNA_CompositorNodeHueSat;
extern StructRNA RNA_CompositorNodeIDMask;
+extern StructRNA RNA_CompositorNodeDblEdgMatte;
extern StructRNA RNA_CompositorNodeImage;
extern StructRNA RNA_CompositorNodeInvert;
extern StructRNA RNA_CompositorNodeLensdist;
Index: source/blender/nodes/composite/nodes/node_composite_dblEdgMatte.c
===================================================================
--- source/blender/nodes/composite/nodes/node_composite_dblEdgMatte.c (revision 0)
+++ source/blender/nodes/composite/nodes/node_composite_dblEdgMatte.c (revision 0)
@@ -0,0 +1,954 @@
+/*
+ * $Id: node_composite_dblEdgMatte.c 35237 2011-08-08 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): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/nodes/composite/nodes/node_composite_dblEdgMatte.c
+ * \ingroup cmpnodes
+ */
+
+#include "node_composite_util.h"
+/* **************** DblEdgMatte ******************** */
+
+static bNodeSocketTemplate cmp_node_dbledgmatte_in[]= {
+ { SOCK_FLOAT, 1, "Inner Mask", 0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f, PROP_NONE}, // inner mask input socket definition
+ { SOCK_FLOAT, 1, "Outer Mask", 0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f, PROP_NONE}, // outer mask input socket definition
+ { -1, 0, "" } // input socket array terminator
+};
+static bNodeSocketTemplate cmp_node_dbledgmatte_out[]= {
+ { SOCK_FLOAT, 0, "D.E.M. Mask"}, // output socket definition
+ { -1, 0, "" } // output socket array terminator
+};
+
+static void node_composit_exec_dbledgmatte(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)
+ float odist; // odist = current outer edge distance
+ float idist; // idist = current inner edge distance
+
+ int x; // x = pixel loop counter
+ int rw; // rw = pixel row width
+ int t; // t = total number of pixels in buffer - 1 (used for loop starts)
+ int a; // a = temporary pixel index buffer loop counter
+ int dx; // dx = X-delta (used for distance proportion calculation)
+ int dy; // dy = Y-delta (used for distance proportion calculation)
+ unsigned int ud; // ud = unscaled edge distance
+ unsigned int dmin; // dmin = minimun edge distance
+
+ 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 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 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 int gradientFillOffset=0; // offset into final buffer where gradient pixel indexes start
+ 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
+ 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
+ /* Test the four corners */
+ /* upper left corner */
+ x=t-rw+1;
+ if(limask[x]){
+ if((!limask[x-rw] && lomask[x-rw]) || (!limask[x+1] && lomask[x+1])){
+ isz++;
+ lres[x]=4;
+ } else {
+ res[x]=1.0f;
+ }
+ } else if(lomask[x]){
+ osz++;
+ lres[x]=3;
+ }
+ /* upper right corner */
+ x=t;
+ if(limask[x]){
+ if((!limask[x-rw] && lomask[x-rw]) || (!limask[x-1] && lomask[x-1])){
+ isz++;
+ lres[x]=4;
+ } else {
+ res[x]=1.0f;
+ }
+ } else if(lomask[x]){
+ osz++;
+ lres[x]=3;
+ }
+ /* lower left corner */
+ x=0;
+ if(limask[x]){
+ if((!limask[x+rw] && lomask[x+rw]) || (!limask[x+1] && lomask[x+1])){
+ isz++;
+ lres[x]=4;
+ } else {
+ res[x]=1.0f;
+ }
+ } else if(lomask[x]){
+ osz++;
+ lres[x]=3;
+ }
+ /* lower right corner */
+ x=rw-1;
+ if(limask[x]){
+ if((!limask[x+rw] && lomask[x+rw]) || (!limask[x-1] && lomask[x-1])){
+ isz++;
+ lres[x]=4;
+ } else {
+ res[x]=1.0f;
+ }
+ } else if(lomask[x]){
+ osz++;
+ lres[x]=3;
+ }
+
+ /* Test the TOP row of pixels in buffer, except corners */
+ for(x= t-1; x>=(t-rw)+2; x--) {
+ if(limask[x]) {
+ if((!limask[x-1] && lomask[x-1]) || (!limask[x+1] && lomask[x+1])) {
+ isz++;
+ lres[x]=4;
+ } else {
+ res[x]=1.0f;
+ }
+ } else if(lomask[x]) {
+ osz++;
+ lres[x]=3;
+ }
+ }
+
+ /* Test the BOTTOM row of pixels in buffer, except corners */
+ for(x= rw-2; x; x--) {
+ if(limask[x]) {
+ if((!limask[x-1] && lomask[x-1]) || (!limask[x+1] && lomask[x+1])) {
+ isz++;
+ lres[x]=4;
+ } else {
+ res[x]=1.0f;
+ }
+ } else if(lomask[x]) {
+ osz++;
+ lres[x]=3;
+ }
+ }
+ /* Test the LEFT edge of pixels in buffer, except corners */
+ for(x= t-(rw<<1)+1; x>=rw; x-=rw) {
+ if(limask[x]) {
+ if((!limask[x-rw] && lomask[x-rw]) || (!limask[x+rw] && lomask[x+rw])) {
+ isz++;
+ lres[x]=4;
+ } else {
+ res[x]=1.0f;
+ }
+ } else if(lomask[x]) {
+ osz++;
+ lres[x]=3;
+ }
+ }
+
+ /* Test the RIGHT edge of pixels in buffer, except corners */
+ for(x= t-rw; x>rw; x-=rw) {
+ if(limask[x]) {
+ if((!limask[x-rw] && lomask[x-rw]) || (!limask[x+rw] && lomask[x+rw])) {
+ isz++;
+ lres[x]=4;
+ } else {
+ res[x]=1.0f;
+ }
+ } else if(lomask[x]) {
+ osz++;
+ lres[x]=3;
+ }
+ }
+ } else {
+ /* Test the four corners */
+ /* upper left corner */
+ x=t-rw+1;
+ if(limask[x]){
+ if((!limask[x-rw] && lomask[x-rw]) || (!limask[x+1] && lomask[x+1])){
+ isz++;
+ lres[x]=4;
+ } else {
+ res[x]=1.0f;
+ }
+ } else if(lomask[x]){
+ if(!lomask[x-rw] || !lomask[x+1]) {
+ osz++;
+ lres[x]=3;
+ } else {
+ gsz++; // increment the gradient pixel count
+ lres[x]=2; // flag pixel as gradient
+ }
+ }
+ /* upper right corner */
+ x=t;
+ if(limask[x]){
+ if((!limask[x-rw] && lomask[x-rw]) || (!limask[x-1] && lomask[x-1])){
+ isz++;
+ lres[x]=4;
+ } else {
+ res[x]=1.0f;
+ }
+ } else if(lomask[x]){
+ if(!lomask[x-rw] || !lomask[x-1]) {
+ osz++;
+ lres[x]=3;
+ } else {
+ gsz++; // increment the gradient pixel count
+ lres[x]=2; // flag pixel as gradient
+ }
+ }
+ /* lower left corner */
+ x=0;
+ if(limask[x]){
+ if((!limask[x+rw] && lomask[x+rw]) || (!limask[x+1] && lomask[x+1])){
+ isz++;
+ lres[x]=4;
+ } else {
+ res[x]=1.0f;
+ }
+ } else if(lomask[x]){
+ if(!lomask[x+rw] || !lomask[x+1]) {
+ osz++;
+ lres[x]=3;
+ } else {
+ gsz++; // increment the gradient pixel count
+ lres[x]=2; // flag pixel as gradient
+ }
+ }
+ /* lower right corner */
+ x=rw-1;
+ if(limask[x]){
+ if((!limask[x+rw] && lomask[x+rw]) || (!limask[x-1] && lomask[x-1])){
+ isz++;
+ lres[x]=4;
+ } else {
+ res[x]=1.0f;
+ }
+ } else if(lomask[x]){
+ if(!lomask[x+rw] || !lomask[x-1]) {
+ osz++;
+ lres[x]=3;
+ } 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--) {
+ if(limask[x]) {
+ if((!limask[x-1] && lomask[x-1]) || (!limask[x+1] && lomask[x+1])) {
+ isz++;
+ lres[x]=4;
+ } else {
+ res[x]=1.0f;
+ }
+ } else if(lomask[x]) {
+ if(!lomask[x-1] || !lomask[x+1]) {
+ osz++;
+ lres[x]=3;
+ } 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--) {
+ if(limask[x]) {
+ if((!limask[x-1] && lomask[x-1]) || (!limask[x+1] && lomask[x+1])) {
+ isz++;
+ lres[x]=4;
+ } else {
+ res[x]=1.0f;
+ }
+ } else if(lomask[x]) {
+ if(!lomask[x-1] || !lomask[x+1]) {
+ osz++;
+ lres[x]=3;
+ } 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) {
+ if(limask[x]) {
+ if((!limask[x-rw] && lomask[x-rw]) || (!limask[x+rw] && lomask[x+rw])) {
+ isz++;
+ lres[x]=4;
+ } else {
+ res[x]=1.0f;
+ }
+ } else if(lomask[x]) {
+ if(!lomask[x-rw] || !lomask[x+rw]) {
+ osz++;
+ lres[x]=3;
+ } 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) {
+ if(limask[x]) {
+ if((!limask[x-rw] && lomask[x-rw]) || (!limask[x+rw] && lomask[x+rw])) {
+ isz++;
+ lres[x]=4;
+ } else {
+ res[x]=1.0f;
+ }
+ } else if(lomask[x]) {
+ if(!lomask[x-rw] || !lomask[x+rw]) {
+ osz++;
+ lres[x]=3;
+ } else {
+ gsz++; // increment the gradient pixel count
+ lres[x]=2; // flag pixel as gradient
+ }
+ }
+ }
+ }
+ /* 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) {
+ for(a=x-2; a>dx-2; a--) {
+ 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[a-1] && !limask[a-1]) || (!lomask[a+1] && !limask[a+1]) || (!lomask[a-rw] && !limask[a-rw]) || (!lomask[a+rw] && !limask[a+rw])) {
+ 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
+ gsz++; // increment the gradient pixel count
+ lres[a]=2; // flag pixel as gradient
+ }
+ }
+
+ } else {
+ if((!limask[a-1] && lomask[a-1]) || (!limask[a+1] && lomask[a+1]) || (!limask[a-rw] && lomask[a-rw]) || (!limask[a+rw] && lomask[a+rw])) {
+ 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
+ }
+ }
+ }
+ }
+ } else {
+ if(node->custom1) { // if keep inside edge mode is turned on
+ /* Test the four corners */
+ /* upper left corner */
+ x=t-rw+1;
+ if(limask[x]){
+ if(!limask[x-rw] || !limask[x+1]){
+ isz++;
+ lres[x]=4;
+ } else {
+ res[x]=1.0f;
+ }
+ } else if(lomask[x]){
+ osz++;
+ lres[x]=3;
+ }
+ /* upper right corner */
+ x=t;
+ if(limask[x]){
+ if(!limask[x-rw] || !limask[x-1]){
+ isz++;
+ lres[x]=4;
+ } else {
+ res[x]=1.0f;
+ }
+ } else if(lomask[x]){
+ osz++;
+ lres[x]=3;
+ }
+ /* lower left corner */
+ x=0;
+ if(limask[x]){
+ if(!limask[x+rw] || !limask[x+1]){
+ isz++;
+ lres[x]=4;
+ } else {
+ res[x]=1.0f;
+ }
+ } else if(lomask[x]){
+ osz++;
+ lres[x]=3;
+ }
+ /* lower right corner */
+ x=rw-1;
+ if(limask[x]){
+ if(!limask[x+rw] || !limask[x-1]){
+ isz++;
+ lres[x]=4;
+ } else {
+ res[x]=1.0f;
+ }
+ } else if(lomask[x]){
+ osz++;
+ lres[x]=3;
+ }
+
+ /* Test the TOP row of pixels in buffer, except corners */
+ for(x= t-1; x>=(t-rw)+2; x--) {
+ if(limask[x]) {
+ if(!limask[x-1] || !limask[x+1]) {
+ isz++;
+ lres[x]=4;
+ } else {
+ res[x]=1.0f;
+ }
+ } else if(lomask[x]) {
+ osz++;
+ lres[x]=3;
+ }
+ }
+
+ /* Test the BOTTOM row of pixels in buffer, except corners */
+ for(x= rw-2; x; x--) {
+ if(limask[x]) {
+ if(!limask[x-1] || !limask[x+1]) {
+ isz++;
+ lres[x]=4;
+ } else {
+ res[x]=1.0f;
+ }
+ } else if(lomask[x]) {
+ osz++;
+ lres[x]=3;
+ }
+ }
+ /* Test the LEFT edge of pixels in buffer, except corners */
+ for(x= t-(rw<<1)+1; x>=rw; x-=rw) {
+ if(limask[x]) {
+ if(!limask[x-rw] || !limask[x+rw]) {
+ isz++;
+ lres[x]=4;
+ } else {
+ res[x]=1.0f;
+ }
+ } else if(lomask[x]) {
+ osz++;
+ lres[x]=3;
+ }
+ }
+
+ /* Test the RIGHT edge of pixels in buffer, except corners */
+ for(x= t-rw; x>rw; x-=rw) {
+ if(limask[x]) {
+ if(!limask[x-rw] || !limask[x+rw]) {
+ isz++;
+ lres[x]=4;
+ } else {
+ res[x]=1.0f;
+ }
+ } else if(lomask[x]) {
+ osz++;
+ lres[x]=3;
+ }
+ }
+ } else {
+ /* Test the four corners */
+ /* upper left corner */
+ x=t-rw+1;
+ if(limask[x]){
+ if(!limask[x-rw] || !limask[x+1]){
+ isz++;
+ lres[x]=4;
+ } else {
+ res[x]=1.0f;
+ }
+ } else if(lomask[x]){
+ if(!lomask[x-rw] || !lomask[x+1]) {
+ osz++;
+ lres[x]=3;
+ } else {
+ gsz++; // increment the gradient pixel count
+ lres[x]=2; // flag pixel as gradient
+ }
+ }
+ /* upper right corner */
+ x=t;
+ if(limask[x]){
+ if(!limask[x-rw] || !limask[x-1]){
+ isz++;
+ lres[x]=4;
+ } else {
+ res[x]=1.0f;
+ }
+ } else if(lomask[x]){
+ if(!lomask[x-rw] || !lomask[x-1]) {
+ osz++;
+ lres[x]=3;
+ } else {
+ gsz++; // increment the gradient pixel count
+ lres[x]=2; // flag pixel as gradient
+ }
+ }
+ /* lower left corner */
+ x=0;
+ if(limask[x]){
+ if(!limask[x+rw] || !limask[x+1]){
+ isz++;
+ lres[x]=4;
+ } else {
+ res[x]=1.0f;
+ }
+ } else if(lomask[x]){
+ if(!lomask[x+rw] || !lomask[x+1]) {
+ osz++;
+ lres[x]=3;
+ } else {
+ gsz++; // increment the gradient pixel count
+ lres[x]=2; // flag pixel as gradient
+ }
+ }
+ /* lower right corner */
+ x=rw-1;
+ if(limask[x]){
+ if(!limask[x+rw] || !limask[x-1]){
+ isz++;
+ lres[x]=4;
+ } else {
+ res[x]=1.0f;
+ }
+ } else if(lomask[x]){
+ if(!lomask[x+rw] || !lomask[x-1]) {
+ osz++;
+ lres[x]=3;
+ } 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--) {
+ if(limask[x]) {
+ if(!limask[x-1] || !limask[x+1]) {
+ isz++;
+ lres[x]=4;
+ } else {
+ res[x]=1.0f;
+ }
+ } else if(lomask[x]) {
+ if(!lomask[x-1] || !lomask[x+1]) {
+ osz++;
+ lres[x]=3;
+ } 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--) {
+ if(limask[x]) {
+ if(!limask[x-1] || !limask[x+1]) {
+ isz++;
+ lres[x]=4;
+ } else {
+ res[x]=1.0f;
+ }
+ } else if(lomask[x]) {
+ if(!lomask[x-1] || !lomask[x+1]) {
+ osz++;
+ lres[x]=3;
+ } 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) {
+ if(limask[x]) {
+ if(!limask[x-rw] || !limask[x+rw]) {
+ isz++;
+ lres[x]=4;
+ } else {
+ res[x]=1.0f;
+ }
+ } else if(lomask[x]) {
+ if(!lomask[x-rw] || !lomask[x+rw]) {
+ osz++;
+ lres[x]=3;
+ } 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) {
+ if(limask[x]) {
+ if(!limask[x-rw] || !limask[x+rw]) {
+ isz++;
+ lres[x]=4;
+ } else {
+ res[x]=1.0f;
+ }
+ } else if(lomask[x]) {
+ if(!lomask[x-rw] || !lomask[x+rw]) {
+ osz++;
+ lres[x]=3;
+ } else {
+ gsz++; // increment the gradient pixel count
+ lres[x]=2; // flag pixel as gradient
+ }
+ }
+ }
+ }
+ /* 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) {
+ for(a=x-2; a>dx-2; a--) {
+ 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[a-1] && !limask[a-1]) || (!lomask[a+1] && !limask[a+1]) || (!lomask[a-rw] && !limask[a-rw]) || (!lomask[a+rw] && !limask[a+rw])) {
+ 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
+ gsz++; // increment the gradient pixel count
+ lres[a]=2; // flag pixel as gradient
+ }
+ }
+
+ } else {
+ if(!limask[a-1] || !limask[a+1] || !limask[a-rw] || !limask[a+rw]) {
+ 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
+ }
+ }
+ }
+ }
+ }
+ // quick check for existance of edges in the buffer...
+ if(!gsz || !isz || !osz) {
+ out[0]->data= stackbuf; // point the node output buffer to our filled buffer
+ return;
+ }
+
+ /*
+ 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) coords
+ +--------------------------------> <----------------> <------------------------> <----------------+
+ |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.
+ */
+
+ 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
+
+ gradientFillOffset=0; // since there are likely "more" of these, putting it first seems good. :)
+ 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
+ }
+ }
+ }
+
+ /*
+ 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 - could be covered by outer mask too, but wouldn't make any difference
+
+ ...............................
+ ...............+++++++++++.....
+ ...+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] *safe to reuse 't' here
+ fsz=gbuf[gradientFillOffset+1]; // calculate row of pixel indexed by gbuf[x] *safe to reuse 'fsz' here
+ 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 we've found
+ 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 gradient pixel intensity
+ }
+
+ 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_dbledgmatte(ListBase *lb) {
+ static bNodeType ntype; // allocate a node type data structure
+
+ node_type_base(&ntype, CMP_NODE_DBLEDGMATTE, "Double Edge Matte", NODE_CLASS_OP_FILTER, NODE_OPTIONS);
+ node_type_socket_templates(&ntype, cmp_node_dbledgmatte_in, cmp_node_dbledgmatte_out);
+ node_type_size(&ntype, 240, 210, 360);
+ node_type_exec(&ntype, node_composit_exec_dbledgmatte);
+
+ nodeRegisterType(lb, &ntype);
+}
Index: source/blender/nodes/NOD_composite.h
===================================================================
--- source/blender/nodes/NOD_composite.h (revision 41530)
+++ source/blender/nodes/NOD_composite.h (working copy)
@@ -82,6 +82,7 @@
void register_node_type_cmp_vecblur(ListBase *lb);
void register_node_type_cmp_dilateerode(ListBase *lb);
void register_node_type_cmp_defocus(ListBase *lb);
+void register_node_type_cmp_dbledgmatte(ListBase *lb);
void register_node_type_cmp_valtorgb(ListBase *lb);
void register_node_type_cmp_rgbtobw(ListBase *lb);
Index: source/blender/nodes/CMakeLists.txt
===================================================================
--- source/blender/nodes/CMakeLists.txt (revision 41530)
+++ source/blender/nodes/CMakeLists.txt (working copy)
@@ -58,6 +58,7 @@
composite/nodes/node_composite_composite.c
composite/nodes/node_composite_crop.c
composite/nodes/node_composite_curves.c
+ composite/nodes/node_composite_dblEdgMatte.c
composite/nodes/node_composite_defocus.c
composite/nodes/node_composite_diffMatte.c
composite/nodes/node_composite_dilate.c
Index: source/blender/editors/space_node/drawnode.c
===================================================================
--- source/blender/editors/space_node/drawnode.c (revision 41530)
+++ source/blender/editors/space_node/drawnode.c (working copy)
@@ -1376,6 +1376,18 @@
uiItemR(col, ptr, "factor", 0, NULL, ICON_NONE);
}
+static void node_composit_buts_dbl_edg_matte(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ uiLayout *col;
+
+ col= uiLayoutColumn(layout, 0);
+
+ uiItemL(col, "Inner Edge:", ICON_NONE);
+ uiItemR(col, ptr, "inner_mode", 0, "", ICON_NONE);
+ uiItemL(col, "Buffer Edge:", ICON_NONE);
+ uiItemR(col, ptr, "edge_mode", 0, "", ICON_NONE);
+}
+
static void node_composit_buts_map_value(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
uiLayout *sub, *col;
@@ -1540,7 +1552,7 @@
static void node_composit_buts_id_mask(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
- uiItemR(layout, ptr, "index", 0, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "index", 0, NULL, ICON_NONE);
uiItemR(layout, ptr, "use_smooth_mask", 0, NULL, ICON_NONE);
}
@@ -1803,6 +1815,9 @@
case CMP_NODE_ID_MASK:
ntype->uifunc= node_composit_buts_id_mask;
break;
+ case CMP_NODE_DBLEDGMATTE:
+ ntype->uifunc= node_composit_buts_dbl_edg_matte;
+ break;
case CMP_NODE_MATH:
ntype->uifunc= node_buts_math;
break;

File Metadata

Mime Type
text/x-diff
Storage Engine
local-disk
Storage Format
Raw Data
Storage Handle
95/cc/397c23bc4bbbc02d6acf33837bc3

Event Timeline