The code from the orange branch has now been copied into HEAD.
[blender-staging.git] / source / blender / blenkernel / intern / node_composite.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, "compbuf RGBA rect");
85                 else
86                         cbuf->rect= MEM_mallocN(sizeof(float)*sizex*sizey, "compbuf Fac 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 void print_compbuf(char *str, CompBuf *cbuf)
105 {
106         printf("Compbuf %s %d %d %p\n", str, cbuf->x, cbuf->y, cbuf->rect);
107         
108 }
109
110
111
112 #if 0
113 /* on first call, disprect should be initialized to 'out', then you can call this on all 'src' images */
114 static void get_overlap_rct(CompBuf *out, CompBuf *src, rcti *disprect)
115 {
116         rcti rect;
117         /* output center is considered (0,0) */
118         
119         if(src==NULL) return;
120         
121         /* translate src into output space */
122         rect= src->disprect;
123         BLI_translate_rcti(&rect, out->xof-src->xof, out->xof-src->xof);
124         /* intersect rect with current disprect */
125         
126         BLI_isect_rcti(&rect, disprect, disprect);
127 }
128
129 static void get_scanline_rcti(CompBuf *out, rcti *disprect, CompBuf *src, rcti *srcrect)
130 {
131         int xof, yof;
132         
133         /* translate src into output space */
134         xof= out->xof-src->xof;
135         yof= out->xof-src->xof;
136         
137         srcrect->xmin= disprect->xmin + xof;
138         srcrect->ymin= disprect->ymin + yof;
139         srcrect->xmax= disprect->xmax + xof;
140         srcrect->ymax= disprect->ymax + yof;
141 }
142 #endif
143
144 /* Pixel-to-Pixel operation, 1 Image in, 1 out */
145 static void composit1_pixel_processor(bNode *node, CompBuf *out, CompBuf *src_buf, float *src_col,
146                                                                           void (*func)(bNode *, float *, float *))
147 {
148         float *outfp, *srcfp, *out_data, *src_data;
149         int outx, outy;
150         int srcx, srcy;
151         int out_pix, out_stride, src_stride, src_pix, x, y;
152         
153         outx= out->x;
154         outy= out->y;
155         out_pix= out->type;
156         out_stride= out->x;
157         out_data= out->rect;
158         
159         /* handle case when input is constant color */
160         if(src_buf==NULL) {
161                 srcx= outx; srcy= outy;
162                 src_stride= 0;
163                 src_pix= 0;
164                 src_data= src_col;
165         }
166         else {
167                 srcx= src_buf->x;
168                 srcy= src_buf->y;
169                 src_stride= srcx;
170                 src_pix= src_buf->type;
171                 src_data= src_buf->rect;
172         }
173         
174         outx= MIN2(outx, srcx);
175         outy= MIN2(outy, srcy);
176
177         for(y=0; y<outy; y++) {
178                 /* set scanlines on right location */
179                 srcfp= src_data + src_pix*y*src_stride;
180                 outfp= out_data + out_pix*y*out_stride;
181                         
182                 for(x=0; x<outx; x++) {
183                         func(node, outfp, srcfp);
184                         srcfp += src_pix;
185                         outfp += out_pix;
186                 }
187         }
188 }
189
190 /* Pixel-to-Pixel operation, 2 Images in, 1 out */
191 static void composit2_pixel_processor(bNode *node, CompBuf *out, CompBuf *src_buf, float *src_col,
192                                                                           CompBuf *fac_buf, float *fac, void (*func)(bNode *, float *, float *, float *))
193 {
194         float *outfp, *srcfp, *src_data, *facfp, *fac_data;
195         int outx= out->x, outy= out->y;
196         int srcx, srcy, facx, facy;
197         int out_pix, src_stride, src_pix, fac_stride, fac_pix, x, y;
198         
199         out_pix= out->type;
200         
201         /* handle case when input is constant color */
202         if(src_buf==NULL) {
203                 srcx= outx; srcy= outy;
204                 src_stride= 0;
205                 src_pix= 0;
206                 src_data= src_col;
207         }
208         else {
209                 srcx= src_buf->x;
210                 srcy= src_buf->y;
211                 src_stride= srcx;
212                 src_pix= src_buf->type;
213                 src_data= src_buf->rect;
214         }
215         
216         /* factor buf or constant? */
217         if(fac_buf==NULL) {
218                 facx= outx; facy= outy;
219                 fac_stride= 0;
220                 fac_pix= 0;
221                 fac_data= fac;
222         }
223         else {
224                 facx= fac_buf->x;
225                 facy= fac_buf->y;
226                 fac_stride= facx;
227                 fac_pix= fac_buf->type;
228                 fac_data= fac_buf->rect;
229         }
230         
231         if(fac_data==NULL) {
232                 printf("fac buffer error, node %s\n", node->name);
233                 return;
234         }
235         
236         facx= MIN2(facx, srcx);
237         facy= MIN2(facy, srcy);
238         
239 #if 0   
240         if(src_buf) {
241                 rcti disprect;
242                 
243                 disprect= out->disprect;
244                 get_overlap_rct(out, src_buf, &disprect);
245                 printf("%s\n", node->name);
246                 printf("union %d %d %d %d\n", disprect.xmin,disprect.ymin,disprect.xmax,disprect.ymax);
247         }
248         /* new approach */
249         outfp= out->rect_float + src.ymin*outx + ;
250         for(y=src.ymin; y<src.ymax; y++) {
251                 
252                 /* all operators available */
253                 if(y>=disp.ymin && y<disp.ymax) {
254                         srcfp= src_data + (src_stride*(y+scrc.ymin) + src.xmin);
255                         facfp= fac_data + (fac_stride*(y+fac.ymin) + fac.xmin);
256                         
257                         for(x= src.xmin; x<src.xmax; x++) {
258                                 if(x>=disp.xmin && x<disp.xmax) {
259                                         
260                                         srcfp+= src_pix;
261                                         facfp+= fac_pix;
262                                 }
263                                 else {
264                                         /* copy src1 */
265                                 }
266                         }
267                 }
268                 else {
269                         /* copy src1 */
270                         srcfp= src_data + (src_stride*(y+scrc.ymin) + src.xmin);
271                         
272                         QUATCOPY(outfp, srcfp);
273                 }
274         }       
275 #endif
276         
277         outfp= out->rect;
278         for(y=0; y<outy; y++) {
279                 /* set source scanline on right location */
280                 srcfp= src_data + src_pix*y*src_stride;
281                 facfp= fac_data + fac_pix*y*fac_stride;
282                 
283                 for(x=0; x<outx; x++, outfp+=out_pix) {
284                         if(x<facx && y<facy)
285                                 func(node, outfp, srcfp, facfp);
286                         srcfp += src_pix;
287                         facfp += fac_pix;
288                 }
289         }
290 }
291
292 /* Pixel-to-Pixel operation, 3 Images in, 1 out */
293 static void composit3_pixel_processor(bNode *node, CompBuf *out, CompBuf *src1_buf, float *src1_col, CompBuf *src2_buf, float *src2_col, 
294                                                                           CompBuf *fac_buf, float fac, void (*func)(bNode *, float *, float *, float *, float))
295 {
296         float *outfp, *src1fp, *src2fp, *facfp, *src1_data, *src2_data, *fac_data;
297         int outx= out->x, outy= out->y;
298         int src1x, src1y, src2x, src2y, facx, facy;
299         int src1_stride, src1_pix, src2_stride, src2_pix, fac_stride, fac_pix, x, y;
300
301         /* handle case when input has constant color */
302         if(src1_buf==NULL) {
303                 src1x= outx; src1y= outy;
304                 src1_stride= 0;
305                 src1_pix= 0;
306                 src1_data= src1_col;
307         }
308         else {
309                 src1x= src1_buf->x;
310                 src1y= src1_buf->y;
311                 src1_stride= src1x;
312                 src1_pix= src1_buf->type;
313                 src1_data= src1_buf->rect;
314         }
315         
316         if(src2_buf==NULL) {
317                 src2x= outx; src2y= outy;
318                 src2_stride= 0;
319                 src2_pix= 0;
320                 src2_data= src2_col;
321         }
322         else {
323                 src2x= src2_buf->x;
324                 src2y= src2_buf->y;
325                 src2_stride= src2x;
326                 src2_pix= src2_buf->type;
327                 src2_data= src2_buf->rect;
328         }
329         
330         /* factor buf or constant? */
331         if(fac_buf==NULL) {
332                 facx= outx; facy= outy;
333                 fac_stride= 0;
334                 fac_pix= 0;
335                 fac_data= &fac;
336         }
337         else {
338                 facx= fac_buf->x;
339                 facy= fac_buf->y;
340                 fac_stride= facx;
341                 fac_pix= 1;
342                 fac_data= fac_buf->rect;
343         }
344         
345         facx= MIN3(facx, src1x, src2x);
346         facy= MIN3(facy, src1y, src2y);
347         
348         outfp= out->rect;
349         for(y=0; y<outy; y++) {
350                 
351                 /* set source scanlines on right location */
352                 src1fp= src1_data + src1_pix*y*src1_stride;
353                 src2fp= src2_data + src2_pix*y*src2_stride;
354                 facfp= fac_data + y*fac_stride;
355                 
356                 for(x=0; x<outx; x++, outfp+=4) {
357                         if(x<facx && y<facy)
358                                 func(node, outfp, src1fp, src2fp, *facfp);
359                         src1fp+= src1_pix;
360                         src2fp+= src2_pix;
361                         facfp+= fac_pix;
362                 }
363         }
364 }
365
366 /*  */
367 static CompBuf *alphabuf_from_rgbabuf(CompBuf *cbuf)
368 {
369         CompBuf *valbuf= alloc_compbuf(cbuf->x, cbuf->y, CB_VAL, 1);
370         float *valf, *rectf;
371         int tot;
372         
373         valf= valbuf->rect;
374         rectf= cbuf->rect + 3;
375         for(tot= cbuf->x*cbuf->y; tot>0; tot--, valf++, rectf+=4)
376                 *valf= *rectf;
377         
378         return valbuf;
379 }
380
381 static void generate_preview(bNode *node, CompBuf *stackbuf)
382 {
383         bNodePreview *preview= node->preview;
384         
385         if(preview) {
386                 ImBuf *ibuf= IMB_allocImBuf(stackbuf->x, stackbuf->y, 32, 0, 0);        /* empty */
387                 
388                 if(stackbuf->x > stackbuf->y) {
389                         preview->xsize= 140;
390                         preview->ysize= (140*stackbuf->y)/stackbuf->x;
391                 }
392                 else {
393                         preview->ysize= 140;
394                         preview->xsize= (140*stackbuf->x)/stackbuf->y;
395                 }
396                 ibuf->rect_float= stackbuf->rect;
397                 ibuf= IMB_scalefastImBuf(ibuf, preview->xsize, preview->ysize);
398                 
399                 /* this ensures free-imbuf does the right stuff */
400                 SWAP(float *, ibuf->rect_float, node->preview->rect);
401                 
402                 IMB_freeImBuf(ibuf);
403         }
404 }
405
406 /* ******************************************************** */
407 /* ********* Composit Node type definitions ***************** */
408 /* ******************************************************** */
409
410 /* SocketType syntax: 
411    socket type, max connections (0 is no limit), name, 4 values for default, 2 values for range */
412
413 /* Verification rule: If name changes, a saved socket and its links will be removed! Type changes are OK */
414
415 /* **************** VIEWER ******************** */
416 static bNodeSocketType cmp_node_viewer_in[]= {
417         {       SOCK_RGBA, 1, "Image",          0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
418         {       SOCK_VALUE, 1, "Alpha",         1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
419         {       SOCK_VALUE, 1, "Z",             1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
420         {       -1, 0, ""       }
421 };
422
423 static void do_copy_rgba(bNode *node, float *out, float *in)
424 {
425         QUATCOPY(out, in);
426 }
427 static void do_copy_value(bNode *node, float *out, float *in)
428 {
429         out[0]= in[0];
430 }
431 static void do_copy_a_rgba(bNode *node, float *out, float *in, float *fac)
432 {
433         VECCOPY(out, in);
434         out[3]= *fac;
435 }
436
437 static void node_composit_exec_viewer(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
438 {
439         /* image assigned to output */
440         /* stack order input sockets: col, alpha, z */
441         
442         if(node->id && (node->flag & NODE_DO_OUTPUT)) { /* only one works on out */
443                 Image *ima= (Image *)node->id;
444                 CompBuf *cbuf;
445                 int rectx, recty;
446                 
447                 /* scene size? */
448                 if(1) {
449                         RenderData *rd= data;
450
451                         /* re-create output, derive size from scene */
452                         rectx= (rd->size*rd->xsch)/100;
453                         recty= (rd->size*rd->ysch)/100;
454                         
455                         if(ima->ibuf) IMB_freeImBuf(ima->ibuf);
456                         ima->ibuf= IMB_allocImBuf(rectx, recty, 32, IB_rectfloat, 0); // do alloc
457                         
458                         cbuf= alloc_compbuf(rectx, recty, CB_RGBA, 0);  // no alloc
459                         cbuf->rect= ima->ibuf->rect_float;
460
461                         /* when no alpha, we can simply copy */
462                         if(in[1]->data==NULL)
463                                 composit1_pixel_processor(node, cbuf, in[0]->data, in[0]->vec, do_copy_rgba);
464                         else
465                                 composit2_pixel_processor(node, cbuf, in[0]->data, in[0]->vec, in[1]->data, in[1]->vec, do_copy_a_rgba);
466                         
467                         if(in[2]->data) {
468                                 CompBuf *zbuf= alloc_compbuf(rectx, recty, CB_VAL, 0);
469                                 addzbuffloatImBuf(ima->ibuf);
470                                 zbuf->rect= ima->ibuf->zbuf_float;
471                                 composit1_pixel_processor(node, zbuf, in[2]->data, in[2]->vec, do_copy_value);
472                                 free_compbuf(zbuf);
473                         }
474
475                         generate_preview(node, cbuf);
476                         free_compbuf(cbuf);
477                 }
478                 else { /* test */
479                         if(ima->ibuf) IMB_freeImBuf(ima->ibuf);
480                         ima->ibuf= IMB_allocImBuf(rectx, recty, 32, 0, 0); // do alloc
481                         ima->ibuf->mall= IB_rectfloat;
482                         cbuf= in[0]->data;
483                         ima->ibuf->rect_float= cbuf->rect;
484                         ima->ibuf->x= cbuf->x;
485                         ima->ibuf->y= cbuf->y;
486                         cbuf->rect= NULL;
487                 }
488
489         }       /* lets make only previews when not done yet, so activating doesnt update */
490         else if(in[0]->data && node->preview && node->preview->rect==NULL)
491                 generate_preview(node, in[0]->data);
492 }
493
494 static bNodeType cmp_node_viewer= {
495         /* type code   */       CMP_NODE_VIEWER,
496         /* name        */       "Viewer",
497         /* width+range */       80, 60, 200,
498         /* class+opts  */       NODE_CLASS_OUTPUT, NODE_PREVIEW,
499         /* input sock  */       cmp_node_viewer_in,
500         /* output sock */       NULL,
501         /* storage     */       "",
502         /* execfunc    */       node_composit_exec_viewer
503         
504 };
505
506 /* **************** COMPOSITE ******************** */
507 static bNodeSocketType cmp_node_composite_in[]= {
508         {       SOCK_RGBA, 1, "Image",          0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
509         {       SOCK_VALUE, 1, "Alpha",         1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
510         {       SOCK_VALUE, 1, "Z",                     1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
511         {       -1, 0, ""       }
512 };
513
514 /* applies to render pipeline */
515 static void node_composit_exec_composite(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
516 {
517         /* image assigned to output */
518         /* stack order input sockets: col, alpha, z */
519         
520         if(node->flag & NODE_DO_OUTPUT) {       /* only one works on out */
521                 RenderData *rd= data;
522                 if(rd->scemode & R_DOCOMP) {
523                         RenderResult *rr= RE_GetResult(RE_GetRender("Render"));
524                         if(rr) {
525                                 CompBuf *outbuf, *zbuf=NULL;
526                                 
527                                 if(rr->rectf) 
528                                         MEM_freeN(rr->rectf);
529                                 outbuf= alloc_compbuf(rr->rectx, rr->recty, CB_RGBA, 1);
530                                 
531                                 if(in[1]->data==NULL)
532                                         composit1_pixel_processor(node, outbuf, in[0]->data, in[0]->vec, do_copy_rgba);
533                                 else
534                                         composit2_pixel_processor(node, outbuf, in[0]->data, in[0]->vec, in[1]->data, in[1]->vec, do_copy_a_rgba);
535                                 
536                                 if(in[2]->data) {
537                                         if(rr->rectz) 
538                                                 MEM_freeN(rr->rectz);
539                                         zbuf= alloc_compbuf(rr->rectx, rr->recty, CB_VAL, 1);
540                                         composit1_pixel_processor(node, zbuf, in[2]->data, in[2]->vec, do_copy_value);
541                                         rr->rectz= zbuf->rect;
542                                         zbuf->malloc= 0;
543                                         free_compbuf(zbuf);
544                                 }
545                                 generate_preview(node, outbuf);
546                                 
547                                 /* we give outbuf to rr... */
548                                 rr->rectf= outbuf->rect;
549                                 outbuf->malloc= 0;
550                                 free_compbuf(outbuf);
551                                 
552                                 return;
553                         }
554                 }
555         }
556         if(in[0]->data)
557                 generate_preview(node, in[0]->data);
558 }
559
560 static bNodeType cmp_node_composite= {
561         /* type code   */       CMP_NODE_COMPOSITE,
562         /* name        */       "Composite",
563         /* width+range */       80, 60, 200,
564         /* class+opts  */       NODE_CLASS_OUTPUT, NODE_PREVIEW,
565         /* input sock  */       cmp_node_composite_in,
566         /* output sock */       NULL,
567         /* storage     */       "",
568         /* execfunc    */       node_composit_exec_composite
569         
570 };
571
572 /* **************** OUTPUT FILE ******************** */
573 static bNodeSocketType cmp_node_output_file_in[]= {
574         {       SOCK_RGBA, 1, "Image",          0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
575         {       SOCK_VALUE, 1, "Alpha",         1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
576         {       -1, 0, ""       }
577 };
578
579
580 static void node_composit_exec_output_file(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
581 {
582         /* image assigned to output */
583         /* stack order input sockets: col, alpha */
584         
585         if(node->id && (node->flag & NODE_DO_OUTPUT)) { /* only one works on out */
586         }
587         else if(in[0]->data)
588                 generate_preview(node, in[0]->data);
589 }
590
591 static bNodeType cmp_node_output_file= {
592         /* type code   */       CMP_NODE_OUTPUT_FILE,
593         /* name        */       "File Output",
594         /* width+range */       80, 60, 200,
595         /* class+opts  */       NODE_CLASS_FILE, NODE_PREVIEW,
596         /* input sock  */       cmp_node_output_file_in,
597         /* output sock */       NULL,
598         /* storage     */       "",
599         /* execfunc    */       node_composit_exec_output_file
600         
601 };
602
603 /* **************** IMAGE ******************** */
604 static bNodeSocketType cmp_node_image_out[]= {
605         {       SOCK_RGBA, 0, "Image",          0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
606         {       SOCK_VALUE, 0, "Alpha",         1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
607         {       SOCK_VALUE, 0, "Z",                     1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
608         {       -1, 0, ""       }
609 };
610
611 static int calcimanr(int cfra, NodeImageAnim *nia)
612 {
613         
614         if(nia->frames==0) return nia->nr;
615         
616         cfra= cfra - nia->sfra;
617         
618         /* cyclic */
619         if(nia->cyclic)
620                 cfra= (cfra % nia->frames);
621         else if(cfra>=nia->frames)
622                 cfra= nia->frames-1;
623         else if(cfra<0)
624                 cfra= 0;
625         
626         cfra+= nia->nr;
627         
628         if(cfra<1) cfra= 1;
629         
630         return cfra;
631 }
632
633
634 static void animated_image(bNode *node, int cfra)
635 {
636         Image *ima;
637         NodeImageAnim *nia;
638         int imanr;
639         unsigned short numlen;
640         char name[FILE_MAXDIR+FILE_MAXFILE], head[FILE_MAXDIR+FILE_MAXFILE], tail[FILE_MAXDIR+FILE_MAXFILE];
641         
642         ima= (Image *)node->id;
643         nia= node->storage;
644         
645         if(nia && nia->frames && ima && ima->name) {    /* frames */
646                 strcpy(name, ima->name);
647                 
648                 imanr= calcimanr(cfra, nia);
649                 if(imanr!=ima->lastframe) {
650                         ima->lastframe= imanr;
651                         
652                         BLI_stringdec(name, head, tail, &numlen);
653                         BLI_stringenc(name, head, tail, numlen, imanr);
654                         
655                         ima= add_image(name);
656                         
657                         if(ima) {
658                                 ima->flag |= IMA_FROMANIM;
659                                 if(node->id) node->id->us--;
660                                 node->id= (ID *)ima;
661                                 
662                                 ima->ok= 1;
663                         }
664                 }
665         }
666 }
667
668
669 static void node_composit_exec_image(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
670 {
671         RenderData *rd= data;
672         
673         /* image assigned to output */
674         /* stack order input sockets: col, alpha */
675         if(node->id) {
676                 Image *ima;
677                 CompBuf *stackbuf;
678                 
679                 /* animated image? */
680                 if(node->storage)
681                         animated_image(node, rd->cfra);
682                 
683                 ima= (Image *)node->id;
684                 
685                 /* test if image is OK */
686                 if(ima->ok==0) return;
687                 
688                 if(ima->ibuf==NULL) {
689                         
690                         load_image(ima, IB_rect, G.sce, rd->cfra);      /* G.sce is current .blend path */
691                         if(ima->ibuf==NULL) {
692                                 ima->ok= 0;
693                                 return;
694                         }
695                 }
696                 if(ima->ibuf->rect_float==NULL)
697                         IMB_float_from_rect(ima->ibuf);
698                 
699                 /* we put imbuf copy on stack, cbuf knows rect is from other ibuf when freed! */
700                 stackbuf= alloc_compbuf(ima->ibuf->x, ima->ibuf->y, CB_RGBA, 0);
701                 stackbuf->rect= ima->ibuf->rect_float;
702                 
703                 /* put ibuf on stack */ 
704                 out[0]->data= stackbuf;
705                 
706                 if(out[1]->hasoutput)
707                         out[1]->data= alphabuf_from_rgbabuf(stackbuf);
708                 
709                 if(out[2]->hasoutput && ima->ibuf->zbuf_float) {
710                         CompBuf *zbuf= alloc_compbuf(ima->ibuf->x, ima->ibuf->y, CB_VAL, 0);
711                         zbuf->rect= ima->ibuf->zbuf_float;
712                         out[2]->data= zbuf;
713                 }
714                 
715                 generate_preview(node, stackbuf);
716         }       
717 }
718
719 /* uses node->storage to indicate animated image */
720
721 static bNodeType cmp_node_image= {
722         /* type code   */       CMP_NODE_IMAGE,
723         /* name        */       "Image",
724         /* width+range */       120, 80, 300,
725         /* class+opts  */       NODE_CLASS_GENERATOR, NODE_PREVIEW|NODE_OPTIONS,
726         /* input sock  */       NULL,
727         /* output sock */       cmp_node_image_out,
728         /* storage     */       "NodeImageAnim",
729         /* execfunc    */       node_composit_exec_image
730         
731 };
732
733 /* **************** RENDER RESULT ******************** */
734 static bNodeSocketType cmp_node_rresult_out[]= {
735         {       SOCK_RGBA, 0, "Image",          0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
736         {       SOCK_VALUE, 0, "Alpha",         1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
737         {       SOCK_VALUE, 0, "Z",                     1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
738         {       -1, 0, ""       }
739 };
740
741 static void node_composit_exec_rresult(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
742 {
743         RenderResult *rr= RE_GetResult(RE_GetRender("Render"));
744         
745         if(rr) {
746                 RenderLayer *rl= BLI_findlink(&rr->layers, node->custom1);
747                 if(rl) {
748                         CompBuf *stackbuf;
749                         
750                         /* we put render rect on stack, cbuf knows rect is from other ibuf when freed! */
751                         stackbuf= alloc_compbuf(rr->rectx, rr->recty, CB_RGBA, 0);
752                         stackbuf->rect= rl->rectf;
753                         
754                         /* put on stack */      
755                         out[0]->data= stackbuf;
756                         
757                         if(out[1]->hasoutput)
758                                 out[1]->data= alphabuf_from_rgbabuf(stackbuf);
759                         if(out[2]->hasoutput && rl->rectz) {
760                                 CompBuf *zbuf= alloc_compbuf(rr->rectx, rr->recty, CB_VAL, 0);
761                                 zbuf->rect= rl->rectz;
762                                 out[2]->data= zbuf;
763                         }
764                         
765                         generate_preview(node, stackbuf);
766                 }
767         }       
768 }
769
770 /* custom1 = render layer in use */
771 static bNodeType cmp_node_rresult= {
772         /* type code   */       CMP_NODE_R_RESULT,
773         /* name        */       "Render Result",
774         /* width+range */       120, 80, 300,
775         /* class+opts  */       NODE_CLASS_GENERATOR, NODE_PREVIEW|NODE_OPTIONS,
776         /* input sock  */       NULL,
777         /* output sock */       cmp_node_rresult_out,
778         /* storage     */       "",
779         /* execfunc    */       node_composit_exec_rresult
780         
781 };
782
783 /* **************** NORMAL  ******************** */
784 static bNodeSocketType cmp_node_normal_in[]= {
785         {       SOCK_VECTOR, 1, "Normal",       0.0f, 0.0f, 0.0f, 1.0f, -1.0f, 1.0f},
786         {       -1, 0, ""       }
787 };
788
789 static bNodeSocketType cmp_node_normal_out[]= {
790         {       SOCK_VECTOR, 0, "Normal",       0.0f, 0.0f, 1.0f, 1.0f, -1.0f, 1.0f},
791         {       SOCK_VALUE, 0, "Dot",           1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
792         {       -1, 0, ""       }
793 };
794
795 /* generates normal, does dot product */
796 static void node_composit_exec_normal(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
797 {
798         bNodeSocket *sock= node->outputs.first;
799         /* stack order input:  normal */
800         /* stack order output: normal, value */
801         
802         VECCOPY(out[0]->vec, sock->ns.vec);
803         /* render normals point inside... the widget points outside */
804         out[1]->vec[0]= -INPR(out[0]->vec, in[0]->vec);
805 }
806
807 static bNodeType cmp_node_normal= {
808         /* type code   */       CMP_NODE_NORMAL,
809         /* name        */       "Normal",
810         /* width+range */       100, 60, 200,
811         /* class+opts  */       NODE_CLASS_OPERATOR, NODE_OPTIONS,
812         /* input sock  */       cmp_node_normal_in,
813         /* output sock */       cmp_node_normal_out,
814         /* storage     */       "",
815         /* execfunc    */       node_composit_exec_normal
816         
817 };
818
819 /* **************** CURVE VEC  ******************** */
820 static bNodeSocketType cmp_node_curve_vec_in[]= {
821         {       SOCK_VECTOR, 1, "Vector",       0.0f, 0.0f, 0.0f, 1.0f, -1.0f, 1.0f},
822         {       -1, 0, ""       }
823 };
824
825 static bNodeSocketType cmp_node_curve_vec_out[]= {
826         {       SOCK_VECTOR, 0, "Vector",       0.0f, 0.0f, 1.0f, 1.0f, -1.0f, 1.0f},
827         {       -1, 0, ""       }
828 };
829
830 static void node_composit_exec_curve_vec(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
831 {
832         /* stack order input:  vec */
833         /* stack order output: vec */
834         
835         curvemapping_evaluate_premulRGBF(node->storage, out[0]->vec, in[0]->vec);
836 }
837
838 static bNodeType cmp_node_curve_vec= {
839         /* type code   */       CMP_NODE_CURVE_VEC,
840         /* name        */       "Vector Curves",
841         /* width+range */       200, 140, 320,
842         /* class+opts  */       NODE_CLASS_OPERATOR, NODE_OPTIONS,
843         /* input sock  */       cmp_node_curve_vec_in,
844         /* output sock */       cmp_node_curve_vec_out,
845         /* storage     */       "CurveMapping",
846         /* execfunc    */       node_composit_exec_curve_vec
847         
848 };
849
850 /* **************** CURVE RGB  ******************** */
851 static bNodeSocketType cmp_node_curve_rgb_in[]= {
852         {       SOCK_RGBA, 1, "Image",  0.0f, 0.0f, 0.0f, 1.0f, -1.0f, 1.0f},
853         {       -1, 0, ""       }
854 };
855
856 static bNodeSocketType cmp_node_curve_rgb_out[]= {
857         {       SOCK_RGBA, 0, "Image",  0.0f, 0.0f, 1.0f, 1.0f, -1.0f, 1.0f},
858         {       -1, 0, ""       }
859 };
860
861 static void do_curves(bNode *node, float *out, float *in)
862 {
863         curvemapping_evaluateRGBF(node->storage, out, in);
864         out[3]= in[3];
865 }
866
867 static void node_composit_exec_curve_rgb(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
868 {
869         /* stack order input:  vec */
870         /* stack order output: vec */
871         
872         if(out[0]->hasoutput==0)
873                 return;
874
875         /* input no image? then only color operation */
876         if(in[0]->data==NULL) {
877                 curvemapping_evaluateRGBF(node->storage, out[0]->vec, in[0]->vec);
878         }
879         else {
880                 /* make output size of input image */
881                 CompBuf *cbuf= in[0]->data;
882                 CompBuf *stackbuf= alloc_compbuf(cbuf->x, cbuf->y, CB_RGBA, 1); // allocs
883                 
884                 curvemapping_premultiply(node->storage, 0);
885                 composit1_pixel_processor(node, stackbuf, in[0]->data, NULL, do_curves);
886                 curvemapping_premultiply(node->storage, 1);
887                 
888                 out[0]->data= stackbuf;
889         }
890         
891 }
892
893 static bNodeType cmp_node_curve_rgb= {
894         /* type code   */       CMP_NODE_CURVE_RGB,
895         /* name        */       "RGB Curves",
896         /* width+range */       200, 140, 320,
897         /* class+opts  */       NODE_CLASS_OPERATOR, NODE_OPTIONS,
898         /* input sock  */       cmp_node_curve_rgb_in,
899         /* output sock */       cmp_node_curve_rgb_out,
900         /* storage     */       "CurveMapping",
901         /* execfunc    */       node_composit_exec_curve_rgb
902         
903 };
904
905 /* **************** VALUE ******************** */
906 static bNodeSocketType cmp_node_value_out[]= {
907         {       SOCK_VALUE, 0, "Value",         0.5f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
908         {       -1, 0, ""       }
909 };
910
911 static void node_composit_exec_value(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
912 {
913         bNodeSocket *sock= node->outputs.first;
914         
915         out[0]->vec[0]= sock->ns.vec[0];
916 }
917
918 static bNodeType cmp_node_value= {
919         /* type code   */       CMP_NODE_VALUE,
920         /* name        */       "Value",
921         /* width+range */       80, 40, 120,
922         /* class+opts  */       NODE_CLASS_GENERATOR, NODE_OPTIONS,
923         /* input sock  */       NULL,
924         /* output sock */       cmp_node_value_out,
925         /* storage     */       "", 
926         /* execfunc    */       node_composit_exec_value
927         
928 };
929
930 /* **************** RGB ******************** */
931 static bNodeSocketType cmp_node_rgb_out[]= {
932         {       SOCK_RGBA, 0, "RGBA",                   0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f},
933         {       -1, 0, ""       }
934 };
935
936 static void node_composit_exec_rgb(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
937 {
938         bNodeSocket *sock= node->outputs.first;
939         
940         VECCOPY(out[0]->vec, sock->ns.vec);
941 }
942
943 static bNodeType cmp_node_rgb= {
944         /* type code   */       CMP_NODE_RGB,
945         /* name        */       "RGB",
946         /* width+range */       100, 60, 140,
947         /* class+opts  */       NODE_CLASS_GENERATOR, NODE_OPTIONS,
948         /* input sock  */       NULL,
949         /* output sock */       cmp_node_rgb_out,
950         /* storage     */       "",
951         /* execfunc    */       node_composit_exec_rgb
952         
953 };
954
955 /* **************** MIX RGB ******************** */
956 static bNodeSocketType cmp_node_mix_rgb_in[]= {
957         {       SOCK_VALUE, 1, "Fac",                   0.5f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
958         {       SOCK_RGBA, 1, "Image",                  0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f},
959         {       SOCK_RGBA, 1, "Image",                  0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f},
960         {       -1, 0, ""       }
961 };
962 static bNodeSocketType cmp_node_mix_rgb_out[]= {
963         {       SOCK_RGBA, 0, "Image",                  0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
964         {       -1, 0, ""       }
965 };
966
967 static void do_mix_rgb(bNode *node, float *out, float *in1, float *in2, float fac)
968 {
969         float col[3];
970         
971         VECCOPY(col, in1);
972         ramp_blend(node->custom1, col, col+1, col+2, fac, in2);
973         VECCOPY(out, col);
974         out[3]= in1[3];
975 }
976
977 static void node_composit_exec_mix_rgb(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
978 {
979         /* stack order in: fac, Image, Image */
980         /* stack order out: Image */
981         float fac= in[0]->vec[0];
982         
983         CLAMP(fac, 0.0f, 1.0f);
984         
985         /* input no image? then only color operation */
986         if(in[1]->data==NULL && in[2]->data==NULL) {
987                 do_mix_rgb(node, out[0]->vec, in[1]->vec, in[2]->vec, fac);
988         }
989         else {
990                 /* make output size of first available input image */
991                 CompBuf *cbuf= in[1]->data?in[1]->data:in[2]->data;
992                 CompBuf *stackbuf= alloc_compbuf(cbuf->x, cbuf->y, CB_RGBA, 1); // allocs
993                 
994                 composit3_pixel_processor(node, stackbuf, in[1]->data, in[1]->vec, in[2]->data, in[2]->vec, in[0]->data, fac, do_mix_rgb);
995                 
996                 out[0]->data= stackbuf;
997         }
998 }
999
1000 /* custom1 = mix type */
1001 static bNodeType cmp_node_mix_rgb= {
1002         /* type code   */       CMP_NODE_MIX_RGB,
1003         /* name        */       "Mix",
1004         /* width+range */       80, 40, 120,
1005         /* class+opts  */       NODE_CLASS_OPERATOR, NODE_OPTIONS,
1006         /* input sock  */       cmp_node_mix_rgb_in,
1007         /* output sock */       cmp_node_mix_rgb_out,
1008         /* storage     */       "", 
1009         /* execfunc    */       node_composit_exec_mix_rgb
1010         
1011 };
1012
1013 /* **************** FILTER  ******************** */
1014 static bNodeSocketType cmp_node_filter_in[]= {
1015         {       SOCK_VALUE, 1, "Fac",                   1.0f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f},
1016         {       SOCK_RGBA, 1, "Image",                  0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f},
1017         {       -1, 0, ""       }
1018 };
1019 static bNodeSocketType cmp_node_filter_out[]= {
1020         {       SOCK_RGBA, 0, "Image",                  0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
1021         {       -1, 0, ""       }
1022 };
1023
1024 static void do_filter_edge(CompBuf *out, CompBuf *in, float *filter, float fac)
1025 {
1026         float *row1, *row2, *row3;
1027         float *fp, f1, f2, mfac= 1.0f-fac;
1028         int rowlen, x, y, c;
1029         
1030         rowlen= in->x;
1031         
1032         if(in->type==CB_RGBA) {
1033                 
1034                 for(y=2; y<in->y; y++) {
1035                         /* setup rows */
1036                         row1= in->rect + 4*(y-2)*rowlen;
1037                         row2= row1 + 4*rowlen;
1038                         row3= row2 + 4*rowlen;
1039                         fp= out->rect + 4*(y-1)*rowlen + 4;
1040                         
1041                         for(x=2; x<rowlen; x++) {
1042                                 for(c=0; c<3; c++) {
1043                                         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];
1044                                         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];
1045                                         fp[0]= mfac*row2[4] + fac*sqrt(f1*f1 + f2*f2);
1046                                         fp++; row1++; row2++; row3++;
1047                                 }
1048                                 fp[0]= row2[4];
1049                                 /* no alpha... will clear it completely */
1050                                 fp++; row1++; row2++; row3++;
1051                         }
1052                 }
1053         }       
1054 }
1055
1056 static void do_filter3(CompBuf *out, CompBuf *in, float *filter, float fac)
1057 {
1058         float *row1, *row2, *row3;
1059         float *fp, mfac= 1.0f-fac;
1060         int rowlen, x, y, c;
1061         
1062         rowlen= in->x;
1063         
1064         if(in->type==CB_RGBA) {
1065                 
1066                 for(y=2; y<in->y; y++) {
1067                         /* setup rows */
1068                         row1= in->rect + 4*(y-2)*rowlen;
1069                         row2= row1 + 4*rowlen;
1070                         row3= row2 + 4*rowlen;
1071                         
1072                         fp= out->rect + 4*(y-1)*rowlen;
1073                         QUATCOPY(fp, row2);
1074                         fp+= 4;
1075                         
1076                         for(x=2; x<rowlen; x++) {
1077                                 for(c=0; c<4; c++) {
1078                                         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]);
1079                                         fp++; row1++; row2++; row3++;
1080                                 }
1081                         }
1082                 }
1083         }       
1084 }
1085
1086 static void node_composit_exec_filter(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
1087 {
1088         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};
1089         float sharp[9]= {-1,-1,-1,-1,9,-1,-1,-1,-1};
1090         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};
1091         float sobel[9]= {1,2,1,0,0,0,-1,-2,-1};
1092         float prewitt[9]= {1,1,1,0,0,0,-1,-1,-1};
1093         float kirsch[9]= {5,5,5,-3,-3,-3,-2,-2,-2};
1094         float shadow[9]= {1,2,1,0,1,0,-1,-2,-1};
1095         
1096         /* stack order in: Image */
1097         /* stack order out: Image */
1098         
1099         if(in[1]->data) {
1100                 /* make output size of first available input image */
1101                 CompBuf *cbuf= in[1]->data;
1102                 CompBuf *stackbuf= alloc_compbuf(cbuf->x, cbuf->y, CB_RGBA, 1); // allocs
1103                 
1104                 switch(node->custom1) {
1105                         case CMP_FILT_SOFT:
1106                                 do_filter3(stackbuf, cbuf, soft, in[0]->vec[0]);
1107                                 break;
1108                         case CMP_FILT_SHARP:
1109                                 do_filter3(stackbuf, cbuf, sharp, in[0]->vec[0]);
1110                                 break;
1111                         case CMP_FILT_LAPLACE:
1112                                 do_filter3(stackbuf, cbuf, laplace, in[0]->vec[0]);
1113                                 break;
1114                         case CMP_FILT_SOBEL:
1115                                 do_filter_edge(stackbuf, cbuf, sobel, in[0]->vec[0]);
1116                                 break;
1117                         case CMP_FILT_PREWITT:
1118                                 do_filter_edge(stackbuf, cbuf, prewitt, in[0]->vec[0]);
1119                                 break;
1120                         case CMP_FILT_KIRSCH:
1121                                 do_filter_edge(stackbuf, cbuf, kirsch, in[0]->vec[0]);
1122                                 break;
1123                         case CMP_FILT_SHADOW:
1124                                 do_filter3(stackbuf, cbuf, shadow, in[0]->vec[0]);
1125                                 break;
1126                 }
1127                         
1128                 out[0]->data= stackbuf;
1129         }
1130 }
1131
1132 /* custom1 = filter type */
1133 static bNodeType cmp_node_filter= {
1134         /* type code   */       CMP_NODE_FILTER,
1135         /* name        */       "Filter",
1136         /* width+range */       80, 40, 120,
1137         /* class+opts  */       NODE_CLASS_OPERATOR, NODE_OPTIONS,
1138         /* input sock  */       cmp_node_filter_in,
1139         /* output sock */       cmp_node_filter_out,
1140         /* storage     */       "", 
1141         /* execfunc    */       node_composit_exec_filter
1142         
1143 };
1144
1145
1146 /* **************** VALTORGB ******************** */
1147 static bNodeSocketType cmp_node_valtorgb_in[]= {
1148         {       SOCK_VALUE, 1, "Fac",                   0.5f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
1149         {       -1, 0, ""       }
1150 };
1151 static bNodeSocketType cmp_node_valtorgb_out[]= {
1152         {       SOCK_RGBA, 0, "Image",                  0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
1153         {       SOCK_VALUE, 0, "Alpha",                 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
1154         {       -1, 0, ""       }
1155 };
1156
1157 static void do_colorband_composit(bNode *node, float *out, float *in)
1158 {
1159         do_colorband(node->storage, in[0], out);
1160 }
1161
1162 static void node_composit_exec_valtorgb(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
1163 {
1164         /* stack order in: fac */
1165         /* stack order out: col, alpha */
1166         
1167         if(node->storage) {
1168                 /* input no image? then only color operation */
1169                 if(in[0]->data==NULL) {
1170                         do_colorband(node->storage, in[0]->vec[0], out[0]->vec);
1171                 }
1172                 else {
1173                         /* make output size of input image */
1174                         CompBuf *cbuf= in[0]->data;
1175                         CompBuf *stackbuf= alloc_compbuf(cbuf->x, cbuf->y, CB_RGBA, 1); // allocs
1176                         
1177                         composit1_pixel_processor(node, stackbuf, in[0]->data, NULL, do_colorband_composit);
1178                         
1179                         out[0]->data= stackbuf;
1180                         
1181                         if(out[1]->hasoutput)
1182                                 out[1]->data= alphabuf_from_rgbabuf(stackbuf);
1183
1184                 }
1185         }
1186 }
1187
1188 static bNodeType cmp_node_valtorgb= {
1189         /* type code   */       CMP_NODE_VALTORGB,
1190         /* name        */       "ColorRamp",
1191         /* width+range */       240, 200, 300,
1192         /* class+opts  */       NODE_CLASS_OPERATOR, NODE_OPTIONS,
1193         /* input sock  */       cmp_node_valtorgb_in,
1194         /* output sock */       cmp_node_valtorgb_out,
1195         /* storage     */       "ColorBand",
1196         /* execfunc    */       node_composit_exec_valtorgb
1197         
1198 };
1199
1200
1201 /* **************** RGBTOBW ******************** */
1202 static bNodeSocketType cmp_node_rgbtobw_in[]= {
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_rgbtobw_out[]= {
1207         {       SOCK_VALUE, 0, "Val",                   0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
1208         {       -1, 0, ""       }
1209 };
1210
1211 static void do_rgbtobw(bNode *node, float *out, float *in)
1212 {
1213         out[0]= in[0]*0.35f + in[1]*0.45f + in[2]*0.2f;
1214 }
1215
1216 static void node_composit_exec_rgbtobw(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
1217 {
1218         /* stack order out: bw */
1219         /* stack order in: col */
1220         
1221         /* input no image? then only color operation */
1222         if(in[0]->data==NULL) {
1223                 out[0]->vec[0]= in[0]->vec[0]*0.35f + in[0]->vec[1]*0.45f + in[0]->vec[2]*0.2f;
1224         }
1225         else {
1226                 /* make output size of input image */
1227                 CompBuf *cbuf= in[0]->data;
1228                 CompBuf *stackbuf= alloc_compbuf(cbuf->x, cbuf->y, CB_VAL, 1); // allocs
1229                 
1230                 composit1_pixel_processor(node, stackbuf, in[0]->data, NULL, do_rgbtobw);
1231                 
1232                 out[0]->data= stackbuf;
1233         }
1234 }
1235
1236 static bNodeType cmp_node_rgbtobw= {
1237         /* type code   */       CMP_NODE_RGBTOBW,
1238         /* name        */       "RGB to BW",
1239         /* width+range */       80, 40, 120,
1240         /* class+opts  */       NODE_CLASS_OPERATOR, 0,
1241         /* input sock  */       cmp_node_rgbtobw_in,
1242         /* output sock */       cmp_node_rgbtobw_out,
1243         /* storage     */       "",
1244         /* execfunc    */       node_composit_exec_rgbtobw
1245         
1246 };
1247
1248 /* **************** ALPHAOVER ******************** */
1249 static bNodeSocketType cmp_node_alphaover_in[]= {
1250         {       SOCK_RGBA, 1, "Image",                  0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f},
1251         {       SOCK_RGBA, 1, "Image",                  0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f},
1252         {       -1, 0, ""       }
1253 };
1254 static bNodeSocketType cmp_node_alphaover_out[]= {
1255         {       SOCK_RGBA, 0, "Image",                  0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
1256         {       -1, 0, ""       }
1257 };
1258
1259 static void do_alphaover(bNode *node, float *out, float *src, float *dest)
1260 {
1261         float mul= 1.0f - dest[3];
1262         
1263         if(mul<=0.0f) {
1264                 QUATCOPY(out, dest);
1265         }
1266         else {
1267                 out[0]= (mul*src[0]) + dest[0];
1268                 out[1]= (mul*src[1]) + dest[1];
1269                 out[2]= (mul*src[2]) + dest[2];
1270                 out[3]= (mul*src[3]) + dest[3];
1271         }       
1272 }
1273
1274 static void node_composit_exec_alphaover(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
1275 {
1276         /* stack order in: col col */
1277         /* stack order out: col */
1278         
1279         /* input no image? then only color operation */
1280         if(in[0]->data==NULL) {
1281                 do_alphaover(node, out[0]->vec, in[0]->vec, in[1]->vec);
1282         }
1283         else {
1284                 /* make output size of input image */
1285                 CompBuf *cbuf= in[0]->data;
1286                 CompBuf *stackbuf= alloc_compbuf(cbuf->x, cbuf->y, CB_RGBA, 1); // allocs
1287                 
1288                 composit2_pixel_processor(node, stackbuf, in[0]->data, in[0]->vec, in[1]->data, in[1]->vec, do_alphaover);
1289                 
1290                 out[0]->data= stackbuf;
1291         }
1292 }
1293
1294 static bNodeType cmp_node_alphaover= {
1295         /* type code   */       CMP_NODE_ALPHAOVER,
1296         /* name        */       "AlphaOver",
1297         /* width+range */       80, 40, 120,
1298         /* class+opts  */       NODE_CLASS_OPERATOR, 0,
1299         /* input sock  */       cmp_node_alphaover_in,
1300         /* output sock */       cmp_node_alphaover_out,
1301         /* storage     */       "",
1302         /* execfunc    */       node_composit_exec_alphaover
1303         
1304 };
1305
1306 /* **************** MAP VALUE ******************** */
1307 static bNodeSocketType cmp_node_map_value_in[]= {
1308         {       SOCK_VALUE, 1, "Value",                 1.0f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f},
1309         {       -1, 0, ""       }
1310 };
1311 static bNodeSocketType cmp_node_map_value_out[]= {
1312         {       SOCK_VALUE, 0, "Value",                 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
1313         {       -1, 0, ""       }
1314 };
1315
1316 static void do_map_value(bNode *node, float *out, float *src)
1317 {
1318         TexMapping *texmap= node->storage;
1319         
1320         out[0]= (src[0] + texmap->loc[0])*texmap->size[0];
1321         if(texmap->flag & TEXMAP_CLIP_MIN)
1322                 if(out[0]<texmap->min[0])
1323                         out[0]= texmap->min[0];
1324         if(texmap->flag & TEXMAP_CLIP_MAX)
1325                 if(out[0]>texmap->max[0])
1326                         out[0]= texmap->max[0];
1327 }
1328
1329 static void node_composit_exec_map_value(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
1330 {
1331         /* stack order in: col col */
1332         /* stack order out: col */
1333         
1334         /* input no image? then only value operation */
1335         if(in[0]->data==NULL) {
1336                 do_map_value(node, out[0]->vec, in[0]->vec);
1337         }
1338         else {
1339                 /* make output size of input image */
1340                 CompBuf *cbuf= in[0]->data;
1341                 CompBuf *stackbuf= alloc_compbuf(cbuf->x, cbuf->y, CB_VAL, 1); // allocs
1342                 
1343                 composit1_pixel_processor(node, stackbuf, in[0]->data, in[0]->vec, do_map_value);
1344                 
1345                 out[0]->data= stackbuf;
1346         }
1347 }
1348
1349 static bNodeType cmp_node_map_value= {
1350         /* type code   */       CMP_NODE_MAP_VALUE,
1351         /* name        */       "Map Value",
1352         /* width+range */       100, 60, 150,
1353         /* class+opts  */       NODE_CLASS_OPERATOR, NODE_OPTIONS,
1354         /* input sock  */       cmp_node_map_value_in,
1355         /* output sock */       cmp_node_map_value_out,
1356         /* storage     */       "TexMapping",
1357         /* execfunc    */       node_composit_exec_map_value
1358         
1359 };
1360
1361 /* **************** GAUSS BLUR ******************** */
1362 static bNodeSocketType cmp_node_blur_in[]= {
1363         {       SOCK_RGBA, 1, "Image",                  0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f},
1364         {       SOCK_VALUE, 1, "Size",                  1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
1365         {       -1, 0, ""       }
1366 };
1367 static bNodeSocketType cmp_node_blur_out[]= {
1368         {       SOCK_RGBA, 0, "Image",                  0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
1369         {       -1, 0, ""       }
1370 };
1371
1372 static float *make_gausstab(int rad)
1373 {
1374         float *gausstab, sum, val;
1375         int i, n;
1376         
1377         n = 2 * rad + 1;
1378         
1379         gausstab = (float *) MEM_mallocN(n * sizeof(float), "gauss");
1380         
1381         sum = 0.0f;
1382         for (i = -rad; i <= rad; i++) {
1383                 val = exp(-4.0*((float)i*i) / (float) (rad*rad));
1384                 sum += val;
1385                 gausstab[i+rad] = val;
1386         }
1387         
1388         sum= 1.0f/sum;
1389         for(i=0; i<n; i++)
1390                 gausstab[i]*= sum;
1391         
1392         return gausstab;
1393 }
1394
1395 static float *make_bloomtab(int rad)
1396 {
1397         float *bloomtab, val;
1398         int i, n;
1399         
1400         n = 2 * rad + 1;
1401         
1402         bloomtab = (float *) MEM_mallocN(n * sizeof(float), "bloom");
1403         
1404         for (i = -rad; i <= rad; i++) {
1405                 val = pow(1.0 - fabs((float)i)/((float)rad), 4.0);
1406                 bloomtab[i+rad] = val;
1407         }
1408         
1409         return bloomtab;
1410 }
1411
1412 static void blur_single_image(CompBuf *new, CompBuf *img, float blurx, float blury)
1413 {
1414         CompBuf *work;
1415         register float sum, val;
1416         float rval, gval, bval, aval;
1417         float *gausstab, *gausstabcent;
1418         int rad, imgx= img->x, imgy= img->y;
1419         int x, y, pix= img->type;
1420         int i, bigstep;
1421         float *src, *dest;
1422
1423         /* helper image */
1424         work= alloc_compbuf(imgx, imgy, img->type, 1); // allocs
1425         
1426         /* horizontal */
1427         rad = ceil(blurx);
1428         if(rad>imgx/2)
1429                 rad= imgx/2;
1430         else if(rad<1) 
1431                 rad= 1;
1432
1433         gausstab= make_gausstab(rad);
1434         gausstabcent= gausstab+rad;
1435         
1436         for (y = 0; y < imgy; y++) {
1437                 float *srcd= img->rect + pix*(y*img->x);
1438                 
1439                 dest = work->rect + pix*(y * img->x);
1440                 
1441                 for (x = 0; x < imgx ; x++) {
1442                         int minr= x-rad<0?-x:-rad;
1443                         int maxr= x+rad>imgx?imgx-x:rad;
1444                         
1445                         src= srcd + pix*(x+minr);
1446                         
1447                         sum= gval = rval= bval= aval= 0.0f;
1448                         for (i= minr; i < maxr; i++) {
1449                                 val= gausstabcent[i];
1450                                 sum+= val;
1451                                 rval += val * (*src++);
1452                                 if(pix==4) {
1453                                         gval += val * (*src++);
1454                                         bval += val * (*src++);
1455                                         aval += val * (*src++);
1456                                 }
1457                         }
1458                         sum= 1.0f/sum;
1459                         *dest++ = rval*sum;
1460                         if(pix==4) {
1461                                 *dest++ = gval*sum;
1462                                 *dest++ = bval*sum;
1463                                 *dest++ = aval*sum;
1464                         }
1465                 }
1466         }
1467         
1468         /* vertical */
1469         MEM_freeN(gausstab);
1470         
1471         rad = ceil(blury);
1472         if(rad>imgy/2)
1473                 rad= imgy/2;
1474         else if(rad<1) 
1475                 rad= 1;
1476
1477         gausstab= make_gausstab(rad);
1478         gausstabcent= gausstab+rad;
1479         
1480         bigstep = pix*imgx;
1481         for (x = 0; x < imgx; x++) {
1482                 float *srcd= work->rect + pix*x;
1483                 
1484                 dest = new->rect + pix*x;
1485                 
1486                 for (y = 0; y < imgy ; y++) {
1487                         int minr= y-rad<0?-y:-rad;
1488                         int maxr= y+rad>imgy?imgy-y:rad;
1489                         
1490                         src= srcd + bigstep*(y+minr);
1491                         
1492                         sum= gval = rval= bval= aval= 0.0f;
1493                         for (i= minr; i < maxr; i++) {
1494                                 val= gausstabcent[i];
1495                                 sum+= val;
1496                                 rval += val * src[0];
1497                                 if(pix==4) {
1498                                         gval += val * src[1];
1499                                         bval += val * src[2];
1500                                         aval += val * src[3];
1501                                 }
1502                                 src += bigstep;
1503                         }
1504                         sum= 1.0f/sum;
1505                         dest[0] = rval*sum;
1506                         if(pix==4) {
1507                                 dest[1] = gval*sum;
1508                                 dest[2] = bval*sum;
1509                                 dest[3] = aval*sum;
1510                         }
1511                         dest+= bigstep;
1512                 }
1513         }
1514         
1515         free_compbuf(work);
1516         MEM_freeN(gausstab);
1517 }
1518
1519 /* reference has to be mapped 0-1, and equal in size */
1520 static void bloom_with_reference(CompBuf *new, CompBuf *img, CompBuf *ref, float blurx, float blury)
1521 {
1522         CompBuf *wbuf;
1523         register float val;
1524         float radxf, radyf;
1525         float **maintabs;
1526         float *gausstabx, *gausstabcenty;
1527         float *gausstaby, *gausstabcentx;
1528         int radx, rady, imgx= img->x, imgy= img->y;
1529         int x, y;
1530         int i, j;
1531         float *src, *dest, *wb;
1532         
1533         wbuf= alloc_compbuf(imgx, imgy, CB_VAL, 1);
1534         memset(wbuf->rect, sizeof(float)*imgx*imgy, 0);
1535         
1536         /* horizontal */
1537         radx = ceil(blurx);
1538         if(radx>imgx/2)
1539                 radx= imgx/2;
1540         else if(radx<1) 
1541                 radx= 1;
1542         
1543         /* vertical */
1544         rady = ceil(blury);
1545         if(rady>imgy/2)
1546                 rady= imgy/2;
1547         else if(rady<1) 
1548                 rady= 1;
1549         
1550         x= MAX2(radx, rady);
1551         maintabs= MEM_mallocN(x*sizeof(void *), "gauss array");
1552         for(i= 0; i<x; i++)
1553                 maintabs[i]= make_bloomtab(i+1);
1554                 
1555         /* vars to store before we go */
1556 //      refd= ref->rect;
1557         src= img->rect;
1558         
1559         memset(new->rect, 4*imgx*imgy, 0);
1560         
1561         radxf= (float)radx;
1562         radyf= (float)rady;
1563         
1564         for (y = 0; y < imgy; y++) {
1565                 for (x = 0; x < imgx ; x++, src+=4) {//, refd++) {
1566                         
1567 //                      int refradx= (int)(refd[0]*radxf);
1568 //                      int refrady= (int)(refd[0]*radyf);
1569                         
1570                         int refradx= (int)(radxf*0.3f*src[3]*(src[0]+src[1]+src[2]));
1571                         int refrady= (int)(radyf*0.3f*src[3]*(src[0]+src[1]+src[2]));
1572                         
1573                         if(refradx>radx) refradx= radx;
1574                         else if(refradx<1) refradx= 1;
1575                         if(refrady>rady) refrady= rady;
1576                         else if(refrady<1) refrady= 1;
1577                         
1578                         if(refradx==1 && refrady==1) {
1579                                 wb= wbuf->rect + ( y*imgx + x);
1580                                 dest= new->rect + 4*( y*imgx + x);
1581                                 wb[0]+= 1.0f;
1582                                 dest[0] += src[0];
1583                                 dest[1] += src[1];
1584                                 dest[2] += src[2];
1585                                 dest[3] += src[3];
1586                         }
1587                         else {
1588                                 int minxr= x-refradx<0?-x:-refradx;
1589                                 int maxxr= x+refradx>imgx?imgx-x:refradx;
1590                                 int minyr= y-refrady<0?-y:-refrady;
1591                                 int maxyr= y+refrady>imgy?imgy-y:refrady;
1592                                 
1593                                 float *destd= new->rect + 4*( (y + minyr)*imgx + x + minxr);
1594                                 float *wbufd= wbuf->rect + ( (y + minyr)*imgx + x + minxr);
1595                                 
1596                                 gausstabx= maintabs[refradx-1];
1597                                 gausstabcentx= gausstabx+refradx;
1598                                 gausstaby= maintabs[refrady-1];
1599                                 gausstabcenty= gausstaby+refrady;
1600                                 
1601                                 for (i= minyr; i < maxyr; i++, destd+= 4*imgx, wbufd+= imgx) {
1602                                         dest= destd;
1603                                         wb= wbufd;
1604                                         for (j= minxr; j < maxxr; j++, dest+=4, wb++) {
1605                                                 
1606                                                 val= gausstabcenty[i]*gausstabcentx[j];
1607                                                 wb[0]+= val;
1608                                                 dest[0] += val * src[0];
1609                                                 dest[1] += val * src[1];
1610                                                 dest[2] += val * src[2];
1611                                                 dest[3] += val * src[3];
1612                                         }
1613                                 }
1614                         }
1615                 }
1616         }
1617         
1618         x= imgx*imgy;
1619         dest= new->rect;
1620         wb= wbuf->rect;
1621         while(x--) {
1622                 val= 1.0f/wb[0];
1623                 dest[0]*= val;
1624                 dest[1]*= val;
1625                 dest[2]*= val;
1626                 dest[3]*= val;
1627                 wb++;
1628                 dest+= 4;
1629         }
1630         
1631         free_compbuf(wbuf);
1632         
1633         x= MAX2(radx, rady);
1634         for(i= 0; i<x; i++)
1635                 MEM_freeN(maintabs[i]);
1636         MEM_freeN(maintabs);
1637         
1638 }
1639
1640 /* reference has to be mapped 0-1, and equal in size */
1641 static void blur_with_reference(CompBuf *new, CompBuf *img, CompBuf *ref, float blurx, float blury)
1642 {
1643         CompBuf *blurbuf;
1644         register float sum, val;
1645         float rval, gval, bval, aval, radxf, radyf;
1646         float **maintabs;
1647         float *gausstabx, *gausstabcenty;
1648         float *gausstaby, *gausstabcentx;
1649         int radx, rady, imgx= img->x, imgy= img->y;
1650         int x, y;
1651         int i, j;
1652         float *src, *dest, *refd, *blurd;
1653
1654         /* trick is; we blur the reference image... but only works with clipped values*/
1655         blurbuf= alloc_compbuf(imgx, imgy, CB_VAL, 1);
1656         blurd= blurbuf->rect;
1657         refd= ref->rect;
1658         for(x= imgx*imgy; x>0; x--, refd++, blurd++) {
1659                 if(refd[0]<0.0f) blurd[0]= 0.0f;
1660                 else if(refd[0]>1.0f) blurd[0]= 1.0f;
1661                 else blurd[0]= refd[0];
1662         }
1663         
1664         blur_single_image(blurbuf, blurbuf, blurx, blury);
1665         
1666         /* horizontal */
1667         radx = ceil(blurx);
1668         if(radx>imgx/2)
1669                 radx= imgx/2;
1670         else if(radx<1) 
1671                 radx= 1;
1672         
1673         /* vertical */
1674         rady = ceil(blury);
1675         if(rady>imgy/2)
1676                 rady= imgy/2;
1677         else if(rady<1) 
1678                 rady= 1;
1679         
1680         x= MAX2(radx, rady);
1681         maintabs= MEM_mallocN(x*sizeof(void *), "gauss array");
1682         for(i= 0; i<x; i++)
1683                 maintabs[i]= make_gausstab(i+1);
1684         
1685         refd= blurbuf->rect;
1686         dest= new->rect;
1687         radxf= (float)radx;
1688         radyf= (float)rady;
1689         
1690         for (y = 0; y < imgy; y++) {
1691                 for (x = 0; x < imgx ; x++, dest+=4, refd++) {
1692                         int refradx= (int)(refd[0]*radxf);
1693                         int refrady= (int)(refd[0]*radyf);
1694                         
1695                         if(refradx>radx) refradx= radx;
1696                         else if(refradx<1) refradx= 1;
1697                         if(refrady>rady) refrady= rady;
1698                         else if(refrady<1) refrady= 1;
1699
1700                         if(refradx==1 && refrady==1) {
1701                                 src= img->rect + 4*( y*imgx + x);
1702                                 QUATCOPY(dest, src);
1703                         }
1704                         else {
1705                                 int minxr= x-refradx<0?-x:-refradx;
1706                                 int maxxr= x+refradx>imgx?imgx-x:refradx;
1707                                 int minyr= y-refrady<0?-y:-refrady;
1708                                 int maxyr= y+refrady>imgy?imgy-y:refrady;
1709         
1710                                 float *srcd= img->rect + 4*( (y + minyr)*imgx + x + minxr);
1711                                 
1712                                 gausstabx= maintabs[refradx-1];
1713                                 gausstabcentx= gausstabx+refradx;
1714                                 gausstaby= maintabs[refrady-1];
1715                                 gausstabcenty= gausstaby+refrady;
1716
1717                                 sum= gval = rval= bval= aval= 0.0f;
1718                                 
1719                                 for (i= minyr; i < maxyr; i++, srcd+= 4*imgx) {
1720                                         src= srcd;
1721                                         for (j= minxr; j < maxxr; j++, src+=4) {
1722                                         
1723                                                 val= gausstabcenty[i]*gausstabcentx[j];
1724                                                 sum+= val;
1725                                                 rval += val * src[0];
1726                                                 gval += val * src[1];
1727                                                 bval += val * src[2];
1728                                                 aval += val * src[3];
1729                                         }
1730                                 }
1731                                 sum= 1.0f/sum;
1732                                 dest[0] = rval*sum;
1733                                 dest[1] = gval*sum;
1734                                 dest[2] = bval*sum;
1735                                 dest[3] = aval*sum;
1736                         }
1737                 }
1738         }
1739         
1740         free_compbuf(blurbuf);
1741         
1742         x= MAX2(radx, rady);
1743         for(i= 0; i<x; i++)
1744                 MEM_freeN(maintabs[i]);
1745         MEM_freeN(maintabs);
1746         
1747 }
1748
1749
1750
1751 static void node_composit_exec_blur(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
1752 {
1753         CompBuf *new, *img= in[0]->data;
1754         
1755         if(img==NULL || out[0]->hasoutput==0)
1756                 return;
1757         
1758         /* if fac input, we do it different */
1759         if(in[1]->data) {
1760                 
1761                 /* test fitness if reference */
1762                 
1763                 /* make output size of input image */
1764                 new= alloc_compbuf(img->x, img->y, CB_RGBA, 1); // allocs
1765                 
1766                 blur_with_reference(new, img, in[1]->data, (float)node->custom1, (float)node->custom2);
1767                 
1768                 out[0]->data= new;
1769         }
1770         else {
1771                 if(in[1]->vec[0]==0.0f) {
1772                         /* pass on image */
1773                         new= alloc_compbuf(img->x, img->y, img->type, 0);
1774                         new->rect= img->rect;
1775                 }
1776                 else {
1777                         /* make output size of input image */
1778                         new= alloc_compbuf(img->x, img->y, img->type, 1); // allocs
1779                         if(1)
1780                                 blur_single_image(new, img, in[1]->vec[0]*(float)node->custom1, in[1]->vec[0]*(float)node->custom2);
1781                         else    /* bloom experimental... */
1782                                 bloom_with_reference(new, img, NULL, in[1]->vec[0]*(float)node->custom1, in[1]->vec[0]*(float)node->custom2);
1783                 }
1784                 out[0]->data= new;
1785         }
1786 }
1787         
1788
1789 /* custom1 custom2 = blur filter size */
1790 static bNodeType cmp_node_blur= {
1791         /* type code   */       CMP_NODE_BLUR,
1792         /* name        */       "Blur",
1793         /* width+range */       120, 80, 200,
1794         /* class+opts  */       NODE_CLASS_OPERATOR, NODE_OPTIONS,
1795         /* input sock  */       cmp_node_blur_in,
1796         /* output sock */       cmp_node_blur_out,
1797         /* storage     */       "",
1798         /* execfunc    */       node_composit_exec_blur
1799         
1800 };
1801
1802
1803 /* ****************** types array for all shaders ****************** */
1804
1805 bNodeType *node_all_composit[]= {
1806         &node_group_typeinfo,
1807         &cmp_node_viewer,
1808         &cmp_node_composite,
1809         &cmp_node_output_file,
1810         &cmp_node_value,
1811         &cmp_node_rgb,
1812         &cmp_node_mix_rgb,
1813         &cmp_node_filter,
1814         &cmp_node_valtorgb,
1815         &cmp_node_rgbtobw,
1816         &cmp_node_normal,
1817         &cmp_node_curve_vec,
1818         &cmp_node_curve_rgb,
1819         &cmp_node_image,
1820         &cmp_node_rresult,
1821         &cmp_node_alphaover,
1822         &cmp_node_blur,
1823         &cmp_node_map_value,
1824         NULL
1825 };
1826
1827 /* ******************* parse ************ */
1828
1829 /* helper call to detect if theres a render-result node */
1830 int ntreeCompositNeedsRender(bNodeTree *ntree)
1831 {
1832         bNode *node;
1833         
1834         if(ntree==NULL) return 1;
1835         
1836         for(node= ntree->nodes.first; node; node= node->next) {
1837                 if(node->type==CMP_NODE_R_RESULT)
1838                         return 1;
1839         }
1840         return 0;
1841 }
1842
1843 void ntreeCompositTagRender(bNodeTree *ntree)
1844 {
1845         bNode *node;
1846         
1847         if(ntree==NULL) return;
1848         
1849         for(node= ntree->nodes.first; node; node= node->next) {
1850                 if(node->type==CMP_NODE_R_RESULT)
1851                         NodeTagChanged(ntree, node);
1852         }
1853 }
1854