From 90fa460d2aad7ca572c0c42e7ecf7e284e1c9c77 Mon Sep 17 00:00:00 2001 From: Matt Ebb Date: Fri, 17 Feb 2006 13:51:55 +0000 Subject: [PATCH] 3 very simple new composite nodes that I wanted for working with here. Hope the code is ok, they work ok in testing here and get done what I need, any checks or fixes are welcome. * Separate RGBA: Separates an input RGBA image into its R, G, B and A channels * Separate HSVA: Separates an input RGBA image into H, S, V and A channels * Set Alpha: Takes an input RGBA image and an alpha value channel and combines them into a single RGBA image channel. You can also set the alpha for the entire image with the number field when there's no input alpha channel. TODO: Allow input alpha channel with no input image, in order to output a solid colour, with alpha. --- source/blender/blenkernel/BKE_node.h | 5 +- .../blenkernel/intern/node_composite.c | 220 +++++++++++++++++- source/blender/src/editnode.c | 2 +- 3 files changed, 220 insertions(+), 7 deletions(-) diff --git a/source/blender/blenkernel/BKE_node.h b/source/blender/blenkernel/BKE_node.h index 19c8af94404..cbae7034d1a 100644 --- a/source/blender/blenkernel/BKE_node.h +++ b/source/blender/blenkernel/BKE_node.h @@ -185,7 +185,7 @@ void nodeShaderSynchronizeID(struct bNode *node, int copyto); /* switch material render loop */ void set_node_shader_lamp_loop(void (*lamp_loop_func)(struct ShadeInput *, struct ShadeResult *)); -/* ************** COMPOSIT NODES *************** */ +/* ************** COMPOSITE NODES *************** */ /* note: types are needed to restore callbacks, don't change values */ #define CMP_NODE_VIEWER 201 @@ -203,6 +203,9 @@ void set_node_shader_lamp_loop(void (*lamp_loop_func)(struct ShadeInput *, str #define CMP_NODE_MAP_VALUE 213 #define CMP_NODE_TIME 214 #define CMP_NODE_VECBLUR 215 +#define CMP_NODE_SEPRGBA 216 +#define CMP_NODE_SEPHSVA 217 +#define CMP_NODE_SETALPHA 218 #define CMP_NODE_IMAGE 220 #define CMP_NODE_R_RESULT 221 diff --git a/source/blender/blenkernel/intern/node_composite.c b/source/blender/blenkernel/intern/node_composite.c index 78f97465cd0..1f022f92a4f 100644 --- a/source/blender/blenkernel/intern/node_composite.c +++ b/source/blender/blenkernel/intern/node_composite.c @@ -75,6 +75,12 @@ typedef struct CompBuf { #define CB_VEC2 2 #define CB_VAL 1 +/* defines for RGBA channels */ +#define CHAN_R 0 +#define CHAN_G 1 +#define CHAN_B 2 +#define CHAN_A 3 + static CompBuf *alloc_compbuf(int sizex, int sizey, int type, int alloc) { CompBuf *cbuf= MEM_callocT(sizeof(CompBuf), "compbuf"); @@ -442,7 +448,7 @@ static void composit3_pixel_processor(bNode *node, CompBuf *out, CompBuf *src1_b } } -/* */ +/* ok to delete this and use the generalised version below? */ static CompBuf *alphabuf_from_rgbabuf(CompBuf *cbuf) { CompBuf *valbuf= alloc_compbuf(cbuf->x, cbuf->y, CB_VAL, 1); @@ -457,6 +463,25 @@ static CompBuf *alphabuf_from_rgbabuf(CompBuf *cbuf) return valbuf; } +static CompBuf *valbuf_from_rgbabuf(CompBuf *cbuf, int channel) +{ + CompBuf *valbuf= alloc_compbuf(cbuf->x, cbuf->y, CB_VAL, 1); + float *valf, *rectf; + int tot; + + valf= valbuf->rect; + + /* defaults to returning alpha channel */ + if ((channel < CHAN_R) && (channel > CHAN_A)) channel = CHAN_A; + + rectf= cbuf->rect + channel; + + for(tot= cbuf->x*cbuf->y; tot>0; tot--, valf++, rectf+=4) + *valf= *rectf; + + return valbuf; +} + static void generate_preview(bNode *node, CompBuf *stackbuf) { bNodePreview *preview= node->preview; @@ -888,7 +913,7 @@ static void node_composit_exec_image(void *data, bNode *node, bNodeStack **in, b if(stackbuf) { if(out[1]->hasoutput) - out[1]->data= alphabuf_from_rgbabuf(stackbuf); + out[1]->data= valbuf_from_rgbabuf(stackbuf, CHAN_A); if(out[2]->hasoutput) out[2]->data= node_composit_get_zimage(node, data); @@ -995,7 +1020,7 @@ static void node_composit_exec_rresult(void *data, bNode *node, bNodeStack **in, out[RRES_OUT_IMAGE]->data= stackbuf; if(out[RRES_OUT_ALPHA]->hasoutput) - out[RRES_OUT_ALPHA]->data= alphabuf_from_rgbabuf(stackbuf); + out[RRES_OUT_ALPHA]->data= valbuf_from_rgbabuf(stackbuf, CHAN_A); if(out[RRES_OUT_Z]->hasoutput) out[RRES_OUT_Z]->data= compbuf_from_pass(rd, rl, rr->rectx, rr->recty, SCE_PASS_Z); if(out[RRES_OUT_VEC]->hasoutput) @@ -1505,7 +1530,7 @@ static void node_composit_exec_valtorgb(void *data, bNode *node, bNodeStack **in out[0]->data= stackbuf; if(out[1]->hasoutput) - out[1]->data= alphabuf_from_rgbabuf(stackbuf); + out[1]->data= valbuf_from_rgbabuf(stackbuf, CHAN_A); } } @@ -1546,7 +1571,7 @@ static void node_composit_exec_rgbtobw(void *data, bNode *node, bNodeStack **in, /* input no image? then only color operation */ if(in[0]->data==NULL) { - out[0]->vec[0]= in[0]->vec[0]*0.35f + in[0]->vec[1]*0.45f + in[0]->vec[2]*0.2f; + do_rgbtobw(node, out[0], in[0]); } else { /* make output size of input image */ @@ -1571,6 +1596,188 @@ static bNodeType cmp_node_rgbtobw= { }; +/* **************** SEPARATE RGBA ******************** */ +static bNodeSocketType cmp_node_seprgba_in[]= { + { SOCK_RGBA, 1, "Image", 0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f}, + { -1, 0, "" } +}; +static bNodeSocketType cmp_node_seprgba_out[]= { + { SOCK_VALUE, 0, "R", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f}, + { SOCK_VALUE, 0, "G", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f}, + { SOCK_VALUE, 0, "B", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f}, + { SOCK_VALUE, 0, "A", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f}, + { -1, 0, "" } +}; + +static void node_composit_exec_seprgba(void *data, bNode *node, bNodeStack **in, bNodeStack **out) +{ + /* stack order out: bw channels */ + /* stack order in: col */ + + /* input no image? then only color operation */ + if(in[0]->data==NULL) { + out[0]->vec[0] = in[0]->vec[0]; + out[1]->vec[0] = in[0]->vec[1]; + out[2]->vec[0] = in[0]->vec[2]; + out[3]->vec[0] = in[0]->vec[3]; + } + else { + /* make output size of input image */ + CompBuf *cbuf= in[0]->data; + + /* don't do any pixel processing, just copy the stack directly (faster, I presume) */ + if(out[0]->hasoutput) + out[0]->data= valbuf_from_rgbabuf(cbuf, CHAN_R); + if(out[1]->hasoutput) + out[1]->data= valbuf_from_rgbabuf(cbuf, CHAN_G); + if(out[2]->hasoutput) + out[2]->data= valbuf_from_rgbabuf(cbuf, CHAN_B); + if(out[3]->hasoutput) + out[3]->data= valbuf_from_rgbabuf(cbuf, CHAN_A); + } +} + +static bNodeType cmp_node_seprgba= { + /* type code */ CMP_NODE_SEPRGBA, + /* name */ "Separate RGBA", + /* width+range */ 80, 40, 140, + /* class+opts */ NODE_CLASS_OPERATOR, 0, + /* input sock */ cmp_node_seprgba_in, + /* output sock */ cmp_node_seprgba_out, + /* storage */ "", + /* execfunc */ node_composit_exec_seprgba + +}; + +/* **************** SEPARATE HSVA ******************** */ +static bNodeSocketType cmp_node_sephsva_in[]= { + { SOCK_RGBA, 1, "Image", 0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f}, + { -1, 0, "" } +}; +static bNodeSocketType cmp_node_sephsva_out[]= { + { SOCK_VALUE, 0, "H", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f}, + { SOCK_VALUE, 0, "S", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f}, + { SOCK_VALUE, 0, "V", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f}, + { SOCK_VALUE, 0, "A", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f}, + { -1, 0, "" } +}; + +static void do_sephsva(bNode *node, float *out, float *in) +{ + float h, s, v; + + rgb_to_hsv(in[0], in[1], in[2], &h, &s, &v); + + out[0]= h; + out[1]= s; + out[2]= v; + out[3]= in[3]; +} + +static void node_composit_exec_sephsva(void *data, bNode *node, bNodeStack **in, bNodeStack **out) +{ + /* stack order out: bw channels */ + /* stack order in: col */ + + /* input no image? then only color operation */ + if(in[0]->data==NULL) { + float h, s, v; + + rgb_to_hsv(in[0]->vec[0], in[0]->vec[1], in[0]->vec[2], &h, &s, &v); + + out[0]->vec[0] = h; + out[1]->vec[0] = s; + out[2]->vec[0] = v; + out[3]->vec[0] = in[0]->vec[3]; + } + else if ((out[0]->hasoutput) || (out[1]->hasoutput) || (out[2]->hasoutput) || (out[3]->hasoutput)) { + /* make output size of input image */ + CompBuf *cbuf= in[0]->data; + + CompBuf *stackbuf= alloc_compbuf(cbuf->x, cbuf->y, CB_RGBA, 1); // allocs + + /* convert the RGB stackbuf to an HSV representation */ + composit1_pixel_processor(node, stackbuf, in[0]->data, NULL, do_sephsva); + + /* separate each of those channels */ + if(out[0]->hasoutput) + out[0]->data= valbuf_from_rgbabuf(stackbuf, CHAN_R); + if(out[1]->hasoutput) + out[1]->data= valbuf_from_rgbabuf(stackbuf, CHAN_G); + if(out[2]->hasoutput) + out[2]->data= valbuf_from_rgbabuf(stackbuf, CHAN_B); + if(out[3]->hasoutput) + out[3]->data= valbuf_from_rgbabuf(stackbuf, CHAN_A); + + free_compbuf(stackbuf); + } +} + +static bNodeType cmp_node_sephsva= { + /* type code */ CMP_NODE_SEPHSVA, + /* name */ "Separate HSVA", + /* width+range */ 80, 40, 140, + /* class+opts */ NODE_CLASS_OPERATOR, 0, + /* input sock */ cmp_node_sephsva_in, + /* output sock */ cmp_node_sephsva_out, + /* storage */ "", + /* execfunc */ node_composit_exec_sephsva + +}; + +/* **************** SET ALPHA ******************** */ +static bNodeSocketType cmp_node_setalpha_in[]= { + { SOCK_RGBA, 1, "Image", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f}, + { SOCK_VALUE, 1, "Alpha", 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f}, + { -1, 0, "" } +}; +static bNodeSocketType cmp_node_setalpha_out[]= { + { SOCK_RGBA, 0, "Image", 0.0f, 0.0f, 1.0f, 1.0f, -1.0f, 1.0f}, + { -1, 0, "" } +}; + +static void node_composit_exec_setalpha(void *data, bNode *node, bNodeStack **in, bNodeStack **out) +{ + /* stack order out: RGBA image */ + /* stack order in: col, alpha */ + + /* input no image? then only color operation */ + if(in[0]->data==NULL) { + out[0]->vec[0] = in[0]->vec[0]; + out[0]->vec[1] = in[0]->vec[1]; + out[0]->vec[2] = in[0]->vec[2]; + out[0]->vec[3] = in[1]->vec[0]; + } + else { + /* make output size of input image */ + CompBuf *cbuf= in[0]->data; + CompBuf *stackbuf= alloc_compbuf(cbuf->x, cbuf->y, CB_RGBA, 1); // allocs + + if(in[1]->vec[0]==1.0f) { + /* pass on image */ + composit1_pixel_processor(node, stackbuf, in[0]->data, in[0]->vec, do_copy_rgb); + } + else { + /* send an compbuf or a value to set as alpha - composit2_pixel_processor handles choosing the right one */ + composit2_pixel_processor(node, stackbuf, in[0]->data, in[0]->vec, in[1]->data, in[1]->vec, do_copy_a_rgba); + } + + out[0]->data= stackbuf; + } +} + +static bNodeType cmp_node_setalpha= { + /* type code */ CMP_NODE_SETALPHA, + /* name */ "Set Alpha", + /* width+range */ 120, 40, 140, + /* class+opts */ NODE_CLASS_OPERATOR, NODE_OPTIONS, + /* input sock */ cmp_node_setalpha_in, + /* output sock */ cmp_node_setalpha_out, + /* storage */ "", + /* execfunc */ node_composit_exec_setalpha + +}; + /* **************** ALPHAOVER ******************** */ static bNodeSocketType cmp_node_alphaover_in[]= { { SOCK_RGBA, 1, "Image", 0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f}, @@ -2363,6 +2570,9 @@ bNodeType *node_all_composit[]= { &cmp_node_blur, &cmp_node_vecblur, &cmp_node_map_value, + &cmp_node_seprgba, + &cmp_node_sephsva, + &cmp_node_setalpha, NULL }; diff --git a/source/blender/src/editnode.c b/source/blender/src/editnode.c index c5e5ee95963..7d09404b9cf 100644 --- a/source/blender/src/editnode.c +++ b/source/blender/src/editnode.c @@ -1254,7 +1254,7 @@ static void node_add_menu(SpaceNode *snode) } else if(snode->treetype==NTREE_COMPOSIT) { /* compo menu, still hardcoded defines... solve */ - event= pupmenu("Add Node%t|Render Result %x221|Composite %x222|Viewer%x201|Image %x220|RGB Curves%x209|AlphaOver %x210|Blur %x211|Vector Blur %x215|Filter %x212|Value %x203|Color %x202|Mix %x204|ColorRamp %x205|Color to BW %x206|Map Value %x213|Time %x214|Normal %x207"); + event= pupmenu("Add Node%t|Render Result %x221|Composite %x222|Viewer%x201|Image %x220|RGB Curves%x209|AlphaOver %x210|Blur %x211|Vector Blur %x215|Filter %x212|Value %x203|Color %x202|Mix %x204|ColorRamp %x205|Color to BW %x206|Map Value %x213|Time %x214|Normal %x207||Separate RGBA %x216|Separate HSVA %x217|Set Alpha %x218"); if(event<1) return; } else return;