2 * ***** BEGIN GPL LICENSE BLOCK *****
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version 2
7 * of the License, or (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software Foundation,
16 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18 * The Original Code is Copyright (C) 2006 Blender Foundation.
19 * All rights reserved.
21 * The Original Code is: all of this file.
23 * Contributor(s): Campbell Barton, Alfredo de Greef, David Millan Escriva,
26 * ***** END GPL LICENSE BLOCK *****
29 /** \file blender/nodes/composite/nodes/node_composite_blur.c
34 #include "node_composite_util.h"
36 /* **************** BLUR ******************** */
37 static bNodeSocketTemplate cmp_node_blur_in[]= {
38 { SOCK_RGBA, 1, N_("Image"), 1.0f, 1.0f, 1.0f, 1.0f},
39 { SOCK_FLOAT, 1, N_("Size"), 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR},
42 static bNodeSocketTemplate cmp_node_blur_out[]= {
43 { SOCK_RGBA, 0, N_("Image")},
47 static float *make_gausstab(int filtertype, int rad)
49 float *gausstab, sum, val;
54 gausstab = (float *) MEM_mallocN(n * sizeof(float), "gauss");
57 for (i = -rad; i <= rad; i++) {
58 val= RE_filter_value(filtertype, (float)i/(float)rad);
60 gausstab[i+rad] = val;
70 static float *make_bloomtab(int rad)
77 bloomtab = (float *) MEM_mallocN(n * sizeof(float), "bloom");
79 for (i = -rad; i <= rad; i++) {
80 val = powf(1.0f - fabsf((float)i)/((float)rad), 4.0f);
81 bloomtab[i+rad] = val;
87 /* both input images of same type, either 4 or 1 channel */
88 void node_composit_blur_single_image(bNode *node, int filtertype, int sizex, int sizey, CompBuf *new, CompBuf *img, float scale)
91 register float sum, val;
92 float rval, gval, bval, aval;
93 float *gausstab, *gausstabcent;
94 int rad, imgx= img->x, imgy= img->y;
95 int x, y, pix= img->type;
100 work= alloc_compbuf(imgx, imgy, img->type, 1); /* allocs */
104 memcpy(work->rect, img->rect, sizeof(float) * img->type * imgx * imgy);
107 rad = scale*(float)sizex;
113 gausstab= make_gausstab(filtertype, rad);
114 gausstabcent= gausstab+rad;
116 for (y = 0; y < imgy; y++) {
117 float *srcd= img->rect + pix*(y*img->x);
119 dest = work->rect + pix*(y * img->x);
121 for (x = 0; x < imgx ; x++) {
122 int minr= x-rad<0?-x:-rad;
123 int maxr= x+rad>imgx?imgx-x:rad;
125 src= srcd + pix*(x+minr);
127 sum= gval = rval= bval= aval= 0.0f;
128 for (i= minr; i < maxr; i++) {
129 val= gausstabcent[i];
131 rval += val * (*src++);
133 gval += val * (*src++);
134 bval += val * (*src++);
135 aval += val * (*src++);
146 if (node->exec & NODE_BREAK)
155 memcpy(new->rect, work->rect, sizeof(float) * img->type * imgx * imgy);
158 rad = scale*(float)sizey;
164 gausstab= make_gausstab(filtertype, rad);
165 gausstabcent= gausstab+rad;
168 for (x = 0; x < imgx; x++) {
169 float *srcd= work->rect + pix*x;
171 dest = new->rect + pix*x;
173 for (y = 0; y < imgy ; y++) {
174 int minr= y-rad<0?-y:-rad;
175 int maxr= y+rad>imgy?imgy-y:rad;
177 src= srcd + bigstep*(y+minr);
179 sum= gval = rval= bval= aval= 0.0f;
180 for (i= minr; i < maxr; i++) {
181 val= gausstabcent[i];
183 rval += val * src[0];
185 gval += val * src[1];
186 bval += val * src[2];
187 aval += val * src[3];
200 if (node->exec & NODE_BREAK)
209 static void blur_single_image(bNode *node, CompBuf *new, CompBuf *img, float scale)
211 NodeBlurData *nbd = node->storage;
213 node_composit_blur_single_image(node, nbd->filtertype, nbd->sizex, nbd->sizey, new, img, scale);
216 /* reference has to be mapped 0-1, and equal in size */
217 static void bloom_with_reference(CompBuf *new, CompBuf *img, CompBuf *UNUSED(ref), float UNUSED(fac), NodeBlurData *nbd)
223 float *gausstabx, *gausstabcenty;
224 float *gausstaby, *gausstabcentx;
225 int radx, rady, imgx= img->x, imgy= img->y;
228 float *src, *dest, *wb;
230 wbuf= alloc_compbuf(imgx, imgy, CB_VAL, 1);
233 radx = (float)nbd->sizex;
240 rady = (float)nbd->sizey;
247 maintabs= MEM_mallocN(x*sizeof(void *), "gauss array");
249 maintabs[i]= make_bloomtab(i+1);
251 /* vars to store before we go */
258 for (y = 0; y < imgy; y++) {
259 for (x = 0; x < imgx ; x++, src+=4) {//, refd++) {
261 // int refradx= (int)(refd[0]*radxf);
262 // int refrady= (int)(refd[0]*radyf);
264 int refradx= (int)(radxf*0.3f*src[3]*(src[0]+src[1]+src[2]));
265 int refrady= (int)(radyf*0.3f*src[3]*(src[0]+src[1]+src[2]));
267 if (refradx>radx) refradx= radx;
268 else if (refradx<1) refradx= 1;
269 if (refrady>rady) refrady= rady;
270 else if (refrady<1) refrady= 1;
272 if (refradx==1 && refrady==1) {
273 wb= wbuf->rect + ( y*imgx + x);
274 dest= new->rect + 4*( y*imgx + x);
282 int minxr= x-refradx<0?-x:-refradx;
283 int maxxr= x+refradx>imgx?imgx-x:refradx;
284 int minyr= y-refrady<0?-y:-refrady;
285 int maxyr= y+refrady>imgy?imgy-y:refrady;
287 float *destd= new->rect + 4*( (y + minyr)*imgx + x + minxr);
288 float *wbufd= wbuf->rect + ( (y + minyr)*imgx + x + minxr);
290 gausstabx= maintabs[refradx-1];
291 gausstabcentx= gausstabx+refradx;
292 gausstaby= maintabs[refrady-1];
293 gausstabcenty= gausstaby+refrady;
295 for (i= minyr; i < maxyr; i++, destd+= 4*imgx, wbufd+= imgx) {
298 for (j= minxr; j < maxxr; j++, dest+=4, wb++) {
300 val= gausstabcenty[i]*gausstabcentx[j];
302 dest[0] += val * src[0];
303 dest[1] += val * src[1];
304 dest[2] += val * src[2];
305 dest[3] += val * src[3];
329 MEM_freeN(maintabs[i]);
335 static float hexagon_filter(float fi, float fj)
341 fj= (fj-0.33f)/0.66f;
351 /* uses full filter, no horizontal/vertical optimize possible */
352 /* both images same type, either 1 or 4 channels */
353 static void bokeh_single_image(bNode *node, CompBuf *new, CompBuf *img, float fac)
355 NodeBlurData *nbd= node->storage;
358 float *gausstab, *dgauss;
359 int radx, rady, imgx= img->x, imgy= img->y;
360 int x, y, pix= img->type;
362 float *src= NULL, *dest, *srcd= NULL;
365 radxf = fac*(float)nbd->sizex;
372 radyf = fac*(float)nbd->sizey;
381 n = (2*radx+1)*(2*rady+1);
383 /* create a full filter image */
384 gausstab= MEM_mallocN(sizeof(float)*n, "filter tab");
387 for (j=-rady; j<=rady; j++) {
388 for (i=-radx; i<=radx; i++, dgauss++) {
389 float fj= (float)j/radyf;
390 float fi= (float)i/radxf;
391 float dist= sqrt(fj*fj + fi*fi);
393 //*dgauss= hexagon_filter(fi, fj);
394 *dgauss= RE_filter_value(nbd->filtertype, dist);
402 for (j= n -1; j>=0; j--)
405 else gausstab[4]= 1.0f;
407 for (y = -rady+1; y < imgy+rady-1; y++) {
409 if (y<=0) srcd= img->rect;
410 else if (y<imgy) srcd+= pix*imgx;
411 else srcd= img->rect + pix*(imgy-1)*imgx;
413 for (x = -radx+1; x < imgx+radx-1 ; x++) {
414 int minxr= x-radx<0?-x:-radx;
415 int maxxr= x+radx>=imgx?imgx-x-1:radx;
416 int minyr= y-rady<0?-y:-rady;
417 int maxyr= y+rady>imgy-1?imgy-y-1:rady;
419 float *destd= new->rect + pix*( (y + minyr)*imgx + x + minxr);
420 float *dgausd= gausstab + (minyr+rady)*(2*radx+1) + minxr+radx;
423 else if (x<imgx) src+= pix;
424 else src= srcd + pix*(imgx-1);
426 for (i= minyr; i <=maxyr; i++, destd+= pix*imgx, dgausd+= 2*radx + 1) {
429 for (j= minxr; j <=maxxr; j++, dest+=pix, dgauss++) {
432 dest[0] += val * src[0];
434 dest[1] += val * src[1];
435 dest[2] += val * src[2];
436 dest[3] += val * src[3];
442 if (node->exec & NODE_BREAK)
450 /* reference has to be mapped 0-1, and equal in size */
451 static void blur_with_reference(bNode *node, CompBuf *new, CompBuf *img, CompBuf *ref)
453 NodeBlurData *nbd= node->storage;
454 CompBuf *blurbuf, *ref_use;
455 register float sum, val;
456 float rval, gval, bval, aval, radxf, radyf;
458 float *gausstabx, *gausstabcenty;
459 float *gausstaby, *gausstabcentx;
460 int radx, rady, imgx= img->x, imgy= img->y;
461 int x, y, pix= img->type;
463 float *src, *dest, *refd, *blurd;
464 float defcol[4] = {1.0f, 1.0f, 1.0f, 1.0f}; /* default color for compbuf_get_pixel */
465 float proccol[4]; /* local color if compbuf is procedural */
466 int refradx, refrady;
468 if (ref->x!=img->x || ref->y!=img->y)
471 ref_use= typecheck_compbuf(ref, CB_VAL);
473 /* trick is; we blur the reference image... but only works with clipped values*/
474 blurbuf= alloc_compbuf(imgx, imgy, CB_VAL, 1);
475 blurbuf->xof= ref_use->xof;
476 blurbuf->yof= ref_use->yof;
477 blurd= blurbuf->rect;
479 for (x= imgx*imgy; x>0; x--, refd++, blurd++) {
480 if (refd[0]<0.0f) blurd[0]= 0.0f;
481 else if (refd[0]>1.0f) blurd[0]= 1.0f;
482 else blurd[0]= refd[0];
485 blur_single_image(node, blurbuf, blurbuf, 1.0f);
488 radx = (float)nbd->sizex;
495 rady = (float)nbd->sizey;
502 maintabs= MEM_mallocN(x*sizeof(void *), "gauss array");
504 maintabs[i]= make_gausstab(nbd->filtertype, i+1);
510 for (y = 0; y < imgy; y++) {
511 for (x = 0; x < imgx ; x++, dest+=pix) {
512 refd= compbuf_get_pixel(blurbuf, defcol, proccol, x-blurbuf->xrad, y-blurbuf->yrad, blurbuf->xrad, blurbuf->yrad);
513 refradx= (int)(refd[0]*radxf);
514 refrady= (int)(refd[0]*radyf);
516 if (refradx>radx) refradx= radx;
517 else if (refradx<1) refradx= 1;
518 if (refrady>rady) refrady= rady;
519 else if (refrady<1) refrady= 1;
521 if (refradx==1 && refrady==1) {
522 src= img->rect + pix*( y*imgx + x);
526 copy_v4_v4(dest, src);
529 int minxr= x-refradx<0?-x:-refradx;
530 int maxxr= x+refradx>imgx?imgx-x:refradx;
531 int minyr= y-refrady<0?-y:-refrady;
532 int maxyr= y+refrady>imgy?imgy-y:refrady;
534 float *srcd= img->rect + pix*( (y + minyr)*imgx + x + minxr);
536 gausstabx= maintabs[refradx-1];
537 gausstabcentx= gausstabx+refradx;
538 gausstaby= maintabs[refrady-1];
539 gausstabcenty= gausstaby+refrady;
541 sum= gval = rval= bval= aval= 0.0f;
543 for (i= minyr; i < maxyr; i++, srcd+= pix*imgx) {
545 for (j= minxr; j < maxxr; j++, src+=pix) {
547 val= gausstabcenty[i]*gausstabcentx[j];
549 rval += val * src[0];
551 gval += val * src[1];
552 bval += val * src[2];
553 aval += val * src[3];
566 if (node->exec & NODE_BREAK)
570 free_compbuf(blurbuf);
574 MEM_freeN(maintabs[i]);
578 free_compbuf(ref_use);
581 static void node_composit_exec_blur(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
583 CompBuf *new, *img= in[0]->data;
584 NodeBlurData *nbd= node->storage;
586 if (img==NULL) return;
588 /* store image in size that is needed for absolute/relative conversions on ui level */
589 nbd->image_in_width= img->x;
590 nbd->image_in_height= img->y;
592 if (out[0]->hasoutput==0) return;
595 if (nbd->aspect==CMP_NODE_BLUR_ASPECT_NONE) {
596 nbd->sizex= (int)(nbd->percentx*0.01f*nbd->image_in_width);
597 nbd->sizey= (int)(nbd->percenty*0.01f*nbd->image_in_height);
599 else if (nbd->aspect==CMP_NODE_BLUR_ASPECT_Y) {
600 nbd->sizex= (int)(nbd->percentx*0.01f*nbd->image_in_width);
601 nbd->sizey= (int)(nbd->percenty*0.01f*nbd->image_in_width);
603 else if (nbd->aspect==CMP_NODE_BLUR_ASPECT_X) {
604 nbd->sizex= (int)(nbd->percentx*0.01f*nbd->image_in_height);
605 nbd->sizey= (int)(nbd->percenty*0.01f*nbd->image_in_height);
609 if (nbd->sizex==0 && nbd->sizey==0) {
610 new= pass_on_compbuf(img);
613 else if (nbd->filtertype == R_FILTER_FAST_GAUSS) {
614 if (in[1]->vec[0] < 0.001f) { /* time node inputs can be a tiny value */
615 new = pass_on_compbuf(img);
618 // TODO: can this be mapped with reference, too?
619 const float sx = ((float)nbd->sizex*in[1]->vec[0])/2.0f, sy = ((float)nbd->sizey*in[1]->vec[0])/2.0f;
622 if ((img==NULL) || (out[0]->hasoutput==0)) return;
624 if (img->type == CB_VEC2)
625 new = typecheck_compbuf(img, CB_VAL);
626 else if (img->type == CB_VEC3)
627 new = typecheck_compbuf(img, CB_RGBA);
629 new = dupalloc_compbuf(img);
631 if ((sx == sy) && (sx > 0.f)) {
632 for (c=0; c<new->type; ++c)
633 IIR_gauss(new, sx, c, 3);
637 for (c=0; c<new->type; ++c)
638 IIR_gauss(new, sx, c, 1);
641 for (c=0; c<new->type; ++c)
642 IIR_gauss(new, sy, c, 2);
649 /* All non fast gauss blur methods */
650 if (img->type==CB_VEC2 || img->type==CB_VEC3) {
651 img= typecheck_compbuf(in[0]->data, CB_RGBA);
654 /* if fac input, we do it different */
658 /* make output size of input image */
659 new= alloc_compbuf(img->x, img->y, img->type, 1); /* allocs */
661 /* accept image offsets from other nodes */
666 gammabuf= dupalloc_compbuf(img);
667 gamma_correct_compbuf(gammabuf, 0);
671 blur_with_reference(node, new, gammabuf, in[1]->data);
674 gamma_correct_compbuf(new, 1);
675 free_compbuf(gammabuf);
677 if (node->exec & NODE_BREAK) {
685 if (in[1]->vec[0]<=0.001f) { /* time node inputs can be a tiny value */
686 new= pass_on_compbuf(img);
691 /* make output size of input image */
692 new= alloc_compbuf(img->x, img->y, img->type, 1); /* allocs */
694 /* accept image offsets from other nodes */
699 gammabuf= dupalloc_compbuf(img);
700 gamma_correct_compbuf(gammabuf, 0);
705 bokeh_single_image(node, new, gammabuf, in[1]->vec[0]);
707 blur_single_image(node, new, gammabuf, in[1]->vec[0]);
708 else /* bloom experimental... */
709 bloom_with_reference(new, gammabuf, NULL, in[1]->vec[0], nbd);
712 gamma_correct_compbuf(new, 1);
713 free_compbuf(gammabuf);
715 if (node->exec & NODE_BREAK) {
722 if (img!=in[0]->data)
726 generate_preview(data, node, out[0]->data);
729 static void node_composit_init_blur(bNodeTree *UNUSED(ntree), bNode* node, bNodeTemplate *UNUSED(ntemp))
731 node->storage= MEM_callocN(sizeof(NodeBlurData), "node blur data");
734 void register_node_type_cmp_blur(bNodeTreeType *ttype)
736 static bNodeType ntype;
738 node_type_base(ttype, &ntype, CMP_NODE_BLUR, "Blur", NODE_CLASS_OP_FILTER, NODE_PREVIEW|NODE_OPTIONS);
739 node_type_socket_templates(&ntype, cmp_node_blur_in, cmp_node_blur_out);
740 node_type_size(&ntype, 120, 80, 200);
741 node_type_init(&ntype, node_composit_init_blur);
742 node_type_storage(&ntype, "NodeBlurData", node_free_standard_storage, node_copy_standard_storage);
743 node_type_exec(&ntype, node_composit_exec_blur);
745 nodeRegisterType(ttype, &ntype);