Page Menu
Home
Search
Configure Global Search
Log In
Files
F18105
dem.patch
Public
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Authored By
Thomas Dinges (dingto)
Nov 13 2013, 4:06 PM
Size
44 KB
Subscribers
None
dem.patch
View Options
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
Details
Mime Type
text/x-diff
Storage Engine
local-disk
Storage Format
Raw Data
Storage Handle
95/cc/397c23bc4bbbc02d6acf33837bc3
Event Timeline
Log In to Comment