4 * ***** BEGIN GPL LICENSE BLOCK *****
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version 2
9 * of the License, or (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software Foundation,
18 * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
20 * The Original Code is Copyright (C) 2006 Blender Foundation.
21 * All rights reserved.
23 * The Original Code is: all of this file.
25 * Contributor(s): none yet.
27 * ***** END GPL LICENSE BLOCK *****
35 #include "DNA_image_types.h"
36 #include "DNA_node_types.h"
37 #include "DNA_material_types.h"
38 #include "DNA_scene_types.h"
39 #include "DNA_texture_types.h"
40 #include "DNA_vec_types.h"
42 #include "BKE_blender.h"
43 #include "BKE_colortools.h"
44 #include "BKE_global.h"
45 #include "BKE_image.h"
47 #include "BKE_material.h"
48 #include "BKE_texture.h"
49 #include "BKE_utildefines.h"
51 #include "BLI_arithb.h"
52 #include "BLI_blenlib.h"
54 #include "MEM_guardedalloc.h"
55 #include "IMB_imbuf.h"
56 #include "IMB_imbuf_types.h"
58 #include "RE_pipeline.h"
60 /* *************************** operations support *************************** */
62 /* general signal that's in output sockets, and goes over the wires */
63 typedef struct CompBuf {
67 rcti disprect; /* cropped part of image */
68 int xof, yof; /* relative to center of target image */
71 /* defines also used for pixel size */
75 static CompBuf *alloc_compbuf(int sizex, int sizey, int type, int alloc)
77 CompBuf *cbuf= MEM_callocN(sizeof(CompBuf), "compbuf");
83 if(cbuf->type==CB_RGBA)
84 cbuf->rect= MEM_mallocN(4*sizeof(float)*sizex*sizey, "new rect");
86 cbuf->rect= MEM_mallocN(sizeof(float)*sizex*sizey, "new rect");
89 cbuf->disprect.xmin= 0;
90 cbuf->disprect.ymin= 0;
91 cbuf->disprect.xmax= sizex;
92 cbuf->disprect.ymax= sizey;
97 void free_compbuf(CompBuf *cbuf)
99 if(cbuf->malloc && cbuf->rect)
100 MEM_freeN(cbuf->rect);
105 /* on first call, disprect should be initialized to 'out', then you can call this on all 'src' images */
106 static void get_overlap_rct(CompBuf *out, CompBuf *src, rcti *disprect)
109 /* output center is considered (0,0) */
111 if(src==NULL) return;
113 /* translate src into output space */
115 BLI_translate_rcti(&rect, out->xof-src->xof, out->xof-src->xof);
116 /* intersect rect with current disprect */
118 BLI_isect_rcti(&rect, disprect, disprect);
121 static void get_scanline_rcti(CompBuf *out, rcti *disprect, CompBuf *src, rcti *srcrect)
125 /* translate src into output space */
126 xof= out->xof-src->xof;
127 yof= out->xof-src->xof;
129 srcrect->xmin= disprect->xmin + xof;
130 srcrect->ymin= disprect->ymin + yof;
131 srcrect->xmax= disprect->xmax + xof;
132 srcrect->ymax= disprect->ymax + yof;
136 /* Pixel-to-Pixel operation, 1 Image in, 1 out */
137 static void composit1_pixel_processor(bNode *node, CompBuf *out, CompBuf *src_buf, float *src_col,
138 void (*func)(bNode *, float *, float *))
140 float *outfp, *srcfp, *out_data, *src_data;
143 int out_pix, out_stride, src_stride, src_pix, x, y;
151 /* handle case when input is constant color */
153 srcx= outx; srcy= outy;
162 src_pix= src_buf->type;
163 src_data= src_buf->rect;
166 outx= MIN2(outx, srcx);
167 outy= MIN2(outy, srcy);
169 for(y=0; y<outy; y++) {
170 /* set scanlines on right location */
171 srcfp= src_data + src_pix*y*src_stride;
172 outfp= out_data + out_pix*y*out_stride;
174 for(x=0; x<outx; x++) {
175 func(node, outfp, srcfp);
182 /* Pixel-to-Pixel operation, 2 Images in, 1 out */
183 static void composit2_pixel_processor(bNode *node, CompBuf *out, CompBuf *src_buf, float *src_col,
184 CompBuf *fac_buf, float *fac, void (*func)(bNode *, float *, float *, float *))
186 float *outfp, *srcfp, *src_data, *facfp, *fac_data;
187 int outx= out->x, outy= out->y;
188 int srcx, srcy, facx, facy;
189 int out_pix, src_stride, src_pix, fac_stride, fac_pix, x, y;
193 /* handle case when input is constant color */
195 srcx= outx; srcy= outy;
204 src_pix= src_buf->type;
205 src_data= src_buf->rect;
208 /* factor buf or constant? */
210 facx= outx; facy= outy;
219 fac_pix= src_buf->type;
220 fac_data= fac_buf->rect;
224 printf("fac buffer error, node %s\n", node->name);
228 facx= MIN2(facx, srcx);
229 facy= MIN2(facy, srcy);
235 disprect= out->disprect;
236 get_overlap_rct(out, src_buf, &disprect);
237 printf("%s\n", node->name);
238 printf("union %d %d %d %d\n", disprect.xmin,disprect.ymin,disprect.xmax,disprect.ymax);
241 outfp= out->rect_float + src.ymin*outx + ;
242 for(y=src.ymin; y<src.ymax; y++) {
244 /* all operators available */
245 if(y>=disp.ymin && y<disp.ymax) {
246 srcfp= src_data + (src_stride*(y+scrc.ymin) + src.xmin);
247 facfp= fac_data + (fac_stride*(y+fac.ymin) + fac.xmin);
249 for(x= src.xmin; x<src.xmax; x++) {
250 if(x>=disp.xmin && x<disp.xmax) {
262 srcfp= src_data + (src_stride*(y+scrc.ymin) + src.xmin);
264 QUATCOPY(outfp, srcfp);
270 for(y=0; y<outy; y++) {
271 /* set source scanline on right location */
272 srcfp= src_data + src_pix*y*src_stride;
273 facfp= fac_data + fac_pix*y*fac_stride;
275 for(x=0; x<outx; x++, outfp+=out_pix) {
277 func(node, outfp, srcfp, facfp);
284 /* Pixel-to-Pixel operation, 3 Images in, 1 out */
285 static void composit3_pixel_processor(bNode *node, CompBuf *out, CompBuf *src1_buf, float *src1_col, CompBuf *src2_buf, float *src2_col,
286 CompBuf *fac_buf, float fac, void (*func)(bNode *, float *, float *, float *, float))
288 float *outfp, *src1fp, *src2fp, *facfp, *src1_data, *src2_data, *fac_data;
289 int outx= out->x, outy= out->y;
290 int src1x, src1y, src2x, src2y, facx, facy;
291 int src1_stride, src1_pix, src2_stride, src2_pix, fac_stride, fac_pix, x, y;
293 /* handle case when input has constant color */
295 src1x= outx; src1y= outy;
304 src1_pix= src1_buf->type;
305 src1_data= src1_buf->rect;
309 src2x= outx; src2y= outy;
318 src2_pix= src2_buf->type;
319 src2_data= src2_buf->rect;
322 /* factor buf or constant? */
324 facx= outx; facy= outy;
334 fac_data= fac_buf->rect;
337 facx= MIN3(facx, src1x, src2x);
338 facy= MIN3(facy, src1y, src2y);
341 for(y=0; y<outy; y++) {
343 /* set source scanlines on right location */
344 src1fp= src1_data + src1_pix*y*src1_stride;
345 src2fp= src2_data + src2_pix*y*src2_stride;
346 facfp= fac_data + y*fac_stride;
348 for(x=0; x<outx; x++, outfp+=4) {
350 func(node, outfp, src1fp, src2fp, *facfp);
359 static CompBuf *alphabuf_from_rgbabuf(CompBuf *cbuf)
361 CompBuf *valbuf= alloc_compbuf(cbuf->x, cbuf->y, CB_VAL, 1);
366 rectf= cbuf->rect + 3;
367 for(tot= cbuf->x*cbuf->y; tot>0; tot--, valf++, rectf+=4)
373 static void generate_preview(bNode *node, CompBuf *stackbuf)
375 bNodePreview *preview= node->preview;
378 ImBuf *ibuf= IMB_allocImBuf(stackbuf->x, stackbuf->y, 32, 0, 0); /* empty */
380 if(stackbuf->x > stackbuf->y) {
382 preview->ysize= (140*stackbuf->y)/stackbuf->x;
386 preview->xsize= (140*stackbuf->x)/stackbuf->y;
388 ibuf->rect_float= stackbuf->rect;
389 ibuf= IMB_scalefastImBuf(ibuf, preview->xsize, preview->ysize);
391 /* this ensures free-imbuf does the right stuff */
392 SWAP(float *, ibuf->rect_float, node->preview->rect);
398 /* ******************************************************** */
399 /* ********* Composit Node type definitions ***************** */
400 /* ******************************************************** */
402 /* SocketType syntax:
403 socket type, max connections (0 is no limit), name, 4 values for default, 2 values for range */
405 /* Verification rule: If name changes, a saved socket and its links will be removed! Type changes are OK */
407 /* **************** VIEWER ******************** */
408 static bNodeSocketType cmp_node_viewer_in[]= {
409 { SOCK_RGBA, 1, "Image", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
410 { SOCK_VALUE, 1, "Alpha", 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
414 static void do_copy_rgba(bNode *node, float *out, float *in)
418 static void do_copy_a_rgba(bNode *node, float *out, float *in, float *fac)
424 static void node_composit_exec_viewer(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
426 /* image assigned to output */
427 /* stack order input sockets: col, alpha */
429 if(node->id && (node->flag & NODE_DO_OUTPUT)) { /* only one works on out */
430 Image *ima= (Image *)node->id;
436 RenderData *rd= data;
438 /* re-create output, derive size from scene */
439 rectx= (rd->size*rd->xsch)/100;
440 recty= (rd->size*rd->ysch)/100;
442 if(ima->ibuf) IMB_freeImBuf(ima->ibuf);
443 ima->ibuf= IMB_allocImBuf(rectx, recty, 32, IB_rectfloat, 0); // do alloc
445 cbuf= alloc_compbuf(rectx, recty, CB_RGBA, 0); // no alloc
446 cbuf->rect= ima->ibuf->rect_float;
448 /* when no alpha, we can simply copy */
449 if(in[1]->data==NULL)
450 composit1_pixel_processor(node, cbuf, in[0]->data, in[0]->vec, do_copy_rgba);
452 composit2_pixel_processor(node, cbuf, in[0]->data, in[0]->vec, in[1]->data, in[1]->vec, do_copy_a_rgba);
454 generate_preview(node, cbuf);
458 if(ima->ibuf) IMB_freeImBuf(ima->ibuf);
459 ima->ibuf= IMB_allocImBuf(rectx, recty, 32, 0, 0); // do alloc
460 ima->ibuf->mall= IB_rectfloat;
462 ima->ibuf->rect_float= cbuf->rect;
463 ima->ibuf->x= cbuf->x;
464 ima->ibuf->y= cbuf->y;
470 generate_preview(node, in[0]->data);
473 static bNodeType cmp_node_viewer= {
474 /* type code */ CMP_NODE_VIEWER,
476 /* width+range */ 80, 60, 200,
477 /* class+opts */ NODE_CLASS_OUTPUT, NODE_PREVIEW,
478 /* input sock */ cmp_node_viewer_in,
479 /* output sock */ NULL,
481 /* execfunc */ node_composit_exec_viewer
485 /* **************** COMPOSITE ******************** */
486 static bNodeSocketType cmp_node_composite_in[]= {
487 { SOCK_RGBA, 1, "Image", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
488 { SOCK_VALUE, 1, "Alpha", 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
492 /* applies to render pipeline */
493 static void node_composit_exec_composite(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
495 /* image assigned to output */
496 /* stack order input sockets: col, alpha */
498 if(node->flag & NODE_DO_OUTPUT) { /* only one works on out */
499 RenderData *rd= data;
500 if(rd->scemode & R_DOCOMP) {
501 RenderResult *rr= RE_GetResult(RE_GetRender("Render"));
506 MEM_freeN(rr->rectf);
507 outbuf= alloc_compbuf(rr->rectx, rr->recty, CB_RGBA, 1);
509 if(in[1]->data==NULL)
510 composit1_pixel_processor(node, outbuf, in[0]->data, in[0]->vec, do_copy_rgba);
512 composit2_pixel_processor(node, outbuf, in[0]->data, in[0]->vec, in[1]->data, in[1]->vec, do_copy_a_rgba);
514 generate_preview(node, outbuf);
516 /* we give outbuf to rr... */
517 rr->rectf= outbuf->rect;
519 free_compbuf(outbuf);
526 generate_preview(node, in[0]->data);
529 static bNodeType cmp_node_composite= {
530 /* type code */ CMP_NODE_COMPOSITE,
531 /* name */ "Composite",
532 /* width+range */ 80, 60, 200,
533 /* class+opts */ NODE_CLASS_OUTPUT, NODE_PREVIEW,
534 /* input sock */ cmp_node_composite_in,
535 /* output sock */ NULL,
537 /* execfunc */ node_composit_exec_composite
541 /* **************** OUTPUT FILE ******************** */
542 static bNodeSocketType cmp_node_output_file_in[]= {
543 { SOCK_RGBA, 1, "Image", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
544 { SOCK_VALUE, 1, "Alpha", 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
549 static void node_composit_exec_output_file(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
551 /* image assigned to output */
552 /* stack order input sockets: col, alpha */
554 if(node->id && (node->flag & NODE_DO_OUTPUT)) { /* only one works on out */
557 generate_preview(node, in[0]->data);
560 static bNodeType cmp_node_output_file= {
561 /* type code */ CMP_NODE_OUTPUT_FILE,
562 /* name */ "File Output",
563 /* width+range */ 80, 60, 200,
564 /* class+opts */ NODE_CLASS_FILE, NODE_PREVIEW,
565 /* input sock */ cmp_node_output_file_in,
566 /* output sock */ NULL,
568 /* execfunc */ node_composit_exec_output_file
572 /* **************** IMAGE ******************** */
573 static bNodeSocketType cmp_node_image_out[]= {
574 { SOCK_RGBA, 0, "Image", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
575 { SOCK_VALUE, 0, "Alpha", 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
576 { SOCK_VALUE, 0, "Z", 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
580 static int calcimanr(int cfra, NodeImageAnim *nia)
583 if(nia->frames==0) return nia->nr;
585 cfra= cfra - nia->sfra;
589 cfra= (cfra % nia->frames);
590 else if(cfra>=nia->frames)
603 static void animated_image(bNode *node, int cfra)
608 unsigned short numlen;
609 char name[FILE_MAXDIR+FILE_MAXFILE], head[FILE_MAXDIR+FILE_MAXFILE], tail[FILE_MAXDIR+FILE_MAXFILE];
611 ima= (Image *)node->id;
614 if(nia && nia->frames && ima && ima->name) { /* frames */
615 strcpy(name, ima->name);
617 imanr= calcimanr(cfra, nia);
618 if(imanr!=ima->lastframe) {
619 ima->lastframe= imanr;
621 BLI_stringdec(name, head, tail, &numlen);
622 BLI_stringenc(name, head, tail, numlen, imanr);
624 ima= add_image(name);
627 ima->flag |= IMA_FROMANIM;
628 if(node->id) node->id->us--;
638 static void node_composit_exec_image(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
640 RenderData *rd= data;
642 /* image assigned to output */
643 /* stack order input sockets: col, alpha */
648 /* animated image? */
650 animated_image(node, rd->cfra);
652 ima= (Image *)node->id;
654 /* test if image is OK */
655 if(ima->ok==0) return;
657 if(ima->ibuf==NULL) {
659 load_image(ima, IB_rect, G.sce, rd->cfra); /* G.sce is current .blend path */
660 if(ima->ibuf==NULL) {
665 if(ima->ibuf->rect_float==NULL)
666 IMB_float_from_rect(ima->ibuf);
668 /* we put imbuf copy on stack, cbuf knows rect is from other ibuf when freed! */
669 stackbuf= alloc_compbuf(ima->ibuf->x, ima->ibuf->y, CB_RGBA, 0);
670 stackbuf->rect= ima->ibuf->rect_float;
672 /* put ibuf on stack */
673 out[0]->data= stackbuf;
675 if(out[1]->hasoutput)
676 out[1]->data= alphabuf_from_rgbabuf(stackbuf);
678 generate_preview(node, stackbuf);
682 /* uses node->storage to indicate animated image */
684 static bNodeType cmp_node_image= {
685 /* type code */ CMP_NODE_IMAGE,
687 /* width+range */ 120, 80, 300,
688 /* class+opts */ NODE_CLASS_GENERATOR, NODE_PREVIEW|NODE_OPTIONS,
689 /* input sock */ NULL,
690 /* output sock */ cmp_node_image_out,
691 /* storage */ "NodeImageAnim",
692 /* execfunc */ node_composit_exec_image
696 /* **************** RENDER RESULT ******************** */
697 static bNodeSocketType cmp_node_rresult_out[]= {
698 { SOCK_RGBA, 0, "Image", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
699 { SOCK_VALUE, 0, "Alpha", 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
700 { SOCK_VALUE, 0, "Z", 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
704 static void node_composit_exec_rresult(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
706 RenderResult *rr= RE_GetResult(RE_GetRender("Render"));
708 RenderLayer *rl= rr->layers.first;
711 /* we put render rect on stack, cbuf knows rect is from other ibuf when freed! */
712 stackbuf= alloc_compbuf(rr->rectx, rr->recty, CB_RGBA, 0);
713 stackbuf->rect= rl->rectf;
716 out[0]->data= stackbuf;
718 if(out[1]->hasoutput)
719 out[1]->data= alphabuf_from_rgbabuf(stackbuf);
721 generate_preview(node, stackbuf);
725 static bNodeType cmp_node_rresult= {
726 /* type code */ CMP_NODE_R_RESULT,
727 /* name */ "Render Result",
728 /* width+range */ 120, 80, 300,
729 /* class+opts */ NODE_CLASS_GENERATOR, NODE_PREVIEW,
730 /* input sock */ NULL,
731 /* output sock */ cmp_node_rresult_out,
733 /* execfunc */ node_composit_exec_rresult
737 /* **************** NORMAL ******************** */
738 static bNodeSocketType cmp_node_normal_in[]= {
739 { SOCK_VECTOR, 1, "Normal", 0.0f, 0.0f, 0.0f, 1.0f, -1.0f, 1.0f},
743 static bNodeSocketType cmp_node_normal_out[]= {
744 { SOCK_VECTOR, 0, "Normal", 0.0f, 0.0f, 1.0f, 1.0f, -1.0f, 1.0f},
745 { SOCK_VALUE, 0, "Dot", 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
749 /* generates normal, does dot product */
750 static void node_composit_exec_normal(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
752 bNodeSocket *sock= node->outputs.first;
753 /* stack order input: normal */
754 /* stack order output: normal, value */
756 VECCOPY(out[0]->vec, sock->ns.vec);
757 /* render normals point inside... the widget points outside */
758 out[1]->vec[0]= -INPR(out[0]->vec, in[0]->vec);
761 static bNodeType cmp_node_normal= {
762 /* type code */ CMP_NODE_NORMAL,
764 /* width+range */ 100, 60, 200,
765 /* class+opts */ NODE_CLASS_OPERATOR, NODE_OPTIONS,
766 /* input sock */ cmp_node_normal_in,
767 /* output sock */ cmp_node_normal_out,
769 /* execfunc */ node_composit_exec_normal
773 /* **************** CURVE VEC ******************** */
774 static bNodeSocketType cmp_node_curve_vec_in[]= {
775 { SOCK_VECTOR, 1, "Vector", 0.0f, 0.0f, 0.0f, 1.0f, -1.0f, 1.0f},
779 static bNodeSocketType cmp_node_curve_vec_out[]= {
780 { SOCK_VECTOR, 0, "Vector", 0.0f, 0.0f, 1.0f, 1.0f, -1.0f, 1.0f},
784 static void node_composit_exec_curve_vec(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
786 /* stack order input: vec */
787 /* stack order output: vec */
789 curvemapping_evaluate_premulRGBF(node->storage, out[0]->vec, in[0]->vec);
792 static bNodeType cmp_node_curve_vec= {
793 /* type code */ CMP_NODE_CURVE_VEC,
794 /* name */ "Vector Curves",
795 /* width+range */ 200, 140, 320,
796 /* class+opts */ NODE_CLASS_OPERATOR, NODE_OPTIONS,
797 /* input sock */ cmp_node_curve_vec_in,
798 /* output sock */ cmp_node_curve_vec_out,
799 /* storage */ "CurveMapping",
800 /* execfunc */ node_composit_exec_curve_vec
804 /* **************** CURVE RGB ******************** */
805 static bNodeSocketType cmp_node_curve_rgb_in[]= {
806 { SOCK_RGBA, 1, "Image", 0.0f, 0.0f, 0.0f, 1.0f, -1.0f, 1.0f},
810 static bNodeSocketType cmp_node_curve_rgb_out[]= {
811 { SOCK_RGBA, 0, "Image", 0.0f, 0.0f, 1.0f, 1.0f, -1.0f, 1.0f},
815 static void do_curves(bNode *node, float *out, float *in)
817 curvemapping_evaluateRGBF(node->storage, out, in);
821 static void node_composit_exec_curve_rgb(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
823 /* stack order input: vec */
824 /* stack order output: vec */
826 if(out[0]->hasoutput==0)
829 /* input no image? then only color operation */
830 if(in[0]->data==NULL) {
831 curvemapping_evaluateRGBF(node->storage, out[0]->vec, in[0]->vec);
834 /* make output size of input image */
835 CompBuf *cbuf= in[0]->data;
836 CompBuf *stackbuf= alloc_compbuf(cbuf->x, cbuf->y, CB_RGBA, 1); // allocs
838 curvemapping_premultiply(node->storage, 0);
839 composit1_pixel_processor(node, stackbuf, in[0]->data, NULL, do_curves);
840 curvemapping_premultiply(node->storage, 1);
842 out[0]->data= stackbuf;
847 static bNodeType cmp_node_curve_rgb= {
848 /* type code */ CMP_NODE_CURVE_RGB,
849 /* name */ "RGB Curves",
850 /* width+range */ 200, 140, 320,
851 /* class+opts */ NODE_CLASS_OPERATOR, NODE_OPTIONS,
852 /* input sock */ cmp_node_curve_rgb_in,
853 /* output sock */ cmp_node_curve_rgb_out,
854 /* storage */ "CurveMapping",
855 /* execfunc */ node_composit_exec_curve_rgb
859 /* **************** VALUE ******************** */
860 static bNodeSocketType cmp_node_value_out[]= {
861 { SOCK_VALUE, 0, "Value", 0.5f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
865 static void node_composit_exec_value(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
867 bNodeSocket *sock= node->outputs.first;
869 out[0]->vec[0]= sock->ns.vec[0];
872 static bNodeType cmp_node_value= {
873 /* type code */ CMP_NODE_VALUE,
875 /* width+range */ 80, 40, 120,
876 /* class+opts */ NODE_CLASS_GENERATOR, NODE_OPTIONS,
877 /* input sock */ NULL,
878 /* output sock */ cmp_node_value_out,
880 /* execfunc */ node_composit_exec_value
884 /* **************** RGB ******************** */
885 static bNodeSocketType cmp_node_rgb_out[]= {
886 { SOCK_RGBA, 0, "RGBA", 0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f},
890 static void node_composit_exec_rgb(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
892 bNodeSocket *sock= node->outputs.first;
894 VECCOPY(out[0]->vec, sock->ns.vec);
897 static bNodeType cmp_node_rgb= {
898 /* type code */ CMP_NODE_RGB,
900 /* width+range */ 100, 60, 140,
901 /* class+opts */ NODE_CLASS_GENERATOR, NODE_OPTIONS,
902 /* input sock */ NULL,
903 /* output sock */ cmp_node_rgb_out,
905 /* execfunc */ node_composit_exec_rgb
909 /* **************** MIX RGB ******************** */
910 static bNodeSocketType cmp_node_mix_rgb_in[]= {
911 { SOCK_VALUE, 1, "Fac", 0.5f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
912 { SOCK_RGBA, 1, "Image", 0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f},
913 { SOCK_RGBA, 1, "Image", 0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f},
916 static bNodeSocketType cmp_node_mix_rgb_out[]= {
917 { SOCK_RGBA, 0, "Image", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
921 static void do_mix_rgb(bNode *node, float *out, float *in1, float *in2, float fac)
926 ramp_blend(node->custom1, col, col+1, col+2, fac, in2);
931 static void node_composit_exec_mix_rgb(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
933 /* stack order in: fac, Image, Image */
934 /* stack order out: Image */
935 float fac= in[0]->vec[0];
937 CLAMP(fac, 0.0f, 1.0f);
939 /* input no image? then only color operation */
940 if(in[1]->data==NULL && in[2]->data==NULL) {
941 do_mix_rgb(node, out[0]->vec, in[1]->vec, in[2]->vec, fac);
944 /* make output size of first available input image */
945 CompBuf *cbuf= in[1]->data?in[1]->data:in[2]->data;
946 CompBuf *stackbuf= alloc_compbuf(cbuf->x, cbuf->y, CB_RGBA, 1); // allocs
948 composit3_pixel_processor(node, stackbuf, in[1]->data, in[1]->vec, in[2]->data, in[2]->vec, in[0]->data, fac, do_mix_rgb);
950 out[0]->data= stackbuf;
954 static bNodeType cmp_node_mix_rgb= {
955 /* type code */ CMP_NODE_MIX_RGB,
957 /* width+range */ 80, 40, 120,
958 /* class+opts */ NODE_CLASS_OPERATOR, NODE_OPTIONS,
959 /* input sock */ cmp_node_mix_rgb_in,
960 /* output sock */ cmp_node_mix_rgb_out,
962 /* execfunc */ node_composit_exec_mix_rgb
966 /* **************** FILTER ******************** */
967 static bNodeSocketType cmp_node_filter_in[]= {
968 { SOCK_VALUE, 1, "Fac", 1.0f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f},
969 { SOCK_RGBA, 1, "Image", 0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f},
972 static bNodeSocketType cmp_node_filter_out[]= {
973 { SOCK_RGBA, 0, "Image", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
977 static void do_filter_edge(CompBuf *out, CompBuf *in, float *filter, float fac)
979 float *row1, *row2, *row3;
980 float *fp, f1, f2, mfac= 1.0f-fac;
985 if(in->type==CB_RGBA) {
987 for(y=2; y<in->y; y++) {
989 row1= in->rect + 4*(y-2)*rowlen;
990 row2= row1 + 4*rowlen;
991 row3= row2 + 4*rowlen;
992 fp= out->rect + 4*(y-1)*rowlen + 4;
994 for(x=2; x<rowlen; x++) {
996 f1= filter[0]*row1[0] + filter[1]*row1[4] + filter[2]*row1[8] + filter[3]*row2[0] + filter[4]*row2[4] + filter[5]*row2[8] + filter[6]*row3[0] + filter[7]*row3[4] + filter[8]*row3[8];
997 f2= filter[0]*row1[0] + filter[3]*row1[4] + filter[6]*row1[8] + filter[1]*row2[0] + filter[4]*row2[4] + filter[7]*row2[8] + filter[2]*row3[0] + filter[5]*row3[4] + filter[8]*row3[8];
998 fp[0]= mfac*row2[4] + fac*sqrt(f1*f1 + f2*f2);
999 fp++; row1++; row2++; row3++;
1002 /* no alpha... will clear it completely */
1003 fp++; row1++; row2++; row3++;
1009 static void do_filter3(CompBuf *out, CompBuf *in, float *filter, float fac)
1011 float *row1, *row2, *row3;
1012 float *fp, mfac= 1.0f-fac;
1013 int rowlen, x, y, c;
1017 if(in->type==CB_RGBA) {
1019 for(y=2; y<in->y; y++) {
1021 row1= in->rect + 4*(y-2)*rowlen;
1022 row2= row1 + 4*rowlen;
1023 row3= row2 + 4*rowlen;
1025 fp= out->rect + 4*(y-1)*rowlen;
1029 for(x=2; x<rowlen; x++) {
1030 for(c=0; c<4; c++) {
1031 fp[0]= mfac*row2[4] + fac*(filter[0]*row1[0] + filter[1]*row1[4] + filter[2]*row1[8] + filter[3]*row2[0] + filter[4]*row2[4] + filter[5]*row2[8] + filter[6]*row3[0] + filter[7]*row3[4] + filter[8]*row3[8]);
1032 fp++; row1++; row2++; row3++;
1039 static void node_composit_exec_filter(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
1041 float soft[9]= {1/16.0f, 2/16.0f, 1/16.0f, 2/16.0f, 4/16.0f, 2/16.0f, 1/16.0f, 2/16.0f, 1/16.0f};
1042 float sharp[9]= {-1,-1,-1,-1,9,-1,-1,-1,-1};
1043 float laplace[9]= {1/8.0f, -1/8.0f, 1/8.0f, -1/8.0f, 1.0f, -1/8.0f, 1/8.0f, -1/8.0f, 1/8.0f};
1044 float sobel[9]= {1,2,1,0,0,0,-1,-2,-1};
1045 float prewitt[9]= {1,1,1,0,0,0,-1,-1,-1};
1046 float kirsch[9]= {5,5,5,-3,-3,-3,-2,-2,-2};
1047 float shadow[9]= {1,2,1,0,1,0,-1,-2,-1};
1049 /* stack order in: Image */
1050 /* stack order out: Image */
1053 /* make output size of first available input image */
1054 CompBuf *cbuf= in[1]->data;
1055 CompBuf *stackbuf= alloc_compbuf(cbuf->x, cbuf->y, CB_RGBA, 1); // allocs
1057 switch(node->custom1) {
1059 do_filter3(stackbuf, cbuf, soft, in[0]->vec[0]);
1061 case CMP_FILT_SHARP:
1062 do_filter3(stackbuf, cbuf, sharp, in[0]->vec[0]);
1064 case CMP_FILT_LAPLACE:
1065 do_filter3(stackbuf, cbuf, laplace, in[0]->vec[0]);
1067 case CMP_FILT_SOBEL:
1068 do_filter_edge(stackbuf, cbuf, sobel, in[0]->vec[0]);
1070 case CMP_FILT_PREWITT:
1071 do_filter_edge(stackbuf, cbuf, prewitt, in[0]->vec[0]);
1073 case CMP_FILT_KIRSCH:
1074 do_filter_edge(stackbuf, cbuf, kirsch, in[0]->vec[0]);
1076 case CMP_FILT_SHADOW:
1077 do_filter3(stackbuf, cbuf, shadow, in[0]->vec[0]);
1081 out[0]->data= stackbuf;
1085 static bNodeType cmp_node_filter= {
1086 /* type code */ CMP_NODE_FILTER,
1087 /* name */ "Filter",
1088 /* width+range */ 80, 40, 120,
1089 /* class+opts */ NODE_CLASS_OPERATOR, NODE_OPTIONS,
1090 /* input sock */ cmp_node_filter_in,
1091 /* output sock */ cmp_node_filter_out,
1093 /* execfunc */ node_composit_exec_filter
1098 /* **************** VALTORGB ******************** */
1099 static bNodeSocketType cmp_node_valtorgb_in[]= {
1100 { SOCK_VALUE, 1, "Fac", 0.5f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
1103 static bNodeSocketType cmp_node_valtorgb_out[]= {
1104 { SOCK_RGBA, 0, "Image", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
1105 { SOCK_VALUE, 0, "Alpha", 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
1109 static void do_colorband_composit(bNode *node, float *out, float *in)
1111 do_colorband(node->storage, in[0], out);
1114 static void node_composit_exec_valtorgb(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
1116 /* stack order in: fac */
1117 /* stack order out: col, alpha */
1120 /* input no image? then only color operation */
1121 if(in[0]->data==NULL) {
1122 do_colorband(node->storage, in[0]->vec[0], out[0]->vec);
1125 /* make output size of input image */
1126 CompBuf *cbuf= in[0]->data;
1127 CompBuf *stackbuf= alloc_compbuf(cbuf->x, cbuf->y, CB_RGBA, 1); // allocs
1129 composit1_pixel_processor(node, stackbuf, in[0]->data, NULL, do_colorband_composit);
1131 out[0]->data= stackbuf;
1133 if(out[1]->hasoutput)
1134 out[1]->data= alphabuf_from_rgbabuf(stackbuf);
1140 static bNodeType cmp_node_valtorgb= {
1141 /* type code */ CMP_NODE_VALTORGB,
1142 /* name */ "ColorRamp",
1143 /* width+range */ 240, 200, 300,
1144 /* class+opts */ NODE_CLASS_OPERATOR, NODE_OPTIONS,
1145 /* input sock */ cmp_node_valtorgb_in,
1146 /* output sock */ cmp_node_valtorgb_out,
1147 /* storage */ "ColorBand",
1148 /* execfunc */ node_composit_exec_valtorgb
1153 /* **************** RGBTOBW ******************** */
1154 static bNodeSocketType cmp_node_rgbtobw_in[]= {
1155 { SOCK_RGBA, 1, "Image", 0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f},
1158 static bNodeSocketType cmp_node_rgbtobw_out[]= {
1159 { SOCK_VALUE, 0, "Val", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
1163 static void do_rgbtobw(bNode *node, float *out, float *in)
1165 out[0]= in[0]*0.35f + in[1]*0.45f + in[2]*0.2f;
1168 static void node_composit_exec_rgbtobw(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
1170 /* stack order out: bw */
1171 /* stack order in: col */
1173 /* input no image? then only color operation */
1174 if(in[0]->data==NULL) {
1175 out[0]->vec[0]= in[0]->vec[0]*0.35f + in[0]->vec[1]*0.45f + in[0]->vec[2]*0.2f;
1178 /* make output size of input image */
1179 CompBuf *cbuf= in[0]->data;
1180 CompBuf *stackbuf= alloc_compbuf(cbuf->x, cbuf->y, CB_VAL, 1); // allocs
1182 composit1_pixel_processor(node, stackbuf, in[0]->data, NULL, do_rgbtobw);
1184 out[0]->data= stackbuf;
1188 static bNodeType cmp_node_rgbtobw= {
1189 /* type code */ CMP_NODE_RGBTOBW,
1190 /* name */ "RGB to BW",
1191 /* width+range */ 80, 40, 120,
1192 /* class+opts */ NODE_CLASS_OPERATOR, 0,
1193 /* input sock */ cmp_node_rgbtobw_in,
1194 /* output sock */ cmp_node_rgbtobw_out,
1196 /* execfunc */ node_composit_exec_rgbtobw
1200 /* **************** ALPHAOVER ******************** */
1201 static bNodeSocketType cmp_node_alphaover_in[]= {
1202 { SOCK_RGBA, 1, "Image", 0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f},
1203 { SOCK_RGBA, 1, "Image", 0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f},
1206 static bNodeSocketType cmp_node_alphaover_out[]= {
1207 { SOCK_RGBA, 0, "Image", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
1211 static void do_alphaover(bNode *node, float *out, float *src, float *dest)
1213 float mul= 1.0f - dest[3];
1216 QUATCOPY(out, dest);
1219 out[0]= (mul*src[0]) + dest[0];
1220 out[1]= (mul*src[1]) + dest[1];
1221 out[2]= (mul*src[2]) + dest[2];
1222 out[3]= (mul*src[3]) + dest[3];
1226 static void node_composit_exec_alphaover(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
1228 /* stack order in: col col */
1229 /* stack order out: col */
1231 /* input no image? then only color operation */
1232 if(in[0]->data==NULL) {
1233 do_alphaover(node, out[0]->vec, in[0]->vec, in[1]->vec);
1236 /* make output size of input image */
1237 CompBuf *cbuf= in[0]->data;
1238 CompBuf *stackbuf= alloc_compbuf(cbuf->x, cbuf->y, CB_RGBA, 1); // allocs
1240 composit2_pixel_processor(node, stackbuf, in[0]->data, in[0]->vec, in[1]->data, in[1]->vec, do_alphaover);
1242 out[0]->data= stackbuf;
1246 static bNodeType cmp_node_alphaover= {
1247 /* type code */ CMP_NODE_ALPHAOVER,
1248 /* name */ "AlphaOver",
1249 /* width+range */ 80, 40, 120,
1250 /* class+opts */ NODE_CLASS_OPERATOR, 0,
1251 /* input sock */ cmp_node_alphaover_in,
1252 /* output sock */ cmp_node_alphaover_out,
1254 /* execfunc */ node_composit_exec_alphaover
1258 /* **************** GAUSS BLUR ******************** */
1259 static bNodeSocketType cmp_node_blur_in[]= {
1260 { SOCK_RGBA, 1, "Image", 0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f},
1263 static bNodeSocketType cmp_node_blur_out[]= {
1264 { SOCK_RGBA, 0, "Image", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
1269 static void node_composit_exec_blur(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
1271 CompBuf *new, *work, *img= in[0]->data;
1272 register float sum, val;
1273 float rval, gval, bval, aval;
1274 float *gausstab, *v;
1282 if(img==NULL || out[0]->hasoutput==0)
1285 /* make output size of input image */
1286 new= alloc_compbuf(img->x, img->y, CB_RGBA, 1); // allocs
1289 /* prepare for gauss tab */
1290 r = (1.5 * node->custom1 + 1.5);
1294 if ((img->x <= n) || (img->y <= n)) {
1295 printf("gauss filter too large/n");
1299 gausstab = (float *) MEM_mallocN(n * sizeof(float), "gauss");
1303 for (x = -r; x <= r; x++) {
1304 val = exp(-4*(float ) (x*x)/ (float) (r*r));
1316 work= alloc_compbuf(img->x, img->y, CB_RGBA, 1); // allocs
1321 for (y = 0; y < img->y; y++) {
1322 src = img->rect + 4*(y * img->x);
1323 dest = work->rect + 4*(y * img->x);
1325 for (x = r; x > 0 ; x--) {
1327 gval = rval= bval= aval= 0.0f;
1330 for (i = 0; i < m; i++) {
1333 rval += val * (*src++);
1334 gval += val * (*src++);
1335 bval += val * (*src++);
1336 aval += val * (*src++);
1338 *dest++ = rval / sum;
1339 *dest++ = gval / sum;
1340 *dest++ = bval / sum;
1341 *dest++ = aval / sum;
1346 for (x = 0; x <= (img->x - n); x++) {
1347 gval = rval= bval= aval= 0.0f;
1350 for (i = 0; i < n; i++) {
1352 rval += val * (*src++);
1353 gval += val * (*src++);
1354 bval += val * (*src++);
1355 aval += val * (*src++);
1364 for (x = 1; x <= r ; x++) {
1366 gval = rval= bval= aval= 0.0f;
1369 for (i = 0; i < m; i++) {
1372 rval += val * (*src++);
1373 gval += val * (*src++);
1374 bval += val * (*src++);
1375 aval += val * (*src++);
1377 *dest++ = rval / sum;
1378 *dest++ = gval / sum;
1379 *dest++ = bval / sum;
1380 *dest++ = aval / sum;
1386 MEM_freeN(gausstab);
1388 /* prepare for gauss tab */
1389 r = (1.5 * node->custom2 + 1.5);
1393 if ((img->x <= n) || (img->y <= n)) {
1394 printf("gauss filter too large/n");
1398 gausstab = (float *) MEM_mallocN(n * sizeof(float), "gauss");
1402 for (x = -r; x <= r; x++) {
1403 val = exp(-4*(float ) (x*x)/ (float) (r*r));
1415 bigstep = (n - 1) * step;
1416 for (x = 0; x < step ; x++) {
1417 dest = new->rect + 4*x;
1418 src = work->rect + 4*x;
1420 for (y = r; y > 0; y--) {
1422 gval = rval= bval= aval= 0.0f;
1425 for (i = 0; i < m; i++) {
1428 rval += val * src[0];
1429 gval += val * src[1];
1430 bval += val * src[2];
1431 aval += val * src[3];
1434 dest[0] = rval / sum;
1435 dest[1] = gval / sum;
1436 dest[2] = bval / sum;
1437 dest[3] = aval / sum;
1438 src -= 4 * m * step;
1441 for (y = 0; y <= (img->y - n); y++) {
1442 gval = rval= bval= aval= 0.0f;
1444 for (i = 0; i < n; i++) {
1446 rval += val * src[0];
1447 gval += val * src[1];
1448 bval += val * src[2];
1449 aval += val * src[3];
1459 for (y = 1; y <= r ; y++) {
1461 gval = rval= bval= aval= 0.0f;
1464 for (i = 0; i < m; i++) {
1467 rval += val * src[0];
1468 gval += val * src[1];
1469 bval += val * src[2];
1470 aval += val * src[3];
1473 dest[0] = rval / sum;
1474 dest[1] = gval / sum;
1475 dest[2] = bval / sum;
1476 dest[3] = aval / sum;
1478 src -= 4 * (m - 1) * step;
1483 MEM_freeN(gausstab);
1486 static bNodeType cmp_node_blur= {
1487 /* type code */ CMP_NODE_BLUR,
1489 /* width+range */ 120, 80, 200,
1490 /* class+opts */ NODE_CLASS_OPERATOR, NODE_OPTIONS,
1491 /* input sock */ cmp_node_blur_in,
1492 /* output sock */ cmp_node_blur_out,
1494 /* execfunc */ node_composit_exec_blur
1499 /* ****************** types array for all shaders ****************** */
1501 bNodeType *node_all_composit[]= {
1502 &node_group_typeinfo,
1504 &cmp_node_composite,
1505 &cmp_node_output_file,
1513 &cmp_node_curve_vec,
1514 &cmp_node_curve_rgb,
1517 &cmp_node_alphaover,
1522 /* ******************* execute and parse ************ */
1524 /* helper call to detect if theres a render-result node */
1525 int ntreeCompositNeedsRender(bNodeTree *ntree)
1529 if(ntree==NULL) return 1;
1531 for(node= ntree->nodes.first; node; node= node->next) {
1532 if(node->type==CMP_NODE_R_RESULT)
1538 /* note; if called without preview, and previews exist, they get updated */
1539 /* render calls it without previews, works nicer for bg render */
1540 void ntreeCompositExecTree(bNodeTree *ntree, RenderData *rd, int do_preview)
1542 if(ntree==NULL) return;
1545 ntreeInitPreview(ntree, 0, 0);
1547 ntreeBeginExecTree(ntree);
1549 /* allocate composit data? */
1551 ntreeExecTree(ntree, rd, 0); /* threads */
1553 ntreeEndExecTree(ntree);
1555 free_unused_animimages();