8c2202f053d823bc14c74788a0b1a8bf545d3fc5
[blender-staging.git] / source / blender / blenkernel / intern / node_composit.c
1 /**
2  * $Id$
3  *
4  * ***** BEGIN GPL LICENSE BLOCK *****
5  *
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. 
10  *
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.
15  *
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.
19  *
20  * The Original Code is Copyright (C) 2006 Blender Foundation.
21  * All rights reserved.
22  *
23  * The Original Code is: all of this file.
24  *
25  * Contributor(s): none yet.
26  *
27  * ***** END GPL LICENSE BLOCK *****
28  */
29
30 #include <stdlib.h>
31 #include <string.h>
32 #include <math.h>
33
34 #include "DNA_ID.h"
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"
41
42 #include "BKE_blender.h"
43 #include "BKE_colortools.h"
44 #include "BKE_global.h"
45 #include "BKE_image.h"
46 #include "BKE_node.h"
47 #include "BKE_material.h"
48 #include "BKE_texture.h"
49 #include "BKE_utildefines.h"
50
51 #include "BLI_arithb.h"
52 #include "BLI_blenlib.h"
53
54 #include "MEM_guardedalloc.h"
55 #include "IMB_imbuf.h"
56 #include "IMB_imbuf_types.h"
57
58 #include "RE_pipeline.h"
59
60 /* *************************** operations support *************************** */
61
62 /* general signal that's in output sockets, and goes over the wires */
63 typedef struct CompBuf {
64         float *rect;
65         int x, y;
66         short type, malloc;
67         rcti disprect;          /* cropped part of image */
68         int xof, yof;           /* relative to center of target image */
69 } CompBuf;
70
71 /* defines also used for pixel size */
72 #define CB_RGBA         4
73 #define CB_VAL          1
74
75 static CompBuf *alloc_compbuf(int sizex, int sizey, int type, int alloc)
76 {
77         CompBuf *cbuf= MEM_callocN(sizeof(CompBuf), "compbuf");
78         
79         cbuf->x= sizex;
80         cbuf->y= sizey;
81         cbuf->type= type;
82         if(alloc) {
83                 if(cbuf->type==CB_RGBA)
84                         cbuf->rect= MEM_mallocN(4*sizeof(float)*sizex*sizey, "new rect");
85                 else
86                         cbuf->rect= MEM_mallocN(sizeof(float)*sizex*sizey, "new rect");
87                 cbuf->malloc= 1;
88         }
89         cbuf->disprect.xmin= 0;
90         cbuf->disprect.ymin= 0;
91         cbuf->disprect.xmax= sizex;
92         cbuf->disprect.ymax= sizey;
93         
94         return cbuf;
95 }
96
97 void free_compbuf(CompBuf *cbuf)
98 {
99         if(cbuf->malloc && cbuf->rect)
100                 MEM_freeN(cbuf->rect);
101         MEM_freeN(cbuf);
102 }
103
104 #if 0
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)
107 {
108         rcti rect;
109         /* output center is considered (0,0) */
110         
111         if(src==NULL) return;
112         
113         /* translate src into output space */
114         rect= src->disprect;
115         BLI_translate_rcti(&rect, out->xof-src->xof, out->xof-src->xof);
116         /* intersect rect with current disprect */
117         
118         BLI_isect_rcti(&rect, disprect, disprect);
119 }
120
121 static void get_scanline_rcti(CompBuf *out, rcti *disprect, CompBuf *src, rcti *srcrect)
122 {
123         int xof, yof;
124         
125         /* translate src into output space */
126         xof= out->xof-src->xof;
127         yof= out->xof-src->xof;
128         
129         srcrect->xmin= disprect->xmin + xof;
130         srcrect->ymin= disprect->ymin + yof;
131         srcrect->xmax= disprect->xmax + xof;
132         srcrect->ymax= disprect->ymax + yof;
133 }
134 #endif
135
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 *))
139 {
140         float *outfp, *srcfp, *out_data, *src_data;
141         int outx, outy;
142         int srcx, srcy;
143         int out_pix, out_stride, src_stride, src_pix, x, y;
144         
145         outx= out->x;
146         outy= out->y;
147         out_pix= out->type;
148         out_stride= out->x;
149         out_data= out->rect;
150         
151         /* handle case when input is constant color */
152         if(src_buf==NULL) {
153                 srcx= outx; srcy= outy;
154                 src_stride= 0;
155                 src_pix= 0;
156                 src_data= src_col;
157         }
158         else {
159                 srcx= src_buf->x;
160                 srcy= src_buf->y;
161                 src_stride= srcx;
162                 src_pix= src_buf->type;
163                 src_data= src_buf->rect;
164         }
165         
166         outx= MIN2(outx, srcx);
167         outy= MIN2(outy, srcy);
168
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;
173                         
174                 for(x=0; x<outx; x++) {
175                         func(node, outfp, srcfp);
176                         srcfp += src_pix;
177                         outfp += out_pix;
178                 }
179         }
180 }
181
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 *))
185 {
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;
190         
191         out_pix= out->type;
192         
193         /* handle case when input is constant color */
194         if(src_buf==NULL) {
195                 srcx= outx; srcy= outy;
196                 src_stride= 0;
197                 src_pix= 0;
198                 src_data= src_col;
199         }
200         else {
201                 srcx= src_buf->x;
202                 srcy= src_buf->y;
203                 src_stride= srcx;
204                 src_pix= src_buf->type;
205                 src_data= src_buf->rect;
206         }
207         
208         /* factor buf or constant? */
209         if(fac_buf==NULL) {
210                 facx= outx; facy= outy;
211                 fac_stride= 0;
212                 fac_pix= 0;
213                 fac_data= fac;
214         }
215         else {
216                 facx= fac_buf->x;
217                 facy= fac_buf->y;
218                 fac_stride= facx;
219                 fac_pix= src_buf->type;
220                 fac_data= fac_buf->rect;
221         }
222         
223         if(fac_data==NULL) {
224                 printf("fac buffer error, node %s\n", node->name);
225                 return;
226         }
227         
228         facx= MIN2(facx, srcx);
229         facy= MIN2(facy, srcy);
230         
231 #if 0   
232         if(src_buf) {
233                 rcti disprect;
234                 
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);
239         }
240         /* new approach */
241         outfp= out->rect_float + src.ymin*outx + ;
242         for(y=src.ymin; y<src.ymax; y++) {
243                 
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);
248                         
249                         for(x= src.xmin; x<src.xmax; x++) {
250                                 if(x>=disp.xmin && x<disp.xmax) {
251                                         
252                                         srcfp+= src_pix;
253                                         facfp+= fac_pix;
254                                 }
255                                 else {
256                                         /* copy src1 */
257                                 }
258                         }
259                 }
260                 else {
261                         /* copy src1 */
262                         srcfp= src_data + (src_stride*(y+scrc.ymin) + src.xmin);
263                         
264                         QUATCOPY(outfp, srcfp);
265                 }
266         }       
267 #endif
268         
269         outfp= out->rect;
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;
274                 
275                 for(x=0; x<outx; x++, outfp+=out_pix) {
276                         if(x<facx && y<facy)
277                                 func(node, outfp, srcfp, facfp);
278                         srcfp += src_pix;
279                         facfp += fac_pix;
280                 }
281         }
282 }
283
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))
287 {
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;
292
293         /* handle case when input has constant color */
294         if(src1_buf==NULL) {
295                 src1x= outx; src1y= outy;
296                 src1_stride= 0;
297                 src1_pix= 0;
298                 src1_data= src1_col;
299         }
300         else {
301                 src1x= src1_buf->x;
302                 src1y= src1_buf->y;
303                 src1_stride= src1x;
304                 src1_pix= src1_buf->type;
305                 src1_data= src1_buf->rect;
306         }
307         
308         if(src2_buf==NULL) {
309                 src2x= outx; src2y= outy;
310                 src2_stride= 0;
311                 src2_pix= 0;
312                 src2_data= src2_col;
313         }
314         else {
315                 src2x= src2_buf->x;
316                 src2y= src2_buf->y;
317                 src2_stride= src2x;
318                 src2_pix= src2_buf->type;
319                 src2_data= src2_buf->rect;
320         }
321         
322         /* factor buf or constant? */
323         if(fac_buf==NULL) {
324                 facx= outx; facy= outy;
325                 fac_stride= 0;
326                 fac_pix= 0;
327                 fac_data= &fac;
328         }
329         else {
330                 facx= fac_buf->x;
331                 facy= fac_buf->y;
332                 fac_stride= facx;
333                 fac_pix= 1;
334                 fac_data= fac_buf->rect;
335         }
336         
337         facx= MIN3(facx, src1x, src2x);
338         facy= MIN3(facy, src1y, src2y);
339         
340         outfp= out->rect;
341         for(y=0; y<outy; y++) {
342                 
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;
347                 
348                 for(x=0; x<outx; x++, outfp+=4) {
349                         if(x<facx && y<facy)
350                                 func(node, outfp, src1fp, src2fp, *facfp);
351                         src1fp+= src1_pix;
352                         src2fp+= src2_pix;
353                         facfp+= fac_pix;
354                 }
355         }
356 }
357
358 /*  */
359 static CompBuf *alphabuf_from_rgbabuf(CompBuf *cbuf)
360 {
361         CompBuf *valbuf= alloc_compbuf(cbuf->x, cbuf->y, CB_VAL, 1);
362         float *valf, *rectf;
363         int tot;
364         
365         valf= valbuf->rect;
366         rectf= cbuf->rect + 3;
367         for(tot= cbuf->x*cbuf->y; tot>0; tot--, valf++, rectf+=4)
368                 *valf= *rectf;
369         
370         return valbuf;
371 }
372
373 static void generate_preview(bNode *node, CompBuf *stackbuf)
374 {
375         bNodePreview *preview= node->preview;
376         
377         if(preview) {
378                 ImBuf *ibuf= IMB_allocImBuf(stackbuf->x, stackbuf->y, 32, 0, 0);        /* empty */
379                 
380                 if(stackbuf->x > stackbuf->y) {
381                         preview->xsize= 140;
382                         preview->ysize= (140*stackbuf->y)/stackbuf->x;
383                 }
384                 else {
385                         preview->ysize= 140;
386                         preview->xsize= (140*stackbuf->x)/stackbuf->y;
387                 }
388                 ibuf->rect_float= stackbuf->rect;
389                 ibuf= IMB_scalefastImBuf(ibuf, preview->xsize, preview->ysize);
390                 
391                 /* this ensures free-imbuf does the right stuff */
392                 SWAP(float *, ibuf->rect_float, node->preview->rect);
393                 
394                 IMB_freeImBuf(ibuf);
395         }
396 }
397
398 /* ******************************************************** */
399 /* ********* Composit Node type definitions ***************** */
400 /* ******************************************************** */
401
402 /* SocketType syntax: 
403    socket type, max connections (0 is no limit), name, 4 values for default, 2 values for range */
404
405 /* Verification rule: If name changes, a saved socket and its links will be removed! Type changes are OK */
406
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},
411         {       -1, 0, ""       }
412 };
413
414 static void do_copy_rgba(bNode *node, float *out, float *in)
415 {
416         QUATCOPY(out, in);
417 }
418 static void do_copy_a_rgba(bNode *node, float *out, float *in, float *fac)
419 {
420         VECCOPY(out, in);
421         out[3]= *fac;
422 }
423
424 static void node_composit_exec_viewer(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
425 {
426         /* image assigned to output */
427         /* stack order input sockets: col, alpha */
428         
429         if(node->id && (node->flag & NODE_DO_OUTPUT)) { /* only one works on out */
430                 Image *ima= (Image *)node->id;
431                 CompBuf *cbuf;
432                 int rectx, recty;
433                 
434                 /* scene size? */
435                 if(1) {
436                         RenderData *rd= data;
437                         
438                         /* re-create output, derive size from scene */
439                         rectx= (rd->size*rd->xsch)/100;
440                         recty= (rd->size*rd->ysch)/100;
441                         
442                         if(ima->ibuf) IMB_freeImBuf(ima->ibuf);
443                         ima->ibuf= IMB_allocImBuf(rectx, recty, 32, IB_rectfloat, 0); // do alloc
444                         
445                         cbuf= alloc_compbuf(rectx, recty, CB_RGBA, 0);  // no alloc
446                         cbuf->rect= ima->ibuf->rect_float;
447                         
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);
451                         else
452                                 composit2_pixel_processor(node, cbuf, in[0]->data, in[0]->vec, in[1]->data, in[1]->vec, do_copy_a_rgba);
453                         
454                         generate_preview(node, cbuf);
455                         free_compbuf(cbuf);
456                 }
457                 else { /* test */
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;
461                         cbuf= in[0]->data;
462                         ima->ibuf->rect_float= cbuf->rect;
463                         ima->ibuf->x= cbuf->x;
464                         ima->ibuf->y= cbuf->y;
465                         cbuf->rect= NULL;
466                 }
467
468         }
469         else if(in[0]->data)
470                 generate_preview(node, in[0]->data);
471 }
472
473 static bNodeType cmp_node_viewer= {
474         /* type code   */       CMP_NODE_VIEWER,
475         /* name        */       "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,
480         /* storage     */       "",
481         /* execfunc    */       node_composit_exec_viewer
482         
483 };
484
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},
489         {       -1, 0, ""       }
490 };
491
492 /* applies to render pipeline */
493 static void node_composit_exec_composite(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
494 {
495         /* image assigned to output */
496         /* stack order input sockets: col, alpha */
497         
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"));
502                         if(rr) {
503                                 CompBuf *outbuf;
504                                 
505                                 if(rr->rectf) 
506                                         MEM_freeN(rr->rectf);
507                                 outbuf= alloc_compbuf(rr->rectx, rr->recty, CB_RGBA, 1);
508                                 
509                                 if(in[1]->data==NULL)
510                                         composit1_pixel_processor(node, outbuf, in[0]->data, in[0]->vec, do_copy_rgba);
511                                 else
512                                         composit2_pixel_processor(node, outbuf, in[0]->data, in[0]->vec, in[1]->data, in[1]->vec, do_copy_a_rgba);
513                                 
514                                 generate_preview(node, outbuf);
515                                 
516                                 /* we give outbuf to rr... */
517                                 rr->rectf= outbuf->rect;
518                                 outbuf->malloc= 0;
519                                 free_compbuf(outbuf);
520                                 
521                                 return;
522                         }
523                 }
524         }
525         if(in[0]->data)
526                 generate_preview(node, in[0]->data);
527 }
528
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,
536         /* storage     */       "",
537         /* execfunc    */       node_composit_exec_composite
538         
539 };
540
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},
545         {       -1, 0, ""       }
546 };
547
548
549 static void node_composit_exec_output_file(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
550 {
551         /* image assigned to output */
552         /* stack order input sockets: col, alpha */
553         
554         if(node->id && (node->flag & NODE_DO_OUTPUT)) { /* only one works on out */
555         }
556         else if(in[0]->data)
557                 generate_preview(node, in[0]->data);
558 }
559
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,
567         /* storage     */       "",
568         /* execfunc    */       node_composit_exec_output_file
569         
570 };
571
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},
577         {       -1, 0, ""       }
578 };
579
580 static void node_composit_exec_image(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
581 {
582         /* image assigned to output */
583         /* stack order input sockets: col, alpha */
584         if(node->id) {
585                 Image *ima= (Image *)node->id;
586                 CompBuf *stackbuf;
587                 
588                 /* test if image is OK */
589                 if(ima->ok==0) return;
590                 if(ima->ibuf==NULL) {
591                         RenderData *rd= data;
592                         
593                         load_image(ima, IB_rect, G.sce, rd->cfra);      /* G.sce is current .blend path */
594                         if(ima->ibuf==NULL) {
595                                 ima->ok= 0;
596                                 return;
597                         }
598                 }
599                 if(ima->ibuf->rect_float==NULL)
600                         IMB_float_from_rect(ima->ibuf);
601                 
602                 /* we put imbuf copy on stack, cbuf knows rect is from other ibuf when freed! */
603                 stackbuf= alloc_compbuf(ima->ibuf->x, ima->ibuf->y, CB_RGBA, 0);
604                 stackbuf->rect= ima->ibuf->rect_float;
605                 
606                 /* put ibuf on stack */ 
607                 out[0]->data= stackbuf;
608                 
609                 if(out[1]->hasoutput)
610                         out[1]->data= alphabuf_from_rgbabuf(stackbuf);
611                 
612                 generate_preview(node, stackbuf);
613         }       
614 }
615
616 static bNodeType cmp_node_image= {
617         /* type code   */       CMP_NODE_IMAGE,
618         /* name        */       "Image",
619         /* width+range */       120, 80, 300,
620         /* class+opts  */       NODE_CLASS_GENERATOR, NODE_PREVIEW|NODE_OPTIONS,
621         /* input sock  */       NULL,
622         /* output sock */       cmp_node_image_out,
623         /* storage     */       "",
624         /* execfunc    */       node_composit_exec_image
625         
626 };
627
628 /* **************** RENDER RESULT ******************** */
629 static bNodeSocketType cmp_node_rresult_out[]= {
630         {       SOCK_RGBA, 0, "Image",          0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
631         {       SOCK_VALUE, 0, "Alpha",         1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
632         {       SOCK_VALUE, 0, "Z",                     1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
633         {       -1, 0, ""       }
634 };
635
636 static void node_composit_exec_rresult(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
637 {
638         RenderResult *rr= RE_GetResult(RE_GetRender("Render"));
639         if(rr) {
640                 RenderLayer *rl= rr->layers.first;
641                 CompBuf *stackbuf;
642                 
643                 /* we put render rect on stack, cbuf knows rect is from other ibuf when freed! */
644                 stackbuf= alloc_compbuf(rr->rectx, rr->recty, CB_RGBA, 0);
645                 stackbuf->rect= rl->rectf;
646                 
647                 /* put on stack */      
648                 out[0]->data= stackbuf;
649                 
650                 if(out[1]->hasoutput)
651                         out[1]->data= alphabuf_from_rgbabuf(stackbuf);
652                 
653                 generate_preview(node, stackbuf);
654         }       
655 }
656
657 static bNodeType cmp_node_rresult= {
658         /* type code   */       CMP_NODE_R_RESULT,
659         /* name        */       "Render Result",
660         /* width+range */       120, 80, 300,
661         /* class+opts  */       NODE_CLASS_GENERATOR, NODE_PREVIEW,
662         /* input sock  */       NULL,
663         /* output sock */       cmp_node_rresult_out,
664         /* storage     */       "",
665         /* execfunc    */       node_composit_exec_rresult
666         
667 };
668
669 /* **************** NORMAL  ******************** */
670 static bNodeSocketType cmp_node_normal_in[]= {
671         {       SOCK_VECTOR, 1, "Normal",       0.0f, 0.0f, 0.0f, 1.0f, -1.0f, 1.0f},
672         {       -1, 0, ""       }
673 };
674
675 static bNodeSocketType cmp_node_normal_out[]= {
676         {       SOCK_VECTOR, 0, "Normal",       0.0f, 0.0f, 1.0f, 1.0f, -1.0f, 1.0f},
677         {       SOCK_VALUE, 0, "Dot",           1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
678         {       -1, 0, ""       }
679 };
680
681 /* generates normal, does dot product */
682 static void node_composit_exec_normal(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
683 {
684         bNodeSocket *sock= node->outputs.first;
685         /* stack order input:  normal */
686         /* stack order output: normal, value */
687         
688         VECCOPY(out[0]->vec, sock->ns.vec);
689         /* render normals point inside... the widget points outside */
690         out[1]->vec[0]= -INPR(out[0]->vec, in[0]->vec);
691 }
692
693 static bNodeType cmp_node_normal= {
694         /* type code   */       CMP_NODE_NORMAL,
695         /* name        */       "Normal",
696         /* width+range */       100, 60, 200,
697         /* class+opts  */       NODE_CLASS_OPERATOR, NODE_OPTIONS,
698         /* input sock  */       cmp_node_normal_in,
699         /* output sock */       cmp_node_normal_out,
700         /* storage     */       "",
701         /* execfunc    */       node_composit_exec_normal
702         
703 };
704
705 /* **************** CURVE VEC  ******************** */
706 static bNodeSocketType cmp_node_curve_vec_in[]= {
707         {       SOCK_VECTOR, 1, "Vector",       0.0f, 0.0f, 0.0f, 1.0f, -1.0f, 1.0f},
708         {       -1, 0, ""       }
709 };
710
711 static bNodeSocketType cmp_node_curve_vec_out[]= {
712         {       SOCK_VECTOR, 0, "Vector",       0.0f, 0.0f, 1.0f, 1.0f, -1.0f, 1.0f},
713         {       -1, 0, ""       }
714 };
715
716 static void node_composit_exec_curve_vec(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
717 {
718         /* stack order input:  vec */
719         /* stack order output: vec */
720         
721         curvemapping_evaluate_premulRGBF(node->storage, out[0]->vec, in[0]->vec);
722 }
723
724 static bNodeType cmp_node_curve_vec= {
725         /* type code   */       CMP_NODE_CURVE_VEC,
726         /* name        */       "Vector Curves",
727         /* width+range */       200, 140, 320,
728         /* class+opts  */       NODE_CLASS_OPERATOR, NODE_OPTIONS,
729         /* input sock  */       cmp_node_curve_vec_in,
730         /* output sock */       cmp_node_curve_vec_out,
731         /* storage     */       "CurveMapping",
732         /* execfunc    */       node_composit_exec_curve_vec
733         
734 };
735
736 /* **************** CURVE RGB  ******************** */
737 static bNodeSocketType cmp_node_curve_rgb_in[]= {
738         {       SOCK_RGBA, 1, "Image",  0.0f, 0.0f, 0.0f, 1.0f, -1.0f, 1.0f},
739         {       -1, 0, ""       }
740 };
741
742 static bNodeSocketType cmp_node_curve_rgb_out[]= {
743         {       SOCK_RGBA, 0, "Image",  0.0f, 0.0f, 1.0f, 1.0f, -1.0f, 1.0f},
744         {       -1, 0, ""       }
745 };
746
747 static void do_curves(bNode *node, float *out, float *in)
748 {
749         curvemapping_evaluateRGBF(node->storage, out, in);
750         out[3]= in[3];
751 }
752
753 static void node_composit_exec_curve_rgb(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
754 {
755         /* stack order input:  vec */
756         /* stack order output: vec */
757         
758         if(out[0]->hasoutput==0)
759                 return;
760
761         /* input no image? then only color operation */
762         if(in[0]->data==NULL) {
763                 curvemapping_evaluateRGBF(node->storage, out[0]->vec, in[0]->vec);
764         }
765         else {
766                 /* make output size of input image */
767                 CompBuf *cbuf= in[0]->data;
768                 CompBuf *stackbuf= alloc_compbuf(cbuf->x, cbuf->y, CB_RGBA, 1); // allocs
769                 
770                 curvemapping_premultiply(node->storage, 0);
771                 composit1_pixel_processor(node, stackbuf, in[0]->data, NULL, do_curves);
772                 curvemapping_premultiply(node->storage, 1);
773                 
774                 out[0]->data= stackbuf;
775         }
776         
777 }
778
779 static bNodeType cmp_node_curve_rgb= {
780         /* type code   */       CMP_NODE_CURVE_RGB,
781         /* name        */       "RGB Curves",
782         /* width+range */       200, 140, 320,
783         /* class+opts  */       NODE_CLASS_OPERATOR, NODE_OPTIONS,
784         /* input sock  */       cmp_node_curve_rgb_in,
785         /* output sock */       cmp_node_curve_rgb_out,
786         /* storage     */       "CurveMapping",
787         /* execfunc    */       node_composit_exec_curve_rgb
788         
789 };
790
791 /* **************** VALUE ******************** */
792 static bNodeSocketType cmp_node_value_out[]= {
793         {       SOCK_VALUE, 0, "Value",         0.5f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
794         {       -1, 0, ""       }
795 };
796
797 static void node_composit_exec_value(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
798 {
799         bNodeSocket *sock= node->outputs.first;
800         
801         out[0]->vec[0]= sock->ns.vec[0];
802 }
803
804 static bNodeType cmp_node_value= {
805         /* type code   */       CMP_NODE_VALUE,
806         /* name        */       "Value",
807         /* width+range */       80, 40, 120,
808         /* class+opts  */       NODE_CLASS_GENERATOR, NODE_OPTIONS,
809         /* input sock  */       NULL,
810         /* output sock */       cmp_node_value_out,
811         /* storage     */       "", 
812         /* execfunc    */       node_composit_exec_value
813         
814 };
815
816 /* **************** RGB ******************** */
817 static bNodeSocketType cmp_node_rgb_out[]= {
818         {       SOCK_RGBA, 0, "RGBA",                   0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f},
819         {       -1, 0, ""       }
820 };
821
822 static void node_composit_exec_rgb(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
823 {
824         bNodeSocket *sock= node->outputs.first;
825         
826         VECCOPY(out[0]->vec, sock->ns.vec);
827 }
828
829 static bNodeType cmp_node_rgb= {
830         /* type code   */       CMP_NODE_RGB,
831         /* name        */       "RGB",
832         /* width+range */       100, 60, 140,
833         /* class+opts  */       NODE_CLASS_GENERATOR, NODE_OPTIONS,
834         /* input sock  */       NULL,
835         /* output sock */       cmp_node_rgb_out,
836         /* storage     */       "",
837         /* execfunc    */       node_composit_exec_rgb
838         
839 };
840
841 /* **************** MIX RGB ******************** */
842 static bNodeSocketType cmp_node_mix_rgb_in[]= {
843         {       SOCK_VALUE, 1, "Fac",                   0.5f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
844         {       SOCK_RGBA, 1, "Image",                  0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f},
845         {       SOCK_RGBA, 1, "Image",                  0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f},
846         {       -1, 0, ""       }
847 };
848 static bNodeSocketType cmp_node_mix_rgb_out[]= {
849         {       SOCK_RGBA, 0, "Image",                  0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
850         {       -1, 0, ""       }
851 };
852
853 static void do_mix_rgb(bNode *node, float *out, float *in1, float *in2, float fac)
854 {
855         float col[3];
856         
857         VECCOPY(col, in1);
858         ramp_blend(node->custom1, col, col+1, col+2, fac, in2);
859         VECCOPY(out, col);
860         out[3]= in1[3];
861 }
862
863 static void node_composit_exec_mix_rgb(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
864 {
865         /* stack order in: fac, Image, Image */
866         /* stack order out: Image */
867         float fac= in[0]->vec[0];
868         
869         CLAMP(fac, 0.0f, 1.0f);
870         
871         /* input no image? then only color operation */
872         if(in[1]->data==NULL && in[2]->data==NULL) {
873                 do_mix_rgb(node, out[0]->vec, in[1]->vec, in[2]->vec, fac);
874         }
875         else {
876                 /* make output size of first available input image */
877                 CompBuf *cbuf= in[1]->data?in[1]->data:in[2]->data;
878                 CompBuf *stackbuf= alloc_compbuf(cbuf->x, cbuf->y, CB_RGBA, 1); // allocs
879                 
880                 composit3_pixel_processor(node, stackbuf, in[1]->data, in[1]->vec, in[2]->data, in[2]->vec, in[0]->data, fac, do_mix_rgb);
881                 
882                 out[0]->data= stackbuf;
883         }
884 }
885
886 static bNodeType cmp_node_mix_rgb= {
887         /* type code   */       CMP_NODE_MIX_RGB,
888         /* name        */       "Mix",
889         /* width+range */       80, 40, 120,
890         /* class+opts  */       NODE_CLASS_OPERATOR, NODE_OPTIONS,
891         /* input sock  */       cmp_node_mix_rgb_in,
892         /* output sock */       cmp_node_mix_rgb_out,
893         /* storage     */       "", 
894         /* execfunc    */       node_composit_exec_mix_rgb
895         
896 };
897
898 /* **************** FILTER  ******************** */
899 static bNodeSocketType cmp_node_filter_in[]= {
900         {       SOCK_VALUE, 1, "Fac",                   1.0f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f},
901         {       SOCK_RGBA, 1, "Image",                  0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f},
902         {       -1, 0, ""       }
903 };
904 static bNodeSocketType cmp_node_filter_out[]= {
905         {       SOCK_RGBA, 0, "Image",                  0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
906         {       -1, 0, ""       }
907 };
908
909 static void do_filter_edge(CompBuf *out, CompBuf *in, float *filter, float fac)
910 {
911         float *row1, *row2, *row3;
912         float *fp, f1, f2, mfac= 1.0f-fac;
913         int rowlen, x, y, c;
914         
915         rowlen= in->x;
916         
917         if(in->type==CB_RGBA) {
918                 
919                 for(y=2; y<in->y; y++) {
920                         /* setup rows */
921                         row1= in->rect + 4*(y-2)*rowlen;
922                         row2= row1 + 4*rowlen;
923                         row3= row2 + 4*rowlen;
924                         fp= out->rect + 4*(y-1)*rowlen + 4;
925                         
926                         for(x=2; x<rowlen; x++) {
927                                 for(c=0; c<3; c++) {
928                                         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];
929                                         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];
930                                         fp[0]= mfac*row2[4] + fac*sqrt(f1*f1 + f2*f2);
931                                         fp++; row1++; row2++; row3++;
932                                 }
933                                 fp[0]= row2[4];
934                                 /* no alpha... will clear it completely */
935                                 fp++; row1++; row2++; row3++;
936                         }
937                 }
938         }       
939 }
940
941 static void do_filter3(CompBuf *out, CompBuf *in, float *filter, float fac)
942 {
943         float *row1, *row2, *row3;
944         float *fp, mfac= 1.0f-fac;
945         int rowlen, x, y, c;
946         
947         rowlen= in->x;
948         
949         if(in->type==CB_RGBA) {
950                 
951                 for(y=2; y<in->y; y++) {
952                         /* setup rows */
953                         row1= in->rect + 4*(y-2)*rowlen;
954                         row2= row1 + 4*rowlen;
955                         row3= row2 + 4*rowlen;
956                         
957                         fp= out->rect + 4*(y-1)*rowlen;
958                         QUATCOPY(fp, row2);
959                         fp+= 4;
960                         
961                         for(x=2; x<rowlen; x++) {
962                                 for(c=0; c<4; c++) {
963                                         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]);
964                                         fp++; row1++; row2++; row3++;
965                                 }
966                         }
967                 }
968         }       
969 }
970
971 static void node_composit_exec_filter(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
972 {
973         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};
974         float sharp[9]= {-1,-1,-1,-1,9,-1,-1,-1,-1};
975         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};
976         float sobel[9]= {1,2,1,0,0,0,-1,-2,-1};
977         float prewitt[9]= {1,1,1,0,0,0,-1,-1,-1};
978         float kirsch[9]= {5,5,5,-3,-3,-3,-2,-2,-2};
979         float shadow[9]= {1,2,1,0,1,0,-1,-2,-1};
980         
981         /* stack order in: Image */
982         /* stack order out: Image */
983         
984         if(in[1]->data) {
985                 /* make output size of first available input image */
986                 CompBuf *cbuf= in[1]->data;
987                 CompBuf *stackbuf= alloc_compbuf(cbuf->x, cbuf->y, CB_RGBA, 1); // allocs
988                 
989                 switch(node->custom1) {
990                         case CMP_FILT_SOFT:
991                                 do_filter3(stackbuf, cbuf, soft, in[0]->vec[0]);
992                                 break;
993                         case CMP_FILT_SHARP:
994                                 do_filter3(stackbuf, cbuf, sharp, in[0]->vec[0]);
995                                 break;
996                         case CMP_FILT_LAPLACE:
997                                 do_filter3(stackbuf, cbuf, laplace, in[0]->vec[0]);
998                                 break;
999                         case CMP_FILT_SOBEL:
1000                                 do_filter_edge(stackbuf, cbuf, sobel, in[0]->vec[0]);
1001                                 break;
1002                         case CMP_FILT_PREWITT:
1003                                 do_filter_edge(stackbuf, cbuf, prewitt, in[0]->vec[0]);
1004                                 break;
1005                         case CMP_FILT_KIRSCH:
1006                                 do_filter_edge(stackbuf, cbuf, kirsch, in[0]->vec[0]);
1007                                 break;
1008                         case CMP_FILT_SHADOW:
1009                                 do_filter3(stackbuf, cbuf, shadow, in[0]->vec[0]);
1010                                 break;
1011                 }
1012                         
1013                 out[0]->data= stackbuf;
1014         }
1015 }
1016
1017 static bNodeType cmp_node_filter= {
1018         /* type code   */       CMP_NODE_FILTER,
1019         /* name        */       "Filter",
1020         /* width+range */       80, 40, 120,
1021         /* class+opts  */       NODE_CLASS_OPERATOR, NODE_OPTIONS,
1022         /* input sock  */       cmp_node_filter_in,
1023         /* output sock */       cmp_node_filter_out,
1024         /* storage     */       "", 
1025         /* execfunc    */       node_composit_exec_filter
1026         
1027 };
1028
1029
1030 /* **************** VALTORGB ******************** */
1031 static bNodeSocketType cmp_node_valtorgb_in[]= {
1032         {       SOCK_VALUE, 1, "Fac",                   0.5f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
1033         {       -1, 0, ""       }
1034 };
1035 static bNodeSocketType cmp_node_valtorgb_out[]= {
1036         {       SOCK_RGBA, 0, "Image",                  0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
1037         {       SOCK_VALUE, 0, "Alpha",                 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
1038         {       -1, 0, ""       }
1039 };
1040
1041 static void do_colorband_composit(bNode *node, float *out, float *in)
1042 {
1043         do_colorband(node->storage, in[0], out);
1044 }
1045
1046 static void node_composit_exec_valtorgb(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
1047 {
1048         /* stack order in: fac */
1049         /* stack order out: col, alpha */
1050         
1051         if(node->storage) {
1052                 /* input no image? then only color operation */
1053                 if(in[0]->data==NULL) {
1054                         do_colorband(node->storage, in[0]->vec[0], out[0]->vec);
1055                 }
1056                 else {
1057                         /* make output size of input image */
1058                         CompBuf *cbuf= in[0]->data;
1059                         CompBuf *stackbuf= alloc_compbuf(cbuf->x, cbuf->y, CB_RGBA, 1); // allocs
1060                         
1061                         composit1_pixel_processor(node, stackbuf, in[0]->data, NULL, do_colorband_composit);
1062                         
1063                         out[0]->data= stackbuf;
1064                         
1065                         if(out[1]->hasoutput)
1066                                 out[1]->data= alphabuf_from_rgbabuf(stackbuf);
1067
1068                 }
1069         }
1070 }
1071
1072 static bNodeType cmp_node_valtorgb= {
1073         /* type code   */       CMP_NODE_VALTORGB,
1074         /* name        */       "ColorRamp",
1075         /* width+range */       240, 200, 300,
1076         /* class+opts  */       NODE_CLASS_OPERATOR, NODE_OPTIONS,
1077         /* input sock  */       cmp_node_valtorgb_in,
1078         /* output sock */       cmp_node_valtorgb_out,
1079         /* storage     */       "ColorBand",
1080         /* execfunc    */       node_composit_exec_valtorgb
1081         
1082 };
1083
1084
1085 /* **************** RGBTOBW ******************** */
1086 static bNodeSocketType cmp_node_rgbtobw_in[]= {
1087         {       SOCK_RGBA, 1, "Image",                  0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f},
1088         {       -1, 0, ""       }
1089 };
1090 static bNodeSocketType cmp_node_rgbtobw_out[]= {
1091         {       SOCK_VALUE, 0, "Val",                   0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
1092         {       -1, 0, ""       }
1093 };
1094
1095 static void do_rgbtobw(bNode *node, float *out, float *in)
1096 {
1097         out[0]= in[0]*0.35f + in[1]*0.45f + in[2]*0.2f;
1098 }
1099
1100 static void node_composit_exec_rgbtobw(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
1101 {
1102         /* stack order out: bw */
1103         /* stack order in: col */
1104         
1105         /* input no image? then only color operation */
1106         if(in[0]->data==NULL) {
1107                 out[0]->vec[0]= in[0]->vec[0]*0.35f + in[0]->vec[1]*0.45f + in[0]->vec[2]*0.2f;
1108         }
1109         else {
1110                 /* make output size of input image */
1111                 CompBuf *cbuf= in[0]->data;
1112                 CompBuf *stackbuf= alloc_compbuf(cbuf->x, cbuf->y, CB_VAL, 1); // allocs
1113                 
1114                 composit1_pixel_processor(node, stackbuf, in[0]->data, NULL, do_rgbtobw);
1115                 
1116                 out[0]->data= stackbuf;
1117         }
1118 }
1119
1120 static bNodeType cmp_node_rgbtobw= {
1121         /* type code   */       CMP_NODE_RGBTOBW,
1122         /* name        */       "RGB to BW",
1123         /* width+range */       80, 40, 120,
1124         /* class+opts  */       NODE_CLASS_OPERATOR, 0,
1125         /* input sock  */       cmp_node_rgbtobw_in,
1126         /* output sock */       cmp_node_rgbtobw_out,
1127         /* storage     */       "",
1128         /* execfunc    */       node_composit_exec_rgbtobw
1129         
1130 };
1131
1132 /* **************** ALPHAOVER ******************** */
1133 static bNodeSocketType cmp_node_alphaover_in[]= {
1134         {       SOCK_RGBA, 1, "Image",                  0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f},
1135         {       SOCK_RGBA, 1, "Image",                  0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f},
1136         {       -1, 0, ""       }
1137 };
1138 static bNodeSocketType cmp_node_alphaover_out[]= {
1139         {       SOCK_RGBA, 0, "Image",                  0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
1140         {       -1, 0, ""       }
1141 };
1142
1143 static void do_alphaover(bNode *node, float *out, float *src, float *dest)
1144 {
1145         float mul= 1.0f - dest[3];
1146         
1147         if(mul<=0.0f) {
1148                 QUATCOPY(out, dest);
1149         }
1150         else {
1151                 out[0]= (mul*src[0]) + dest[0];
1152                 out[1]= (mul*src[1]) + dest[1];
1153                 out[2]= (mul*src[2]) + dest[2];
1154                 out[3]= (mul*src[3]) + dest[3];
1155         }       
1156 }
1157
1158 static void node_composit_exec_alphaover(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
1159 {
1160         /* stack order in: col col */
1161         /* stack order out: col */
1162         
1163         /* input no image? then only color operation */
1164         if(in[0]->data==NULL) {
1165                 do_alphaover(node, out[0]->vec, in[0]->vec, in[1]->vec);
1166         }
1167         else {
1168                 /* make output size of input image */
1169                 CompBuf *cbuf= in[0]->data;
1170                 CompBuf *stackbuf= alloc_compbuf(cbuf->x, cbuf->y, CB_RGBA, 1); // allocs
1171                 
1172                 composit2_pixel_processor(node, stackbuf, in[0]->data, in[0]->vec, in[1]->data, in[1]->vec, do_alphaover);
1173                 
1174                 out[0]->data= stackbuf;
1175         }
1176 }
1177
1178 static bNodeType cmp_node_alphaover= {
1179         /* type code   */       CMP_NODE_ALPHAOVER,
1180         /* name        */       "AlphaOver",
1181         /* width+range */       80, 40, 120,
1182         /* class+opts  */       NODE_CLASS_OPERATOR, 0,
1183         /* input sock  */       cmp_node_alphaover_in,
1184         /* output sock */       cmp_node_alphaover_out,
1185         /* storage     */       "",
1186         /* execfunc    */       node_composit_exec_alphaover
1187         
1188 };
1189
1190 /* **************** GAUSS BLUR ******************** */
1191 static bNodeSocketType cmp_node_blur_in[]= {
1192         {       SOCK_RGBA, 1, "Image",                  0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f},
1193         {       -1, 0, ""       }
1194 };
1195 static bNodeSocketType cmp_node_blur_out[]= {
1196         {       SOCK_RGBA, 0, "Image",                  0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
1197         {       -1, 0, ""       }
1198 };
1199
1200
1201 static void node_composit_exec_blur(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
1202 {
1203         CompBuf *new, *work, *img= in[0]->data;
1204         register float sum, val;
1205         float rval, gval, bval, aval;
1206         float *gausstab, *v;
1207         int r, n, m;
1208         int x, y;
1209         int i;
1210         int step, bigstep;
1211         float *src, *dest;
1212
1213         
1214         if(img==NULL || out[0]->hasoutput==0)
1215                 return;
1216         
1217         /* make output size of input image */
1218         new= alloc_compbuf(img->x, img->y, CB_RGBA, 1); // allocs
1219         out[0]->data= new;
1220         
1221         /* prepare for gauss tab */
1222         r = (1.5 * node->custom1 + 1.5);
1223         n = 2 * r + 1;
1224         
1225         /* ugly : */
1226         if ((img->x <= n) || (img->y <= n)) {
1227                 printf("gauss filter too large/n");
1228                 return;
1229         }
1230         
1231         gausstab = (float *) MEM_mallocN(n * sizeof(float), "gauss");
1232         
1233         sum = 0.0f;
1234         v = gausstab;
1235         for (x = -r; x <= r; x++) {
1236                 val = exp(-4*(float ) (x*x)/ (float) (r*r));
1237                 sum += val;
1238                 *v++ = val;
1239         }
1240         
1241         i = n;
1242         v = gausstab;
1243         while (i--) {
1244                 *v++ /= sum;
1245         }
1246         
1247         /* helper image */
1248         work= alloc_compbuf(img->x, img->y, CB_RGBA, 1); // allocs
1249         
1250         /* horizontal */
1251         step = (n - 1);
1252         
1253         for (y = 0; y < img->y; y++) {
1254                 src = img->rect + 4*(y * img->x);
1255                 dest = work->rect + 4*(y * img->x);
1256                 
1257                 for (x = r; x > 0 ; x--) {
1258                         m = n - x;
1259                         gval = rval= bval= aval= 0.0f;
1260                         sum = 0.0;
1261                         v = gausstab + x;
1262                         for (i = 0; i < m; i++) {
1263                                 val = *v++;
1264                                 sum += val;
1265                                 rval += val * (*src++);
1266                                 gval += val * (*src++);
1267                                 bval += val * (*src++);
1268                                 aval += val * (*src++);
1269                         }
1270                         *dest++ = rval / sum;
1271                         *dest++ = gval / sum;
1272                         *dest++ = bval / sum;
1273                         *dest++ = aval / sum;
1274                         
1275                         src -= 4*m;
1276                 }
1277                 
1278                 for (x = 0; x <= (img->x - n); x++) {
1279                         gval = rval= bval= aval= 0.0f;
1280                         v = gausstab;
1281                         
1282                         for (i = 0; i < n; i++) {
1283                                 val = *v++;
1284                                 rval += val * (*src++);
1285                                 gval += val * (*src++);
1286                                 bval += val * (*src++);
1287                                 aval += val * (*src++);
1288                         }
1289                         *dest++ = rval;
1290                         *dest++ = gval;
1291                         *dest++ = bval;
1292                         *dest++ = aval;
1293                         src -= 4*step;
1294                 }       
1295                 
1296                 for (x = 1; x <= r ; x++) {
1297                         m = n - x;
1298                         gval = rval= bval= aval= 0.0f;
1299                         sum = 0.0;
1300                         v = gausstab;
1301                         for (i = 0; i < m; i++) {
1302                                 val = *v++;
1303                                 sum += val;
1304                                 rval += val * (*src++);
1305                                 gval += val * (*src++);
1306                                 bval += val * (*src++);
1307                                 aval += val * (*src++);
1308                         }
1309                         *dest++ = rval / sum;
1310                         *dest++ = gval / sum;
1311                         *dest++ = bval / sum;
1312                         *dest++ = aval / sum;
1313                         src -= 4*(m - 1);
1314                 }
1315         }
1316         
1317         /* vertical */
1318         MEM_freeN(gausstab);
1319         
1320         /* prepare for gauss tab */
1321         r = (1.5 * node->custom2 + 1.5);
1322         n = 2 * r + 1;
1323         
1324         /* ugly : */
1325         if ((img->x <= n) || (img->y <= n)) {
1326                 printf("gauss filter too large/n");
1327                 return;
1328         }
1329         
1330         gausstab = (float *) MEM_mallocN(n * sizeof(float), "gauss");
1331         
1332         sum = 0.0f;
1333         v = gausstab;
1334         for (x = -r; x <= r; x++) {
1335                 val = exp(-4*(float ) (x*x)/ (float) (r*r));
1336                 sum += val;
1337                 *v++ = val;
1338         }
1339         
1340         i = n;
1341         v = gausstab;
1342         while (i--) {
1343                 *v++ /= sum;
1344         }
1345         
1346         step = img->x;
1347         bigstep = (n - 1) * step;
1348         for (x = 0; x < step  ; x++) {
1349                 dest = new->rect + 4*x;
1350                 src = work->rect + 4*x;
1351                 
1352                 for (y = r; y > 0; y--) {
1353                         m = n - y;
1354                         gval = rval= bval= aval= 0.0f;
1355                         sum = 0.0;
1356                         v = gausstab + y;
1357                         for (i = 0; i < m; i++) {
1358                                 val = *v++;
1359                                 sum += val;
1360                                 rval += val * src[0];
1361                                 gval += val * src[1];
1362                                 bval += val * src[2];
1363                                 aval += val * src[3];
1364                                 src += 4 * step;
1365                         }
1366                         dest[0] = rval / sum;
1367                         dest[1] = gval / sum;
1368                         dest[2] = bval / sum;
1369                         dest[3] = aval / sum;
1370                         src -= 4 * m * step;
1371                         dest+= 4 * step;
1372                 }
1373                 for (y = 0; y <= (img->y - n); y++) {
1374                         gval = rval= bval= aval= 0.0f;
1375                         v = gausstab;
1376                         for (i = 0; i < n; i++) {
1377                                 val = *v++;
1378                                 rval += val * src[0];
1379                                 gval += val * src[1];
1380                                 bval += val * src[2];
1381                                 aval += val * src[3];
1382                                 src += 4 * step;
1383                         }
1384                         dest[0] = rval;
1385                         dest[1] = gval;
1386                         dest[2] = bval;
1387                         dest[3] = aval;
1388                         dest += 4 * step;
1389                         src -= 4 * bigstep;
1390                 }
1391                 for (y = 1; y <= r ; y++) {
1392                         m = n - y;
1393                         gval = rval= bval= aval= 0.0f;
1394                         sum = 0.0;
1395                         v = gausstab;
1396                         for (i = 0; i < m; i++) {
1397                                 val = *v++;
1398                                 sum += val;
1399                                 rval += val * src[0];
1400                                 gval += val * src[1];
1401                                 bval += val * src[2];
1402                                 aval += val * src[3];
1403                                 src += 4 * step;
1404                         }
1405                         dest[0] = rval / sum;
1406                         dest[1] = gval / sum;
1407                         dest[2] = bval / sum;
1408                         dest[3] = aval / sum;
1409                         dest += 4* step;
1410                         src -= 4 * (m - 1) * step;
1411                 }
1412         }
1413
1414         free_compbuf(work);
1415         MEM_freeN(gausstab);
1416 }
1417
1418 static bNodeType cmp_node_blur= {
1419         /* type code   */       CMP_NODE_BLUR,
1420         /* name        */       "Blur",
1421         /* width+range */       120, 80, 200,
1422         /* class+opts  */       NODE_CLASS_OPERATOR, NODE_OPTIONS,
1423         /* input sock  */       cmp_node_blur_in,
1424         /* output sock */       cmp_node_blur_out,
1425         /* storage     */       "",
1426         /* execfunc    */       node_composit_exec_blur
1427         
1428 };
1429
1430
1431 /* ****************** types array for all shaders ****************** */
1432
1433 bNodeType *node_all_composit[]= {
1434         &node_group_typeinfo,
1435         &cmp_node_viewer,
1436         &cmp_node_composite,
1437         &cmp_node_output_file,
1438         &cmp_node_value,
1439         &cmp_node_rgb,
1440         &cmp_node_mix_rgb,
1441         &cmp_node_filter,
1442         &cmp_node_valtorgb,
1443         &cmp_node_rgbtobw,
1444         &cmp_node_normal,
1445         &cmp_node_curve_vec,
1446         &cmp_node_curve_rgb,
1447         &cmp_node_image,
1448         &cmp_node_rresult,
1449         &cmp_node_alphaover,
1450         &cmp_node_blur,
1451         NULL
1452 };
1453
1454 /* ******************* execute and parse ************ */
1455
1456 /* helper call to detect if theres a render-result node */
1457 int ntreeCompositNeedsRender(bNodeTree *ntree)
1458 {
1459         bNode *node;
1460         
1461         if(ntree==NULL) return 1;
1462         
1463         for(node= ntree->nodes.first; node; node= node->next) {
1464                 if(node->type==CMP_NODE_R_RESULT)
1465                         return 1;
1466         }
1467         return 0;
1468 }
1469
1470 /* note; if called without preview, and previews exist, they get updated */
1471 /* render calls it without previews, works nicer for bg render */
1472 void ntreeCompositExecTree(bNodeTree *ntree, RenderData *rd, int do_preview)
1473 {
1474         if(ntree==NULL) return;
1475         
1476         if(do_preview)
1477                 ntreeInitPreview(ntree, 0, 0);
1478         
1479         ntreeBeginExecTree(ntree);
1480
1481         /* allocate composit data? */
1482         
1483         ntreeExecTree(ntree, rd, 0);    /* threads */
1484         
1485         ntreeEndExecTree(ntree);
1486 }
1487