diff options
Diffstat (limited to 'source/blender/nodes')
49 files changed, 2054 insertions, 328 deletions
diff --git a/source/blender/nodes/CMP_node.h b/source/blender/nodes/CMP_node.h index 4b7e721ca57..020bbdebfa2 100644 --- a/source/blender/nodes/CMP_node.h +++ b/source/blender/nodes/CMP_node.h @@ -66,6 +66,8 @@ extern bNodeType cmp_node_normalize; extern bNodeType cmp_node_filter; extern bNodeType cmp_node_blur; +extern bNodeType cmp_node_dblur; +extern bNodeType cmp_node_bilateralblur; extern bNodeType cmp_node_vecblur; extern bNodeType cmp_node_dilateerode; extern bNodeType cmp_node_defocus; @@ -83,6 +85,7 @@ extern bNodeType cmp_node_sepyuva; extern bNodeType cmp_node_combyuva; extern bNodeType cmp_node_sepycca; extern bNodeType cmp_node_combycca; +extern bNodeType cmp_node_premulkey; extern bNodeType cmp_node_diff_matte; extern bNodeType cmp_node_chroma; diff --git a/source/blender/nodes/CMakeLists.txt b/source/blender/nodes/CMakeLists.txt index 0be26622536..7f003cb2b42 100644 --- a/source/blender/nodes/CMakeLists.txt +++ b/source/blender/nodes/CMakeLists.txt @@ -26,13 +26,14 @@ FILE(GLOB SRC intern/*.c intern/CMP_nodes/*.c intern/SHD_nodes/*.c) SET(INC - . ../../../intern/guardedalloc ../include ../blenlib ../makesdna + . ../../../intern/guardedalloc ../editors/include ../blenlib ../makesdna ../python ../render/extern/include ../../../intern/decimation/extern ../imbuf ../avi ../../../intern/elbeem/extern ../../../intern/iksolver/extern ../blenloader ../quicktime - ../blenkernel ../editors/include + ../blenkernel ../../../extern/glew/include ../gpu ${SDL_INC} ${ZLIB_INC} + ${PYTHON_INC} ) IF(WITH_VERSE) diff --git a/source/blender/nodes/Makefile b/source/blender/nodes/Makefile index 65a0e591848..57f57ebebfe 100644 --- a/source/blender/nodes/Makefile +++ b/source/blender/nodes/Makefile @@ -6,7 +6,7 @@ # 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. +# 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 diff --git a/source/blender/nodes/SConscript b/source/blender/nodes/SConscript index 746be45eb91..5f7f29dab83 100644 --- a/source/blender/nodes/SConscript +++ b/source/blender/nodes/SConscript @@ -7,40 +7,44 @@ sources += env.Glob('intern/SHD_nodes/*.c') incs = '. ./intern ' incs += '#/intern/guardedalloc ../editors/include ../blenlib ../makesdna' -incs += ' ../python ../render/extern/include ' +incs += ' ../render/extern/include ' incs += ' ../imbuf ../avi ' -incs += ' ../blenloader ../quicktime' +incs += ' ../blenloader' incs += ' ../blenkernel ../renderconverter ' - - +incs += ' ../gpu #/extern/glew/include ' incs += ' ' + env['BF_OPENGL_INC'] incs += ' ' + env['BF_ZLIB_INC'] -incs += ' ' + env['BF_SDL_INC'] defs = '' +if env['WITH_BF_PYTHON']: + incs += ' ' + env['BF_PYTHON_INC'] + incs += ' ../python' +else: + defs += 'DISABLE_PYTHON' + if env['WITH_BF_INTERNATIONAL']: - defs += 'WITH_FREETYPE2' + defs += ' WITH_FREETYPE2' if env['WITH_BF_VERSE']: - defs += ' WITH_VERSE' - incs += ' ' + env['BF_VERSE_INCLUDE'] + defs += ' WITH_VERSE' + incs += ' ' + env['BF_VERSE_INCLUDE'] if env['WITH_BF_VERSE']: - defs += ' WITH_VERSE' + defs += ' WITH_VERSE' -if env['WITH_BF_OPENEXR'] == 1: - defs += ' WITH_OPENEXR' +if env['WITH_BF_OPENEXR']: + defs += ' WITH_OPENEXR' -if env['WITH_BF_FFMPEG'] == 1: - defs += ' WITH_FFMPEG' - incs += ' ' + env['BF_FFMPEG_INC'] +if env['WITH_BF_FFMPEG']: + defs += ' WITH_FFMPEG' + incs += ' ' + env['BF_FFMPEG_INC'] -if env['WITH_BF_QUICKTIME'] == 1: - defs += ' WITH_QUICKTIME' - incs += ' ' + env['BF_QUICKTIME_INC'] +if env['WITH_BF_QUICKTIME']: + defs += ' WITH_QUICKTIME' + incs += ' ' + env['BF_QUICKTIME_INC'] -defs += ' WITH_CCGSUBSURF' +defs += ' WITH_CCGSUBSURF ' env.BlenderLib ( libname = 'bf_nodes', sources = sources, includes = Split(incs), defines = Split(defs), libtype=['core','player'], priority = [80, 15] ) diff --git a/source/blender/nodes/SHD_node.h b/source/blender/nodes/SHD_node.h index 8064a543ca0..d75d7c9f568 100644 --- a/source/blender/nodes/SHD_node.h +++ b/source/blender/nodes/SHD_node.h @@ -56,13 +56,13 @@ extern bNodeType sh_node_curve_rgb; extern bNodeType sh_node_math; extern bNodeType sh_node_vect_math; extern bNodeType sh_node_squeeze; +extern bNodeType node_dynamic_typeinfo; extern bNodeType sh_node_material_ext; extern bNodeType sh_node_invert; extern bNodeType sh_node_seprgb; extern bNodeType sh_node_combrgb; extern bNodeType sh_node_hue_sat; - #endif diff --git a/source/blender/nodes/intern/CMP_nodes/CMP_alphaOver.c b/source/blender/nodes/intern/CMP_nodes/CMP_alphaOver.c index f108098750c..4972ff4ae5a 100644 --- a/source/blender/nodes/intern/CMP_nodes/CMP_alphaOver.c +++ b/source/blender/nodes/intern/CMP_nodes/CMP_alphaOver.c @@ -47,16 +47,16 @@ static void do_alphaover_premul(bNode *node, float *out, float *src, float *over if(over[3]<=0.0f) { QUATCOPY(out, src); } - else if(*fac==1.0f && over[3]>=1.0f) { + else if(fac[0]==1.0f && over[3]>=1.0f) { QUATCOPY(out, over); } else { - float mul= 1.0f - *fac*over[3]; + float mul= 1.0f - fac[0]*over[3]; - out[0]= (mul*src[0]) + *fac*over[0]; - out[1]= (mul*src[1]) + *fac*over[1]; - out[2]= (mul*src[2]) + *fac*over[2]; - out[3]= (mul*src[3]) + *fac*over[3]; + out[0]= (mul*src[0]) + fac[0]*over[0]; + out[1]= (mul*src[1]) + fac[0]*over[1]; + out[2]= (mul*src[2]) + fac[0]*over[2]; + out[3]= (mul*src[3]) + fac[0]*over[3]; } } @@ -67,7 +67,7 @@ static void do_alphaover_key(bNode *node, float *out, float *src, float *over, f if(over[3]<=0.0f) { QUATCOPY(out, src); } - else if(*fac==1.0f && over[3]>=1.0f) { + else if(fac[0]==1.0f && over[3]>=1.0f) { QUATCOPY(out, over); } else { @@ -81,6 +81,31 @@ static void do_alphaover_key(bNode *node, float *out, float *src, float *over, f } } +/* result will be still premul, but the over part is premulled */ +static void do_alphaover_mixed(bNode *node, float *out, float *src, float *over, float *fac) +{ + + if(over[3]<=0.0f) { + QUATCOPY(out, src); + } + else if(fac[0]==1.0f && over[3]>=1.0f) { + QUATCOPY(out, over); + } + else { + NodeTwoFloats *ntf= node->storage; + float addfac= 1.0f - ntf->x + over[3]*ntf->x; + float premul= fac[0]*addfac; + float mul= 1.0f - fac[0]*over[3]; + + out[0]= (mul*src[0]) + premul*over[0]; + out[1]= (mul*src[1]) + premul*over[1]; + out[2]= (mul*src[2]) + premul*over[2]; + out[3]= (mul*src[3]) + fac[0]*over[3]; + } +} + + + static void node_composit_exec_alphaover(void *data, bNode *node, bNodeStack **in, bNodeStack **out) { @@ -97,8 +122,11 @@ static void node_composit_exec_alphaover(void *data, bNode *node, bNodeStack **i /* make output size of input image */ CompBuf *cbuf= in[1]->data?in[1]->data:in[2]->data; CompBuf *stackbuf= alloc_compbuf(cbuf->x, cbuf->y, CB_RGBA, 1); /* allocs */ + NodeTwoFloats *ntf= node->storage; - if(node->custom1) + if(ntf->x != 0.0f) + composit3_pixel_processor(node, stackbuf, in[1]->data, in[1]->vec, in[2]->data, in[2]->vec, in[0]->data, in[0]->vec, do_alphaover_mixed, CB_RGBA, CB_RGBA, CB_VAL); + else if(node->custom1) composit3_pixel_processor(node, stackbuf, in[1]->data, in[1]->vec, in[2]->data, in[2]->vec, in[0]->data, in[0]->vec, do_alphaover_key, CB_RGBA, CB_RGBA, CB_VAL); else composit3_pixel_processor(node, stackbuf, in[1]->data, in[1]->vec, in[2]->data, in[2]->vec, in[0]->data, in[0]->vec, do_alphaover_premul, CB_RGBA, CB_RGBA, CB_VAL); @@ -107,6 +135,11 @@ static void node_composit_exec_alphaover(void *data, bNode *node, bNodeStack **i } } +static void node_alphaover_init(bNode* node) +{ + node->storage= MEM_callocN(sizeof(NodeTwoFloats), "NodeTwoFloats"); +} + bNodeType cmp_node_alphaover= { /* *next,*prev */ NULL, NULL, /* type code */ CMP_NODE_ALPHAOVER, @@ -115,12 +148,12 @@ bNodeType cmp_node_alphaover= { /* class+opts */ NODE_CLASS_OP_COLOR, NODE_OPTIONS, /* input sock */ cmp_node_alphaover_in, /* output sock */ cmp_node_alphaover_out, - /* storage */ "", + /* storage */ "NodeTwoFloats", /* execfunc */ node_composit_exec_alphaover, /* butfunc */ NULL, - /* initfunc */ NULL, - /* freestoragefunc */ NULL, - /* copystoragefunc */ NULL, + /* initfunc */ node_alphaover_init, + /* freestoragefunc */ node_free_standard_storage, + /* copystoragefunc */ node_copy_standard_storage, /* id */ NULL }; diff --git a/source/blender/nodes/intern/CMP_nodes/CMP_bilateralblur.c b/source/blender/nodes/intern/CMP_nodes/CMP_bilateralblur.c new file mode 100644 index 00000000000..b954e876ea1 --- /dev/null +++ b/source/blender/nodes/intern/CMP_nodes/CMP_bilateralblur.c @@ -0,0 +1,272 @@ +/** + * + * + * ***** 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2006 Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): Vilem Novak + * + * ***** END GPL LICENSE BLOCK ***** + */ +#include "../CMP_util.h" + +/* **************** BILATERALBLUR ******************** */ +static bNodeSocketType cmp_node_bilateralblur_in[]= { + { SOCK_RGBA, 1, "Image", 0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f}, + { SOCK_RGBA, 1, "Determinator", 0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f}, + { -1, 0, "" } +}; + +static bNodeSocketType cmp_node_bilateralblur_out[]= { + { SOCK_RGBA, 0, "Image", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f}, + { -1, 0, "" } +}; + +#define INIT_C3\ + mean0 = 1; mean1[0] = src[0];mean1[1] = src[1];mean1[2] = src[2];mean1[3] = src[3]; + +/* finds color distances */ +#define COLOR_DISTANCE_C3(c1, c2)\ + ((c1[0] - c2[0])*(c1[0] - c2[0]) + \ + (c1[1] - c2[1])*(c1[1] - c2[1]) + \ + (c1[2] - c2[2])*(c1[2] - c2[2]) + \ + (c1[3] - c2[3])*(c1[3] - c2[3])) + +/* this is the main kernel function for comparing color distances + and adding them weighted to the final color */ +#define KERNEL_ELEMENT_C3(k)\ + temp_color = src + deltas[k];\ + ref_color = ref + deltas[k];\ + w = weight_tab[k] + COLOR_DISTANCE_C3(ref, ref_color )*i2sigma_color;\ + w = 1./(w*w + 1); \ + mean0 += w;\ + mean1[0] += temp_color[0]*w; \ + mean1[1] += temp_color[1]*w; \ + mean1[2] += temp_color[2]*w; \ + mean1[3] += temp_color[3]*w; + +/* write blurred values to image */ +#define UPDATE_OUTPUT_C3\ + mean0 = 1./mean0;\ + dest[x*pix + 0] = mean1[0]*mean0; \ + dest[x*pix + 1] = mean1[1]*mean0; \ + dest[x*pix + 2] = mean1[2]*mean0; \ + dest[x*pix + 3] = mean1[3]*mean0; + +/* initializes deltas for fast access to neighbour pixels */ +#define INIT_3X3_DELTAS( deltas, step, nch ) \ + ((deltas)[0] = (nch), (deltas)[1] = -(step) + (nch), \ + (deltas)[2] = -(step), (deltas)[3] = -(step) - (nch), \ + (deltas)[4] = -(nch), (deltas)[5] = (step) - (nch), \ + (deltas)[6] = (step), (deltas)[7] = (step) + (nch)); + + +/* code of this node was heavily inspired by the smooth function of opencv library. +The main change is an optional image input */ +static void node_composit_exec_bilateralblur(void *data, bNode *node, bNodeStack **in, bNodeStack **out) +{ + NodeBilateralBlurData *nbbd= node->storage; + CompBuf *new, *source, *img= in[0]->data , *refimg= in[1]->data; + double mean0, w, i2sigma_color, i2sigma_space; + double mean1[4]; + double weight_tab[8]; + float *src, *dest, *ref, *temp_color, *ref_color; + float sigma_color, sigma_space; + int imgx, imgy, x, y, pix, i, step; + int deltas[8]; + short found_determinator= 0; + + if(img == NULL || out[0]->hasoutput == 0) + return; + + if(img->type != CB_RGBA) { + img= typecheck_compbuf(in[0]->data, CB_RGBA); + } + + imgx= img->x; + imgy= img->y; + pix= img->type; + step= pix * imgx; + + if(refimg) { + if(refimg->x == imgx && refimg->y == imgy) { + if(ELEM3(refimg->type, CB_VAL, CB_VEC2, CB_VEC3)) { + refimg= typecheck_compbuf(in[1]->data, CB_RGBA); + found_determinator= 1; + } + } + } + else { + refimg= img; + } + + /* allocs */ + source= dupalloc_compbuf(img); + new= alloc_compbuf(imgx, imgy, pix, 1); + + /* accept image offsets from other nodes */ + new->xof= img->xof; + new->yof= img->yof; + + /* bilateral code properties */ + sigma_color= nbbd->sigma_color; + sigma_space= nbbd->sigma_space; + + i2sigma_color= 1. / (sigma_color * sigma_color); + i2sigma_space= 1. / (sigma_space * sigma_space); + + INIT_3X3_DELTAS(deltas, step, pix); + + weight_tab[0] = weight_tab[2] = weight_tab[4] = weight_tab[6] = i2sigma_space; + weight_tab[1] = weight_tab[3] = weight_tab[5] = weight_tab[7] = i2sigma_space * 2; + + /* iterations */ + for(i= 0; i < nbbd->iter; i++) { + src= source->rect; + ref= refimg->rect; + dest= new->rect; + /*goes through image, there are more loops for 1st/last line and all other lines*/ + /*kernel element accumulates surrounding colors, which are then written with the update_output function*/ + for(x= 0; x < imgx; x++, src+= pix, ref+= pix) { + INIT_C3; + + KERNEL_ELEMENT_C3(6); + + if(x > 0) { + KERNEL_ELEMENT_C3(5); + KERNEL_ELEMENT_C3(4); + } + + if(x < imgx - 1) { + KERNEL_ELEMENT_C3(7); + KERNEL_ELEMENT_C3(0); + } + + UPDATE_OUTPUT_C3; + } + + dest+= step; + + for(y= 1; y < imgy - 1; y++, dest+= step, src+= pix, ref+= pix) { + x= 0; + + INIT_C3; + + KERNEL_ELEMENT_C3(0); + KERNEL_ELEMENT_C3(1); + KERNEL_ELEMENT_C3(2); + KERNEL_ELEMENT_C3(6); + KERNEL_ELEMENT_C3(7); + + UPDATE_OUTPUT_C3; + + src+= pix; + ref+= pix; + + for(x= 1; x < imgx - 1; x++, src+= pix, ref+= pix) { + INIT_C3; + + KERNEL_ELEMENT_C3(0); + KERNEL_ELEMENT_C3(1); + KERNEL_ELEMENT_C3(2); + KERNEL_ELEMENT_C3(3); + KERNEL_ELEMENT_C3(4); + KERNEL_ELEMENT_C3(5); + KERNEL_ELEMENT_C3(6); + KERNEL_ELEMENT_C3(7); + + UPDATE_OUTPUT_C3; + } + + INIT_C3; + + KERNEL_ELEMENT_C3(2); + KERNEL_ELEMENT_C3(3); + KERNEL_ELEMENT_C3(4); + KERNEL_ELEMENT_C3(5); + KERNEL_ELEMENT_C3(6); + + UPDATE_OUTPUT_C3; + } + + for(x= 0; x < imgx; x++, src+= pix, ref+= pix) { + INIT_C3; + + KERNEL_ELEMENT_C3(2); + + if(x > 0) { + KERNEL_ELEMENT_C3(3); + KERNEL_ELEMENT_C3(4); + } + if(x < imgx - 1) { + KERNEL_ELEMENT_C3(1); + KERNEL_ELEMENT_C3(0); + } + + UPDATE_OUTPUT_C3; + } + + if(node->exec & NODE_BREAK) break; + + SWAP(CompBuf, *source, *new); + } + + if(node->exec & NODE_BREAK) + free_compbuf(source); + + if(img != in[0]->data) + free_compbuf(img); + + if(found_determinator == 1) { + if(refimg != in[1]->data) + free_compbuf(refimg); + } + + out[0]->data= source; + + free_compbuf(new); +} + +static void node_composit_init_bilateralblur(bNode* node) +{ + NodeBilateralBlurData *nbbd= MEM_callocN(sizeof(NodeBilateralBlurData), "node bilateral blur data"); + node->storage= nbbd; + nbbd->sigma_color= 0.3; + nbbd->sigma_space= 5.0; +} + +bNodeType cmp_node_bilateralblur= { + /* *next,*prev */ NULL, NULL, + /* type code */ CMP_NODE_BILATERALBLUR, + /* name */ "Bilateral Blur", + /* width+range */ 150, 120, 200, + /* class+opts */ NODE_CLASS_OP_FILTER, NODE_OPTIONS, + /* input sock */ cmp_node_bilateralblur_in, + /* output sock */ cmp_node_bilateralblur_out, + /* storage */ "NodeBilateralBlurData", + /* execfunc */ node_composit_exec_bilateralblur, + /* butfunc */ NULL, + /* initfunc */ node_composit_init_bilateralblur, + /* freestoragefunc */ node_free_standard_storage, + /* copystoragefunc */ node_copy_standard_storage, + /* id */ NULL + +}; diff --git a/source/blender/nodes/intern/CMP_nodes/CMP_blur.c b/source/blender/nodes/intern/CMP_nodes/CMP_blur.c index 8ef4af4d219..e7e799b6e76 100644 --- a/source/blender/nodes/intern/CMP_nodes/CMP_blur.c +++ b/source/blender/nodes/intern/CMP_nodes/CMP_blur.c @@ -22,7 +22,8 @@ * * The Original Code is: all of this file. * - * Contributor(s): none yet. + * Contributor(s): Campbell Barton, Alfredo de Greef, David Millan Escriva, + * Juho Vepsäläinen * * ***** END GPL LICENSE BLOCK ***** */ @@ -397,7 +398,7 @@ static void bokeh_single_image(bNode *node, CompBuf *new, CompBuf *img, float fa int maxyr= y+rady>imgy-1?imgy-y-1:rady; float *destd= new->rect + pix*( (y + minyr)*imgx + x + minxr); - float *dgausd= gausstab + (minyr+rady)*2*radx + minxr+radx; + float *dgausd= gausstab + (minyr+rady)*(2*radx+1) + minxr+radx; if(x<=0) src= srcd; else if(x<imgx) src+= pix; @@ -556,16 +557,20 @@ static void blur_with_reference(bNode *node, CompBuf *new, CompBuf *img, CompBuf static void node_composit_exec_blur(void *data, bNode *node, bNodeStack **in, bNodeStack **out) { CompBuf *new, *img= in[0]->data; + NodeBlurData *nbd= node->storage; - if(img==NULL || out[0]->hasoutput==0) - return; + if(img==NULL) return; + + /* store image in size that is needed for absolute/relative conversions on ui level */ + nbd->image_in_width= img->x; + nbd->image_in_height= img->y; + + if(out[0]->hasoutput==0) return; if (((NodeBlurData *)node->storage)->filtertype == R_FILTER_FAST_GAUSS) { CompBuf *new, *img = in[0]->data; /*from eeshlo's original patch, removed to fit in with the existing blur node */ /*const float sx = in[1]->vec[0], sy = in[2]->vec[0];*/ - - NodeBlurData *nbd= node->storage; const float sx = ((float)nbd->sizex)/2.0f, sy = ((float)nbd->sizey)/2.0f; int c; diff --git a/source/blender/nodes/intern/CMP_nodes/CMP_brightness.c b/source/blender/nodes/intern/CMP_nodes/CMP_brightness.c index c87307434b5..f6363cc7ffa 100644 --- a/source/blender/nodes/intern/CMP_nodes/CMP_brightness.c +++ b/source/blender/nodes/intern/CMP_nodes/CMP_brightness.c @@ -35,8 +35,8 @@ static bNodeSocketType cmp_node_brightcontrast_in[]= { { SOCK_RGBA, 1, "Image", 0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f}, - { SOCK_VALUE, 1, "bright", 0.0f, 0.0f, 0.0f, 0.0f, -100.0f, 100.0f}, - { SOCK_VALUE, 1, "contrast", 0.0f, 0.0f, 0.0f, 0.0f, -100.0f, 100.0f}, + { SOCK_VALUE, 1, "Bright", 0.0f, 0.0f, 0.0f, 0.0f, -100.0f, 100.0f}, + { SOCK_VALUE, 1, "Contrast", 0.0f, 0.0f, 0.0f, 0.0f, -100.0f, 100.0f}, { -1, 0, "" } }; static bNodeSocketType cmp_node_brightcontrast_out[]= { diff --git a/source/blender/nodes/intern/CMP_nodes/CMP_curves.c b/source/blender/nodes/intern/CMP_nodes/CMP_curves.c index 17d9821a5ef..01af0e1db1d 100644 --- a/source/blender/nodes/intern/CMP_nodes/CMP_curves.c +++ b/source/blender/nodes/intern/CMP_nodes/CMP_curves.c @@ -22,7 +22,7 @@ * * The Original Code is: all of this file. * - * Contributor(s): none yet. + * Contributor(s): Björn C. Schaefer * * ***** END GPL LICENSE BLOCK ***** */ @@ -123,6 +123,8 @@ bNodeType cmp_node_curve_vec= { static bNodeSocketType cmp_node_curve_rgb_in[]= { { SOCK_VALUE, 1, "Fac", 1.0f, 0.0f, 0.0f, 1.0f, -1.0f, 1.0f}, { SOCK_RGBA, 1, "Image", 0.0f, 0.0f, 0.0f, 1.0f, -1.0f, 1.0f}, + { SOCK_RGBA, 1, "Black Level", 0.0f, 0.0f, 0.0f, 1.0f, -1.0f, 1.0f}, + { SOCK_RGBA, 1, "White Level", 1.0f, 1.0f, 1.0f, 1.0f, -1.0f, 1.0f}, { -1, 0, "" } }; @@ -157,7 +159,7 @@ static void do_curves_fac(bNode *node, float *out, float *in, float *fac) static void node_composit_exec_curve_rgb(void *data, bNode *node, bNodeStack **in, bNodeStack **out) { - /* stack order input: fac, image */ + /* stack order input: fac, image, black level, white level */ /* stack order output: image */ if(out[0]->hasoutput==0) @@ -172,6 +174,8 @@ static void node_composit_exec_curve_rgb(void *data, bNode *node, bNodeStack **i CompBuf *cbuf= in[1]->data; CompBuf *stackbuf= alloc_compbuf(cbuf->x, cbuf->y, CB_RGBA, 1); /* allocs */ + curvemapping_set_black_white(node->storage, in[2]->vec, in[3]->vec); + if(in[0]->vec[0] == 1.0) composit1_pixel_processor(node, stackbuf, in[1]->data, in[1]->vec, do_curves, CB_RGBA); else diff --git a/source/blender/nodes/intern/CMP_nodes/CMP_defocus.c b/source/blender/nodes/intern/CMP_nodes/CMP_defocus.c index 53d01ab1d12..6f175671296 100644 --- a/source/blender/nodes/intern/CMP_nodes/CMP_defocus.c +++ b/source/blender/nodes/intern/CMP_nodes/CMP_defocus.c @@ -235,7 +235,7 @@ static void IIR_gauss_single(CompBuf* buf, float sigma) #undef YVV } -static void defocus_blur(bNode *node, CompBuf *new, CompBuf *img, CompBuf *zbuf, float inpval) +static void defocus_blur(bNode *node, CompBuf *new, CompBuf *img, CompBuf *zbuf, float inpval, int no_zbuf) { NodeDefocus *nqd = node->storage; CompBuf *wts; // weights buffer @@ -283,7 +283,7 @@ static void defocus_blur(bNode *node, CompBuf *new, CompBuf *img, CompBuf *zbuf, // if 'no_zbuf' flag set (which is always set if input is not an image), // values are instead interpreted directly as blur radius values - if (nqd->no_zbuf) { + if (no_zbuf) { // to prevent *reaaallly* big radius values and impossible calculation times, // limit the maximum to half the image width or height, whichever is smaller float maxr = 0.5f*(float)MIN2(img->x, img->y); @@ -376,8 +376,10 @@ static void defocus_blur(bNode *node, CompBuf *new, CompBuf *img, CompBuf *zbuf, // some sort of visual feedback would be nice, or at least this text in the renderwin header // but for now just print some info in the console every 8 scanlines. if (((y & 7)==0) || (y==(img->y-1))) { - printf("\rdefocus: Processing Line %d of %d ... ", y+1, img->y); - fflush(stdout); + if(G.background==0) { + printf("\rdefocus: Processing Line %d of %d ... ", y+1, img->y); + fflush(stdout); + } } // esc set by main calling process if(node->exec & NODE_BREAK) @@ -698,7 +700,7 @@ static void defocus_blur(bNode *node, CompBuf *new, CompBuf *img, CompBuf *zbuf, // sampled, simple rejection sampling here, good enough unsigned int maxsam, s, ui = BLI_rand()*BLI_rand(); float wcor, cpr = BLI_frand(); - if (nqd->no_zbuf) + if (no_zbuf) maxsam = nqd->samples; // no zbuffer input, use sample value directly else { // depth adaptive sampling hack, the more out of focus, the more samples taken, 16 minimum. @@ -772,14 +774,13 @@ static void node_composit_exec_defocus(void *data, bNode *node, bNodeStack **in, { CompBuf *new, *old, *zbuf_use = NULL, *img = in[0]->data, *zbuf = in[1]->data; NodeDefocus *nqd = node->storage; + int no_zbuf = nqd->no_zbuf; if ((img==NULL) || (out[0]->hasoutput==0)) return; // if image not valid type or fstop==infinite (128), nothing to do, pass in to out - if (((img->type!=CB_RGBA) && (img->type!=CB_VAL)) || ((nqd->no_zbuf==0) && (nqd->fstop==128.f))) { - new = alloc_compbuf(img->x, img->y, img->type, 0); - new->rect = img->rect; - out[0]->data = new; + if (((img->type!=CB_RGBA) && (img->type!=CB_VAL)) || ((no_zbuf==0) && (nqd->fstop==128.f))) { + out[0]->data = pass_on_compbuf(img); return; } @@ -793,21 +794,27 @@ static void node_composit_exec_defocus(void *data, bNode *node, bNodeStack **in, } zbuf_use = typecheck_compbuf(zbuf, CB_VAL); } - else nqd->no_zbuf = 1; // no zbuffer input + else no_zbuf = 1; // no zbuffer input // ok, process old = img; if (nqd->gamco) { - // gamma correct, blender func is simplified, fixed value & RGBA only, should make user param + // gamma correct, blender func is simplified, fixed value & RGBA only, + // should make user param. also depremul and premul afterwards, gamma + // correction can't work with premul alpha old = dupalloc_compbuf(img); + premul_compbuf(old, 1); gamma_correct_compbuf(old, 0); + premul_compbuf(old, 0); } new = alloc_compbuf(old->x, old->y, old->type, 1); - defocus_blur(node, new, old, zbuf_use, in[1]->vec[0]*nqd->scale); + defocus_blur(node, new, old, zbuf_use, in[1]->vec[0]*nqd->scale, no_zbuf); if (nqd->gamco) { + premul_compbuf(new, 1); gamma_correct_compbuf(new, 1); + premul_compbuf(new, 0); free_compbuf(old); } if(node->exec & NODE_BREAK) { diff --git a/source/blender/nodes/intern/CMP_nodes/CMP_directionalblur.c b/source/blender/nodes/intern/CMP_nodes/CMP_directionalblur.c new file mode 100644 index 00000000000..27f535186db --- /dev/null +++ b/source/blender/nodes/intern/CMP_nodes/CMP_directionalblur.c @@ -0,0 +1,143 @@ +/** + * + * ***** 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2006 Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): Alfredo de Greef (eeshlo) + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#include "../CMP_util.h" + +static bNodeSocketType cmp_node_dblur_in[]= { + { SOCK_RGBA, 1, "Image", 0.8f, 0.8f, 0.8f, 1.f, 0.f, 1.f}, + { -1, 0, "" } +}; + +static bNodeSocketType cmp_node_dblur_out[]= { + { SOCK_RGBA, 0, "Image", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f}, + { -1, 0, "" } +}; + +static CompBuf *dblur(bNode *node, CompBuf *img, int iterations, int wrap, + float center_x, float center_y, float dist, float angle, float spin, float zoom) +{ + if ((dist != 0.f) || (spin != 0.f) || (zoom != 0.f)) { + void (*getpix)(CompBuf*, float, float, float*) = wrap ? qd_getPixelLerpWrap : qd_getPixelLerp; + const float a= angle * (float)M_PI / 180.f; + const float itsc= 1.f / pow(2.f, (float)iterations); + float D; + float center_x_pix, center_y_pix; + float tx, ty; + float sc, rot; + CompBuf *tmp; + int i, j; + + tmp= dupalloc_compbuf(img); + + D= dist * sqrtf(img->x * img->x + img->y * img->y); + center_x_pix= center_x * img->x; + center_y_pix= center_y * img->y; + + tx= itsc * D * cos(a); + ty= -itsc * D * sin(a); + sc= itsc * zoom; + rot= itsc * spin * (float)M_PI / 180.f; + + /* blur the image */ + for(i= 0; i < iterations; ++i) { + const float cs= cos(rot), ss= sin(rot); + const float isc= 1.f / (1.f + sc); + unsigned int x, y; + float col[4]= {0,0,0,0}; + + for(y= 0; y < img->y; ++y) { + const float v= isc * (y - center_y_pix) + ty; + + for(x= 0; x < img->x; ++x) { + const float u= isc * (x - center_x_pix) + tx; + unsigned int p= (x + y * img->x) * img->type; + + getpix(tmp, cs * u + ss * v + center_x_pix, cs * v - ss * u + center_y_pix, col); + + /* mix img and transformed tmp */ + for(j= 0; j < 4; ++j) + img->rect[p + j]= AVG2(img->rect[p + j], col[j]); + } + } + + /* copy img to tmp */ + if(i != (iterations - 1)) + memcpy(tmp->rect, img->rect, sizeof(float) * img->x * img->y * img->type); + + /* double transformations */ + tx *= 2.f, ty *= 2.f; + sc *= 2.f, rot *= 2.f; + + if(node->exec & NODE_BREAK) break; + } + + free_compbuf(tmp); + } + + return img; +} + +static void node_composit_exec_dblur(void *data, bNode *node, bNodeStack **in, bNodeStack **out) +{ + NodeDBlurData *ndbd= node->storage; + CompBuf *new, *img= in[0]->data; + + if((img == NULL) || (out[0]->hasoutput == 0)) return; + + if (img->type != CB_RGBA) + new = typecheck_compbuf(img, CB_RGBA); + else + new = dupalloc_compbuf(img); + + out[0]->data= dblur(node, new, ndbd->iter, ndbd->wrap, ndbd->center_x, ndbd->center_y, ndbd->distance, ndbd->angle, ndbd->spin, ndbd->zoom); +} + +static void node_composit_init_dblur(bNode* node) +{ + NodeDBlurData *ndbd= MEM_callocN(sizeof(NodeDBlurData), "node dblur data"); + node->storage= ndbd; + ndbd->center_x= 0.5; + ndbd->center_y= 0.5; +} + +bNodeType cmp_node_dblur = { + /* *next,*prev */ NULL, NULL, + /* type code */ CMP_NODE_DBLUR, + /* name */ "Directional Blur", + /* width+range */ 150, 120, 200, + /* class+opts */ NODE_CLASS_OP_FILTER, NODE_OPTIONS, + /* input sock */ cmp_node_dblur_in, + /* output sock */ cmp_node_dblur_out, + /* storage */ "NodeDBlurData", + /* execfunc */ node_composit_exec_dblur, + /* butfunc */ NULL, + /* initfunc */ node_composit_init_dblur, + /* freestoragefunc */ node_free_standard_storage, + /* copystoragefunc */ node_copy_standard_storage, + /* id */ NULL +}; diff --git a/source/blender/nodes/intern/CMP_nodes/CMP_displace.c b/source/blender/nodes/intern/CMP_nodes/CMP_displace.c index 0ec15d9eb77..f5b6edcea80 100644 --- a/source/blender/nodes/intern/CMP_nodes/CMP_displace.c +++ b/source/blender/nodes/intern/CMP_nodes/CMP_displace.c @@ -44,18 +44,22 @@ static bNodeSocketType cmp_node_displace_out[]= { { -1, 0, "" } }; +static float *vecbuf_get_pixel(CompBuf *vecbuf, float *veccol, int x, int y) +{ + /* the x-xrad stuff is a bit weird, but i seem to need it otherwise + * my returned pixels are offset weirdly */ + return compbuf_get_pixel(vecbuf, veccol, x-vecbuf->xrad, y-vecbuf->yrad, vecbuf->xrad, vecbuf->yrad); +} + static void do_displace(CompBuf *stackbuf, CompBuf *cbuf, CompBuf *vecbuf, float *veccol, float *xscale, float *yscale) { ImBuf *ibuf; - int x, y, sx, sy; float dx=0.0, dy=0.0; float dspx, dspy; - float uv[2]; - - float *out= stackbuf->rect, *vec=vecbuf->rect, *in= cbuf->rect; + float uv[2], col[4], colnext[4], colprev[4]; float *vp, *vpnext, *vpprev; - - int row = 3*vecbuf->x; + float *out= stackbuf->rect, *vec=vecbuf->rect, *in= cbuf->rect; + int x, y, vx, vy, sx, sy; /* ibuf needed for sampling */ ibuf= IMB_allocImBuf(cbuf->x, cbuf->y, 32, 0, 0); @@ -65,37 +69,50 @@ static void do_displace(CompBuf *stackbuf, CompBuf *cbuf, CompBuf *vecbuf, float sx= stackbuf->x; sy= stackbuf->y; + + QUATCOPY(col, veccol); + QUATCOPY(colnext, veccol); + QUATCOPY(colprev, veccol); for(y=0; y<sy; y++) { for(x= 0; x< sx; x++, out+=4, in+=4, vec+=3) { - /* the x-xrad stuff is a bit weird, but i seem to need it otherwise - * my returned pixels are offset weirdly */ - vp = compbuf_get_pixel(vecbuf, veccol, x-vecbuf->xrad, y-vecbuf->yrad, vecbuf->xrad, vecbuf->yrad); + vp = vecbuf_get_pixel(vecbuf, col, x, y); + + /* this happens in compbuf_get_pixel, need to make sure the following + * check takes them into account */ + vx= x-vecbuf->xof; + vy= y-vecbuf->yof; /* find the new displaced co-ords, also correcting for translate offset */ - dspx = x - (*xscale * vp[0]); - dspy = y - (*yscale * vp[1]); + dspx = vx - (*xscale * vp[0]); + dspy = vy - (*yscale * vp[1]); /* convert image space to 0.0-1.0 UV space for sampling, correcting for translate offset */ uv[0] = dspx / (float)sx; uv[1] = dspy / (float)sy; - - if(x>0 && x< vecbuf->x-1 && y>0 && y< vecbuf->y-1) { - vpnext = vp+row; - vpprev = vp-row; - - /* adaptive sampling, X channel */ - dx= 0.5f*(fabs(vp[0]-vp[-3]) + fabs(vp[0]-vp[3])); - - dx+= 0.25f*(fabs(vp[0]-vpprev[-3]) + fabs(vp[0]-vpnext[-3])); - dx+= 0.25f*(fabs(vp[0]-vpprev[+3]) + fabs(vp[0]-vpnext[+3])); - - /* adaptive sampling, Y channel */ - dy= 0.5f*(fabs(vp[1]-vp[-row+1]) + fabs(vp[1]-vp[row+1])); - - dy+= 0.25f*(fabs(vp[1]-vpprev[+1-3]) + fabs(vp[1]-vpnext[+1-3])); - dy+= 0.25f*(fabs(vp[1]-vpprev[+1+3]) + fabs(vp[1]-vpnext[+1+3])); + + if(vx>0 && vx< vecbuf->x-1 && vy>0 && vy< vecbuf->y-1) { + /* adaptive sampling, X and Y channel. + * we call vecbuf_get_pixel for every pixel since the input + * might be a procedural, and then we can't use offsets */ + vpprev = vecbuf_get_pixel(vecbuf, colprev, x-1, y); + vpnext = vecbuf_get_pixel(vecbuf, colnext, x+1, y); + dx= 0.5f*(fabs(vp[0]-vpprev[0]) + fabs(vp[0]-vpnext[0])); + + vpprev = vecbuf_get_pixel(vecbuf, colprev, x, y-1); + vpnext = vecbuf_get_pixel(vecbuf, colnext, x, y+1); + dy= 0.5f*(fabs(vp[1]-vpnext[1]) + fabs(vp[1]-vpprev[1])); + + vpprev = vecbuf_get_pixel(vecbuf, colprev, x-1, y-1); + vpnext = vecbuf_get_pixel(vecbuf, colnext, x-1, y+1); + dx+= 0.25f*(fabs(vp[0]-vpprev[0]) + fabs(vp[0]-vpnext[0])); + dy+= 0.25f*(fabs(vp[1]-vpprev[1]) + fabs(vp[1]-vpnext[1])); + + vpprev = vecbuf_get_pixel(vecbuf, colprev, x+1, y-1); + vpnext = vecbuf_get_pixel(vecbuf, colnext, x+1, y+1); + dx+= 0.25f*(fabs(vp[0]-vpprev[0]) + fabs(vp[0]-vpnext[0])); + dy+= 0.25f*(fabs(vp[1]-vpprev[1]) + fabs(vp[1]-vpnext[1])); /* scaled down to prevent blurriness */ /* 8: magic number, provides a good level of sharpness without getting too aliased */ diff --git a/source/blender/nodes/intern/CMP_nodes/CMP_gamma.c b/source/blender/nodes/intern/CMP_nodes/CMP_gamma.c index 5d0ab729e08..e77de3726cb 100644 --- a/source/blender/nodes/intern/CMP_nodes/CMP_gamma.c +++ b/source/blender/nodes/intern/CMP_nodes/CMP_gamma.c @@ -34,7 +34,7 @@ static bNodeSocketType cmp_node_gamma_in[]= { { SOCK_RGBA, 1, "Image", 0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f}, - { SOCK_VALUE, 1, "Gamma", 1.0f, 0.0f, 0.0f, 0.0f, 0.001f, 2.0f}, + { SOCK_VALUE, 1, "Gamma", 1.0f, 0.0f, 0.0f, 0.0f, 0.001f, 10.0f}, { -1, 0, "" } }; static bNodeSocketType cmp_node_gamma_out[]= { @@ -46,7 +46,8 @@ static void do_gamma(bNode *node, float *out, float *in, float *fac) { int i=0; for(i=0; i<3; i++) { - out[i] = pow(in[i],fac[0]); + /* check for negative to avoid nan's */ + out[i] = (in[i] > 0.0f)? pow(in[i],fac[0]): in[i]; } out[3] = in[3]; } diff --git a/source/blender/nodes/intern/CMP_nodes/CMP_glare.c b/source/blender/nodes/intern/CMP_nodes/CMP_glare.c index e7b8fd00c93..9ab4038607f 100644 --- a/source/blender/nodes/intern/CMP_nodes/CMP_glare.c +++ b/source/blender/nodes/intern/CMP_nodes/CMP_glare.c @@ -424,15 +424,18 @@ static void fglow(NodeGlare* ndg, CompBuf* dst, CompBuf* src) static void node_composit_exec_glare(void *data, bNode *node, bNodeStack **in, bNodeStack **out) { - CompBuf *new, *img = in[0]->data; + CompBuf *new, *src, *img = in[0]->data; NodeGlare* ndg = node->storage; if ((img == NULL) || (out[0]->hasoutput == 0)) return; - if (img->type != CB_RGBA) + if (img->type != CB_RGBA) { new = typecheck_compbuf(img, CB_RGBA); - else + src = typecheck_compbuf(img, CB_RGBA); + } else { new = dupalloc_compbuf(img); + src = dupalloc_compbuf(img); + } { int x, y; @@ -448,19 +451,20 @@ static void node_composit_exec_glare(void *data, bNode *node, bNodeStack **in, b switch (ndg->type) { case 0: - star4(ndg, new, img); + star4(ndg, new, src); break; case 1: - fglow(ndg, new, img); + fglow(ndg, new, src); break; case 3: - ghosts(ndg, new, img); + ghosts(ndg, new, src); break; case 2: default: - streaks(ndg, new, img); + streaks(ndg, new, src); } + free_compbuf(src); out[0]->data = new; } diff --git a/source/blender/nodes/intern/CMP_nodes/CMP_hueSatVal.c b/source/blender/nodes/intern/CMP_nodes/CMP_hueSatVal.c index eeddb4ce756..92614d1cc6a 100644 --- a/source/blender/nodes/intern/CMP_nodes/CMP_hueSatVal.c +++ b/source/blender/nodes/intern/CMP_nodes/CMP_hueSatVal.c @@ -52,9 +52,7 @@ static void do_hue_sat_fac(bNode *node, float *out, float *in, float *fac) hsv[0]+= (nhs->hue - 0.5f); if(hsv[0]>1.0) hsv[0]-=1.0; else if(hsv[0]<0.0) hsv[0]+= 1.0; hsv[1]*= nhs->sat; - if(hsv[1]>1.0) hsv[1]= 1.0; else if(hsv[1]<0.0) hsv[1]= 0.0; hsv[2]*= nhs->val; - if(hsv[2]>1.0) hsv[2]= 1.0; else if(hsv[2]<0.0) hsv[2]= 0.0; hsv_to_rgb(hsv[0], hsv[1], hsv[2], col, col+1, col+2); out[0]= mfac*in[0] + *fac*col[0]; diff --git a/source/blender/nodes/intern/CMP_nodes/CMP_idMask.c b/source/blender/nodes/intern/CMP_nodes/CMP_idMask.c index abb9fa98d97..a40579ac3b2 100644 --- a/source/blender/nodes/intern/CMP_nodes/CMP_idMask.c +++ b/source/blender/nodes/intern/CMP_nodes/CMP_idMask.c @@ -63,8 +63,25 @@ static void do_idmask(CompBuf *stackbuf, CompBuf *cbuf, float idnr) MEM_freeN(abuf); } +/* full sample version */ +static void do_idmask_fsa(CompBuf *stackbuf, CompBuf *cbuf, float idnr) +{ + float *rect, *rs; + int x; + + rect= cbuf->rect; + rs= stackbuf->rect; + for(x= cbuf->x*cbuf->y - 1; x>=0; x--) + if(rect[x]==idnr) + rs[x]= 1.0f; + +} + + static void node_composit_exec_idmask(void *data, bNode *node, bNodeStack **in, bNodeStack **out) { + RenderData *rd= data; + if(out[0]->hasoutput==0) return; @@ -77,7 +94,10 @@ static void node_composit_exec_idmask(void *data, bNode *node, bNodeStack **in, stackbuf= alloc_compbuf(cbuf->x, cbuf->y, CB_VAL, 1); /* allocs */; - do_idmask(stackbuf, cbuf, (float)node->custom1); + if(rd->scemode & R_FULL_SAMPLE) + do_idmask_fsa(stackbuf, cbuf, (float)node->custom1); + else + do_idmask(stackbuf, cbuf, (float)node->custom1); out[0]->data= stackbuf; } diff --git a/source/blender/nodes/intern/CMP_nodes/CMP_image.c b/source/blender/nodes/intern/CMP_nodes/CMP_image.c index 20308e968d3..be5a1d7241b 100644 --- a/source/blender/nodes/intern/CMP_nodes/CMP_image.c +++ b/source/blender/nodes/intern/CMP_nodes/CMP_image.c @@ -48,6 +48,7 @@ static bNodeSocketType cmp_node_rlayers_out[]= { { SOCK_RGBA, 0, "Refract", 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f}, { SOCK_RGBA, 0, "Radio", 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f}, { SOCK_VALUE, 0, "IndexOB", 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f}, + { SOCK_VALUE, 0, "Mist", 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f}, { -1, 0, "" } }; @@ -78,6 +79,21 @@ static CompBuf *node_composit_get_image(RenderData *rd, Image *ima, ImageUser *i stackbuf->rect= ibuf->rect_float; } + /*code to respect the premul flag of images; I'm + not sure if this is a good idea for multilayer images, + since it never worked before for them. + if (type==CB_RGBA && ima->flag & IMA_DO_PREMUL) { + //premul the image + int i; + float *pixel = stackbuf->rect; + + for (i=0; i<stackbuf->x*stackbuf->y; i++, pixel += 4) { + pixel[0] *= pixel[3]; + pixel[1] *= pixel[3]; + pixel[2] *= pixel[3]; + } + } + */ return stackbuf; }; @@ -149,6 +165,8 @@ void outputs_multilayer_get(RenderData *rd, RenderLayer *rl, bNodeStack **out, I out[RRES_OUT_RADIO]->data= compbuf_multilayer_get(rd, rl, ima, iuser, SCE_PASS_RADIO); if(out[RRES_OUT_INDEXOB]->hasoutput) out[RRES_OUT_INDEXOB]->data= compbuf_multilayer_get(rd, rl, ima, iuser, SCE_PASS_INDEXOB); + if(out[RRES_OUT_MIST]->hasoutput) + out[RRES_OUT_MIST]->data= compbuf_multilayer_get(rd, rl, ima, iuser, SCE_PASS_MIST); }; @@ -184,11 +202,32 @@ static void node_composit_exec_image(void *data, bNode *node, bNodeStack **in, b else { stackbuf= node_composit_get_image(rd, ima, iuser); - /* put image on stack */ - out[0]->data= stackbuf; + if (stackbuf) { + /*respect image premul option*/ + if (stackbuf->type==CB_RGBA && ima->flag & IMA_DO_PREMUL) { + int i; + float *pixel; + + /*first duplicate stackbuf->rect, since it's just a pointer + to the source imbuf, and we don't want to change that.*/ + stackbuf->rect = MEM_dupallocN(stackbuf->rect); + + /*premul the image*/ + + pixel = stackbuf->rect; + for (i=0; i<stackbuf->x*stackbuf->y; i++, pixel += 4) { + pixel[0] *= pixel[3]; + pixel[1] *= pixel[3]; + pixel[2] *= pixel[3]; + } + } - if(out[2]->hasoutput) - out[2]->data= node_composit_get_zimage(node, rd); + /* put image on stack */ + out[0]->data= stackbuf; + + if(out[2]->hasoutput) + out[2]->data= node_composit_get_zimage(node, rd); + } } /* alpha and preview for both types */ @@ -205,6 +244,7 @@ static void node_composit_init_image(bNode* node) { ImageUser *iuser= MEM_callocN(sizeof(ImageUser), "node image user"); node->storage= iuser; + iuser->frames= 1; iuser->sfra= 1; iuser->fie_ima= 2; iuser->ok= 1; @@ -236,7 +276,7 @@ static CompBuf *compbuf_from_pass(RenderData *rd, RenderLayer *rl, int rectx, in CompBuf *buf; int buftype= CB_VEC3; - if(ELEM(passcode, SCE_PASS_Z, SCE_PASS_INDEXOB)) + if(ELEM3(passcode, SCE_PASS_Z, SCE_PASS_INDEXOB, SCE_PASS_MIST)) buftype= CB_VAL; else if(passcode==SCE_PASS_VECTOR) buftype= CB_VEC4; @@ -282,7 +322,9 @@ void node_composit_rlayers_out(RenderData *rd, RenderLayer *rl, bNodeStack **out if(out[RRES_OUT_RADIO]->hasoutput) out[RRES_OUT_RADIO]->data= compbuf_from_pass(rd, rl, rectx, recty, SCE_PASS_RADIO); if(out[RRES_OUT_INDEXOB]->hasoutput) - out[RRES_OUT_INDEXOB]->data= compbuf_from_pass(rd, rl, rectx, recty, SCE_PASS_INDEXOB); + out[RRES_OUT_INDEXOB]->data= compbuf_from_pass(rd, rl, rectx, recty, SCE_PASS_INDEXOB); + if(out[RRES_OUT_MIST]->hasoutput) + out[RRES_OUT_MIST]->data= compbuf_from_pass(rd, rl, rectx, recty, SCE_PASS_MIST); }; diff --git a/source/blender/nodes/intern/CMP_nodes/CMP_math.c b/source/blender/nodes/intern/CMP_nodes/CMP_math.c index cf2af9bbc11..421c1343df7 100644 --- a/source/blender/nodes/intern/CMP_nodes/CMP_math.c +++ b/source/blender/nodes/intern/CMP_nodes/CMP_math.c @@ -57,7 +57,7 @@ static void do_math(bNode *node, float *out, float *in, float *in2) break; case 3: /* Divide */ { - if(in[1]==0) /* We don't want to divide by zero. */ + if(in2[0]==0) /* We don't want to divide by zero. */ out[0]= 0.0; else out[0]= in[0] / in2[0]; @@ -131,7 +131,23 @@ static void do_math(bNode *node, float *out, float *in, float *in2) { out[0]= (int)(in[0] + 0.5f); } - break; + break; + case 15: /* Less Than */ + { + if( in[0] < in2[0] ) + out[0]= 1.0f; + else + out[0]= 0.0f; + } + break; + case 16: /* Greater Than */ + { + if( in[0] > in2[0] ) + out[0]= 1.0f; + else + out[0]= 0.0f; + } + break; } } @@ -142,7 +158,6 @@ static void node_composit_exec_math(void *data, bNode *node, bNodeStack **in, bN CompBuf *stackbuf; /* check for inputs and outputs for early out*/ - if(in[0]->hasinput==0 && in[1]->hasinput==0) return; if(out[0]->hasoutput==0) return; /* no image-color operation */ diff --git a/source/blender/nodes/intern/CMP_nodes/CMP_premulkey.c b/source/blender/nodes/intern/CMP_nodes/CMP_premulkey.c new file mode 100644 index 00000000000..4fde652c59d --- /dev/null +++ b/source/blender/nodes/intern/CMP_nodes/CMP_premulkey.c @@ -0,0 +1,77 @@ +/** +* $Id$ +* +* ***** 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +* +* The Original Code is Copyright (C) 2006 Blender Foundation. +* All rights reserved. +* +* The Original Code is: all of this file. +* +* Contributor(s): none yet. +* +* ***** END GPL LICENSE BLOCK ***** + +*/ + +#include "../CMP_util.h" + +/* **************** Premul and Key Alpha Convert ******************** */ + +static bNodeSocketType cmp_node_premulkey_in[]= { + { SOCK_RGBA, 1, "Image", 0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f}, + { -1, 0, "" } +}; +static bNodeSocketType cmp_node_premulkey_out[]= { + { SOCK_RGBA, 0, "Image", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f}, + { -1, 0, "" } +}; + +static void node_composit_exec_premulkey(void *data, bNode *node, bNodeStack **in, bNodeStack **out) +{ + if(out[0]->hasoutput==0) + return; + + if(in[0]->data) { + CompBuf *stackbuf, *cbuf= typecheck_compbuf(in[0]->data, CB_RGBA); + + stackbuf= dupalloc_compbuf(cbuf); + premul_compbuf(stackbuf, node->custom1 == 1); + + out[0]->data = stackbuf; + if(cbuf != in[0]->data) + free_compbuf(cbuf); + } +} + +bNodeType cmp_node_premulkey= { + /* *next,*prev */ NULL, NULL, + /* type code */ CMP_NODE_PREMULKEY, + /* name */ "Alpha Convert", + /* width+range */ 140, 100, 320, + /* class+opts */ NODE_CLASS_CONVERTOR, NODE_OPTIONS, + /* input sock */ cmp_node_premulkey_in, + /* output sock */ cmp_node_premulkey_out, + /* storage */ "", + /* execfunc */ node_composit_exec_premulkey, + /* butfunc */ NULL, + /* initfunc */ NULL, + /* freestoragefunc */ NULL, + /* copysotragefunc */ NULL, + /* id */ NULL +}; + diff --git a/source/blender/nodes/intern/CMP_nodes/CMP_texture.c b/source/blender/nodes/intern/CMP_nodes/CMP_texture.c index 31afe74bd11..c1f1948dba1 100644 --- a/source/blender/nodes/intern/CMP_nodes/CMP_texture.c +++ b/source/blender/nodes/intern/CMP_nodes/CMP_texture.c @@ -42,19 +42,18 @@ static bNodeSocketType cmp_node_texture_out[]= { }; /* called without rect allocated */ -static void texture_procedural(CompBuf *cbuf, float *col, float xco, float yco) +static void texture_procedural(CompBuf *cbuf, float *out, float xco, float yco) { bNode *node= cbuf->node; - bNodeSocket *sock= node->inputs.first; TexResult texres= {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0, NULL}; - float vec[3], *size, nor[3]={0.0f, 0.0f, 0.0f}; - int retval, type= cbuf->type; + float vec[3], *size, nor[3]={0.0f, 0.0f, 0.0f}, col[4]; + int retval, type= cbuf->procedural_type; - size= sock->next->ns.vec; + size= cbuf->procedural_size; - vec[0]= size[0]*(xco + sock->ns.vec[0]); - vec[1]= size[1]*(yco + sock->ns.vec[1]); - vec[2]= size[2]*sock->ns.vec[2]; + vec[0]= size[0]*(xco + cbuf->procedural_offset[0]); + vec[1]= size[1]*(yco + cbuf->procedural_offset[1]); + vec[2]= size[2]*cbuf->procedural_offset[2]; retval= multitex_ext((Tex *)node->id, vec, NULL, NULL, 0, &texres); @@ -80,6 +79,8 @@ static void texture_procedural(CompBuf *cbuf, float *col, float xco, float yco) else { VECCOPY(col, nor); } + + typecheck_compbuf_color(out, col, cbuf->type, cbuf->procedural_type); } /* texture node outputs get a small rect, to make sure all other nodes accept it */ @@ -106,6 +107,9 @@ static void node_composit_exec_texture(void *data, bNode *node, bNodeStack **in, prevbuf->rect_procedural= texture_procedural; prevbuf->node= node; + VECCOPY(prevbuf->procedural_offset, in[0]->vec); + VECCOPY(prevbuf->procedural_size, in[1]->vec); + prevbuf->procedural_type= CB_RGBA; composit1_pixel_processor(node, prevbuf, prevbuf, out[0]->vec, do_copy_rgba, CB_RGBA); generate_preview(node, prevbuf); free_compbuf(prevbuf); @@ -115,6 +119,9 @@ static void node_composit_exec_texture(void *data, bNode *node, bNodeStack **in, stackbuf->rect_procedural= texture_procedural; stackbuf->node= node; + VECCOPY(stackbuf->procedural_offset, in[0]->vec); + VECCOPY(stackbuf->procedural_size, in[1]->vec); + stackbuf->procedural_type= CB_VAL; out[0]->data= stackbuf; } @@ -123,6 +130,9 @@ static void node_composit_exec_texture(void *data, bNode *node, bNodeStack **in, stackbuf->rect_procedural= texture_procedural; stackbuf->node= node; + VECCOPY(stackbuf->procedural_offset, in[0]->vec); + VECCOPY(stackbuf->procedural_size, in[1]->vec); + stackbuf->procedural_type= CB_RGBA; out[1]->data= stackbuf; } diff --git a/source/blender/nodes/intern/CMP_nodes/CMP_tonemap.c b/source/blender/nodes/intern/CMP_nodes/CMP_tonemap.c index 662d8e8dde9..950ad97a397 100644 --- a/source/blender/nodes/intern/CMP_nodes/CMP_tonemap.c +++ b/source/blender/nodes/intern/CMP_nodes/CMP_tonemap.c @@ -63,7 +63,7 @@ static float avgLogLum(CompBuf *src, float* auto_key, float* Lav, float* Cav) } -void static tonemap(NodeTonemap* ntm, CompBuf* dst, CompBuf* src) +static void tonemap(NodeTonemap* ntm, CompBuf* dst, CompBuf* src) { int x, y; float dr, dg, db, al, igm = (ntm->gamma==0.f) ? 1 : (1.f / ntm->gamma); @@ -130,13 +130,16 @@ static void node_composit_exec_tonemap(void *data, bNode *node, bNodeStack **in, if ((img==NULL) || (out[0]->hasoutput==0)) return; if (img->type != CB_RGBA) - new = typecheck_compbuf(img, CB_RGBA); - else - new = dupalloc_compbuf(img); + img = typecheck_compbuf(img, CB_RGBA); + + new = dupalloc_compbuf(img); tonemap(node->storage, new, img); out[0]->data = new; + + if(img!=in[0]->data) + free_compbuf(img); } static void node_composit_init_tonemap(bNode* node) diff --git a/source/blender/nodes/intern/CMP_nodes/CMP_zcombine.c b/source/blender/nodes/intern/CMP_nodes/CMP_zcombine.c index 29cf8f34d54..daf61609692 100644 --- a/source/blender/nodes/intern/CMP_nodes/CMP_zcombine.c +++ b/source/blender/nodes/intern/CMP_nodes/CMP_zcombine.c @@ -45,6 +45,19 @@ static bNodeSocketType cmp_node_zcombine_out[]= { { -1, 0, "" } }; +static void do_zcombine(bNode *node, float *out, float *src1, float *z1, float *src2, float *z2) +{ + if(*z1 <= *z2) { + QUATCOPY(out, src1); + } + else { + QUATCOPY(out, src2); + + if(node->custom1) + *z1= *z2; + } +} + static void do_zcombine_mask(bNode *node, float *out, float *z1, float *z2) { if(*z1 > *z2) { @@ -67,43 +80,58 @@ static void do_zcombine_add(bNode *node, float *out, float *col1, float *col2, f static void node_composit_exec_zcombine(void *data, bNode *node, bNodeStack **in, bNodeStack **out) { + RenderData *rd= data; + CompBuf *cbuf= in[0]->data; + CompBuf *zbuf; + /* stack order in: col z col z */ /* stack order out: col z */ - if(out[0]->hasoutput==0) + if(out[0]->hasoutput==0 && out[1]->hasoutput==0) return; /* no input image; do nothing now */ if(in[0]->data==NULL) { return; } + + if(out[1]->hasoutput) { + /* copy or make a buffer for for the first z value, here we write result in */ + if(in[1]->data) + zbuf= dupalloc_compbuf(in[1]->data); + else { + float *zval; + int tot= cbuf->x*cbuf->y; + + zbuf= alloc_compbuf(cbuf->x, cbuf->y, CB_VAL, 1); + for(zval= zbuf->rect; tot; tot--, zval++) + *zval= in[1]->vec[0]; + } + /* lazy coder hack */ + node->custom1= 1; + out[1]->data= zbuf; + } + else { + node->custom1= 0; + zbuf= in[1]->data; + } + + if(rd->scemode & R_FULL_SAMPLE) { + /* make output size of first input image */ + CompBuf *stackbuf= alloc_compbuf(cbuf->x, cbuf->y, CB_RGBA, 1); // allocs + + composit4_pixel_processor(node, stackbuf, in[0]->data, in[0]->vec, zbuf, in[1]->vec, in[2]->data, in[2]->vec, + in[3]->data, in[3]->vec, do_zcombine, CB_RGBA, CB_VAL, CB_RGBA, CB_VAL); + + out[0]->data= stackbuf; + } else { /* make output size of first input image */ - CompBuf *cbuf= in[0]->data; CompBuf *stackbuf= alloc_compbuf(cbuf->x, cbuf->y, CB_RGBA, 1); /* allocs */ - CompBuf *zbuf, *mbuf; + CompBuf *mbuf; float *fp; int x; char *aabuf; - if(out[1]->hasoutput) { - /* copy or make a buffer for for the first z value, here we write result in */ - if(in[1]->data) - zbuf= dupalloc_compbuf(in[1]->data); - else { - float *zval; - int tot= cbuf->x*cbuf->y; - - zbuf= alloc_compbuf(cbuf->x, cbuf->y, CB_VAL, 1); - for(zval= zbuf->rect; tot; tot--, zval++) - *zval= in[1]->vec[0]; - } - /* lazy coder hack */ - node->custom1= 1; - } - else { - node->custom1= 0; - zbuf= in[1]->data; - } /* make a mask based on comparison, optionally write zvalue */ mbuf= alloc_compbuf(cbuf->x, cbuf->y, CB_VAL, 1); @@ -131,9 +159,8 @@ static void node_composit_exec_zcombine(void *data, bNode *node, bNodeStack **in MEM_freeN(aabuf); out[0]->data= stackbuf; - if(node->custom1) - out[1]->data= zbuf; } + } bNodeType cmp_node_zcombine= { diff --git a/source/blender/nodes/intern/CMP_nodes/Makefile b/source/blender/nodes/intern/CMP_nodes/Makefile index bf79d14c020..b70b591a588 100644 --- a/source/blender/nodes/intern/CMP_nodes/Makefile +++ b/source/blender/nodes/intern/CMP_nodes/Makefile @@ -42,3 +42,5 @@ CPPFLAGS += -I../../../blenlib CPPFLAGS += -I../../../editors/include CPPFLAGS += -I../../../imbuf CPPFLAGS += -I../../../render/extern/include +CPPFLAGS += -I$(NAN_GLEW)/include +CPPFLAGS += -I$(OPENGL_HEADERS) diff --git a/source/blender/nodes/intern/CMP_util.c b/source/blender/nodes/intern/CMP_util.c index eee33e33ff5..f9805645115 100644 --- a/source/blender/nodes/intern/CMP_util.c +++ b/source/blender/nodes/intern/CMP_util.c @@ -122,6 +122,48 @@ void print_compbuf(char *str, CompBuf *cbuf) } +/* used for disabling node (similar code in drawnode.c for disable line) */ +void node_compo_pass_on(bNode *node, bNodeStack **nsin, bNodeStack **nsout) +{ + CompBuf *valbuf= NULL, *colbuf= NULL, *vecbuf= NULL; + bNodeSocket *sock; + int a; + + /* connect the first value buffer in with first value out */ + /* connect the first RGBA buffer in with first RGBA out */ + + /* test the inputs */ + for(a=0, sock= node->inputs.first; sock; sock= sock->next, a++) { + if(nsin[a]->data) { + CompBuf *cbuf= nsin[a]->data; + if(cbuf->type==1 && valbuf==NULL) valbuf= cbuf; + if(cbuf->type==3 && vecbuf==NULL) vecbuf= cbuf; + if(cbuf->type==4 && colbuf==NULL) colbuf= cbuf; + } + } + + /* outputs */ + if(valbuf || colbuf || vecbuf) { + for(a=0, sock= node->outputs.first; sock; sock= sock->next, a++) { + if(nsout[a]->hasoutput) { + if(sock->type==SOCK_VALUE && valbuf) { + nsout[a]->data= pass_on_compbuf(valbuf); + valbuf= NULL; + } + if(sock->type==SOCK_VECTOR && vecbuf) { + nsout[a]->data= pass_on_compbuf(vecbuf); + vecbuf= NULL; + } + if(sock->type==SOCK_RGBA && colbuf) { + nsout[a]->data= pass_on_compbuf(colbuf); + colbuf= NULL; + } + } + } + } +} + + CompBuf *get_cropped_compbuf(rcti *drect, float *rectf, int rectx, int recty, int type) { CompBuf *cbuf; @@ -183,17 +225,100 @@ CompBuf *scalefast_compbuf(CompBuf *inbuf, int newx, int newy) return outbuf; } +void typecheck_compbuf_color(float *out, float *in, int outtype, int intype) +{ + if(intype == outtype) { + memcpy(out, in, sizeof(float)*outtype); + } + else if(outtype==CB_VAL) { + if(intype==CB_VEC2) { + *out= 0.5f*(in[0]+in[1]); + } + else if(intype==CB_VEC3) { + *out= 0.333333f*(in[0]+in[1]+in[2]); + } + else if(intype==CB_RGBA) { + *out= in[0]*0.35f + in[1]*0.45f + in[2]*0.2f; + } + } + else if(outtype==CB_VEC2) { + if(intype==CB_VAL) { + out[0]= in[0]; + out[1]= in[0]; + } + else if(intype==CB_VEC3) { + out[0]= in[0]; + out[1]= in[1]; + } + else if(intype==CB_RGBA) { + out[0]= in[0]; + out[1]= in[1]; + } + } + else if(outtype==CB_VEC3) { + if(intype==CB_VAL) { + out[0]= in[0]; + out[1]= in[0]; + out[2]= in[0]; + } + else if(intype==CB_VEC2) { + out[0]= in[0]; + out[1]= in[1]; + out[2]= 0.0f; + } + else if(intype==CB_RGBA) { + out[0]= in[0]; + out[1]= in[1]; + out[2]= in[2]; + } + } + else if(outtype==CB_RGBA) { + if(intype==CB_VAL) { + out[0]= in[0]; + out[1]= in[0]; + out[2]= in[0]; + out[3]= 1.0f; + } + else if(intype==CB_VEC2) { + out[0]= in[0]; + out[1]= in[1]; + out[2]= 0.0f; + out[3]= 1.0f; + } + else if(intype==CB_VEC3) { + out[0]= in[0]; + out[1]= in[1]; + out[2]= in[2]; + out[3]= 1.0f; + } + } +} + CompBuf *typecheck_compbuf(CompBuf *inbuf, int type) { - if(inbuf && inbuf->type!=type && inbuf->rect_procedural==NULL) { - CompBuf *outbuf= alloc_compbuf(inbuf->x, inbuf->y, type, 1); - float *inrf= inbuf->rect; - float *outrf= outbuf->rect; - int x= inbuf->x*inbuf->y; - + if(inbuf && inbuf->type!=type) { + CompBuf *outbuf; + float *inrf, *outrf; + int x; + + outbuf= alloc_compbuf(inbuf->x, inbuf->y, type, 1); + /* warning note: xof and yof are applied in pixelprocessor, but should be copied otherwise? */ outbuf->xof= inbuf->xof; outbuf->yof= inbuf->yof; + + if(inbuf->rect_procedural) { + outbuf->rect_procedural= inbuf->rect_procedural; + VECCOPY(outbuf->procedural_size, inbuf->procedural_size); + VECCOPY(outbuf->procedural_offset, inbuf->procedural_offset); + outbuf->procedural_type= inbuf->procedural_type; + outbuf->node= inbuf->node; + return outbuf; + } + + inrf= inbuf->rect; + outrf= outbuf->rect; + x= inbuf->x*inbuf->y; if(type==CB_VAL) { if(inbuf->type==CB_VEC2) { @@ -460,6 +585,25 @@ CompBuf *valbuf_from_rgbabuf(CompBuf *cbuf, int channel) return valbuf; } +static CompBuf *generate_procedural_preview(CompBuf *cbuf, int newx, int newy) +{ + CompBuf *outbuf; + float *outfp; + int xrad, yrad, x, y; + + outbuf= alloc_compbuf(newx, newy, CB_RGBA, 1); + + outfp= outbuf->rect; + xrad= outbuf->xrad; + yrad= outbuf->yrad; + + for(y= -yrad; y<-yrad+outbuf->y; y++) + for(x= -xrad; x<-xrad+outbuf->x; x++, outfp+=outbuf->type) + cbuf->rect_procedural(cbuf, outfp, (float)x/(float)xrad, (float)y/(float)yrad); + + return outbuf; +} + void generate_preview(bNode *node, CompBuf *stackbuf) { bNodePreview *preview= node->preview; @@ -467,7 +611,7 @@ void generate_preview(bNode *node, CompBuf *stackbuf) if(preview && stackbuf) { CompBuf *cbuf, *stackbuf_use; - if(stackbuf->rect==NULL) return; + if(stackbuf->rect==NULL && stackbuf->rect_procedural==NULL) return; stackbuf_use= typecheck_compbuf(stackbuf, CB_RGBA); @@ -480,7 +624,10 @@ void generate_preview(bNode *node, CompBuf *stackbuf) preview->xsize= (140*stackbuf->x)/stackbuf->y; } - cbuf= scalefast_compbuf(stackbuf_use, preview->xsize, preview->ysize); + if(stackbuf_use->rect_procedural) + cbuf= generate_procedural_preview(stackbuf_use, preview->xsize, preview->ysize); + else + cbuf= scalefast_compbuf(stackbuf_use, preview->xsize, preview->ysize); /* this ensures free-compbuf does the right stuff */ SWAP(float *, cbuf->rect, node->preview->rect); @@ -575,6 +722,36 @@ void gamma_correct_compbuf(CompBuf *img, int inversed) } } +void premul_compbuf(CompBuf *img, int inversed) +{ + float *drect; + int x; + + if(img->type!=CB_RGBA) return; + + drect= img->rect; + if(inversed) { + for(x=img->x*img->y; x>0; x--, drect+=4) { + if(fabs(drect[3]) < 1e-5f) { + drect[0]= 0.0f; + drect[1]= 0.0f; + drect[2]= 0.0f; + } + else { + drect[0] /= drect[3]; + drect[1] /= drect[3]; + drect[2] /= drect[3]; + } + } + } + else { + for(x=img->x*img->y; x>0; x--, drect+=4) { + drect[0] *= drect[3]; + drect[1] *= drect[3]; + drect[2] *= drect[3]; + } + } +} diff --git a/source/blender/nodes/intern/CMP_util.h b/source/blender/nodes/intern/CMP_util.h index 44f76b0822e..8443c022d17 100644 --- a/source/blender/nodes/intern/CMP_util.h +++ b/source/blender/nodes/intern/CMP_util.h @@ -92,6 +92,8 @@ typedef struct CompBuf { int xof, yof; /* relative to center of target image */ void (*rect_procedural)(struct CompBuf *, float *, float, float); + float procedural_size[3], procedural_offset[3]; + int procedural_type; bNode *node; /* only in use for procedural bufs */ struct CompBuf *next, *prev; /* for pass-on, works nicer than reference counting */ @@ -117,10 +119,12 @@ CompBuf *dupalloc_compbuf(CompBuf *cbuf); CompBuf *pass_on_compbuf(CompBuf *cbuf); void free_compbuf(CompBuf *cbuf); void print_compbuf(char *str, CompBuf *cbuf); +void node_compo_pass_on(struct bNode *node, struct bNodeStack **nsin, struct bNodeStack **nsout); CompBuf *get_cropped_compbuf(rcti *drect, float *rectf, int rectx, int recty, int type); CompBuf *scalefast_compbuf(CompBuf *inbuf, int newx, int newy); CompBuf *typecheck_compbuf(CompBuf *inbuf, int type); +void typecheck_compbuf_color(float *out, float *in, int outtype, int intype); float *compbuf_get_pixel(CompBuf *cbuf, float *rectf, int x, int y, int xrad, int yrad); /* **************************************************** */ @@ -161,6 +165,7 @@ void do_hsva_to_rgba(bNode *node, float *out, float *in); void do_ycca_to_rgba(bNode *node, float *out, float *in); void gamma_correct_compbuf(CompBuf *img, int inversed); +void premul_compbuf(CompBuf *img, int inversed); void convolve(CompBuf* dst, CompBuf* in1, CompBuf* in2); extern void node_ID_title_cb(void *node_v, void *unused_v); diff --git a/source/blender/nodes/intern/Makefile b/source/blender/nodes/intern/Makefile index 59c57e42bc1..7c9a67b6cc5 100644 --- a/source/blender/nodes/intern/Makefile +++ b/source/blender/nodes/intern/Makefile @@ -42,6 +42,8 @@ CPPFLAGS += -I../../blenlib CPPFLAGS += -I../../editors/include CPPFLAGS += -I../../imbuf CPPFLAGS += -I../../render/extern/include +CPPFLAGS += -I../../gpu +CPPFLAGS += -I$(NAN_GLEW)/include CPPFLAGS += -I$(OPENGL_HEADERS) DIRS = SHD_nodes CMP_nodes diff --git a/source/blender/nodes/intern/SHD_nodes/Makefile b/source/blender/nodes/intern/SHD_nodes/Makefile index ca83c25d277..1369d346fc6 100644 --- a/source/blender/nodes/intern/SHD_nodes/Makefile +++ b/source/blender/nodes/intern/SHD_nodes/Makefile @@ -35,6 +35,8 @@ include nan_compile.mk CFLAGS += $(LEVEL_1_C_WARNINGS) +CPPFLAGS += -I$(NAN_PYTHON)/include/python$(NAN_PYTHON_VERSION) +CPPFLAGS += -I../../../python CPPFLAGS += -I../../../blenkernel CPPFLAGS += -I$(NAN_GUARDEDALLOC)/include CPPFLAGS += -I../../../makesdna @@ -42,3 +44,6 @@ CPPFLAGS += -I../../../blenlib CPPFLAGS += -I../../../editors/include CPPFLAGS += -I../../../imbuf CPPFLAGS += -I../../../render/extern/include +CPPFLAGS += -I../../../gpu +CPPFLAGS += -I$(NAN_GLEW)/include +CPPFLAGS += -I$(OPENGL_HEADERS) diff --git a/source/blender/nodes/intern/SHD_nodes/SHD_camera.c b/source/blender/nodes/intern/SHD_nodes/SHD_camera.c index 63260ff91ed..20136d75540 100644 --- a/source/blender/nodes/intern/SHD_nodes/SHD_camera.c +++ b/source/blender/nodes/intern/SHD_nodes/SHD_camera.c @@ -46,8 +46,13 @@ static void node_shader_exec_camera(void *data, bNode *node, bNodeStack **in, bN VECCOPY(out[0]->vec, shi->co); /* get view vector */ out[1]->vec[0]= fabs(shi->co[2]); /* get view z-depth */ out[2]->vec[0]= Normalize(out[0]->vec); /* get view distance */ - } } +} + +static int gpu_shader_camera(GPUMaterial *mat, bNode *node, GPUNodeStack *in, GPUNodeStack *out) +{ + return GPU_stack_link(mat, "camera", in, out, GPU_builtin(GPU_VIEW_POSITION)); +} bNodeType sh_node_camera= { /* *next,*prev */ NULL, NULL, @@ -63,6 +68,7 @@ bNodeType sh_node_camera= { /* initfunc */ NULL, /* freestoragefunc */ NULL, /* copystoragefunc */ NULL, - /* id */ NULL + /* id */ NULL, NULL, NULL, + /* gpufunc */ gpu_shader_camera }; diff --git a/source/blender/nodes/intern/SHD_nodes/SHD_curves.c b/source/blender/nodes/intern/SHD_nodes/SHD_curves.c index b6f1f8d52cd..d277547b636 100644 --- a/source/blender/nodes/intern/SHD_nodes/SHD_curves.c +++ b/source/blender/nodes/intern/SHD_nodes/SHD_curves.c @@ -56,6 +56,15 @@ static void node_shader_init_curve_vec(bNode* node) node->storage= curvemapping_add(3, -1.0f, -1.0f, 1.0f, 1.0f); } +static int gpu_shader_curve_vec(GPUMaterial *mat, bNode *node, GPUNodeStack *in, GPUNodeStack *out) +{ + float *array; + int size; + + curvemapping_table_RGBA(node->storage, &array, &size); + return GPU_stack_link(mat, "curves_vec", in, out, GPU_texture(size, array)); +} + bNodeType sh_node_curve_vec= { /* *next,*prev */ NULL, NULL, /* type code */ SH_NODE_CURVE_VEC, @@ -70,7 +79,8 @@ bNodeType sh_node_curve_vec= { /* initfunc */ node_shader_init_curve_vec, /* freestoragefunc */ node_free_curves, /* copystoragefunc */ node_copy_curves, - /* id */ NULL + /* id */ NULL, NULL, NULL, + /* gpufunc */ gpu_shader_curve_vec }; @@ -100,6 +110,15 @@ static void node_shader_init_curve_rgb(bNode *node) node->storage= curvemapping_add(4, 0.0f, 0.0f, 1.0f, 1.0f); } +static int gpu_shader_curve_rgb(GPUMaterial *mat, bNode *node, GPUNodeStack *in, GPUNodeStack *out) +{ + float *array; + int size; + + curvemapping_table_RGBA(node->storage, &array, &size); + return GPU_stack_link(mat, "curves_rgb", in, out, GPU_texture(size, array)); +} + bNodeType sh_node_curve_rgb= { /* *next,*prev */ NULL, NULL, /* type code */ SH_NODE_CURVE_RGB, @@ -114,6 +133,7 @@ bNodeType sh_node_curve_rgb= { /* initfunc */ node_shader_init_curve_rgb, /* freestoragefunc */ node_free_curves, /* copystoragefunc */ node_copy_curves, - /* id */ NULL + /* id */ NULL, NULL, NULL, + /* gpufunc */ gpu_shader_curve_rgb }; diff --git a/source/blender/nodes/intern/SHD_nodes/SHD_dynamic.c b/source/blender/nodes/intern/SHD_nodes/SHD_dynamic.c index 1ba777a0533..4fcfe3a789a 100644 --- a/source/blender/nodes/intern/SHD_nodes/SHD_dynamic.c +++ b/source/blender/nodes/intern/SHD_nodes/SHD_dynamic.c @@ -27,221 +27,749 @@ * ***** END GPL LICENSE BLOCK ***** */ -#ifdef USE_PYNODES /* note: won't work without patch */ - +#ifndef DISABLE_PYTHON #include <Python.h> +#include <compile.h> #include <eval.h> +#endif #include "DNA_text_types.h" #include "BKE_text.h" +#include "BKE_utildefines.h" +// XXX +#if 0 +#ifndef DISABLE_PYTHON #include "api2_2x/Node.h" #include "api2_2x/gen_utils.h" #include "BPY_extern.h" +#endif +#endif #include "../SHD_util.h" +// XXX +#if 0 +static void node_dynamic_setup(bNode *node); +static void node_dynamic_exec_cb(void *data, bNode *node, bNodeStack **in, bNodeStack **out); +static void node_dynamic_free_storage_cb(bNode *node); + +#ifndef DISABLE_PYTHON static PyObject *init_dynamicdict(void) { - PyObject *newscriptdict= PyDict_New(); + PyObject *newscriptdict; + PyGILState_STATE gilstate = PyGILState_Ensure(); + + newscriptdict= PyDict_New(); + PyDict_SetItemString(newscriptdict, "__builtins__", PyEval_GetBuiltins()); EXPP_dict_set_item_str(newscriptdict, "__name__", PyString_FromString("__main__")); + + PyGILState_Release(gilstate); + return newscriptdict; } +#endif + +static bNodeType *node_dynamic_find_typeinfo(ListBase *list, ID *id) +{ + bNodeType *ntype = list->first; -static void free_dynamicdict(PyObject *dict) { - if(dict!=NULL) { - Py_DECREF(dict); + while(ntype) { + if (ntype->type == NODE_DYNAMIC && ntype->id == id) + break; + ntype = ntype->next; } + + return ntype; /* NULL if doesn't exist */ } -static void node_dynamic_init(bNode *node) { - NodeScriptDict *nsd= MEM_callocN(sizeof(NodeScriptDict), "node script dictionary"); - int type= node->custom2; - node->custom2= 0; - node->storage= nsd; - if(type>=NODE_DYNAMIC_MENU) { - if(type==NODE_DYNAMIC_MENU) { - nodeMakeDynamicType(node); - node->custom1= SH_NODE_DYNAMIC_NEW; - } else { - node->custom1= SH_NODE_DYNAMIC_ADDEXIST; +static void node_dynamic_free_typeinfo_sockets(bNodeType *tinfo) +{ + bNodeSocketType *sock; + + if (!tinfo) return; + + if (tinfo->inputs) { + sock = tinfo->inputs; + while (sock->type != -1) { + MEM_freeN(sock->name); + sock++; + } + MEM_freeN(tinfo->inputs); + tinfo->inputs = NULL; + } + if (tinfo->outputs) { + sock = tinfo->outputs; + while (sock->type != -1) { + MEM_freeN(sock->name); + sock++; + } + MEM_freeN(tinfo->outputs); + tinfo->outputs = NULL; + } +} + +static void node_dynamic_free_typeinfo(bNodeType *tinfo) +{ + if (!tinfo) return; + + node_dynamic_free_typeinfo_sockets(tinfo); + + if (tinfo->name) { MEM_freeN(tinfo->name); } + + MEM_freeN(tinfo); +} + +static void node_dynamic_free_sockets(bNode *node) +{ + BLI_freelistN(&node->inputs); + BLI_freelistN(&node->outputs); +} + +/* For now we just remove the socket links. It's the safest + * route, since an update in the script may change completely the + * inputs and outputs. Trying to recreate the node links would be + * nicer for pynode authors, though. */ +static void node_dynamic_update_socket_links(bNode *node, bNodeTree *ntree) +{ + if (ntree) { + nodeVerifyType(ntree, node); + } + else { + Material *ma; + + for (ma= G.main->mat.first; ma; ma= ma->id.next) { + if (ma->nodetree) { + bNode *nd; + for (nd= ma->nodetree->nodes.first; nd; nd = nd->next) { + if (nd == node) nodeVerifyType(ma->nodetree, node); + } + } } - node->id= node->typeinfo->id; - nodeDynamicParse(node); - } else { - if(node->custom1== SH_NODE_DYNAMIC_LOADED) { - nodeMakeDynamicType(node); - nodeDynamicParse(node); - } else if(node->custom1== SH_NODE_DYNAMIC_ADDEXIST) - nodeDynamicParse(node); } } -static void node_dynamic_free(bNode *node) +static void node_dynamic_free_storage_cb(bNode *node) { - NodeScriptDict *nsd= (NodeScriptDict *)(node->storage); - BPy_Node *pynode= nsd->node; - Py_XDECREF(pynode); - free_dynamicdict((PyObject *)(nsd->dict)); +#ifndef DISABLE_PYTHON + NodeScriptDict *nsd; + PyObject *pydict; + BPy_Node *pynode; + + if (!node->storage) return; + nsd = (NodeScriptDict *)(node->storage); + pydict = nsd->dict; + if (pydict) { + Py_DECREF(pydict); + } + pynode = nsd->node; + if (pynode) { + Py_DECREF(pynode); + } +#endif MEM_freeN(node->storage); + node->storage = NULL; } -static void node_dynamic_copy(bNode *orig_node, bNode *new_node) +/* Disable pynode when its script fails */ +static void node_dynamic_disable(bNode *node) { - NodeScriptDict *nsd= (NodeScriptDict *)(orig_node->storage); - new_node->storage= MEM_dupallocN(orig_node->storage); - if(nsd->node) - Py_INCREF((PyObject *)(nsd->node)); - if(nsd->dict) - Py_INCREF((PyObject *)(nsd->dict)); + node->custom1 = 0; + node->custom1 = BSET(node->custom1, NODE_DYNAMIC_ERROR); } -static void node_dynamic_exec(void *data, bNode *node, bNodeStack **in, bNodeStack **out) { - BPy_Node *mynode = NULL; - NodeScriptDict *nsd = NULL; - PyObject *pyresult = NULL; - PyObject *args = NULL; - ShadeInput *shi= ((ShaderCallData *)data)->shi; +/* Disable all pynodes using the given text (script) id */ +static void node_dynamic_disable_all_by_id(ID *id) +{ +#ifndef DISABLE_PYTHON + Material *ma; /* XXX hardcoded for shaders */ - if(node->custom1==SH_NODE_DYNAMIC_NEW) { - nodeDynamicParse(node); - return; + for (ma= G.main->mat.first; ma; ma= ma->id.next) { + if (ma->nodetree) { + bNode *nd; + bNodeTree *ntree = ma->nodetree; + for (nd= ntree->nodes.first; nd; nd= nd->next) { + if (nd->id == id) { + nd->custom1 = 0; + nd->custom1 = BSET(nd->custom1, NODE_DYNAMIC_ERROR); + } + } + } } +#endif +} - if(node->custom2<0) - return; +static void node_rem_socklist_links(bNodeTree *ntree, ListBase *lb) +{ + bNodeLink *link, *next; + bNodeSocket *sock; - if(node->custom1==SH_NODE_DYNAMIC_READY || node->custom1==SH_NODE_DYNAMIC_UPDATED) { - if(node->custom1== SH_NODE_DYNAMIC_UPDATED) - node->custom1= SH_NODE_DYNAMIC_READY; + if (!lb) return; - nsd = (NodeScriptDict *)node->storage; + for (sock= lb->first; sock; sock= sock->next) { + for (link= ntree->links.first; link; link= next) { + next= link->next; + if (link->fromsock==sock || link->tosock==sock) { + nodeRemLink(ntree, link); + } + } + } +} - mynode = (BPy_Node *)(nsd->node); - if(mynode && PyCallable_Check((PyObject *)mynode)) { - mynode->node= node; - Node_SetStack(mynode, in, NODE_INPUTSTACK); - Node_SetStack(mynode, out, NODE_OUTPUTSTACK); - Node_SetShi(mynode, shi); - args=Py_BuildValue("()"); - pyresult= PyObject_Call((PyObject *)mynode, args, NULL); - if(!pyresult) { - if(PyErr_Occurred()) { - PyErr_Print(); - node->custom2= -1; - } else { - printf("PyObject_Call __call__ failed\n"); +/* XXX hardcoded for shaders */ +static void node_dynamic_rem_all_links(bNodeType *tinfo) +{ + Material *ma; + int in, out; + + in = tinfo->inputs ? 1 : 0; + out = tinfo->outputs ? 1 : 0; + + if (!in && !out) return; + + for (ma= G.main->mat.first; ma; ma= ma->id.next) { + if (ma->nodetree) { + bNode *nd; + bNodeTree *ntree = ma->nodetree; + for (nd= ntree->nodes.first; nd; nd= nd->next) { + if (nd->typeinfo == tinfo) { + if (in) + node_rem_socklist_links(ntree, &nd->inputs); + if (out) + node_rem_socklist_links(ntree, &nd->outputs); } } - Py_XDECREF(pyresult); - Py_DECREF(args); } } } -void nodeDynamicParse(struct bNode *node) +/* node_dynamic_reset: clean a pynode, getting rid of all + * data dynamically created for it. */ +static void node_dynamic_reset(bNode *node, int unlink_text) +{ + bNodeType *tinfo, *tinfo_default; + Material *ma; + + tinfo = node->typeinfo; + tinfo_default = node_dynamic_find_typeinfo(&node_all_shaders, NULL); + + if ((tinfo == tinfo_default) && unlink_text) { + ID *textID = node->id; + /* already at default (empty) state, which happens if this node's + * script failed to parse at the first stage: definition. We're here + * because its text was removed from Blender. */ + for (ma= G.main->mat.first; ma; ma= ma->id.next) { + if (ma->nodetree) { + bNode *nd; + for (nd= ma->nodetree->nodes.first; nd; nd = nd->next) { + if (nd->id == textID) { + nd->id = NULL; + nd->custom1 = 0; + nd->custom1 = BSET(nd->custom1, NODE_DYNAMIC_NEW); + BLI_strncpy(nd->name, "Dynamic", 8); + return; + } + } + } + } + } + + node_dynamic_rem_all_links(tinfo); + node_dynamic_free_typeinfo_sockets(tinfo); + + /* reset all other XXX shader nodes sharing this typeinfo */ + for (ma= G.main->mat.first; ma; ma= ma->id.next) { + if (ma->nodetree) { + bNode *nd; + for (nd= ma->nodetree->nodes.first; nd; nd = nd->next) { + if (nd->typeinfo == tinfo) { + node_dynamic_free_storage_cb(nd); + node_dynamic_free_sockets(nd); + //node_dynamic_update_socket_links(nd, ma->nodetree); + nd->typeinfo = tinfo_default; + if (unlink_text) { + nd->id = NULL; + nd->custom1 = 0; + nd->custom1 = BSET(nd->custom1, NODE_DYNAMIC_NEW); + BLI_strncpy(nd->name, "Dynamic", 8); + } + } + } + } + } + + /* XXX hardcoded for shaders: */ + if (tinfo->id) { BLI_remlink(&node_all_shaders, tinfo); } + node_dynamic_free_typeinfo(tinfo); +} + +/* Special case of the above function: for working pynodes + * that were saved on a .blend but fail for some reason when + * the file is opened. We need this because pynodes are initialized + * before G.main. */ +static void node_dynamic_reset_loaded(bNode *node) +{ + bNodeType *tinfo = node->typeinfo; + + node_dynamic_rem_all_links(tinfo); + node_dynamic_free_typeinfo_sockets(tinfo); + node_dynamic_free_storage_cb(node); + /* XXX hardcoded for shaders: */ + if (tinfo->id) { BLI_remlink(&node_all_shaders, tinfo); } + + node_dynamic_free_typeinfo(tinfo); + node->typeinfo = node_dynamic_find_typeinfo(&node_all_shaders, NULL); +} + +int nodeDynamicUnlinkText(ID *txtid) { + Material *ma; + bNode *nd; + + /* find one node that uses this text */ + for (ma= G.main->mat.first; ma; ma= ma->id.next) { + if (ma->nodetree) { + for (nd= ma->nodetree->nodes.first; nd; nd = nd->next) { + if ((nd->type == NODE_DYNAMIC) && (nd->id == txtid)) { + node_dynamic_reset(nd, 1); /* found, reset all */ + return 1; + } + } + } + } + return 0; /* no pynodes used this text */ +} + +static void node_dynamic_pyerror_print(bNode *node) +{ +#ifndef DISABLE_PYTHON + PyGILState_STATE gilstate = PyGILState_Ensure(); + + fprintf(stderr, "\nError in dynamic node script \"%s\":\n", node->name); + if (PyErr_Occurred()) { PyErr_Print(); } + else { fprintf(stderr, "Not a valid dynamic node Python script.\n"); } + + PyGILState_Release(gilstate); +#endif +} + +static void node_dynamic_register_type(bNode *node) +{ + nodeRegisterType(&node_all_shaders, node->typeinfo); + /* nodeRegisterType copied it to a new one, so we + * free the typeinfo itself, but not what it + * points to: */ + MEM_freeN(node->typeinfo); + node->typeinfo = node_dynamic_find_typeinfo(&node_all_shaders, node->id); + MEM_freeN(node->typeinfo->name); + node->typeinfo->name = BLI_strdup(node->name); +} + +#ifndef DISABLE_PYTHON +/* node_dynamic_get_pynode: + * Find the pynode definition from the script */ +static PyObject *node_dynamic_get_pynode(PyObject *dict) { - BPy_Node *pynode= NULL; - PyObject *dict= NULL; PyObject *key= NULL; - PyObject *value= NULL; - PyObject *testinst= NULL; + Py_ssize_t pos = 0; + PyObject *value = NULL; + + /* script writer specified a node? */ + value = PyDict_GetItemString(dict, "__node__"); + + if (value) { + if (PyObject_TypeCheck(value, &PyType_Type)) { + Py_INCREF(value); + return value; + } + else { + PyErr_SetString(PyExc_TypeError, + "expected class object derived from Scripted node"); + return NULL; + } + } + + /* case not, search for it in the script's global dictionary */ + while (PyDict_Next(dict, &pos, &key, &value)) { + /* skip names we know belong to other available objects */ + if (strcmp("Socket", PyString_AsString(key)) == 0) + continue; + else if (strcmp("Scripted", PyString_AsString(key)) == 0) + continue; + /* naive: we grab the first ob of type 'type': */ + else if (PyObject_TypeCheck(value, &PyType_Type)) { + Py_INCREF(value); + return value; + } + } + + PyErr_SetString(PyExc_TypeError, + "no PyNode definition found in the script!"); + return NULL; +} +#endif /* DISABLE_PYTHON */ + +static int node_dynamic_parse(struct bNode *node) +{ +#ifdef DISABLE_PYTHON + return -1; +#else + PyObject *dict= NULL; + PyObject *pynode_data= NULL; + PyObject *pynode= NULL; PyObject *args= NULL; - int pos = 0; - NodeScriptDict *nsd= NULL; + NodeScriptDict *nsd = NULL; PyObject *pyresult = NULL; - PyObject *pycompiled = NULL; - Text *txt = NULL; - char *buf= NULL; + char *buf = NULL; + int is_valid_script = 0; + PyGILState_STATE gilstate; + + if (!node->id || !node->storage) + return 0; + + /* READY, no need to be here */ + if (BTST(node->custom1, NODE_DYNAMIC_READY)) + return 0; + + /* for threading */ + gilstate = PyGILState_Ensure(); + + nsd = (NodeScriptDict *)node->storage; + + dict = (PyObject *)(nsd->dict); + buf = txt_to_buf((Text *)node->id); + + pyresult = PyRun_String(buf, Py_file_input, dict, dict); + + MEM_freeN(buf); + + if (!pyresult) { + if (BTST(node->custom1, NODE_DYNAMIC_LOADED)) { + node_dynamic_disable(node); + } else { + node_dynamic_disable_all_by_id(node->id); + } + node_dynamic_pyerror_print(node); + PyGILState_Release(gilstate); + return -1; + } + + Py_DECREF(pyresult); + + pynode_data = node_dynamic_get_pynode(dict); + + if (pynode_data) { + BPy_NodeSocketLists *socklists = Node_CreateSocketLists(node); + + args = Py_BuildValue("(O)", socklists); + + /* init it to get the input and output sockets */ + pynode = PyObject_Call(pynode_data, args, NULL); + + Py_DECREF(pynode_data); + Py_DECREF(socklists); + Py_DECREF(args); + + if (!PyErr_Occurred() && pynode && pytype_is_pynode(pynode)) { + InitNode((BPy_Node *)(pynode), node); + nsd->node = pynode; + node->typeinfo->execfunc = node_dynamic_exec_cb; + is_valid_script = 1; + + /* for NEW, LOADED, REPARSE */ + if (BNTST(node->custom1, NODE_DYNAMIC_ADDEXIST)) { + node->typeinfo->pydict = dict; + node->typeinfo->pynode = pynode; + node->typeinfo->id = node->id; + if (BNTST(node->custom1, NODE_DYNAMIC_LOADED)) + nodeAddSockets(node, node->typeinfo); + if (BNTST(node->custom1, NODE_DYNAMIC_REPARSE)) + node_dynamic_register_type(node); + } + + node->custom1 = 0; + node->custom1 = BSET(node->custom1, NODE_DYNAMIC_READY); + } + } + + PyGILState_Release(gilstate); + + if (!is_valid_script) { /* not a valid pynode script */ + node_dynamic_disable_all_by_id(node->id); + node_dynamic_pyerror_print(node); + return -1; + } + + return 0; +#endif +} + +/* node_dynamic_setup: prepare for execution (state: NODE_DYNAMIC_READY) + * pynodes already linked to a script (node->id != NULL). */ +static void node_dynamic_setup(bNode *node) +{ +#ifndef DISABLE_PYTHON + NodeScriptDict *nsd = NULL; + bNodeTree *nodetree = NULL; + bNodeType *ntype = NULL; + PyGILState_STATE gilstate; - if(! node->id) { + /* Possible cases: + * NEW + * ADDEXIST + * LOADED + * REPARSE + * ERROR + * READY + */ + + /* NEW, but not linked to a script: link default (empty) typeinfo */ + if (!node->id) { + node->typeinfo = node_dynamic_find_typeinfo(&node_all_shaders, + NULL); return; } - if(node->custom1!=SH_NODE_DYNAMIC_READY) { - txt = (Text *)node->id; - nsd = (NodeScriptDict *)node->storage; + /* READY, no need to be here */ + if (BTST(node->custom1, NODE_DYNAMIC_READY)) + return; + + gilstate = PyGILState_Ensure(); + + /* ERROR, reset to (empty) defaults */ + if (BCLR(node->custom1, NODE_DYNAMIC_ERROR) == 0) { + node_dynamic_reset(node, 0); + PyGILState_Release(gilstate); + return; + } + + /* User asked to update this pynode, prepare it for reparsing */ + if (BTST(node->custom1, NODE_DYNAMIC_REPARSE)) { + int needs_parsing = 1; + + node->custom1 = BSET(node->custom1, NODE_DYNAMIC_NEW); + + if (BTST(node->custom1, NODE_DYNAMIC_ERROR)) { + node->custom1 = BCLR(node->custom1, NODE_DYNAMIC_REPARSE); + ntype = node_dynamic_find_typeinfo(&node_all_shaders, node->id); + + if (ntype) { + node->typeinfo = ntype; + node->custom1 = BSET(node->custom1, NODE_DYNAMIC_ADDEXIST); + node->custom1 = BCLR(node->custom1, NODE_DYNAMIC_ERROR); + needs_parsing = 0; + } + else { nodeMakeDynamicType(node); } + + } else { + node_dynamic_rem_all_links(node->typeinfo); + node_dynamic_free_typeinfo_sockets(node->typeinfo); + node_dynamic_update_socket_links(node, NULL); + node_dynamic_free_storage_cb(node); + } - if(nsd->dict==NULL && (node->custom1==SH_NODE_DYNAMIC_NEW||node->custom1==SH_NODE_DYNAMIC_LOADED)) { - nsd->dict= init_dynamicdict(); - } else if(nsd->dict==NULL && node->custom1==SH_NODE_DYNAMIC_ADDEXIST) { - nsd->dict= node->typeinfo->pydict; - nsd->node= node->typeinfo->pynode; - Py_INCREF((PyObject *)(nsd->dict)); - Py_INCREF((PyObject *)(nsd->node)); - node->custom1= SH_NODE_DYNAMIC_READY; + if (needs_parsing) { + nsd = MEM_callocN(sizeof(NodeScriptDict), "node script dictionary"); + nsd->dict = init_dynamicdict(); + node->storage = nsd; + /* prepared, now reparse: */ + node_dynamic_parse(node); + PyGILState_Release(gilstate); return; } - dict= (PyObject *)(nsd->dict); + } + else if (BTST(node->custom1, NODE_DYNAMIC_LOADED)) { + /* when loading from a .blend we don't have G.main yet, so we + * quickly abuse node->storage in ntreeInitTypes (node.c) to have + * our nodetree ptr (needed if a pynode script that worked before + * saving the .blend for some reason fails upon loading): */ + nodetree = (bNodeTree *)node->storage; + node->storage = NULL; + } - if(node->custom1!=SH_NODE_DYNAMIC_ADDEXIST) { - buf = txt_to_buf( txt ); - /*printf("Running script (%s, %d)...", node->name, node->custom1);*/ - pyresult = PyRun_String(buf, Py_file_input, dict, dict); - /*printf(" done\n");*/ + if (node->storage) + fprintf(stderr, "\nDEBUG: PYNODES ERROR: non NULL node->storage in node_dynamic_setup()\n"); - MEM_freeN(buf); + nsd = MEM_callocN(sizeof(NodeScriptDict), "node script dictionary"); + node->storage = nsd; + + /* NEW, LOADED or REPARSE */ + if (BNTST(node->custom1, NODE_DYNAMIC_ADDEXIST)) { + /* check if there's already a bNodeType linked to this script */ + /* (XXX hardcoded for shader nodes for now) */ + ntype = node_dynamic_find_typeinfo(&node_all_shaders, node->id); - if(!pyresult) { - if(PyErr_Occurred()) { - PyErr_Print(); - } - Py_XDECREF(pyresult); - return; + if (ntype) { /* if so, reuse it */ + node->typeinfo = ntype; + /* so this is actually an ADDEXIST type */ + node->custom1 = BSET(node->custom1, NODE_DYNAMIC_ADDEXIST); + } + else { /* create bNodeType for this pynode */ + nodeMakeDynamicType(node); + nsd->dict = init_dynamicdict(); + if ((node_dynamic_parse(node) == -1) && nodetree) { + node_dynamic_reset_loaded(node); } + PyGILState_Release(gilstate); + return; + } + } - Py_DECREF(pyresult); + /* ADDEXIST: new pynode linked to an already registered dynamic type, + * we just reuse existing py dict and pynode */ + nsd->dict = node->typeinfo->pydict; + nsd->node = node->typeinfo->pynode; - while(PyDict_Next( (PyObject *)(nsd->dict), &pos, &key, &value) ) { - if(PyObject_TypeCheck(value, &PyType_Type)==1) { - BPy_DefinitionMap *outputdef= Node_CreateOutputDefMap(node); - BPy_DefinitionMap *inputdef= Node_CreateInputDefMap(node); - - args= Py_BuildValue("(OO)", inputdef, outputdef); - testinst= PyObject_Call(value, args, NULL); - - Py_DECREF(outputdef); - Py_DECREF(inputdef); - if(testinst && PyObject_TypeCheck(testinst, &Node_Type)==1) { - Py_INCREF(testinst); - Py_INCREF(dict); - InitNode((BPy_Node *)(testinst), node); - nsd->node= testinst; - node->typeinfo->execfunc= node_dynamic_exec; - if(node->custom1== SH_NODE_DYNAMIC_NEW || node->custom1== SH_NODE_DYNAMIC_LOADED) { - node->typeinfo->pynode= testinst; - node->typeinfo->pydict= nsd->dict; - node->typeinfo->id= node->id; - nodeAddSockets(node, node->typeinfo); - nodeRegisterType(&node_all_shaders, node->typeinfo); - node->custom1= SH_NODE_DYNAMIC_READY; - } - break; - } - Py_DECREF(args); - } - } + Py_INCREF((PyObject *)(nsd->dict)); + Py_INCREF((PyObject *)(nsd->node)); + + if (BTST(node->custom1, NODE_DYNAMIC_NEW)) { + nodeAddSockets(node, node->typeinfo); + node->custom1 = BCLR(node->custom1, NODE_DYNAMIC_NEW); + } + + node->custom1 = BCLR(node->custom1, NODE_DYNAMIC_ADDEXIST); + node->custom1 = BSET(node->custom1, NODE_DYNAMIC_READY); + + PyGILState_Release(gilstate); +#endif /* DISABLE_PYTHON */ + return; +} + +/* node_dynamic_init_cb callback: called when a pynode is created. + * The pynode type is passed via node->custom2. It can be: + * 0: for loaded empty nodes + * NODE_DYNAMIC_MENU: for the default Dynamic node type + * > NODE_DYNAMIC_MENU: for the new types defined by scripts +*/ +static void node_dynamic_init_cb(bNode *node) { + int type = node->custom2; + + node->custom2 = 0; + + if (type >= NODE_DYNAMIC_MENU) { + node->custom1 = 0; + + if (type == NODE_DYNAMIC_MENU) { + node->custom1 = BSET(node->custom1, NODE_DYNAMIC_NEW); + return; } + + node->custom1 = BSET(node->custom1, NODE_DYNAMIC_ADDEXIST); + node->id = node->typeinfo->id; } + + node_dynamic_setup(node); +} + +/* node_dynamic_copy_cb: pynode copy callback */ +static void node_dynamic_copy_cb(bNode *orig_node, bNode *new_node) +{ +#ifdef DISABLE_PYTHON + return; +#else + NodeScriptDict *nsd; + PyGILState_STATE gilstate; + + if (!orig_node->storage) return; + + nsd = (NodeScriptDict *)(orig_node->storage); + new_node->storage = MEM_dupallocN(orig_node->storage); + + gilstate = PyGILState_Ensure(); + + if (nsd->node) + Py_INCREF((PyObject *)(nsd->node)); + if (nsd->dict) + Py_INCREF((PyObject *)(nsd->dict)); + + PyGILState_Release(gilstate); +#endif } +/* node_dynamic_exec_cb: the execution callback called per pixel + * during rendering. */ +static void node_dynamic_exec_cb(void *data, bNode *node, bNodeStack **in, bNodeStack **out) { +#ifdef DISABLE_PYTHON + return; +#else + BPy_Node *mynode = NULL; + NodeScriptDict *nsd = NULL; + PyObject *pyresult = NULL; + PyObject *args = NULL; + ShadeInput *shi; + PyGILState_STATE gilstate; + + if (!node->id) + return; + + /*if (G.scene->r.threads > 1) + return;*/ + + if (BTST2(node->custom1, NODE_DYNAMIC_NEW, NODE_DYNAMIC_REPARSE)) { + node_dynamic_setup(node); + return; + } + + if (BTST(node->custom1, NODE_DYNAMIC_ERROR)) { + if (node->storage) node_dynamic_setup(node); + return; + } + + if (BTST(node->custom1, NODE_DYNAMIC_READY)) { + nsd = (NodeScriptDict *)node->storage; + mynode = (BPy_Node *)(nsd->node); + + + if (mynode && PyCallable_Check((PyObject *)mynode)) { + + gilstate = PyGILState_Ensure(); + + mynode->node = node; + shi = ((ShaderCallData *)data)->shi; + + Node_SetStack(mynode, in, NODE_INPUTSTACK); + Node_SetStack(mynode, out, NODE_OUTPUTSTACK); + Node_SetShi(mynode, shi); + + args=Py_BuildValue("()"); + pyresult= PyObject_Call((PyObject *)mynode, args, NULL); + Py_DECREF(args); -bNodeType sh_node_dynamic = { + if (!pyresult) { + PyGILState_Release(gilstate); + node_dynamic_disable_all_by_id(node->id); + node_dynamic_pyerror_print(node); + node_dynamic_setup(node); + return; + } + Py_DECREF(pyresult); + PyGILState_Release(gilstate); + } + } +#endif +} + +bNodeType node_dynamic_typeinfo = { /* next, prev */ NULL, NULL, - /* type code */ SH_NODE_DYNAMIC, + /* type code */ NODE_DYNAMIC, /* name */ "Dynamic", /* width+range */ 150, 60, 300, /* class+opts */ NODE_CLASS_OP_DYNAMIC, NODE_OPTIONS, /* input sock */ NULL, /* output sock */ NULL, /* storage */ "NodeScriptDict", - /* execfunc */ node_dynamic_exec, + /* execfunc */ node_dynamic_exec_cb, /* butfunc */ NULL, - /* initfunc */ node_dynamic_init, - /* freefunc */ node_dynamic_free, - /* copyfunc */ node_dynamic_copy, + /* initfunc */ node_dynamic_init_cb, + /* freefunc */ node_dynamic_free_storage_cb, + /* copyfunc */ node_dynamic_copy_cb, /* id */ NULL }; -#endif /* USE_PYNODES */ +#else + +bNodeType node_dynamic_typeinfo = {NULL}; + +#endif + diff --git a/source/blender/nodes/intern/SHD_nodes/SHD_geom.c b/source/blender/nodes/intern/SHD_nodes/SHD_geom.c index 24395059c60..bc345759b98 100644 --- a/source/blender/nodes/intern/SHD_nodes/SHD_geom.c +++ b/source/blender/nodes/intern/SHD_nodes/SHD_geom.c @@ -29,6 +29,7 @@ #include "../SHD_util.h" +#include "DNA_customdata_types.h" /* **************** GEOMETRY ******************** */ @@ -124,6 +125,18 @@ static void node_shader_init_geometry(bNode *node) node->storage= MEM_callocN(sizeof(NodeGeometry), "NodeGeometry"); } +static int gpu_shader_geom(GPUMaterial *mat, bNode *node, GPUNodeStack *in, GPUNodeStack *out) +{ + NodeGeometry *ngeo= (NodeGeometry*)node->storage; + GPUNodeLink *orco = GPU_attribute(CD_ORCO, ""); + GPUNodeLink *mtface = GPU_attribute(CD_MTFACE, ngeo->uvname); + GPUNodeLink *mcol = GPU_attribute(CD_MCOL, ngeo->colname); + + return GPU_stack_link(mat, "geom", in, out, + GPU_builtin(GPU_VIEW_POSITION), GPU_builtin(GPU_VIEW_NORMAL), + GPU_builtin(GPU_INVERSE_VIEW_MATRIX), orco, mtface, mcol); +} + /* node type definition */ bNodeType sh_node_geom= { /* *next,*prev */ NULL, NULL, @@ -139,6 +152,7 @@ bNodeType sh_node_geom= { /* initfunc */ node_shader_init_geometry, /* freestoragefunc */ node_free_standard_storage, /* copystoragefunc */ node_copy_standard_storage, - /* id */ NULL + /* id */ NULL, NULL, NULL, + /* gpufunc */ gpu_shader_geom }; diff --git a/source/blender/nodes/intern/SHD_nodes/SHD_hueSatVal.c b/source/blender/nodes/intern/SHD_nodes/SHD_hueSatVal.c index 8c07a2d1dc8..1b7b2dfb8e7 100644 --- a/source/blender/nodes/intern/SHD_nodes/SHD_hueSatVal.c +++ b/source/blender/nodes/intern/SHD_nodes/SHD_hueSatVal.c @@ -54,9 +54,7 @@ static void do_hue_sat_fac(bNode *node, float *out, float *hue, float *sat, floa hsv[0]+= (*hue - 0.5f); if(hsv[0]>1.0) hsv[0]-=1.0; else if(hsv[0]<0.0) hsv[0]+= 1.0; hsv[1]*= *sat; - if(hsv[1]>1.0) hsv[1]= 1.0; else if(hsv[1]<0.0) hsv[1]= 0.0; hsv[2]*= *val; - if(hsv[2]>1.0) hsv[2]= 1.0; else if(hsv[2]<0.0) hsv[2]= 0.0; hsv_to_rgb(hsv[0], hsv[1], hsv[2], col, col+1, col+2); out[0]= mfac*in[0] + *fac*col[0]; @@ -73,6 +71,12 @@ static void node_shader_exec_hue_sat(void *data, bNode *node, bNodeStack **in, b do_hue_sat_fac(node, out[0]->vec, in[0]->vec, in[1]->vec, in[2]->vec, in[4]->vec, in[3]->vec); } + +static int gpu_shader_hue_sat(GPUMaterial *mat, bNode *node, GPUNodeStack *in, GPUNodeStack *out) +{ + return GPU_stack_link(mat, "hue_sat", in, out); +} + bNodeType sh_node_hue_sat= { /* *next,*prev */ NULL, NULL, /* type code */ SH_NODE_HUE_SAT, @@ -87,7 +91,8 @@ bNodeType sh_node_hue_sat= { /* initfunc */ NULL, /* freestoragefunc */ NULL, /* copystoragefunc */ NULL, - /* id */ NULL + /* id */ NULL, NULL, NULL, + /* gpufunc */ gpu_shader_hue_sat }; diff --git a/source/blender/nodes/intern/SHD_nodes/SHD_invert.c b/source/blender/nodes/intern/SHD_nodes/SHD_invert.c index 4d1ce282fce..72ee1483ecf 100644 --- a/source/blender/nodes/intern/SHD_nodes/SHD_invert.c +++ b/source/blender/nodes/intern/SHD_nodes/SHD_invert.c @@ -64,6 +64,11 @@ bNodeStack **out) VECCOPY(out[0]->vec, col); } +static int gpu_shader_invert(GPUMaterial *mat, bNode *node, GPUNodeStack *in, GPUNodeStack *out) +{ + return GPU_stack_link(mat, "invert", in, out); +} + bNodeType sh_node_invert= { /* *next,*prev */ NULL, NULL, /* type code */ SH_NODE_INVERT, @@ -78,6 +83,7 @@ bNodeType sh_node_invert= { /* initfunc */ NULL, /* freestoragefunc */ NULL, /* copystoragefunc */ NULL, - /* id */ NULL + /* id */ NULL, NULL, NULL, + /* gpufunc */ gpu_shader_invert }; diff --git a/source/blender/nodes/intern/SHD_nodes/SHD_mapping.c b/source/blender/nodes/intern/SHD_nodes/SHD_mapping.c index 589954c8f7b..c081929a2fc 100644 --- a/source/blender/nodes/intern/SHD_nodes/SHD_mapping.c +++ b/source/blender/nodes/intern/SHD_nodes/SHD_mapping.c @@ -69,6 +69,20 @@ static void node_shader_init_mapping(bNode *node) node->storage= add_mapping(); } +static int gpu_shader_mapping(GPUMaterial *mat, bNode *node, GPUNodeStack *in, GPUNodeStack *out) +{ + TexMapping *texmap= node->storage; + float domin= (texmap->flag & TEXMAP_CLIP_MIN) != 0; + float domax= (texmap->flag & TEXMAP_CLIP_MAX) != 0; + GPUNodeLink *tmat = GPU_uniform((float*)texmap->mat); + GPUNodeLink *tmin = GPU_uniform(texmap->min); + GPUNodeLink *tmax = GPU_uniform(texmap->max); + GPUNodeLink *tdomin = GPU_uniform(&domin); + GPUNodeLink *tdomax = GPU_uniform(&domax); + + return GPU_stack_link(mat, "mapping", in, out, tmat, tmin, tmax, tdomin, tdomax); +} + bNodeType sh_node_mapping= { /* *next,*prev */ NULL, NULL, /* type code */ SH_NODE_MAPPING, @@ -83,7 +97,8 @@ bNodeType sh_node_mapping= { /* initfunc */ node_shader_init_mapping, /* freestoragefunc */ node_free_standard_storage, /* copystoragefunc */ node_copy_standard_storage, - /* id */ NULL + /* id */ NULL, NULL, NULL, + /* gpufunc */ gpu_shader_mapping }; diff --git a/source/blender/nodes/intern/SHD_nodes/SHD_material.c b/source/blender/nodes/intern/SHD_nodes/SHD_material.c index bdceb134c0d..c0a2534ac4a 100644 --- a/source/blender/nodes/intern/SHD_nodes/SHD_material.c +++ b/source/blender/nodes/intern/SHD_nodes/SHD_material.c @@ -54,7 +54,6 @@ static bNodeSocketType sh_node_material_ext_in[]= { { SOCK_VALUE, 1, "Refl", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f}, { SOCK_VECTOR, 1, "Normal", 0.0f, 0.0f, 0.0f, 1.0f, -1.0f, 1.0f}, { SOCK_RGBA, 1, "Mirror", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f}, - { SOCK_RGBA, 1, "AmbCol", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f}, { SOCK_VALUE, 1, "Ambient", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f}, { SOCK_VALUE, 1, "Emit", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f}, { SOCK_VALUE, 1, "SpecTra", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f}, @@ -117,8 +116,6 @@ static void node_shader_exec_material(void *data, bNode *node, bNodeStack **in, if (node->type == SH_NODE_MATERIAL_EXT) { if(in[MAT_IN_MIR]->hasinput) nodestack_get_vec(&shi->mirr, SOCK_VECTOR, in[MAT_IN_MIR]); - if(in[MAT_IN_AMBCOL]->hasinput) - nodestack_get_vec(&shi->ambr, SOCK_VECTOR, in[MAT_IN_AMBCOL]); if(in[MAT_IN_AMB]->hasinput) nodestack_get_vec(&shi->amb, SOCK_VALUE, in[MAT_IN_AMB]); if(in[MAT_IN_EMIT]->hasinput) @@ -185,6 +182,77 @@ static void node_shader_init_material(bNode* node) node->custom1= SH_NODE_MAT_DIFF|SH_NODE_MAT_SPEC; } +static int gpu_shader_material(GPUMaterial *mat, bNode *node, GPUNodeStack *in, GPUNodeStack *out) +{ + if(node->id) { + GPUShadeInput shi; + GPUShadeResult shr; + + GPU_shadeinput_set(mat, (Material*)node->id, &shi); + + /* write values */ + if(in[MAT_IN_COLOR].hasinput) + shi.rgb = in[MAT_IN_COLOR].link; + + if(in[MAT_IN_SPEC].hasinput) + shi.specrgb = in[MAT_IN_SPEC].link; + + if(in[MAT_IN_REFL].hasinput) + shi.refl = in[MAT_IN_REFL].link; + + /* retrieve normal */ + if(in[MAT_IN_NORMAL].hasinput) { + GPUNodeLink *tmp; + shi.vn = in[MAT_IN_NORMAL].link; + GPU_link(mat, "vec_math_normalize", shi.vn, &shi.vn, &tmp); + } + + /* custom option to flip normal */ + if(node->custom1 & SH_NODE_MAT_NEG) + GPU_link(mat, "vec_math_negate", shi.vn, &shi.vn); + + if (node->type == SH_NODE_MATERIAL_EXT) { + if(in[MAT_IN_AMB].hasinput) + shi.amb= in[MAT_IN_AMB].link; + if(in[MAT_IN_EMIT].hasinput) + shi.emit= in[MAT_IN_EMIT].link; + if(in[MAT_IN_ALPHA].hasinput) + shi.alpha= in[MAT_IN_ALPHA].link; + } + + GPU_shaderesult_set(&shi, &shr); /* clears shr */ + + /* write to outputs */ + if(node->custom1 & SH_NODE_MAT_DIFF) { + if(node->custom1 & SH_NODE_MAT_SPEC) + out[MAT_OUT_COLOR].link= shr.combined; + else + out[MAT_OUT_COLOR].link= shr.diff; + } + else if(node->custom1 & SH_NODE_MAT_SPEC) { + out[MAT_OUT_COLOR].link= shr.spec; + } + else + GPU_link(mat, "set_rgb_zero", &out[MAT_OUT_COLOR].link); + + GPU_link(mat, "mtex_alpha_to_col", out[MAT_OUT_COLOR].link, shr.alpha, &out[MAT_OUT_COLOR].link); + + out[MAT_OUT_ALPHA].link = shr.alpha; // + + if(node->custom1 & SH_NODE_MAT_NEG) + GPU_link(mat, "vec_math_negate", shi.vn, &shi.vn); + out[MAT_OUT_NORMAL].link = shi.vn; + + if (node->type == SH_NODE_MATERIAL_EXT) { + out[MAT_OUT_DIFFUSE].link = shr.diff; + out[MAT_OUT_SPEC].link = shr.spec; + } + + return 1; + } + + return 0; +} bNodeType sh_node_material= { /* *next,*prev */ NULL, NULL, @@ -200,8 +268,8 @@ bNodeType sh_node_material= { /* initfunc */ node_shader_init_material, /* freestoragefunc */ NULL, /* copystoragefunc */ NULL, - /* id */ NULL - + /* id */ NULL, NULL, NULL, + /* gpufunc */ gpu_shader_material }; bNodeType sh_node_material_ext= { @@ -218,7 +286,7 @@ bNodeType sh_node_material_ext= { /* initfunc */ node_shader_init_material, /* freestoragefunc */ NULL, /* copystoragefunc */ NULL, - /* id */ NULL - + /* id */ NULL, NULL, NULL, + /* gpufunc */ gpu_shader_material }; diff --git a/source/blender/nodes/intern/SHD_nodes/SHD_math.c b/source/blender/nodes/intern/SHD_nodes/SHD_math.c index 95162e508d5..050c2cdcc95 100644 --- a/source/blender/nodes/intern/SHD_nodes/SHD_math.c +++ b/source/blender/nodes/intern/SHD_nodes/SHD_math.c @@ -174,10 +174,66 @@ bNodeStack **out) else out[0]->vec[0]= (int)(in[1]->vec[0] + 0.5f); } - break; + break; + case 15: /* Less Than */ + { + if( in[0]->vec[0] < in[1]->vec[0] ) + out[0]->vec[0]= 1.0f; + else + out[0]->vec[0]= 0.0f; + } + break; + case 16: /* Greater Than */ + { + if( in[0]->vec[0] > in[1]->vec[0] ) + out[0]->vec[0]= 1.0f; + else + out[0]->vec[0]= 0.0f; + } + break; } } +static int gpu_shader_math(GPUMaterial *mat, bNode *node, GPUNodeStack *in, GPUNodeStack *out) +{ + static char *names[] = {"math_add", "math_subtract", "math_multiply", + "math_divide", "math_sine", "math_cosine", "math_tangnet", "math_asin", + "math_acos", "math_atan", "math_pow", "math_log", "math_min", "math_max", + "math_round", "math_less_than", "math_greater_than"}; + + switch (node->custom1) { + case 0: + case 1: + case 2: + case 3: + case 10: + case 11: + case 12: + case 13: + case 15: + case 16: + GPU_stack_link(mat, names[node->custom1], NULL, out, + GPU_socket(&in[0]), GPU_socket(&in[1])); + break; + case 4: + case 5: + case 6: + case 7: + case 8: + case 9: + case 14: + if(in[0].hasinput || !in[1].hasinput) + GPU_stack_link(mat, names[node->custom1], NULL, out, GPU_socket(&in[0])); + else + GPU_stack_link(mat, names[node->custom1], NULL, out, GPU_socket(&in[1])); + break; + default: + return 0; + } + + return 1; +} + bNodeType sh_node_math= { /* *next,*prev */ NULL, NULL, /* type code */ SH_NODE_MATH, @@ -192,6 +248,7 @@ bNodeType sh_node_math= { /* initfunc */ NULL, /* freestoragefunc */ NULL, /* copystoragefunc */ NULL, - /* id */ NULL + /* id */ NULL, NULL, NULL, + /* gpufunc */ gpu_shader_math }; diff --git a/source/blender/nodes/intern/SHD_nodes/SHD_mixRgb.c b/source/blender/nodes/intern/SHD_nodes/SHD_mixRgb.c index dba70253fda..2da1dee5623 100644 --- a/source/blender/nodes/intern/SHD_nodes/SHD_mixRgb.c +++ b/source/blender/nodes/intern/SHD_nodes/SHD_mixRgb.c @@ -60,6 +60,17 @@ static void node_shader_exec_mix_rgb(void *data, bNode *node, bNodeStack **in, b VECCOPY(out[0]->vec, col); } +static int gpu_shader_mix_rgb(GPUMaterial *mat, bNode *node, GPUNodeStack *in, GPUNodeStack *out) +{ + static char *names[] = {"mix_blend", "mix_add", "mix_mult", "mix_sub", + "mix_screen", "mix_div", "mix_diff", "mix_dark", "mix_light", + "mix_overlay", "mix_dodge", "mix_burn", "mix_hue", "mix_sat", + "mix_val", "mix_color"}; + + return GPU_stack_link(mat, names[node->custom1], in, out); +} + + bNodeType sh_node_mix_rgb= { /* *next,*prev */ NULL, NULL, /* type code */ SH_NODE_MIX_RGB, @@ -74,6 +85,7 @@ bNodeType sh_node_mix_rgb= { /* initfunc */ NULL, /* freestoragefunc */ NULL, /* copystoragefunc */ NULL, - /* id */ NULL + /* id */ NULL, NULL, NULL, + /* gpufunc */ gpu_shader_mix_rgb }; diff --git a/source/blender/nodes/intern/SHD_nodes/SHD_normal.c b/source/blender/nodes/intern/SHD_nodes/SHD_normal.c index f1ffd3446af..9d4ea1ccf67 100644 --- a/source/blender/nodes/intern/SHD_nodes/SHD_normal.c +++ b/source/blender/nodes/intern/SHD_nodes/SHD_normal.c @@ -57,6 +57,14 @@ static void node_shader_exec_normal(void *data, bNode *node, bNodeStack **in, bN out[1]->vec[0]= -INPR(out[0]->vec, vec); } +static int gpu_shader_normal(GPUMaterial *mat, bNode *node, GPUNodeStack *in, GPUNodeStack *out) +{ + bNodeSocket *sock= node->outputs.first; + GPUNodeLink *vec = GPU_uniform(sock->ns.vec); + + return GPU_stack_link(mat, "normal", in, out, vec); +} + bNodeType sh_node_normal= { /* *next,*prev */ NULL, NULL, /* type code */ SH_NODE_NORMAL, @@ -71,6 +79,7 @@ bNodeType sh_node_normal= { /* initfunc */ NULL, /* freestoragefunc */ NULL, /* copystoragefunc */ NULL, - /* id */ NULL + /* id */ NULL, NULL, NULL, + /* gpufunc */ gpu_shader_normal }; diff --git a/source/blender/nodes/intern/SHD_nodes/SHD_output.c b/source/blender/nodes/intern/SHD_nodes/SHD_output.c index 0a9a30c452b..76856cfd2e8 100644 --- a/source/blender/nodes/intern/SHD_nodes/SHD_output.c +++ b/source/blender/nodes/intern/SHD_nodes/SHD_output.c @@ -62,6 +62,19 @@ static void node_shader_exec_output(void *data, bNode *node, bNodeStack **in, bN } } +static int gpu_shader_output(GPUMaterial *mat, bNode *node, GPUNodeStack *in, GPUNodeStack *out) +{ + GPUNodeLink *outlink; + + /*if(in[1].hasinput) + GPU_material_enable_alpha(mat);*/ + + GPU_stack_link(mat, "output_node", in, out, &outlink); + GPU_material_output_link(mat, outlink); + + return 1; +} + bNodeType sh_node_output= { /* *next,*prev */ NULL, NULL, /* type code */ SH_NODE_OUTPUT, @@ -76,7 +89,8 @@ bNodeType sh_node_output= { /* initfunc */ NULL, /* freestoragefunc */ NULL, /* copystoragefunc */ NULL, - /* id */ NULL + /* id */ NULL, NULL, NULL, + /* gpufunc */ gpu_shader_output }; diff --git a/source/blender/nodes/intern/SHD_nodes/SHD_rgb.c b/source/blender/nodes/intern/SHD_nodes/SHD_rgb.c index 4e56e26d3ad..1aa1a2ffc33 100644 --- a/source/blender/nodes/intern/SHD_nodes/SHD_rgb.c +++ b/source/blender/nodes/intern/SHD_nodes/SHD_rgb.c @@ -42,6 +42,14 @@ static void node_shader_exec_rgb(void *data, bNode *node, bNodeStack **in, bNode VECCOPY(out[0]->vec, sock->ns.vec); } +static int gpu_shader_rgb(GPUMaterial *mat, bNode *node, GPUNodeStack *in, GPUNodeStack *out) +{ + bNodeSocket *sock= node->outputs.first; + GPUNodeLink *vec = GPU_uniform(sock->ns.vec); + + return GPU_stack_link(mat, "set_rgba", in, out, vec); +} + bNodeType sh_node_rgb= { /* *next,*prev */ NULL, NULL, /* type code */ SH_NODE_RGB, @@ -56,6 +64,7 @@ bNodeType sh_node_rgb= { /* initfunc */ NULL, /* freestoragefunc */ NULL, /* copystoragefunc */ NULL, - /* id */ NULL + /* id */ NULL, NULL, NULL, + /* gpufunc */ gpu_shader_rgb }; diff --git a/source/blender/nodes/intern/SHD_nodes/SHD_sepcombRGB.c b/source/blender/nodes/intern/SHD_nodes/SHD_sepcombRGB.c index 2b52a8e2229..6d5df2a1321 100644 --- a/source/blender/nodes/intern/SHD_nodes/SHD_sepcombRGB.c +++ b/source/blender/nodes/intern/SHD_nodes/SHD_sepcombRGB.c @@ -48,6 +48,11 @@ static void node_shader_exec_seprgb(void *data, bNode *node, bNodeStack **in, bN out[2]->vec[0] = in[0]->vec[2]; } +static int gpu_shader_seprgb(GPUMaterial *mat, bNode *node, GPUNodeStack *in, GPUNodeStack *out) +{ + return GPU_stack_link(mat, "separate_rgb", in, out); +} + bNodeType sh_node_seprgb= { /* *next,*prev */ NULL, NULL, /* type code */ SH_NODE_SEPRGB, @@ -62,7 +67,8 @@ bNodeType sh_node_seprgb= { /* initfunc */ NULL, /* freestoragefunc */ NULL, /* copystoragefunc */ NULL, - /* id */ NULL + /* id */ NULL, NULL, NULL, + /* gpufunc */ gpu_shader_seprgb }; @@ -86,6 +92,11 @@ static void node_shader_exec_combrgb(void *data, bNode *node, bNodeStack **in, b out[0]->vec[2] = in[2]->vec[0]; } +static int gpu_shader_combrgb(GPUMaterial *mat, bNode *node, GPUNodeStack *in, GPUNodeStack *out) +{ + return GPU_stack_link(mat, "combine_rgb", in, out); +} + bNodeType sh_node_combrgb= { /* *next,*prev */ NULL, NULL, /* type code */ SH_NODE_COMBRGB, @@ -100,6 +111,7 @@ bNodeType sh_node_combrgb= { /* initfunc */ NULL, /* freestoragefunc */ NULL, /* copystoragefunc */ NULL, - /* id */ NULL + /* id */ NULL, NULL, NULL, + /* gpufunc */ gpu_shader_combrgb }; diff --git a/source/blender/nodes/intern/SHD_nodes/SHD_squeeze.c b/source/blender/nodes/intern/SHD_nodes/SHD_squeeze.c index 30abad666c4..d3480a6ae9d 100644 --- a/source/blender/nodes/intern/SHD_nodes/SHD_squeeze.c +++ b/source/blender/nodes/intern/SHD_nodes/SHD_squeeze.c @@ -54,6 +54,11 @@ bNodeStack **out) out[0]->vec[0] = 1.0f / (1.0f + pow(2.71828183,-((vec[0]-vec[2])*vec[1]))) ; } +static int gpu_shader_squeeze(GPUMaterial *mat, bNode *node, GPUNodeStack *in, GPUNodeStack *out) +{ + return GPU_stack_link(mat, "squeeze", in, out); +} + bNodeType sh_node_squeeze= { /* *next,*prev */ NULL, NULL, /* type code */ SH_NODE_SQUEEZE, @@ -68,6 +73,7 @@ bNodeType sh_node_squeeze= { /* initfunc */ NULL, /* freestoragefunc */ NULL, /* copystoragefunc */ NULL, - /* id */ NULL + /* id */ NULL, NULL, NULL, + /* gpufunc */ gpu_shader_squeeze }; diff --git a/source/blender/nodes/intern/SHD_nodes/SHD_texture.c b/source/blender/nodes/intern/SHD_nodes/SHD_texture.c index ace11a20d42..31dbde940fd 100644 --- a/source/blender/nodes/intern/SHD_nodes/SHD_texture.c +++ b/source/blender/nodes/intern/SHD_nodes/SHD_texture.c @@ -27,6 +27,8 @@ * ***** END GPL LICENSE BLOCK ***** */ +#include "DNA_texture_types.h" + #include "../SHD_util.h" /* **************** TEXTURE ******************** */ @@ -110,6 +112,18 @@ static void node_shader_exec_texture(void *data, bNode *node, bNodeStack **in, b } } +static int gpu_shader_texture(GPUMaterial *mat, bNode *node, GPUNodeStack *in, GPUNodeStack *out) +{ + Tex *tex = (Tex*)node->id; + + if(tex && tex->type == TEX_IMAGE && tex->ima) { + GPUNodeLink *texlink = GPU_image(tex->ima, NULL); + return GPU_stack_link(mat, "texture_image", in, out, texlink); + } + else + return 0; +} + bNodeType sh_node_texture= { /* *next,*prev */ NULL, NULL, /* type code */ SH_NODE_TEXTURE, @@ -124,7 +138,8 @@ bNodeType sh_node_texture= { /* initfunc */ NULL, /* freestoragefunc */ NULL, /* copystoragefunc */ NULL, - /* id */ NULL + /* id */ NULL, NULL, NULL, + /* gpufunc */ gpu_shader_texture }; diff --git a/source/blender/nodes/intern/SHD_nodes/SHD_valToRgb.c b/source/blender/nodes/intern/SHD_nodes/SHD_valToRgb.c index cf7e33d9dca..301c0cb7031 100644 --- a/source/blender/nodes/intern/SHD_nodes/SHD_valToRgb.c +++ b/source/blender/nodes/intern/SHD_nodes/SHD_valToRgb.c @@ -59,6 +59,15 @@ static void node_shader_init_valtorgb(bNode *node) node->storage= add_colorband(1); } +static int gpu_shader_valtorgb(GPUMaterial *mat, bNode *node, GPUNodeStack *in, GPUNodeStack *out) +{ + float *array; + int size; + + colorband_table_RGBA(node->storage, &array, &size); + return GPU_stack_link(mat, "valtorgb", in, out, GPU_texture(size, array)); +} + bNodeType sh_node_valtorgb= { /* *next,*prev */ NULL, NULL, /* type code */ SH_NODE_VALTORGB, @@ -73,7 +82,8 @@ bNodeType sh_node_valtorgb= { /* initfunc */ node_shader_init_valtorgb, /* freestoragefunc */ node_free_standard_storage, /* copystoragefunc */ node_copy_standard_storage, - /* id */ NULL + /* id */ NULL, NULL, NULL, + /* gpufunc */ gpu_shader_valtorgb }; @@ -96,6 +106,11 @@ static void node_shader_exec_rgbtobw(void *data, bNode *node, bNodeStack **in, b out[0]->vec[0]= in[0]->vec[0]*0.35f + in[0]->vec[1]*0.45f + in[0]->vec[2]*0.2f; } +static int gpu_shader_rgbtobw(GPUMaterial *mat, bNode *node, GPUNodeStack *in, GPUNodeStack *out) +{ + return GPU_stack_link(mat, "rgbtobw", in, out); +} + bNodeType sh_node_rgbtobw= { /* *next,*prev */ NULL, NULL, /* type code */ SH_NODE_RGBTOBW, @@ -110,7 +125,8 @@ bNodeType sh_node_rgbtobw= { /* initfunc */ NULL, /* freestoragefunc */ NULL, /* copystoragefunc */ NULL, - /* id */ NULL + /* id */ NULL, NULL, NULL, + /* gpufunc */ gpu_shader_rgbtobw }; diff --git a/source/blender/nodes/intern/SHD_nodes/SHD_value.c b/source/blender/nodes/intern/SHD_nodes/SHD_value.c index 57ef7226066..768ef3cda3d 100644 --- a/source/blender/nodes/intern/SHD_nodes/SHD_value.c +++ b/source/blender/nodes/intern/SHD_nodes/SHD_value.c @@ -42,7 +42,13 @@ static void node_shader_exec_value(void *data, bNode *node, bNodeStack **in, bNo out[0]->vec[0]= sock->ns.vec[0]; } +static int gpu_shader_value(GPUMaterial *mat, bNode *node, GPUNodeStack *in, GPUNodeStack *out) +{ + bNodeSocket *sock= node->outputs.first; + GPUNodeLink *vec = GPU_uniform(sock->ns.vec); + return GPU_stack_link(mat, "set_value", in, out, vec); +} bNodeType sh_node_value= { /* *next,*prev */ NULL, NULL, @@ -58,7 +64,8 @@ bNodeType sh_node_value= { /* initfunc */ NULL, /* freestoragefunc */ NULL, /* copystoragefunc */ NULL, - /* id */ NULL + /* id */ NULL, NULL, NULL, + /* gpufunc */ gpu_shader_value }; diff --git a/source/blender/nodes/intern/SHD_nodes/SHD_vectMath.c b/source/blender/nodes/intern/SHD_nodes/SHD_vectMath.c index 8d0a4b3abe3..96db8db18a6 100644 --- a/source/blender/nodes/intern/SHD_nodes/SHD_vectMath.c +++ b/source/blender/nodes/intern/SHD_nodes/SHD_vectMath.c @@ -99,6 +99,34 @@ static void node_shader_exec_vect_math(void *data, bNode *node, bNodeStack **in, } +static int gpu_shader_vect_math(GPUMaterial *mat, bNode *node, GPUNodeStack *in, GPUNodeStack *out) +{ + static char *names[] = {"vec_math_add", "vec_math_subtract", + "vec_math_average", "vec_math_dot", "vec_math_cross", + "vec_math_normalize"}; + + switch (node->custom1) { + case 0: + case 1: + case 2: + case 3: + case 4: + GPU_stack_link(mat, names[node->custom1], NULL, out, + GPU_socket(&in[0]), GPU_socket(&in[1])); + break; + case 5: + if(in[0].hasinput || !in[1].hasinput) + GPU_stack_link(mat, names[node->custom1], NULL, out, GPU_socket(&in[0])); + else + GPU_stack_link(mat, names[node->custom1], NULL, out, GPU_socket(&in[1])); + break; + default: + return 0; + } + + return 1; +} + bNodeType sh_node_vect_math= { /* *next,*prev */ NULL, NULL, /* type code */ SH_NODE_VECT_MATH, @@ -113,6 +141,7 @@ bNodeType sh_node_vect_math= { /* initfunc */ NULL, /* freestoragefunc */ NULL, /* copystoragefunc */ NULL, - /* id */ NULL + /* id */ NULL, NULL, NULL, + /* gpufunc */ gpu_shader_vect_math }; diff --git a/source/blender/nodes/intern/SHD_util.c b/source/blender/nodes/intern/SHD_util.c index c9f58fbce49..f673834d2b7 100644 --- a/source/blender/nodes/intern/SHD_util.c +++ b/source/blender/nodes/intern/SHD_util.c @@ -164,7 +164,7 @@ void nodeShaderSynchronizeID(bNode *node, int copyto) case MAT_IN_MIR: VECCOPY(&ma->mirr, sock->ns.vec); break; case MAT_IN_AMB: - VECCOPY(&ma->ambr, sock->ns.vec); break; + ma->amb= sock->ns.vec[0]; break; case MAT_IN_EMIT: ma->emit= sock->ns.vec[0]; break; case MAT_IN_SPECTRA: @@ -188,7 +188,7 @@ void nodeShaderSynchronizeID(bNode *node, int copyto) case MAT_IN_MIR: VECCOPY(sock->ns.vec, &ma->mirr); break; case MAT_IN_AMB: - VECCOPY(sock->ns.vec, &ma->ambr); break; + sock->ns.vec[0]= ma->amb; break; case MAT_IN_EMIT: sock->ns.vec[0]= ma->emit; break; case MAT_IN_SPECTRA: diff --git a/source/blender/nodes/intern/SHD_util.h b/source/blender/nodes/intern/SHD_util.h index fcab420f3f2..0d9783fdd4b 100644 --- a/source/blender/nodes/intern/SHD_util.h +++ b/source/blender/nodes/intern/SHD_util.h @@ -72,6 +72,8 @@ #include "RE_pipeline.h" #include "RE_shader_ext.h" +#include "GPU_material.h" + //XXX #include "butspace.h" //XXX #include "wm_event_types.h" @@ -100,13 +102,12 @@ typedef struct ShaderCallData { #define MAT_IN_REFL 2 #define MAT_IN_NORMAL 3 #define MAT_IN_MIR 4 -#define MAT_IN_AMBCOL 5 -#define MAT_IN_AMB 6 -#define MAT_IN_EMIT 7 -#define MAT_IN_SPECTRA 8 -#define MAT_IN_RAY_MIRROR 9 -#define MAT_IN_ALPHA 10 -#define MAT_IN_TRANSLUCENCY 11 +#define MAT_IN_AMB 5 +#define MAT_IN_EMIT 6 +#define MAT_IN_SPECTRA 7 +#define MAT_IN_RAY_MIRROR 8 +#define MAT_IN_ALPHA 9 +#define MAT_IN_TRANSLUCENCY 10 /* output socket defines */ #define MAT_OUT_COLOR 0 |