Orange; fresh morning feature:
[blender.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 int calcimanr(int cfra, NodeImageAnim *nia)
581 {
582         
583         if(nia->frames==0) return nia->nr;
584         
585         cfra= cfra - nia->sfra;
586         
587         /* cyclic */
588         if(nia->cyclic)
589                 cfra= (cfra % nia->frames);
590         else if(cfra>=nia->frames)
591                 cfra= nia->frames-1;
592         else if(cfra<0)
593                 cfra= 0;
594         
595         cfra+= nia->nr;
596         
597         if(cfra<1) cfra= 1;
598         
599         return cfra;
600 }
601
602
603 static void animated_image(bNode *node, int cfra)
604 {
605         Image *ima;
606         NodeImageAnim *nia;
607         int imanr;
608         unsigned short numlen;
609         char name[FILE_MAXDIR+FILE_MAXFILE], head[FILE_MAXDIR+FILE_MAXFILE], tail[FILE_MAXDIR+FILE_MAXFILE];
610         
611         ima= (Image *)node->id;
612         nia= node->storage;
613         
614         if(nia && nia->frames && ima && ima->name) {    /* frames */
615                 strcpy(name, ima->name);
616                 
617                 imanr= calcimanr(cfra, nia);
618                 if(imanr!=ima->lastframe) {
619                         ima->lastframe= imanr;
620                         
621                         BLI_stringdec(name, head, tail, &numlen);
622                         BLI_stringenc(name, head, tail, numlen, imanr);
623                         
624                         ima= add_image(name);
625                         
626                         if(ima) {
627                                 ima->flag |= IMA_FROMANIM;
628                                 if(node->id) node->id->us--;
629                                 node->id= (ID *)ima;
630                                 
631                                 ima->ok= 1;
632                         }
633                 }
634         }
635 }
636
637
638 static void node_composit_exec_image(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
639 {
640         RenderData *rd= data;
641         
642         /* image assigned to output */
643         /* stack order input sockets: col, alpha */
644         if(node->id) {
645                 Image *ima;
646                 CompBuf *stackbuf;
647                 
648                 /* animated image? */
649                 if(node->storage)
650                         animated_image(node, rd->cfra);
651                 
652                 ima= (Image *)node->id;
653                 
654                 /* test if image is OK */
655                 if(ima->ok==0) return;
656                 
657                 if(ima->ibuf==NULL) {
658                         
659                         load_image(ima, IB_rect, G.sce, rd->cfra);      /* G.sce is current .blend path */
660                         if(ima->ibuf==NULL) {
661                                 ima->ok= 0;
662                                 return;
663                         }
664                 }
665                 if(ima->ibuf->rect_float==NULL)
666                         IMB_float_from_rect(ima->ibuf);
667                 
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;
671                 
672                 /* put ibuf on stack */ 
673                 out[0]->data= stackbuf;
674                 
675                 if(out[1]->hasoutput)
676                         out[1]->data= alphabuf_from_rgbabuf(stackbuf);
677                 
678                 generate_preview(node, stackbuf);
679         }       
680 }
681
682 /* uses node->storage to indicate animated image */
683
684 static bNodeType cmp_node_image= {
685         /* type code   */       CMP_NODE_IMAGE,
686         /* name        */       "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
693         
694 };
695
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},
701         {       -1, 0, ""       }
702 };
703
704 static void node_composit_exec_rresult(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
705 {
706         RenderResult *rr= RE_GetResult(RE_GetRender("Render"));
707         if(rr) {
708                 RenderLayer *rl= rr->layers.first;
709                 CompBuf *stackbuf;
710                 
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;
714                 
715                 /* put on stack */      
716                 out[0]->data= stackbuf;
717                 
718                 if(out[1]->hasoutput)
719                         out[1]->data= alphabuf_from_rgbabuf(stackbuf);
720                 
721                 generate_preview(node, stackbuf);
722         }       
723 }
724
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,
732         /* storage     */       "",
733         /* execfunc    */       node_composit_exec_rresult
734         
735 };
736
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},
740         {       -1, 0, ""       }
741 };
742
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},
746         {       -1, 0, ""       }
747 };
748
749 /* generates normal, does dot product */
750 static void node_composit_exec_normal(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
751 {
752         bNodeSocket *sock= node->outputs.first;
753         /* stack order input:  normal */
754         /* stack order output: normal, value */
755         
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);
759 }
760
761 static bNodeType cmp_node_normal= {
762         /* type code   */       CMP_NODE_NORMAL,
763         /* name        */       "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,
768         /* storage     */       "",
769         /* execfunc    */       node_composit_exec_normal
770         
771 };
772
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},
776         {       -1, 0, ""       }
777 };
778
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},
781         {       -1, 0, ""       }
782 };
783
784 static void node_composit_exec_curve_vec(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
785 {
786         /* stack order input:  vec */
787         /* stack order output: vec */
788         
789         curvemapping_evaluate_premulRGBF(node->storage, out[0]->vec, in[0]->vec);
790 }
791
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
801         
802 };
803
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},
807         {       -1, 0, ""       }
808 };
809
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},
812         {       -1, 0, ""       }
813 };
814
815 static void do_curves(bNode *node, float *out, float *in)
816 {
817         curvemapping_evaluateRGBF(node->storage, out, in);
818         out[3]= in[3];
819 }
820
821 static void node_composit_exec_curve_rgb(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
822 {
823         /* stack order input:  vec */
824         /* stack order output: vec */
825         
826         if(out[0]->hasoutput==0)
827                 return;
828
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);
832         }
833         else {
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
837                 
838                 curvemapping_premultiply(node->storage, 0);
839                 composit1_pixel_processor(node, stackbuf, in[0]->data, NULL, do_curves);
840                 curvemapping_premultiply(node->storage, 1);
841                 
842                 out[0]->data= stackbuf;
843         }
844         
845 }
846
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
856         
857 };
858
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},
862         {       -1, 0, ""       }
863 };
864
865 static void node_composit_exec_value(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
866 {
867         bNodeSocket *sock= node->outputs.first;
868         
869         out[0]->vec[0]= sock->ns.vec[0];
870 }
871
872 static bNodeType cmp_node_value= {
873         /* type code   */       CMP_NODE_VALUE,
874         /* name        */       "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,
879         /* storage     */       "", 
880         /* execfunc    */       node_composit_exec_value
881         
882 };
883
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},
887         {       -1, 0, ""       }
888 };
889
890 static void node_composit_exec_rgb(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
891 {
892         bNodeSocket *sock= node->outputs.first;
893         
894         VECCOPY(out[0]->vec, sock->ns.vec);
895 }
896
897 static bNodeType cmp_node_rgb= {
898         /* type code   */       CMP_NODE_RGB,
899         /* name        */       "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,
904         /* storage     */       "",
905         /* execfunc    */       node_composit_exec_rgb
906         
907 };
908
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},
914         {       -1, 0, ""       }
915 };
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},
918         {       -1, 0, ""       }
919 };
920
921 static void do_mix_rgb(bNode *node, float *out, float *in1, float *in2, float fac)
922 {
923         float col[3];
924         
925         VECCOPY(col, in1);
926         ramp_blend(node->custom1, col, col+1, col+2, fac, in2);
927         VECCOPY(out, col);
928         out[3]= in1[3];
929 }
930
931 static void node_composit_exec_mix_rgb(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
932 {
933         /* stack order in: fac, Image, Image */
934         /* stack order out: Image */
935         float fac= in[0]->vec[0];
936         
937         CLAMP(fac, 0.0f, 1.0f);
938         
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);
942         }
943         else {
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
947                 
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);
949                 
950                 out[0]->data= stackbuf;
951         }
952 }
953
954 static bNodeType cmp_node_mix_rgb= {
955         /* type code   */       CMP_NODE_MIX_RGB,
956         /* name        */       "Mix",
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,
961         /* storage     */       "", 
962         /* execfunc    */       node_composit_exec_mix_rgb
963         
964 };
965
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},
970         {       -1, 0, ""       }
971 };
972 static bNodeSocketType cmp_node_filter_out[]= {
973         {       SOCK_RGBA, 0, "Image",                  0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
974         {       -1, 0, ""       }
975 };
976
977 static void do_filter_edge(CompBuf *out, CompBuf *in, float *filter, float fac)
978 {
979         float *row1, *row2, *row3;
980         float *fp, f1, f2, mfac= 1.0f-fac;
981         int rowlen, x, y, c;
982         
983         rowlen= in->x;
984         
985         if(in->type==CB_RGBA) {
986                 
987                 for(y=2; y<in->y; y++) {
988                         /* setup rows */
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;
993                         
994                         for(x=2; x<rowlen; x++) {
995                                 for(c=0; c<3; c++) {
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++;
1000                                 }
1001                                 fp[0]= row2[4];
1002                                 /* no alpha... will clear it completely */
1003                                 fp++; row1++; row2++; row3++;
1004                         }
1005                 }
1006         }       
1007 }
1008
1009 static void do_filter3(CompBuf *out, CompBuf *in, float *filter, float fac)
1010 {
1011         float *row1, *row2, *row3;
1012         float *fp, mfac= 1.0f-fac;
1013         int rowlen, x, y, c;
1014         
1015         rowlen= in->x;
1016         
1017         if(in->type==CB_RGBA) {
1018                 
1019                 for(y=2; y<in->y; y++) {
1020                         /* setup rows */
1021                         row1= in->rect + 4*(y-2)*rowlen;
1022                         row2= row1 + 4*rowlen;
1023                         row3= row2 + 4*rowlen;
1024                         
1025                         fp= out->rect + 4*(y-1)*rowlen;
1026                         QUATCOPY(fp, row2);
1027                         fp+= 4;
1028                         
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++;
1033                                 }
1034                         }
1035                 }
1036         }       
1037 }
1038
1039 static void node_composit_exec_filter(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
1040 {
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};
1048         
1049         /* stack order in: Image */
1050         /* stack order out: Image */
1051         
1052         if(in[1]->data) {
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
1056                 
1057                 switch(node->custom1) {
1058                         case CMP_FILT_SOFT:
1059                                 do_filter3(stackbuf, cbuf, soft, in[0]->vec[0]);
1060                                 break;
1061                         case CMP_FILT_SHARP:
1062                                 do_filter3(stackbuf, cbuf, sharp, in[0]->vec[0]);
1063                                 break;
1064                         case CMP_FILT_LAPLACE:
1065                                 do_filter3(stackbuf, cbuf, laplace, in[0]->vec[0]);
1066                                 break;
1067                         case CMP_FILT_SOBEL:
1068                                 do_filter_edge(stackbuf, cbuf, sobel, in[0]->vec[0]);
1069                                 break;
1070                         case CMP_FILT_PREWITT:
1071                                 do_filter_edge(stackbuf, cbuf, prewitt, in[0]->vec[0]);
1072                                 break;
1073                         case CMP_FILT_KIRSCH:
1074                                 do_filter_edge(stackbuf, cbuf, kirsch, in[0]->vec[0]);
1075                                 break;
1076                         case CMP_FILT_SHADOW:
1077                                 do_filter3(stackbuf, cbuf, shadow, in[0]->vec[0]);
1078                                 break;
1079                 }
1080                         
1081                 out[0]->data= stackbuf;
1082         }
1083 }
1084
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,
1092         /* storage     */       "", 
1093         /* execfunc    */       node_composit_exec_filter
1094         
1095 };
1096
1097
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},
1101         {       -1, 0, ""       }
1102 };
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},
1106         {       -1, 0, ""       }
1107 };
1108
1109 static void do_colorband_composit(bNode *node, float *out, float *in)
1110 {
1111         do_colorband(node->storage, in[0], out);
1112 }
1113
1114 static void node_composit_exec_valtorgb(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
1115 {
1116         /* stack order in: fac */
1117         /* stack order out: col, alpha */
1118         
1119         if(node->storage) {
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);
1123                 }
1124                 else {
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
1128                         
1129                         composit1_pixel_processor(node, stackbuf, in[0]->data, NULL, do_colorband_composit);
1130                         
1131                         out[0]->data= stackbuf;
1132                         
1133                         if(out[1]->hasoutput)
1134                                 out[1]->data= alphabuf_from_rgbabuf(stackbuf);
1135
1136                 }
1137         }
1138 }
1139
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
1149         
1150 };
1151
1152
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},
1156         {       -1, 0, ""       }
1157 };
1158 static bNodeSocketType cmp_node_rgbtobw_out[]= {
1159         {       SOCK_VALUE, 0, "Val",                   0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
1160         {       -1, 0, ""       }
1161 };
1162
1163 static void do_rgbtobw(bNode *node, float *out, float *in)
1164 {
1165         out[0]= in[0]*0.35f + in[1]*0.45f + in[2]*0.2f;
1166 }
1167
1168 static void node_composit_exec_rgbtobw(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
1169 {
1170         /* stack order out: bw */
1171         /* stack order in: col */
1172         
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;
1176         }
1177         else {
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
1181                 
1182                 composit1_pixel_processor(node, stackbuf, in[0]->data, NULL, do_rgbtobw);
1183                 
1184                 out[0]->data= stackbuf;
1185         }
1186 }
1187
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,
1195         /* storage     */       "",
1196         /* execfunc    */       node_composit_exec_rgbtobw
1197         
1198 };
1199
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},
1204         {       -1, 0, ""       }
1205 };
1206 static bNodeSocketType cmp_node_alphaover_out[]= {
1207         {       SOCK_RGBA, 0, "Image",                  0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
1208         {       -1, 0, ""       }
1209 };
1210
1211 static void do_alphaover(bNode *node, float *out, float *src, float *dest)
1212 {
1213         float mul= 1.0f - dest[3];
1214         
1215         if(mul<=0.0f) {
1216                 QUATCOPY(out, dest);
1217         }
1218         else {
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];
1223         }       
1224 }
1225
1226 static void node_composit_exec_alphaover(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
1227 {
1228         /* stack order in: col col */
1229         /* stack order out: col */
1230         
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);
1234         }
1235         else {
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
1239                 
1240                 composit2_pixel_processor(node, stackbuf, in[0]->data, in[0]->vec, in[1]->data, in[1]->vec, do_alphaover);
1241                 
1242                 out[0]->data= stackbuf;
1243         }
1244 }
1245
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,
1253         /* storage     */       "",
1254         /* execfunc    */       node_composit_exec_alphaover
1255         
1256 };
1257
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},
1261         {       -1, 0, ""       }
1262 };
1263 static bNodeSocketType cmp_node_blur_out[]= {
1264         {       SOCK_RGBA, 0, "Image",                  0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
1265         {       -1, 0, ""       }
1266 };
1267
1268
1269 static void node_composit_exec_blur(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
1270 {
1271         CompBuf *new, *work, *img= in[0]->data;
1272         register float sum, val;
1273         float rval, gval, bval, aval;
1274         float *gausstab, *v;
1275         int r, n, m;
1276         int x, y;
1277         int i;
1278         int step, bigstep;
1279         float *src, *dest;
1280
1281         
1282         if(img==NULL || out[0]->hasoutput==0)
1283                 return;
1284         
1285         /* make output size of input image */
1286         new= alloc_compbuf(img->x, img->y, CB_RGBA, 1); // allocs
1287         out[0]->data= new;
1288         
1289         /* prepare for gauss tab */
1290         r = (1.5 * node->custom1 + 1.5);
1291         n = 2 * r + 1;
1292         
1293         /* ugly : */
1294         if ((img->x <= n) || (img->y <= n)) {
1295                 printf("gauss filter too large/n");
1296                 return;
1297         }
1298         
1299         gausstab = (float *) MEM_mallocN(n * sizeof(float), "gauss");
1300         
1301         sum = 0.0f;
1302         v = gausstab;
1303         for (x = -r; x <= r; x++) {
1304                 val = exp(-4*(float ) (x*x)/ (float) (r*r));
1305                 sum += val;
1306                 *v++ = val;
1307         }
1308         
1309         i = n;
1310         v = gausstab;
1311         while (i--) {
1312                 *v++ /= sum;
1313         }
1314         
1315         /* helper image */
1316         work= alloc_compbuf(img->x, img->y, CB_RGBA, 1); // allocs
1317         
1318         /* horizontal */
1319         step = (n - 1);
1320         
1321         for (y = 0; y < img->y; y++) {
1322                 src = img->rect + 4*(y * img->x);
1323                 dest = work->rect + 4*(y * img->x);
1324                 
1325                 for (x = r; x > 0 ; x--) {
1326                         m = n - x;
1327                         gval = rval= bval= aval= 0.0f;
1328                         sum = 0.0;
1329                         v = gausstab + x;
1330                         for (i = 0; i < m; i++) {
1331                                 val = *v++;
1332                                 sum += val;
1333                                 rval += val * (*src++);
1334                                 gval += val * (*src++);
1335                                 bval += val * (*src++);
1336                                 aval += val * (*src++);
1337                         }
1338                         *dest++ = rval / sum;
1339                         *dest++ = gval / sum;
1340                         *dest++ = bval / sum;
1341                         *dest++ = aval / sum;
1342                         
1343                         src -= 4*m;
1344                 }
1345                 
1346                 for (x = 0; x <= (img->x - n); x++) {
1347                         gval = rval= bval= aval= 0.0f;
1348                         v = gausstab;
1349                         
1350                         for (i = 0; i < n; i++) {
1351                                 val = *v++;
1352                                 rval += val * (*src++);
1353                                 gval += val * (*src++);
1354                                 bval += val * (*src++);
1355                                 aval += val * (*src++);
1356                         }
1357                         *dest++ = rval;
1358                         *dest++ = gval;
1359                         *dest++ = bval;
1360                         *dest++ = aval;
1361                         src -= 4*step;
1362                 }       
1363                 
1364                 for (x = 1; x <= r ; x++) {
1365                         m = n - x;
1366                         gval = rval= bval= aval= 0.0f;
1367                         sum = 0.0;
1368                         v = gausstab;
1369                         for (i = 0; i < m; i++) {
1370                                 val = *v++;
1371                                 sum += val;
1372                                 rval += val * (*src++);
1373                                 gval += val * (*src++);
1374                                 bval += val * (*src++);
1375                                 aval += val * (*src++);
1376                         }
1377                         *dest++ = rval / sum;
1378                         *dest++ = gval / sum;
1379                         *dest++ = bval / sum;
1380                         *dest++ = aval / sum;
1381                         src -= 4*(m - 1);
1382                 }
1383         }
1384         
1385         /* vertical */
1386         MEM_freeN(gausstab);
1387         
1388         /* prepare for gauss tab */
1389         r = (1.5 * node->custom2 + 1.5);
1390         n = 2 * r + 1;
1391         
1392         /* ugly : */
1393         if ((img->x <= n) || (img->y <= n)) {
1394                 printf("gauss filter too large/n");
1395                 return;
1396         }
1397         
1398         gausstab = (float *) MEM_mallocN(n * sizeof(float), "gauss");
1399         
1400         sum = 0.0f;
1401         v = gausstab;
1402         for (x = -r; x <= r; x++) {
1403                 val = exp(-4*(float ) (x*x)/ (float) (r*r));
1404                 sum += val;
1405                 *v++ = val;
1406         }
1407         
1408         i = n;
1409         v = gausstab;
1410         while (i--) {
1411                 *v++ /= sum;
1412         }
1413         
1414         step = img->x;
1415         bigstep = (n - 1) * step;
1416         for (x = 0; x < step  ; x++) {
1417                 dest = new->rect + 4*x;
1418                 src = work->rect + 4*x;
1419                 
1420                 for (y = r; y > 0; y--) {
1421                         m = n - y;
1422                         gval = rval= bval= aval= 0.0f;
1423                         sum = 0.0;
1424                         v = gausstab + y;
1425                         for (i = 0; i < m; i++) {
1426                                 val = *v++;
1427                                 sum += val;
1428                                 rval += val * src[0];
1429                                 gval += val * src[1];
1430                                 bval += val * src[2];
1431                                 aval += val * src[3];
1432                                 src += 4 * step;
1433                         }
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;
1439                         dest+= 4 * step;
1440                 }
1441                 for (y = 0; y <= (img->y - n); y++) {
1442                         gval = rval= bval= aval= 0.0f;
1443                         v = gausstab;
1444                         for (i = 0; i < n; i++) {
1445                                 val = *v++;
1446                                 rval += val * src[0];
1447                                 gval += val * src[1];
1448                                 bval += val * src[2];
1449                                 aval += val * src[3];
1450                                 src += 4 * step;
1451                         }
1452                         dest[0] = rval;
1453                         dest[1] = gval;
1454                         dest[2] = bval;
1455                         dest[3] = aval;
1456                         dest += 4 * step;
1457                         src -= 4 * bigstep;
1458                 }
1459                 for (y = 1; y <= r ; y++) {
1460                         m = n - y;
1461                         gval = rval= bval= aval= 0.0f;
1462                         sum = 0.0;
1463                         v = gausstab;
1464                         for (i = 0; i < m; i++) {
1465                                 val = *v++;
1466                                 sum += val;
1467                                 rval += val * src[0];
1468                                 gval += val * src[1];
1469                                 bval += val * src[2];
1470                                 aval += val * src[3];
1471                                 src += 4 * step;
1472                         }
1473                         dest[0] = rval / sum;
1474                         dest[1] = gval / sum;
1475                         dest[2] = bval / sum;
1476                         dest[3] = aval / sum;
1477                         dest += 4* step;
1478                         src -= 4 * (m - 1) * step;
1479                 }
1480         }
1481
1482         free_compbuf(work);
1483         MEM_freeN(gausstab);
1484 }
1485
1486 static bNodeType cmp_node_blur= {
1487         /* type code   */       CMP_NODE_BLUR,
1488         /* name        */       "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,
1493         /* storage     */       "",
1494         /* execfunc    */       node_composit_exec_blur
1495         
1496 };
1497
1498
1499 /* ****************** types array for all shaders ****************** */
1500
1501 bNodeType *node_all_composit[]= {
1502         &node_group_typeinfo,
1503         &cmp_node_viewer,
1504         &cmp_node_composite,
1505         &cmp_node_output_file,
1506         &cmp_node_value,
1507         &cmp_node_rgb,
1508         &cmp_node_mix_rgb,
1509         &cmp_node_filter,
1510         &cmp_node_valtorgb,
1511         &cmp_node_rgbtobw,
1512         &cmp_node_normal,
1513         &cmp_node_curve_vec,
1514         &cmp_node_curve_rgb,
1515         &cmp_node_image,
1516         &cmp_node_rresult,
1517         &cmp_node_alphaover,
1518         &cmp_node_blur,
1519         NULL
1520 };
1521
1522 /* ******************* execute and parse ************ */
1523
1524 /* helper call to detect if theres a render-result node */
1525 int ntreeCompositNeedsRender(bNodeTree *ntree)
1526 {
1527         bNode *node;
1528         
1529         if(ntree==NULL) return 1;
1530         
1531         for(node= ntree->nodes.first; node; node= node->next) {
1532                 if(node->type==CMP_NODE_R_RESULT)
1533                         return 1;
1534         }
1535         return 0;
1536 }
1537
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)
1541 {
1542         if(ntree==NULL) return;
1543         
1544         if(do_preview)
1545                 ntreeInitPreview(ntree, 0, 0);
1546         
1547         ntreeBeginExecTree(ntree);
1548
1549         /* allocate composit data? */
1550         
1551         ntreeExecTree(ntree, rd, 0);    /* threads */
1552         
1553         ntreeEndExecTree(ntree);
1554         
1555         free_unused_animimages();
1556 }
1557