Bug in Composite AddAlpha node. The option premul added alpha wrong.
[blender.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 #include "BLI_threads.h"
54
55 /* NOTE: no imbuf calls allowed in composit, we need threadsafe malloc! */
56 #include "IMB_imbuf_types.h"
57
58 #include "RE_pipeline.h"
59 #include "RE_shader_ext.h"              /* <- TexResult */
60
61 /* *************************** operations support *************************** */
62
63 /* general signal that's in output sockets, and goes over the wires */
64 typedef struct CompBuf {
65         float *rect;
66         int x, y, xrad, yrad;
67         short type, malloc;
68         rcti disprect;          /* cropped part of image */
69         int xof, yof;           /* relative to center of target image */
70         
71         void (*rect_procedural)(struct CompBuf *, float *, float, float);
72         bNode *node;
73 } CompBuf;
74
75 /* defines also used for pixel size */
76 #define CB_RGBA         4
77 #define CB_VEC4         4
78 #define CB_VEC3         3
79 #define CB_VEC2         2
80 #define CB_VAL          1
81
82 /* defines for RGBA channels */
83 #define CHAN_R  0
84 #define CHAN_G  1
85 #define CHAN_B  2
86 #define CHAN_A  3
87
88 static CompBuf *alloc_compbuf(int sizex, int sizey, int type, int alloc)
89 {
90         CompBuf *cbuf= MEM_callocT(sizeof(CompBuf), "compbuf");
91         
92         cbuf->x= sizex;
93         cbuf->y= sizey;
94         cbuf->xrad= sizex/2;
95         cbuf->yrad= sizey/2;
96         
97         cbuf->type= type;
98         if(alloc) {
99                 if(cbuf->type==CB_RGBA)
100                         cbuf->rect= MEM_mapallocT(4*sizeof(float)*sizex*sizey, "compbuf RGBA rect");
101                 else if(cbuf->type==CB_VEC3)
102                         cbuf->rect= MEM_mapallocT(3*sizeof(float)*sizex*sizey, "compbuf Vector3 rect");
103                 else if(cbuf->type==CB_VEC2)
104                         cbuf->rect= MEM_mapallocT(2*sizeof(float)*sizex*sizey, "compbuf Vector2 rect");
105                 else
106                         cbuf->rect= MEM_mapallocT(sizeof(float)*sizex*sizey, "compbuf Fac rect");
107                 cbuf->malloc= 1;
108         }
109         cbuf->disprect.xmin= 0;
110         cbuf->disprect.ymin= 0;
111         cbuf->disprect.xmax= sizex;
112         cbuf->disprect.ymax= sizey;
113         
114         return cbuf;
115 }
116
117 static CompBuf *dupalloc_compbuf(CompBuf *cbuf)
118 {
119         CompBuf *dupbuf= alloc_compbuf(cbuf->x, cbuf->y, cbuf->type, 1);
120         if(dupbuf)
121                 memcpy(dupbuf->rect, cbuf->rect, cbuf->type*sizeof(float)*cbuf->x*cbuf->y);
122         return dupbuf;
123 }
124
125 void free_compbuf(CompBuf *cbuf)
126 {
127         if(cbuf->malloc && cbuf->rect)
128                 MEM_freeT(cbuf->rect);
129
130         MEM_freeT(cbuf);
131 }
132
133 void print_compbuf(char *str, CompBuf *cbuf)
134 {
135         printf("Compbuf %s %d %d %p\n", str, cbuf->x, cbuf->y, cbuf->rect);
136         
137 }
138
139 static CompBuf *get_cropped_compbuf(rcti *drect, float *rectf, int rectx, int recty, int type)
140 {
141         CompBuf *cbuf;
142         rcti disprect= *drect;
143         float *outfp;
144         int dx, y;
145         
146         if(disprect.xmax>rectx) disprect.xmax= rectx;
147         if(disprect.ymax>recty) disprect.ymax= recty;
148         if(disprect.xmin>= disprect.xmax) return NULL;
149         if(disprect.ymin>= disprect.ymax) return NULL;
150         
151         cbuf= alloc_compbuf(disprect.xmax-disprect.xmin, disprect.ymax-disprect.ymin, type, 1);
152         outfp= cbuf->rect;
153         rectf += type*(disprect.ymin*rectx + disprect.xmin);
154         dx= type*cbuf->x;
155         for(y=cbuf->y; y>0; y--, outfp+=dx, rectf+=type*rectx)
156                 memcpy(outfp, rectf, sizeof(float)*dx);
157         
158         return cbuf;
159 }
160
161 static CompBuf *scalefast_compbuf(CompBuf *inbuf, int newx, int newy)
162 {
163         CompBuf *outbuf; 
164         float *rectf, *newrectf, *rf;
165         int x, y, c, pixsize= inbuf->type;
166         int ofsx, ofsy, stepx, stepy;
167         
168         if(inbuf->x==newx && inbuf->y==newy)
169                 return dupalloc_compbuf(inbuf);
170         
171         outbuf= alloc_compbuf(newx, newy, inbuf->type, 1);
172         newrectf= outbuf->rect;
173         
174         stepx = (65536.0 * (inbuf->x - 1.0) / (newx - 1.0)) + 0.5;
175         stepy = (65536.0 * (inbuf->y - 1.0) / (newy - 1.0)) + 0.5;
176         ofsy = 32768;
177         
178         for (y = newy; y > 0 ; y--){
179                 rectf = inbuf->rect;
180                 rectf += pixsize * (ofsy >> 16) * inbuf->x;
181
182                 ofsy += stepy;
183                 ofsx = 32768;
184                 
185                 for (x = newx ; x>0 ; x--) {
186                         
187                         rf= rectf + pixsize*(ofsx >> 16);
188                         for(c=0; c<pixsize; c++)
189                                 newrectf[c] = rf[c];
190                         
191                         newrectf+= pixsize;
192                         
193                         ofsx += stepx;
194                 }
195         }
196         
197         return outbuf;
198 }
199
200 static CompBuf *typecheck_compbuf(CompBuf *inbuf, int type)
201 {
202         if(inbuf && inbuf->type!=type && inbuf->rect_procedural==NULL) {
203                 CompBuf *outbuf= alloc_compbuf(inbuf->x, inbuf->y, type, 1); 
204                 float *inrf= inbuf->rect;
205                 float *outrf= outbuf->rect;
206                 int x= inbuf->x*inbuf->y;
207                 
208                 if(type==CB_VAL && inbuf->type==CB_VEC3) {
209                         for(; x>0; x--, outrf+= 1, inrf+= 3)
210                                 *outrf= 0.333333f*(inrf[0]+inrf[1]+inrf[2]);
211                 }
212                 else if(type==CB_VAL && inbuf->type==CB_RGBA) {
213                         for(; x>0; x--, outrf+= 1, inrf+= 4)
214                                 *outrf= inrf[0]*0.35f + inrf[1]*0.45f + inrf[2]*0.2f;
215                 }
216                 else if(type==CB_VEC3 && inbuf->type==CB_VAL) {
217                         for(; x>0; x--, outrf+= 3, inrf+= 1) {
218                                 outrf[0]= inrf[0];
219                                 outrf[1]= inrf[0];
220                                 outrf[2]= inrf[0];
221                         }
222                 }
223                 else if(type==CB_VEC3 && inbuf->type==CB_RGBA) {
224                         for(; x>0; x--, outrf+= 3, inrf+= 4) {
225                                 outrf[0]= inrf[0];
226                                 outrf[1]= inrf[1];
227                                 outrf[2]= inrf[2];
228                         }
229                 }
230                 else if(type==CB_RGBA && inbuf->type==CB_VAL) {
231                         for(; x>0; x--, outrf+= 4, inrf+= 1) {
232                                 outrf[0]= inrf[0];
233                                 outrf[1]= inrf[0];
234                                 outrf[2]= inrf[0];
235                                 outrf[3]= inrf[0];
236                         }
237                 }
238                 else if(type==CB_RGBA && inbuf->type==CB_VEC3) {
239                         for(; x>0; x--, outrf+= 4, inrf+= 3) {
240                                 outrf[0]= inrf[0];
241                                 outrf[1]= inrf[1];
242                                 outrf[2]= inrf[2];
243                                 outrf[3]= 1.0f;
244                         }
245                 }
246                 
247                 return outbuf;
248         }
249         return inbuf;
250 }
251
252 float *compbuf_get_pixel(CompBuf *cbuf, float *rectf, int x, int y, int xrad, int yrad)
253 {
254         if(cbuf) {
255                 if(cbuf->rect_procedural) {
256                         cbuf->rect_procedural(cbuf, rectf, (float)x/(float)xrad, (float)y/(float)yrad);
257                         return rectf;
258                 }
259                 else {
260                         static float col[4]= {0.0f, 0.0f, 0.0f, 0.0f};
261                         
262                         /* map coords */
263                         x-= cbuf->xof;
264                         y-= cbuf->yof;
265                         
266                         if(y<-cbuf->yrad || y>= -cbuf->yrad+cbuf->y) return col;
267                         if(x<-cbuf->xrad || x>= -cbuf->xrad+cbuf->x) return col;
268                         
269                         return cbuf->rect + cbuf->type*( (cbuf->yrad+y)*cbuf->x + (cbuf->xrad+x) );
270                 }
271         }
272         else return rectf;
273 }
274
275 /* **************************************************** */
276
277 /* Pixel-to-Pixel operation, 1 Image in, 1 out */
278 static void composit1_pixel_processor(bNode *node, CompBuf *out, CompBuf *src_buf, float *src_col,
279                                                                           void (*func)(bNode *, float *, float *), 
280                                                                           int src_type)
281 {
282         CompBuf *src_use;
283         float *outfp=out->rect, *srcfp;
284         int xrad, yrad, x, y;
285         
286         src_use= typecheck_compbuf(src_buf, src_type);
287         
288         xrad= out->xrad;
289         yrad= out->yrad;
290         
291         for(y= -yrad; y<-yrad+out->y; y++) {
292                 for(x= -xrad; x<-xrad+out->x; x++, outfp+=out->type) {
293                         srcfp= compbuf_get_pixel(src_use, src_col, x, y, xrad, yrad);
294                         func(node, outfp, srcfp);
295                 }
296         }
297         
298         if(src_use!=src_buf)
299                 free_compbuf(src_use);
300 }
301
302 /* Pixel-to-Pixel operation, 2 Images in, 1 out */
303 static void composit2_pixel_processor(bNode *node, CompBuf *out, CompBuf *src_buf, float *src_col,
304                                                                           CompBuf *fac_buf, float *fac, void (*func)(bNode *, float *, float *, float *), 
305                                                                           int src_type, int fac_type)
306 {
307         CompBuf *src_use, *fac_use;
308         float *outfp=out->rect, *srcfp, *facfp;
309         int xrad, yrad, x, y;
310         
311         src_use= typecheck_compbuf(src_buf, src_type);
312         fac_use= typecheck_compbuf(fac_buf, fac_type);
313
314         xrad= out->xrad;
315         yrad= out->yrad;
316         
317         for(y= -yrad; y<-yrad+out->y; y++) {
318                 for(x= -xrad; x<-xrad+out->x; x++, outfp+=out->type) {
319                         srcfp= compbuf_get_pixel(src_use, src_col, x, y, xrad, yrad);
320                         facfp= compbuf_get_pixel(fac_use, fac, x, y, xrad, yrad);
321                         
322                         func(node, outfp, srcfp, facfp);
323                 }
324         }
325         if(src_use!=src_buf)
326                 free_compbuf(src_use);
327         if(fac_use!=fac_buf)
328                 free_compbuf(fac_use);
329 }
330
331 /* Pixel-to-Pixel operation, 3 Images in, 1 out */
332 static void composit3_pixel_processor(bNode *node, CompBuf *out, CompBuf *src1_buf, float *src1_col, CompBuf *src2_buf, float *src2_col, 
333                                                                           CompBuf *fac_buf, float fac, void (*func)(bNode *, float *, float *, float *, float), 
334                                                                           int src1_type, int src2_type, int fac_type)
335 {
336         CompBuf *src1_use, *src2_use, *fac_use;
337         float *outfp=out->rect, *src1fp, *src2fp, *facfp;
338         int xrad, yrad, x, y;
339         
340         src1_use= typecheck_compbuf(src1_buf, src1_type);
341         src2_use= typecheck_compbuf(src2_buf, src2_type);
342         fac_use= typecheck_compbuf(fac_buf, fac_type);
343         
344         xrad= out->xrad;
345         yrad= out->yrad;
346         
347         for(y= -yrad; y<-yrad+out->y; y++) {
348                 for(x= -xrad; x<-xrad+out->x; x++, outfp+=out->type) {
349                         src1fp= compbuf_get_pixel(src1_use, src1_col, x, y, xrad, yrad);
350                         src2fp= compbuf_get_pixel(src2_use, src2_col, x, y, xrad, yrad);
351                         facfp= compbuf_get_pixel(fac_use, &fac, x, y, xrad, yrad);
352                         
353                         func(node, outfp, src1fp, src2fp, *facfp);
354                 }
355         }
356         
357         if(src1_use!=src1_buf)
358                 free_compbuf(src1_use);
359         if(src2_use!=src2_buf)
360                 free_compbuf(src2_use);
361         if(fac_use!=fac_buf)
362                 free_compbuf(fac_use);
363 }
364
365 /* Pixel-to-Pixel operation, 4 Images in, 1 out */
366 static void composit4_pixel_processor(bNode *node, CompBuf *out, CompBuf *src1_buf, float *src1_col, CompBuf *fac1_buf, float *fac1, 
367                                                                           CompBuf *src2_buf, float *src2_col, CompBuf *fac2_buf, float *fac2, 
368                                                                           void (*func)(bNode *, float *, float *, float *, float *, float *), 
369                                                                           int src1_type, int fac1_type, int src2_type, int fac2_type)
370 {
371         CompBuf *src1_use, *src2_use, *fac1_use, *fac2_use;
372         float *outfp=out->rect, *src1fp, *src2fp, *fac1fp, *fac2fp;
373         int xrad, yrad, x, y;
374         
375         src1_use= typecheck_compbuf(src1_buf, src1_type);
376         src2_use= typecheck_compbuf(src2_buf, src2_type);
377         fac1_use= typecheck_compbuf(fac1_buf, fac1_type);
378         fac2_use= typecheck_compbuf(fac2_buf, fac2_type);
379         
380         xrad= out->xrad;
381         yrad= out->yrad;
382         
383         for(y= -yrad; y<-yrad+out->y; y++) {
384                 for(x= -xrad; x<-xrad+out->x; x++, outfp+=out->type) {
385                         src1fp= compbuf_get_pixel(src1_use, src1_col, x, y, xrad, yrad);
386                         src2fp= compbuf_get_pixel(src2_use, src2_col, x, y, xrad, yrad);
387                         fac1fp= compbuf_get_pixel(fac1_use, fac1, x, y, xrad, yrad);
388                         fac2fp= compbuf_get_pixel(fac2_use, fac2, x, y, xrad, yrad);
389                         
390                         func(node, outfp, src1fp, fac1fp, src2fp, fac2fp);
391                 }
392         }
393         
394         if(src1_use!=src1_buf)
395                 free_compbuf(src1_use);
396         if(src2_use!=src2_buf)
397                 free_compbuf(src2_use);
398         if(fac1_use!=fac1_buf)
399                 free_compbuf(fac1_use);
400         if(fac2_use!=fac2_buf)
401                 free_compbuf(fac2_use);
402 }
403
404
405 static CompBuf *valbuf_from_rgbabuf(CompBuf *cbuf, int channel)
406 {
407         CompBuf *valbuf= alloc_compbuf(cbuf->x, cbuf->y, CB_VAL, 1);
408         float *valf, *rectf;
409         int tot;
410         
411         valf= valbuf->rect;
412         
413         /* defaults to returning alpha channel */
414         if ((channel < CHAN_R) && (channel > CHAN_A)) channel = CHAN_A;
415
416         rectf= cbuf->rect + channel;
417         
418         for(tot= cbuf->x*cbuf->y; tot>0; tot--, valf++, rectf+=4)
419                 *valf= *rectf;
420         
421         return valbuf;
422 }
423
424 static void generate_preview(bNode *node, CompBuf *stackbuf)
425 {
426         bNodePreview *preview= node->preview;
427         
428         if(preview && stackbuf) {
429                 CompBuf *cbuf;
430                 
431                 if(stackbuf->rect==NULL) return;
432                 
433                 if(stackbuf->x > stackbuf->y) {
434                         preview->xsize= 140;
435                         preview->ysize= (140*stackbuf->y)/stackbuf->x;
436                 }
437                 else {
438                         preview->ysize= 140;
439                         preview->xsize= (140*stackbuf->x)/stackbuf->y;
440                 }
441                 
442                 cbuf= scalefast_compbuf(stackbuf, preview->xsize, preview->ysize);
443                 
444                 /* this ensures free-compbuf does the right stuff */
445                 SWAP(float *, cbuf->rect, node->preview->rect);
446                 
447                 free_compbuf(cbuf);
448         }
449 }
450
451 /* ******************************************************** */
452 /* ********* Composit Node type definitions ***************** */
453 /* ******************************************************** */
454
455 /* SocketType syntax: 
456    socket type, max connections (0 is no limit), name, 4 values for default, 2 values for range */
457
458 /* Verification rule: If name changes, a saved socket and its links will be removed! Type changes are OK */
459
460 /* **************** VIEWER ******************** */
461 static bNodeSocketType cmp_node_viewer_in[]= {
462         {       SOCK_RGBA, 1, "Image",          0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
463         {       SOCK_VALUE, 1, "Alpha",         1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
464         {       SOCK_VALUE, 1, "Z",                     1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
465         {       -1, 0, ""       }
466 };
467
468 static void do_copy_rgba(bNode *node, float *out, float *in)
469 {
470         QUATCOPY(out, in);
471 }
472 static void do_copy_rgb(bNode *node, float *out, float *in)
473 {
474         VECCOPY(out, in);
475         out[3]= 1.0f;
476 }
477 static void do_copy_value(bNode *node, float *out, float *in)
478 {
479         out[0]= in[0];
480 }
481 static void do_copy_a_rgba(bNode *node, float *out, float *in, float *fac)
482 {
483         VECCOPY(out, in);
484         out[3]= *fac;
485 }
486
487 static void node_composit_exec_viewer(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
488 {
489         /* image assigned to output */
490         /* stack order input sockets: col, alpha, z */
491         
492         if(node->id && (node->flag & NODE_DO_OUTPUT)) { /* only one works on out */
493                 Image *ima= (Image *)node->id;
494                 CompBuf *cbuf, *tbuf;
495                 int rectx, recty;
496                 
497                 tbuf= in[0]->data?in[0]->data:(in[1]->data?in[1]->data:in[2]->data);
498                 if(tbuf==NULL) {
499                         rectx= 320; recty= 256;
500                 }
501                 else {
502                         rectx= tbuf->x;
503                         recty= tbuf->y;
504                 }
505                 
506                 /* full copy of imbuf, but threadsafe... */
507                 if(ima->ibuf==NULL) {
508                         ima->ibuf = MEM_callocT(sizeof(struct ImBuf), "ImBuf_struct");
509                         ima->ibuf->depth= 32;
510                         ima->ibuf->ftype= TGA;
511                 }
512                 
513                 /* cleanup of composit image */
514                 if(ima->ibuf->rect) {
515                         MEM_freeT(ima->ibuf->rect);
516                         ima->ibuf->rect= NULL;
517                         ima->ibuf->mall &= ~IB_rect;
518                 }
519                 if(ima->ibuf->zbuf_float) {
520                         MEM_freeT(ima->ibuf->zbuf_float);
521                         ima->ibuf->zbuf_float= NULL;
522                         ima->ibuf->mall &= ~IB_zbuffloat;
523                 }
524                 if(ima->ibuf->rect_float)
525                         MEM_freeT(ima->ibuf->rect_float);
526                 
527                 ima->ibuf->x= rectx;
528                 ima->ibuf->y= recty;
529                 ima->ibuf->mall |= IB_rectfloat;
530                 ima->ibuf->rect_float= MEM_mallocT(4*rectx*recty*sizeof(float), "viewer rect");
531                 
532                 /* now we combine the input with ibuf */
533                 cbuf= alloc_compbuf(rectx, recty, CB_RGBA, 0);  // no alloc
534                 cbuf->rect= ima->ibuf->rect_float;
535                 
536                 /* when no alpha, we can simply copy */
537                 if(in[1]->data==NULL) {
538                         composit1_pixel_processor(node, cbuf, in[0]->data, in[0]->vec, do_copy_rgba, CB_RGBA);
539                 }
540                 else
541                         composit2_pixel_processor(node, cbuf, in[0]->data, in[0]->vec, in[1]->data, in[1]->vec, do_copy_a_rgba, CB_RGBA, CB_VAL);
542                 
543                 if(in[2]->data) {
544                         CompBuf *zbuf= alloc_compbuf(rectx, recty, CB_VAL, 1);
545                         ima->ibuf->zbuf_float= zbuf->rect;
546                         ima->ibuf->mall |= IB_zbuffloat;
547                         
548                         composit1_pixel_processor(node, zbuf, in[2]->data, in[2]->vec, do_copy_value, CB_VAL);
549                         
550                         /* free compbuf, but not the rect */
551                         zbuf->malloc= 0;
552                         free_compbuf(zbuf);
553                 }
554
555                 generate_preview(node, cbuf);
556                 free_compbuf(cbuf);
557
558         }       /* lets make only previews when not done yet, so activating doesnt update */
559         else if(in[0]->data && node->preview && node->preview->rect==NULL) {
560                 CompBuf *cbuf, *inbuf= in[0]->data;
561                 
562                 if(inbuf->type!=CB_RGBA) {
563                         cbuf= alloc_compbuf(inbuf->x, inbuf->y, CB_RGBA, 1);
564                         composit1_pixel_processor(node, cbuf, inbuf, in[0]->vec, do_copy_rgba, CB_RGBA);
565                         generate_preview(node, cbuf);
566                         free_compbuf(cbuf);
567                 }
568                 else
569                         generate_preview(node, inbuf);
570         }
571 }
572
573 static bNodeType cmp_node_viewer= {
574         /* type code   */       CMP_NODE_VIEWER,
575         /* name        */       "Viewer",
576         /* width+range */       80, 60, 200,
577         /* class+opts  */       NODE_CLASS_OUTPUT, NODE_PREVIEW,
578         /* input sock  */       cmp_node_viewer_in,
579         /* output sock */       NULL,
580         /* storage     */       "",
581         /* execfunc    */       node_composit_exec_viewer
582         
583 };
584
585 /* **************** COMPOSITE ******************** */
586 static bNodeSocketType cmp_node_composite_in[]= {
587         {       SOCK_RGBA, 1, "Image",          0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
588         {       SOCK_VALUE, 1, "Alpha",         1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
589         {       SOCK_VALUE, 1, "Z",                     1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
590         {       -1, 0, ""       }
591 };
592
593 /* applies to render pipeline */
594 static void node_composit_exec_composite(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
595 {
596         /* image assigned to output */
597         /* stack order input sockets: col, alpha, z */
598         
599         if(node->flag & NODE_DO_OUTPUT) {       /* only one works on out */
600                 RenderData *rd= data;
601                 if(rd->scemode & R_DOCOMP) {
602                         RenderResult *rr= RE_GetResult(RE_GetRender("Render"));
603                         if(rr) {
604                                 CompBuf *outbuf, *zbuf=NULL;
605                                 
606                                 if(rr->rectf) 
607                                         MEM_freeT(rr->rectf);
608                                 outbuf= alloc_compbuf(rr->rectx, rr->recty, CB_RGBA, 1);
609                                 
610                                 if(in[1]->data==NULL)
611                                         composit1_pixel_processor(node, outbuf, in[0]->data, in[0]->vec, do_copy_rgba, CB_RGBA);
612                                 else
613                                         composit2_pixel_processor(node, outbuf, in[0]->data, in[0]->vec, in[1]->data, in[1]->vec, do_copy_a_rgba, CB_RGBA, CB_VAL);
614                                 
615                                 if(in[2]->data) {
616                                         if(rr->rectz) 
617                                                 MEM_freeT(rr->rectz);
618                                         zbuf= alloc_compbuf(rr->rectx, rr->recty, CB_VAL, 1);
619                                         composit1_pixel_processor(node, zbuf, in[2]->data, in[2]->vec, do_copy_value, CB_VAL);
620                                         rr->rectz= zbuf->rect;
621                                         zbuf->malloc= 0;
622                                         free_compbuf(zbuf);
623                                 }
624                                 generate_preview(node, outbuf);
625                                 
626                                 /* we give outbuf to rr... */
627                                 rr->rectf= outbuf->rect;
628                                 outbuf->malloc= 0;
629                                 free_compbuf(outbuf);
630                                 
631                                 return;
632                         }
633                 }
634         }
635         if(in[0]->data)
636                 generate_preview(node, in[0]->data);
637 }
638
639 static bNodeType cmp_node_composite= {
640         /* type code   */       CMP_NODE_COMPOSITE,
641         /* name        */       "Composite",
642         /* width+range */       80, 60, 200,
643         /* class+opts  */       NODE_CLASS_OUTPUT, NODE_PREVIEW,
644         /* input sock  */       cmp_node_composite_in,
645         /* output sock */       NULL,
646         /* storage     */       "",
647         /* execfunc    */       node_composit_exec_composite
648         
649 };
650
651 /* **************** OUTPUT FILE ******************** */
652 static bNodeSocketType cmp_node_output_file_in[]= {
653         {       SOCK_RGBA, 1, "Image",          0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
654         {       SOCK_VALUE, 1, "Alpha",         1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
655         {       -1, 0, ""       }
656 };
657
658
659 static void node_composit_exec_output_file(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
660 {
661         /* image assigned to output */
662         /* stack order input sockets: col, alpha */
663         
664         if(node->id && (node->flag & NODE_DO_OUTPUT)) { /* only one works on out */
665         }
666         else if(in[0]->data)
667                 generate_preview(node, in[0]->data);
668 }
669
670 static bNodeType cmp_node_output_file= {
671         /* type code   */       CMP_NODE_OUTPUT_FILE,
672         /* name        */       "File Output",
673         /* width+range */       80, 60, 200,
674         /* class+opts  */       NODE_CLASS_FILE, NODE_PREVIEW,
675         /* input sock  */       cmp_node_output_file_in,
676         /* output sock */       NULL,
677         /* storage     */       "",
678         /* execfunc    */       node_composit_exec_output_file
679         
680 };
681
682 /* **************** IMAGE ******************** */
683 static bNodeSocketType cmp_node_image_out[]= {
684         {       SOCK_RGBA, 0, "Image",          0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
685         {       SOCK_VALUE, 0, "Alpha",         1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
686         {       SOCK_VALUE, 0, "Z",                     1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
687         {       -1, 0, ""       }
688 };
689
690 static int calcimanr(int cfra, NodeImageAnim *nia)
691 {
692         
693         if(nia->frames==0) return nia->nr;
694         
695         cfra= cfra - nia->sfra;
696         
697         /* cyclic */
698         if(nia->cyclic)
699                 cfra= (cfra % nia->frames);
700         else if(cfra>=nia->frames)
701                 cfra= nia->frames-1;
702         else if(cfra<0)
703                 cfra= 0;
704         
705         cfra+= nia->nr;
706         
707         if(cfra<1) cfra= 1;
708         
709         return cfra;
710 }
711
712
713 static void animated_image(bNode *node, int cfra)
714 {
715         Image *ima;
716         NodeImageAnim *nia;
717         int imanr;
718         unsigned short numlen;
719         char name[FILE_MAXDIR+FILE_MAXFILE], head[FILE_MAXDIR+FILE_MAXFILE], tail[FILE_MAXDIR+FILE_MAXFILE];
720         
721         ima= (Image *)node->id;
722         nia= node->storage;
723         
724         if(nia && nia->frames && ima && ima->name) {    /* frames */
725                 strcpy(name, ima->name);
726                 
727                 imanr= calcimanr(cfra, nia);
728                 if(imanr!=ima->lastframe) {
729                         ima->lastframe= imanr;
730                         
731                         BLI_stringdec(name, head, tail, &numlen);
732                         BLI_stringenc(name, head, tail, numlen, imanr);
733                         
734                         ima= add_image(name);
735                         
736                         if(ima) {
737                                 ima->flag |= IMA_FROMANIM;
738                                 if(node->id) node->id->us--;
739                                 node->id= (ID *)ima;
740                                 
741                                 ima->ok= 1;
742                         }
743                 }
744         }
745 }
746
747 static float *float_from_byte_rect(int rectx, int recty, char *rect)
748 {
749         /* quick method to convert byte to floatbuf */
750         float *rect_float= MEM_mallocT(4*sizeof(float)*rectx*recty, "float rect");
751         float *tof = rect_float;
752         int i;
753         
754         for (i = rectx*recty; i > 0; i--) {
755                 tof[0] = ((float)rect[0])*(1.0f/255.0f);
756                 tof[1] = ((float)rect[1])*(1.0f/255.0f);
757                 tof[2] = ((float)rect[2])*(1.0f/255.0f);
758                 tof[3] = ((float)rect[3])*(1.0f/255.0f);
759                 rect += 4; 
760                 tof += 4;
761         }
762         return rect_float;
763 }
764
765
766
767 static CompBuf *node_composit_get_image(bNode *node, RenderData *rd)
768 {
769         Image *ima;
770         CompBuf *stackbuf;
771         
772         /* animated image? */
773         if(node->storage)
774                 animated_image(node, rd->cfra);
775         
776         ima= (Image *)node->id;
777         
778         /* test if image is OK */
779         if(ima->ok==0) return NULL;
780         
781         if(ima->ibuf==NULL) {
782                 BLI_lock_thread();
783                 load_image(ima, IB_rect, G.sce, rd->cfra);      /* G.sce is current .blend path */
784                 BLI_unlock_thread();
785                 if(ima->ibuf==NULL) {
786                         ima->ok= 0;
787                         return NULL;
788                 }
789         }
790         if(ima->ibuf->rect_float==NULL) {
791                 /* can't use imbuf module, we need secure malloc */
792                 ima->ibuf->rect_float= float_from_byte_rect(ima->ibuf->x, ima->ibuf->y, (char *)ima->ibuf->rect);
793                 ima->ibuf->mall |= IB_rectfloat;
794         }
795         
796         if(rd->scemode & R_COMP_CROP) {
797                 stackbuf= get_cropped_compbuf(&rd->disprect, ima->ibuf->rect_float, ima->ibuf->x, ima->ibuf->y, CB_RGBA);
798         }
799         else {
800                 /* we put imbuf copy on stack, cbuf knows rect is from other ibuf when freed! */
801                 stackbuf= alloc_compbuf(ima->ibuf->x, ima->ibuf->y, CB_RGBA, 0);
802                 stackbuf->rect= ima->ibuf->rect_float;
803         }
804         
805         return stackbuf;
806 }
807
808 static CompBuf *node_composit_get_zimage(bNode *node, RenderData *rd)
809 {
810         Image *ima= (Image *)node->id;
811         CompBuf *zbuf= NULL;
812         
813         if(ima->ibuf && ima->ibuf->zbuf_float) {
814                 if(rd->scemode & R_COMP_CROP) {
815                         zbuf= get_cropped_compbuf(&rd->disprect, ima->ibuf->zbuf_float, ima->ibuf->x, ima->ibuf->y, CB_VAL);
816                 }
817                 else {
818                         zbuf= alloc_compbuf(ima->ibuf->x, ima->ibuf->y, CB_VAL, 0);
819                         zbuf->rect= ima->ibuf->zbuf_float;
820                 }
821         }
822         return zbuf;
823 }
824
825 static void node_composit_exec_image(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
826 {
827         
828         /* image assigned to output */
829         /* stack order input sockets: col, alpha */
830         if(node->id) {
831                 CompBuf *stackbuf= node_composit_get_image(node, data);
832                 
833                 /* put ibuf on stack */ 
834                 out[0]->data= stackbuf;
835                 
836                 if(stackbuf) {
837                         if(out[1]->hasoutput)
838                                 out[1]->data= valbuf_from_rgbabuf(stackbuf, CHAN_A);
839                         
840                         if(out[2]->hasoutput)
841                                 out[2]->data= node_composit_get_zimage(node, data);
842                         
843                         generate_preview(node, stackbuf);
844                 }
845         }       
846 }
847
848 /* uses node->storage to indicate animated image */
849
850 static bNodeType cmp_node_image= {
851         /* type code   */       CMP_NODE_IMAGE,
852         /* name        */       "Image",
853         /* width+range */       120, 80, 300,
854         /* class+opts  */       NODE_CLASS_INPUT, NODE_PREVIEW|NODE_OPTIONS,
855         /* input sock  */       NULL,
856         /* output sock */       cmp_node_image_out,
857         /* storage     */       "NodeImageAnim",
858         /* execfunc    */       node_composit_exec_image
859         
860 };
861
862 /* **************** RENDER RESULT ******************** */
863
864 /* output socket defines */
865 #define RRES_OUT_IMAGE  0
866 #define RRES_OUT_ALPHA  1
867 #define RRES_OUT_Z              2
868 #define RRES_OUT_NOR    3
869 #define RRES_OUT_VEC    4
870 #define RRES_OUT_COL    5
871 #define RRES_OUT_DIFF   6
872 #define RRES_OUT_SPEC   7
873 #define RRES_OUT_SHAD   8
874 #define RRES_OUT_AO             9
875 #define RRES_OUT_RAY    10
876
877 static bNodeSocketType cmp_node_rresult_out[]= {
878         {       SOCK_RGBA, 0, "Image",          0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
879         {       SOCK_VALUE, 0, "Alpha",         1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
880         {       SOCK_VALUE, 0, "Z",                     1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
881         {       SOCK_VECTOR, 0, "Normal",       0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
882         {       SOCK_VECTOR, 0, "Speed",        1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
883 //      {       SOCK_RGBA, 0, "Color",          0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
884 //      {       SOCK_RGBA, 0, "Diffuse",        0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
885 //      {       SOCK_RGBA, 0, "Specular",       0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
886 //      {       SOCK_RGBA, 0, "Shadow",         0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
887 //      {       SOCK_RGBA, 0, "AO",                     0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
888 //      {       SOCK_RGBA, 0, "Ray",            0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
889         {       -1, 0, ""       }
890 };
891
892
893 static CompBuf *compbuf_from_pass(RenderData *rd, RenderLayer *rl, int rectx, int recty, int passcode)
894 {
895         float *fp= RE_RenderLayerGetPass(rl, passcode);
896         if(fp) {
897                 CompBuf *buf;
898                 int buftype= CB_VEC3;
899                 
900                 if(passcode==SCE_PASS_Z)
901                         buftype= CB_VAL;
902                 else if(passcode==SCE_PASS_VECTOR)
903                         buftype= CB_VEC4;
904                 else if(passcode==SCE_PASS_RGBA)
905                         buftype= CB_RGBA;
906
907                 if(rd->scemode & R_COMP_CROP)
908                         buf= get_cropped_compbuf(&rd->disprect, fp, rectx, recty, buftype);
909                 else {
910                         buf= alloc_compbuf(rectx, recty, buftype, 0);
911                         buf->rect= fp;
912                 }
913                 return buf;
914         }
915         return NULL;
916 }
917
918 static void node_composit_exec_rresult(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
919 {
920         RenderData *rd= data;
921         RenderResult *rr;
922         
923         if(node->id && node->id!=&G.scene->id)
924                 rr= RE_GetResult(RE_GetRender(node->id->name+2));
925         else
926                 rr= RE_GetResult(RE_GetRender("Render"));
927                 
928         if(rr) {
929                 RenderLayer *rl= BLI_findlink(&rr->layers, node->custom1);
930                 if(rl) {
931                         CompBuf *stackbuf;
932                         
933                         /* we put render rect on stack, cbuf knows rect is from other ibuf when freed! */
934                         if(rd->scemode & R_COMP_CROP)
935                                 stackbuf= get_cropped_compbuf(&rd->disprect, rl->rectf, rr->rectx, rr->recty, CB_RGBA);
936                         else {
937                                 stackbuf= alloc_compbuf(rr->rectx, rr->recty, CB_RGBA, 0);
938                                 stackbuf->rect= rl->rectf;
939                         }
940                         
941                         /* put on stack */      
942                         out[RRES_OUT_IMAGE]->data= stackbuf;
943                         
944                         if(out[RRES_OUT_ALPHA]->hasoutput)
945                                 out[RRES_OUT_ALPHA]->data= valbuf_from_rgbabuf(stackbuf, CHAN_A);
946                         if(out[RRES_OUT_Z]->hasoutput)
947                                 out[RRES_OUT_Z]->data= compbuf_from_pass(rd, rl, rr->rectx, rr->recty, SCE_PASS_Z);
948                         if(out[RRES_OUT_VEC]->hasoutput)
949                                 out[RRES_OUT_VEC]->data= compbuf_from_pass(rd, rl, rr->rectx, rr->recty, SCE_PASS_VECTOR);
950                         if(out[RRES_OUT_NOR]->hasoutput)
951                                 out[RRES_OUT_NOR]->data= compbuf_from_pass(rd, rl, rr->rectx, rr->recty, SCE_PASS_NORMAL);
952 /*                      
953                         if(out[RRES_OUT_COL]->hasoutput)
954                                 out[RRES_OUT_COL]->data= compbuf_from_pass(rd, rl, rr->rectx, rr->recty, SCE_PASS_RGBA);
955                         if(out[RRES_OUT_DIFF]->hasoutput)
956                                 out[RRES_OUT_DIFF]->data= compbuf_from_pass(rd, rl, rr->rectx, rr->recty, SCE_PASS_DIFFUSE);
957                         if(out[RRES_OUT_SPEC]->hasoutput)
958                                 out[RRES_OUT_SPEC]->data= compbuf_from_pass(rd, rl, rr->rectx, rr->recty, SCE_PASS_SPEC);
959                         if(out[RRES_OUT_SHAD]->hasoutput)
960                                 out[RRES_OUT_SHAD]->data= compbuf_from_pass(rd, rl, rr->rectx, rr->recty, SCE_PASS_SHADOW);
961                         if(out[RRES_OUT_AO]->hasoutput)
962                                 out[RRES_OUT_AO]->data= compbuf_from_pass(rd, rl, rr->rectx, rr->recty, SCE_PASS_AO);
963                         if(out[RRES_OUT_RAY]->hasoutput)
964                                 out[RRES_OUT_RAY]->data= compbuf_from_pass(rd, rl, rr->rectx, rr->recty, SCE_PASS_RAY);
965 */                      
966                         generate_preview(node, stackbuf);
967                 }
968         }       
969 }
970
971 /* custom1 = render layer in use */
972 static bNodeType cmp_node_rresult= {
973         /* type code   */       CMP_NODE_R_RESULT,
974         /* name        */       "Render Result",
975         /* width+range */       120, 80, 300,
976         /* class+opts  */       NODE_CLASS_INPUT, NODE_PREVIEW|NODE_OPTIONS,
977         /* input sock  */       NULL,
978         /* output sock */       cmp_node_rresult_out,
979         /* storage     */       "",
980         /* execfunc    */       node_composit_exec_rresult
981         
982 };
983
984 /* **************** TEXTURE ******************** */
985 static bNodeSocketType cmp_node_texture_in[]= {
986         {       SOCK_VECTOR, 0, "Offset",               0.0f, 0.0f, 0.0f, 0.0f, -2.0f, 2.0f},
987         {       SOCK_VECTOR, 0, "Scale",                1.0f, 1.0f, 1.0f, 1.0f, -10.0f, 10.0f},
988         {       -1, 0, ""       }
989 };
990 static bNodeSocketType cmp_node_texture_out[]= {
991         {       SOCK_VALUE, 0, "Value",         1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
992         {       SOCK_RGBA , 0, "Color",         1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f},
993         {       -1, 0, ""       }
994 };
995
996 /* called without rect allocated */
997 static void texture_procedural(CompBuf *cbuf, float *col, float xco, float yco)
998 {
999         bNode *node= cbuf->node;
1000         bNodeSocket *sock= node->inputs.first;
1001         TexResult texres;
1002         float vec[3], *size, nor[3]={0.0f, 0.0f, 0.0f};
1003         int retval, type= cbuf->type;
1004         
1005         texres.nor= NULL;
1006         size= sock->next->ns.vec;
1007         
1008         vec[0]= size[0]*(xco + sock->ns.vec[0]);
1009         vec[1]= size[1]*(yco + sock->ns.vec[1]);
1010         vec[2]= size[2]*sock->ns.vec[2];
1011         
1012         retval= multitex((Tex *)node->id, vec, NULL, NULL, 0, &texres);
1013         
1014         if(type==CB_VAL) {
1015                 if(texres.talpha)
1016                         col[0]= texres.ta;
1017                 else
1018                         col[0]= texres.tin;
1019         }
1020         else if(type==CB_RGBA) {
1021                 if(texres.talpha)
1022                         col[3]= texres.ta;
1023                 else
1024                         col[3]= texres.tin;
1025                 
1026                 if((retval & TEX_RGB)) {
1027                         col[0]= texres.tr;
1028                         col[1]= texres.tg;
1029                         col[2]= texres.tb;
1030                 }
1031                 else col[0]= col[1]= col[2]= col[3];
1032         }
1033         else { 
1034                 VECCOPY(col, nor);
1035         }
1036 }
1037
1038 /* texture node outputs get a small rect, to make sure all other nodes accept it */
1039 /* only the pixel-processor nodes do something with it though */
1040 static void node_composit_exec_texture(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
1041 {
1042         /* outputs: value, color, normal */
1043         
1044         if(node->id) {
1045                 /* first make the preview image */
1046                 CompBuf *prevbuf= alloc_compbuf(140, 140, CB_RGBA, 1); // alloc
1047                 
1048                 prevbuf->rect_procedural= texture_procedural;
1049                 prevbuf->node= node;
1050                 composit1_pixel_processor(node, prevbuf, prevbuf, out[0]->vec, do_copy_rgba, CB_RGBA);
1051                 generate_preview(node, prevbuf);
1052                 free_compbuf(prevbuf);
1053                 
1054                 if(out[0]->hasoutput) {
1055                         CompBuf *stackbuf= alloc_compbuf(140, 140, CB_VAL, 1); // alloc
1056                         
1057                         stackbuf->rect_procedural= texture_procedural;
1058                         stackbuf->node= node;
1059                         
1060                         out[0]->data= stackbuf;
1061                 }
1062                 if(out[1]->hasoutput) {
1063                         CompBuf *stackbuf= alloc_compbuf(140, 140, CB_RGBA, 1); // alloc
1064                         
1065                         stackbuf->rect_procedural= texture_procedural;
1066                         stackbuf->node= node;
1067                         
1068                         out[1]->data= stackbuf;
1069                 }
1070         }
1071 }
1072
1073 static bNodeType cmp_node_texture= {
1074         /* type code   */       CMP_NODE_TEXTURE,
1075         /* name        */       "Texture",
1076         /* width+range */       120, 80, 240,
1077         /* class+opts  */       NODE_CLASS_INPUT, NODE_OPTIONS|NODE_PREVIEW,
1078         /* input sock  */       cmp_node_texture_in,
1079         /* output sock */       cmp_node_texture_out,
1080         /* storage     */       "",
1081         /* execfunc    */       node_composit_exec_texture
1082         
1083 };
1084
1085 /* **************** NORMAL  ******************** */
1086 static bNodeSocketType cmp_node_normal_in[]= {
1087         {       SOCK_VECTOR, 1, "Normal",       0.0f, 0.0f, 0.0f, 1.0f, -1.0f, 1.0f},
1088         {       -1, 0, ""       }
1089 };
1090
1091 static bNodeSocketType cmp_node_normal_out[]= {
1092         {       SOCK_VECTOR, 0, "Normal",       0.0f, 0.0f, 1.0f, 1.0f, -1.0f, 1.0f},
1093         {       SOCK_VALUE, 0, "Dot",           1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
1094         {       -1, 0, ""       }
1095 };
1096
1097 static void do_normal(bNode *node, float *out, float *in)
1098 {
1099         bNodeSocket *sock= node->outputs.first;
1100         float *nor= sock->ns.vec;
1101         
1102         /* render normals point inside... the widget points outside */
1103         out[0]= -INPR(nor, in);
1104 }
1105
1106 /* generates normal, does dot product */
1107 static void node_composit_exec_normal(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
1108 {
1109         bNodeSocket *sock= node->outputs.first;
1110         /* stack order input:  normal */
1111         /* stack order output: normal, value */
1112         
1113         /* input no image? then only vector op */
1114         if(in[0]->data==NULL) {
1115                 VECCOPY(out[0]->vec, sock->ns.vec);
1116                 /* render normals point inside... the widget points outside */
1117                 out[1]->vec[0]= -INPR(out[0]->vec, in[0]->vec);
1118         }
1119         else if(out[1]->hasoutput) {
1120                 /* make output size of input image */
1121                 CompBuf *cbuf= in[0]->data;
1122                 CompBuf *stackbuf= alloc_compbuf(cbuf->x, cbuf->y, CB_VAL, 1); // allocs
1123                 
1124                 composit1_pixel_processor(node, stackbuf, in[0]->data, in[0]->vec, do_normal, CB_VEC3);
1125                 
1126                 out[1]->data= stackbuf;
1127         }
1128         
1129         
1130 }
1131
1132 static bNodeType cmp_node_normal= {
1133         /* type code   */       CMP_NODE_NORMAL,
1134         /* name        */       "Normal",
1135         /* width+range */       100, 60, 200,
1136         /* class+opts  */       NODE_CLASS_OP_VECTOR, NODE_OPTIONS,
1137         /* input sock  */       cmp_node_normal_in,
1138         /* output sock */       cmp_node_normal_out,
1139         /* storage     */       "",
1140         /* execfunc    */       node_composit_exec_normal
1141         
1142 };
1143
1144 /* **************** CURVE Time  ******************** */
1145
1146 /* custom1 = sfra, custom2 = efra */
1147 static bNodeSocketType cmp_node_time_out[]= {
1148         {       SOCK_VALUE, 0, "Fac",   1.0f, 0.0f, 1.0f, 1.0f, 0.0f, 1.0f},
1149         {       -1, 0, ""       }
1150 };
1151
1152 static void node_composit_exec_time(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
1153 {
1154         /* stack order output: fac */
1155         float fac= 0.0f;
1156         
1157         if(node->custom1 < node->custom2)
1158                 fac= (G.scene->r.cfra - node->custom1)/(float)(node->custom2-node->custom1);
1159         
1160         out[0]->vec[0]= curvemapping_evaluateF(node->storage, 0, fac);
1161 }
1162
1163 static bNodeType cmp_node_time= {
1164         /* type code   */       CMP_NODE_TIME,
1165         /* name        */       "Time",
1166         /* width+range */       140, 100, 320,
1167         /* class+opts  */       NODE_CLASS_GENERATOR, NODE_OPTIONS,
1168         /* input sock  */       NULL,
1169         /* output sock */       cmp_node_time_out,
1170         /* storage     */       "CurveMapping",
1171         /* execfunc    */       node_composit_exec_time
1172 };
1173
1174 /* **************** CURVE VEC  ******************** */
1175 static bNodeSocketType cmp_node_curve_vec_in[]= {
1176         {       SOCK_VECTOR, 1, "Vector",       0.0f, 0.0f, 0.0f, 1.0f, -1.0f, 1.0f},
1177         {       -1, 0, ""       }
1178 };
1179
1180 static bNodeSocketType cmp_node_curve_vec_out[]= {
1181         {       SOCK_VECTOR, 0, "Vector",       0.0f, 0.0f, 1.0f, 1.0f, -1.0f, 1.0f},
1182         {       -1, 0, ""       }
1183 };
1184
1185 static void node_composit_exec_curve_vec(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
1186 {
1187         /* stack order input:  vec */
1188         /* stack order output: vec */
1189         
1190         curvemapping_evaluate_premulRGBF(node->storage, out[0]->vec, in[0]->vec);
1191 }
1192
1193 static bNodeType cmp_node_curve_vec= {
1194         /* type code   */       CMP_NODE_CURVE_VEC,
1195         /* name        */       "Vector Curves",
1196         /* width+range */       200, 140, 320,
1197         /* class+opts  */       NODE_CLASS_OP_VECTOR, NODE_OPTIONS,
1198         /* input sock  */       cmp_node_curve_vec_in,
1199         /* output sock */       cmp_node_curve_vec_out,
1200         /* storage     */       "CurveMapping",
1201         /* execfunc    */       node_composit_exec_curve_vec
1202         
1203 };
1204
1205 /* **************** CURVE RGB  ******************** */
1206 static bNodeSocketType cmp_node_curve_rgb_in[]= {
1207         {       SOCK_VALUE, 1, "Fac",   1.0f, 0.0f, 0.0f, 1.0f, -1.0f, 1.0f},
1208         {       SOCK_RGBA, 1, "Image",  0.0f, 0.0f, 0.0f, 1.0f, -1.0f, 1.0f},
1209         {       -1, 0, ""       }
1210 };
1211
1212 static bNodeSocketType cmp_node_curve_rgb_out[]= {
1213         {       SOCK_RGBA, 0, "Image",  0.0f, 0.0f, 1.0f, 1.0f, -1.0f, 1.0f},
1214         {       -1, 0, ""       }
1215 };
1216
1217 static void do_curves(bNode *node, float *out, float *in)
1218 {
1219         curvemapping_evaluate_premulRGBF(node->storage, out, in);
1220         out[3]= in[3];
1221 }
1222
1223 static void do_curves_fac(bNode *node, float *out, float *in, float *fac)
1224 {
1225         
1226         if(*fac>=1.0)
1227                 curvemapping_evaluate_premulRGBF(node->storage, out, in);
1228         else if(*fac<=0.0) {
1229                 VECCOPY(out, in);
1230         }
1231         else {
1232                 float col[4], mfac= 1.0f-*fac;
1233                 curvemapping_evaluate_premulRGBF(node->storage, col, in);
1234                 out[0]= mfac*in[0] + *fac*col[0];
1235                 out[1]= mfac*in[1] + *fac*col[1];
1236                 out[2]= mfac*in[2] + *fac*col[2];
1237         }
1238         out[3]= in[3];
1239 }
1240
1241 static void node_composit_exec_curve_rgb(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
1242 {
1243         /* stack order input:  fac, image */
1244         /* stack order output: image */
1245         
1246         if(out[0]->hasoutput==0)
1247                 return;
1248
1249         /* input no image? then only color operation */
1250         if(in[1]->data==NULL) {
1251                 curvemapping_evaluateRGBF(node->storage, out[0]->vec, in[1]->vec);
1252         }
1253         else {
1254                 /* make output size of input image */
1255                 CompBuf *cbuf= in[1]->data;
1256                 CompBuf *stackbuf= alloc_compbuf(cbuf->x, cbuf->y, CB_RGBA, 1); // allocs
1257                 
1258                 if(in[0]->data)
1259                         composit2_pixel_processor(node, stackbuf, in[1]->data, in[1]->vec, in[0]->data, in[0]->vec, do_curves_fac, CB_RGBA, CB_VAL);
1260                 else
1261                         composit1_pixel_processor(node, stackbuf, in[1]->data, in[1]->vec, do_curves, CB_RGBA);
1262                 
1263                 out[0]->data= stackbuf;
1264         }
1265         
1266 }
1267
1268 static bNodeType cmp_node_curve_rgb= {
1269         /* type code   */       CMP_NODE_CURVE_RGB,
1270         /* name        */       "RGB Curves",
1271         /* width+range */       200, 140, 320,
1272         /* class+opts  */       NODE_CLASS_OP_COLOR, NODE_OPTIONS,
1273         /* input sock  */       cmp_node_curve_rgb_in,
1274         /* output sock */       cmp_node_curve_rgb_out,
1275         /* storage     */       "CurveMapping",
1276         /* execfunc    */       node_composit_exec_curve_rgb
1277         
1278 };
1279
1280 /* **************** VALUE ******************** */
1281 static bNodeSocketType cmp_node_value_out[]= {
1282         {       SOCK_VALUE, 0, "Value",         0.5f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
1283         {       -1, 0, ""       }
1284 };
1285
1286 static void node_composit_exec_value(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
1287 {
1288         bNodeSocket *sock= node->outputs.first;
1289         
1290         out[0]->vec[0]= sock->ns.vec[0];
1291 }
1292
1293 static bNodeType cmp_node_value= {
1294         /* type code   */       CMP_NODE_VALUE,
1295         /* name        */       "Value",
1296         /* width+range */       80, 40, 120,
1297         /* class+opts  */       NODE_CLASS_GENERATOR, NODE_OPTIONS,
1298         /* input sock  */       NULL,
1299         /* output sock */       cmp_node_value_out,
1300         /* storage     */       "", 
1301         /* execfunc    */       node_composit_exec_value
1302         
1303 };
1304
1305 /* **************** RGB ******************** */
1306 static bNodeSocketType cmp_node_rgb_out[]= {
1307         {       SOCK_RGBA, 0, "RGBA",                   0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f},
1308         {       -1, 0, ""       }
1309 };
1310
1311 static void node_composit_exec_rgb(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
1312 {
1313         bNodeSocket *sock= node->outputs.first;
1314         
1315         VECCOPY(out[0]->vec, sock->ns.vec);
1316 }
1317
1318 static bNodeType cmp_node_rgb= {
1319         /* type code   */       CMP_NODE_RGB,
1320         /* name        */       "RGB",
1321         /* width+range */       100, 60, 140,
1322         /* class+opts  */       NODE_CLASS_GENERATOR, NODE_OPTIONS,
1323         /* input sock  */       NULL,
1324         /* output sock */       cmp_node_rgb_out,
1325         /* storage     */       "",
1326         /* execfunc    */       node_composit_exec_rgb
1327         
1328 };
1329
1330 /* **************** Hue Saturation ******************** */
1331 static bNodeSocketType cmp_node_hue_sat_in[]= {
1332         {       SOCK_VALUE, 1, "Fac",                   1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
1333         {       SOCK_RGBA, 1, "Image",                  0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f},
1334         {       -1, 0, ""       }
1335 };
1336 static bNodeSocketType cmp_node_hue_sat_out[]= {
1337         {       SOCK_RGBA, 0, "Image",                  0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
1338         {       -1, 0, ""       }
1339 };
1340
1341 static void do_hue_sat_fac(bNode *node, float *out, float *in, float *fac)
1342 {
1343         NodeHueSat *nhs= node->storage;
1344         
1345         if(*fac!=0.0f && (nhs->hue!=0.5f || nhs->sat!=1.0)) {
1346                 float col[3], hsv[3], mfac= 1.0f - *fac;
1347                 
1348                 rgb_to_hsv(in[0], in[1], in[2], hsv, hsv+1, hsv+2);
1349                 hsv[0]+= (nhs->hue - 0.5f);
1350                 if(hsv[0]>1.0) hsv[0]-=1.0; else if(hsv[0]<0.0) hsv[0]+= 1.0;
1351                 hsv[1]*= nhs->sat;
1352                 if(hsv[1]>1.0) hsv[1]= 1.0; else if(hsv[1]<0.0) hsv[1]= 0.0;
1353                 hsv_to_rgb(hsv[0], hsv[1], hsv[2], col, col+1, col+2);
1354                 
1355                 out[0]= mfac*in[0] + *fac*col[0];
1356                 out[1]= mfac*in[1] + *fac*col[1];
1357                 out[2]= mfac*in[2] + *fac*col[2];
1358                 out[3]= in[3];
1359         }
1360         else {
1361                 QUATCOPY(out, in);
1362         }
1363 }
1364
1365 static void node_composit_exec_hue_sat(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
1366 {
1367         /* stack order in: Fac, Image */
1368         /* stack order out: Image */
1369         if(out[0]->hasoutput==0) return;
1370         
1371         /* input no image? then only color operation */
1372         if(in[1]->data==NULL) {
1373                 do_hue_sat_fac(node, out[0]->vec, in[1]->vec, in[0]->vec);
1374         }
1375         else {
1376                 /* make output size of input image */
1377                 CompBuf *cbuf= in[1]->data;
1378                 CompBuf *stackbuf= alloc_compbuf(cbuf->x, cbuf->y, CB_RGBA, 1); // allocs
1379                 
1380                 composit2_pixel_processor(node, stackbuf, cbuf, in[1]->vec, in[0]->data, in[0]->vec, do_hue_sat_fac, CB_RGBA, CB_VAL);
1381
1382                 out[0]->data= stackbuf;
1383         }
1384 }
1385
1386 static bNodeType cmp_node_hue_sat= {
1387         /* type code   */       CMP_NODE_HUE_SAT,
1388         /* name        */       "Hue Saturation",
1389         /* width+range */       150, 80, 250,
1390         /* class+opts  */       NODE_CLASS_OP_COLOR, NODE_OPTIONS,
1391         /* input sock  */       cmp_node_hue_sat_in,
1392         /* output sock */       cmp_node_hue_sat_out,
1393         /* storage     */       "NodeHueSat", 
1394         /* execfunc    */       node_composit_exec_hue_sat
1395         
1396 };
1397
1398 /* **************** MIX RGB ******************** */
1399 static bNodeSocketType cmp_node_mix_rgb_in[]= {
1400         {       SOCK_VALUE, 1, "Fac",                   0.5f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
1401         {       SOCK_RGBA, 1, "Image",                  0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f},
1402         {       SOCK_RGBA, 1, "Image",                  0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f},
1403         {       -1, 0, ""       }
1404 };
1405 static bNodeSocketType cmp_node_mix_rgb_out[]= {
1406         {       SOCK_RGBA, 0, "Image",                  0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
1407         {       -1, 0, ""       }
1408 };
1409
1410 static void do_mix_rgb(bNode *node, float *out, float *in1, float *in2, float fac)
1411 {
1412         float col[3];
1413         
1414         VECCOPY(col, in1);
1415         ramp_blend(node->custom1, col, col+1, col+2, fac, in2);
1416         VECCOPY(out, col);
1417         out[3]= in1[3];
1418 }
1419
1420 static void node_composit_exec_mix_rgb(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
1421 {
1422         /* stack order in: fac, Image, Image */
1423         /* stack order out: Image */
1424         float fac= in[0]->vec[0];
1425         
1426         if(out[0]->hasoutput==0) return;
1427         
1428         CLAMP(fac, 0.0f, 1.0f);
1429         
1430         /* input no image? then only color operation */
1431         if(in[1]->data==NULL && in[2]->data==NULL) {
1432                 do_mix_rgb(node, out[0]->vec, in[1]->vec, in[2]->vec, fac);
1433         }
1434         else {
1435                 /* make output size of first available input image */
1436                 CompBuf *cbuf= in[1]->data?in[1]->data:in[2]->data;
1437                 CompBuf *stackbuf= alloc_compbuf(cbuf->x, cbuf->y, CB_RGBA, 1); // allocs
1438                 
1439                 composit3_pixel_processor(node, stackbuf, in[1]->data, in[1]->vec, in[2]->data, in[2]->vec, in[0]->data, fac, do_mix_rgb, CB_RGBA, CB_RGBA, CB_VAL);
1440                 
1441                 out[0]->data= stackbuf;
1442         }
1443 }
1444
1445 /* custom1 = mix type */
1446 static bNodeType cmp_node_mix_rgb= {
1447         /* type code   */       CMP_NODE_MIX_RGB,
1448         /* name        */       "Mix",
1449         /* width+range */       80, 40, 120,
1450         /* class+opts  */       NODE_CLASS_OP_COLOR, NODE_OPTIONS,
1451         /* input sock  */       cmp_node_mix_rgb_in,
1452         /* output sock */       cmp_node_mix_rgb_out,
1453         /* storage     */       "", 
1454         /* execfunc    */       node_composit_exec_mix_rgb
1455         
1456 };
1457
1458 /* **************** FILTER  ******************** */
1459 static bNodeSocketType cmp_node_filter_in[]= {
1460         {       SOCK_VALUE, 1, "Fac",                   1.0f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f},
1461         {       SOCK_RGBA, 1, "Image",                  0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f},
1462         {       -1, 0, ""       }
1463 };
1464 static bNodeSocketType cmp_node_filter_out[]= {
1465         {       SOCK_RGBA, 0, "Image",                  0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
1466         {       -1, 0, ""       }
1467 };
1468
1469 static void do_filter_edge(CompBuf *out, CompBuf *in, float *filter, float fac)
1470 {
1471         float *row1, *row2, *row3;
1472         float *fp, f1, f2, mfac= 1.0f-fac;
1473         int rowlen, x, y, c, pix= in->type;
1474         
1475         rowlen= in->x;
1476         
1477         for(y=2; y<in->y; y++) {
1478                 /* setup rows */
1479                 row1= in->rect + pix*(y-2)*rowlen;
1480                 row2= row1 + pix*rowlen;
1481                 row3= row2 + pix*rowlen;
1482                 fp= out->rect + pix*(y-1)*rowlen + pix;
1483                 
1484                 if(pix==CB_RGBA) {
1485                         for(x=2; x<rowlen; x++) {
1486                                 for(c=0; c<3; c++) {
1487                                         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];
1488                                         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];
1489                                         fp[0]= mfac*row2[4] + fac*sqrt(f1*f1 + f2*f2);
1490                                         fp++; row1++; row2++; row3++;
1491                                 }
1492                                 fp[0]= row2[4];
1493                                 /* no alpha... will clear it completely */
1494                                 fp++; row1++; row2++; row3++;
1495                         }
1496                 }
1497                 else if(pix==CB_VAL) {
1498                         for(x=2; x<rowlen; x++) {
1499                                 f1= filter[0]*row1[0] + filter[1]*row1[1] + filter[2]*row1[2] + filter[3]*row2[0] + filter[4]*row2[1] + filter[5]*row2[2] + filter[6]*row3[0] + filter[7]*row3[1] + filter[8]*row3[2];
1500                                 f2= filter[0]*row1[0] + filter[3]*row1[1] + filter[6]*row1[2] + filter[1]*row2[0] + filter[4]*row2[1] + filter[7]*row2[2] + filter[2]*row3[0] + filter[5]*row3[1] + filter[8]*row3[2];
1501                                 fp[0]= mfac*row2[1] + fac*sqrt(f1*f1 + f2*f2);
1502                                 fp++; row1++; row2++; row3++;
1503                         }
1504                 }
1505         }
1506 }
1507
1508 static void do_filter3(CompBuf *out, CompBuf *in, float *filter, float fac)
1509 {
1510         float *row1, *row2, *row3;
1511         float *fp, mfac= 1.0f-fac;
1512         int rowlen, x, y, c;
1513         int pixlen= in->type;
1514         
1515         rowlen= in->x;
1516         
1517         for(y=2; y<in->y; y++) {
1518                 /* setup rows */
1519                 row1= in->rect + pixlen*(y-2)*rowlen;
1520                 row2= row1 + pixlen*rowlen;
1521                 row3= row2 + pixlen*rowlen;
1522                 
1523                 fp= out->rect + pixlen*(y-1)*rowlen;
1524                 QUATCOPY(fp, row2);
1525                 fp+= pixlen;
1526                 
1527                 if(pixlen==1) {
1528                         for(x=2; x<rowlen; x++) {
1529                                 fp[0]= mfac*row2[1] + fac*(filter[0]*row1[0] + filter[1]*row1[1] + filter[2]*row1[2] + filter[3]*row2[0] + filter[4]*row2[1] + filter[5]*row2[2] + filter[6]*row3[0] + filter[7]*row3[1] + filter[8]*row3[2]);
1530                                 fp++; row1++; row2++; row3++;
1531                         }
1532                 }
1533                 else if(pixlen==3) {
1534                         for(x=2; x<rowlen; x++) {
1535                                 for(c=0; c<pixlen; c++) {
1536                                         fp[0]= mfac*row2[3] + fac*(filter[0]*row1[0] + filter[1]*row1[3] + filter[2]*row1[6] + filter[3]*row2[0] + filter[4]*row2[3] + filter[5]*row2[6] + filter[6]*row3[0] + filter[7]*row3[3] + filter[8]*row3[6]);
1537                                         fp++; row1++; row2++; row3++;
1538                                 }
1539                         }
1540                 }
1541                 else {
1542                         for(x=2; x<rowlen; x++) {
1543                                 for(c=0; c<pixlen; c++) {
1544                                         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]);
1545                                         fp++; row1++; row2++; row3++;
1546                                 }
1547                         }
1548                 }
1549         }
1550 }
1551
1552
1553 static void node_composit_exec_filter(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
1554 {
1555         static 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};
1556         float sharp[9]= {-1,-1,-1,-1,9,-1,-1,-1,-1};
1557         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};
1558         float sobel[9]= {1,2,1,0,0,0,-1,-2,-1};
1559         float prewitt[9]= {1,1,1,0,0,0,-1,-1,-1};
1560         float kirsch[9]= {5,5,5,-3,-3,-3,-2,-2,-2};
1561         float shadow[9]= {1,2,1,0,1,0,-1,-2,-1};
1562         
1563         if(out[0]->hasoutput==0) return;
1564         
1565         /* stack order in: Image */
1566         /* stack order out: Image */
1567         
1568         if(in[1]->data) {
1569                 /* make output size of first available input image */
1570                 CompBuf *cbuf= in[1]->data;
1571                 CompBuf *stackbuf= alloc_compbuf(cbuf->x, cbuf->y, cbuf->type, 1); // allocs
1572                 
1573                 switch(node->custom1) {
1574                         case CMP_FILT_SOFT:
1575                                 do_filter3(stackbuf, cbuf, soft, in[0]->vec[0]);
1576                                 break;
1577                         case CMP_FILT_SHARP:
1578                                 do_filter3(stackbuf, cbuf, sharp, in[0]->vec[0]);
1579                                 break;
1580                         case CMP_FILT_LAPLACE:
1581                                 do_filter3(stackbuf, cbuf, laplace, in[0]->vec[0]);
1582                                 break;
1583                         case CMP_FILT_SOBEL:
1584                                 do_filter_edge(stackbuf, cbuf, sobel, in[0]->vec[0]);
1585                                 break;
1586                         case CMP_FILT_PREWITT:
1587                                 do_filter_edge(stackbuf, cbuf, prewitt, in[0]->vec[0]);
1588                                 break;
1589                         case CMP_FILT_KIRSCH:
1590                                 do_filter_edge(stackbuf, cbuf, kirsch, in[0]->vec[0]);
1591                                 break;
1592                         case CMP_FILT_SHADOW:
1593                                 do_filter3(stackbuf, cbuf, shadow, in[0]->vec[0]);
1594                                 break;
1595                 }
1596                         
1597                 out[0]->data= stackbuf;
1598         }
1599 }
1600
1601 /* custom1 = filter type */
1602 static bNodeType cmp_node_filter= {
1603         /* type code   */       CMP_NODE_FILTER,
1604         /* name        */       "Filter",
1605         /* width+range */       80, 40, 120,
1606         /* class+opts  */       NODE_CLASS_OP_FILTER, NODE_OPTIONS,
1607         /* input sock  */       cmp_node_filter_in,
1608         /* output sock */       cmp_node_filter_out,
1609         /* storage     */       "", 
1610         /* execfunc    */       node_composit_exec_filter
1611         
1612 };
1613
1614
1615 /* **************** VALTORGB ******************** */
1616 static bNodeSocketType cmp_node_valtorgb_in[]= {
1617         {       SOCK_VALUE, 1, "Fac",                   0.5f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
1618         {       -1, 0, ""       }
1619 };
1620 static bNodeSocketType cmp_node_valtorgb_out[]= {
1621         {       SOCK_RGBA, 0, "Image",                  0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
1622         {       SOCK_VALUE, 0, "Alpha",                 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
1623         {       -1, 0, ""       }
1624 };
1625
1626 static void do_colorband_composit(bNode *node, float *out, float *in)
1627 {
1628         do_colorband(node->storage, in[0], out);
1629 }
1630
1631 static void node_composit_exec_valtorgb(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
1632 {
1633         /* stack order in: fac */
1634         /* stack order out: col, alpha */
1635         
1636         if(out[0]->hasoutput==0 && out[1]->hasoutput==0) 
1637                 return;
1638         
1639         if(node->storage) {
1640                 /* input no image? then only color operation */
1641                 if(in[0]->data==NULL) {
1642                         do_colorband(node->storage, in[0]->vec[0], out[0]->vec);
1643                 }
1644                 else {
1645                         /* make output size of input image */
1646                         CompBuf *cbuf= in[0]->data;
1647                         CompBuf *stackbuf= alloc_compbuf(cbuf->x, cbuf->y, CB_RGBA, 1); // allocs
1648                         
1649                         composit1_pixel_processor(node, stackbuf, in[0]->data, in[0]->vec, do_colorband_composit, CB_VAL);
1650                         
1651                         out[0]->data= stackbuf;
1652                         
1653                         if(out[1]->hasoutput)
1654                                 out[1]->data= valbuf_from_rgbabuf(stackbuf, CHAN_A);
1655
1656                 }
1657         }
1658 }
1659
1660 static bNodeType cmp_node_valtorgb= {
1661         /* type code   */       CMP_NODE_VALTORGB,
1662         /* name        */       "ColorRamp",
1663         /* width+range */       240, 200, 300,
1664         /* class+opts  */       NODE_CLASS_CONVERTOR, NODE_OPTIONS,
1665         /* input sock  */       cmp_node_valtorgb_in,
1666         /* output sock */       cmp_node_valtorgb_out,
1667         /* storage     */       "ColorBand",
1668         /* execfunc    */       node_composit_exec_valtorgb
1669         
1670 };
1671
1672
1673 /* **************** RGBTOBW ******************** */
1674 static bNodeSocketType cmp_node_rgbtobw_in[]= {
1675         {       SOCK_RGBA, 1, "Image",                  0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f},
1676         {       -1, 0, ""       }
1677 };
1678 static bNodeSocketType cmp_node_rgbtobw_out[]= {
1679         {       SOCK_VALUE, 0, "Val",                   0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
1680         {       -1, 0, ""       }
1681 };
1682
1683 static void do_rgbtobw(bNode *node, float *out, float *in)
1684 {
1685         out[0]= in[0]*0.35f + in[1]*0.45f + in[2]*0.2f;
1686 }
1687
1688 static void node_composit_exec_rgbtobw(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
1689 {
1690         /* stack order out: bw */
1691         /* stack order in: col */
1692         
1693         if(out[0]->hasoutput==0)
1694                 return;
1695         
1696         /* input no image? then only color operation */
1697         if(in[0]->data==NULL) {
1698                 do_rgbtobw(node, out[0]->vec, in[0]->vec);
1699         }
1700         else {
1701                 /* make output size of input image */
1702                 CompBuf *cbuf= in[0]->data;
1703                 CompBuf *stackbuf= alloc_compbuf(cbuf->x, cbuf->y, CB_VAL, 1); // allocs
1704                 
1705                 composit1_pixel_processor(node, stackbuf, in[0]->data, in[0]->vec, do_rgbtobw, CB_RGBA);
1706                 
1707                 out[0]->data= stackbuf;
1708         }
1709 }
1710
1711 static bNodeType cmp_node_rgbtobw= {
1712         /* type code   */       CMP_NODE_RGBTOBW,
1713         /* name        */       "RGB to BW",
1714         /* width+range */       80, 40, 120,
1715         /* class+opts  */       NODE_CLASS_CONVERTOR, 0,
1716         /* input sock  */       cmp_node_rgbtobw_in,
1717         /* output sock */       cmp_node_rgbtobw_out,
1718         /* storage     */       "",
1719         /* execfunc    */       node_composit_exec_rgbtobw
1720         
1721 };
1722
1723 /* **************** SEPARATE RGBA ******************** */
1724 static bNodeSocketType cmp_node_seprgba_in[]= {
1725         {       SOCK_RGBA, 1, "Image",                  0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f},
1726         {       -1, 0, ""       }
1727 };
1728 static bNodeSocketType cmp_node_seprgba_out[]= {
1729         {       SOCK_VALUE, 0, "R",                     0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
1730         {       SOCK_VALUE, 0, "G",                     0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
1731         {       SOCK_VALUE, 0, "B",                     0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
1732         {       SOCK_VALUE, 0, "A",                     0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
1733         {       -1, 0, ""       }
1734 };
1735
1736 static void node_composit_exec_seprgba(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
1737 {
1738         /* stack order out: bw channels */
1739         /* stack order in: col */
1740         
1741         /* input no image? then only color operation */
1742         if(in[0]->data==NULL) {
1743                 out[0]->vec[0] = in[0]->vec[0];
1744                 out[1]->vec[0] = in[0]->vec[1];
1745                 out[2]->vec[0] = in[0]->vec[2];
1746                 out[3]->vec[0] = in[0]->vec[3];
1747         }
1748         else {
1749                 /* make output size of input image */
1750                 CompBuf *cbuf= in[0]->data;
1751
1752                 /* don't do any pixel processing, just copy the stack directly (faster, I presume) */
1753                 if(out[0]->hasoutput)
1754                         out[0]->data= valbuf_from_rgbabuf(cbuf, CHAN_R);
1755                 if(out[1]->hasoutput)
1756                         out[1]->data= valbuf_from_rgbabuf(cbuf, CHAN_G);
1757                 if(out[2]->hasoutput)
1758                         out[2]->data= valbuf_from_rgbabuf(cbuf, CHAN_B);
1759                 if(out[3]->hasoutput)
1760                         out[3]->data= valbuf_from_rgbabuf(cbuf, CHAN_A);
1761         }
1762 }
1763
1764 static bNodeType cmp_node_seprgba= {
1765         /* type code   */       CMP_NODE_SEPRGBA,
1766         /* name        */       "Separate RGBA",
1767         /* width+range */       80, 40, 140,
1768         /* class+opts  */       NODE_CLASS_CONVERTOR, 0,
1769         /* input sock  */       cmp_node_seprgba_in,
1770         /* output sock */       cmp_node_seprgba_out,
1771         /* storage     */       "",
1772         /* execfunc    */       node_composit_exec_seprgba
1773         
1774 };
1775
1776 /* **************** SEPARATE HSVA ******************** */
1777 static bNodeSocketType cmp_node_sephsva_in[]= {
1778         {       SOCK_RGBA, 1, "Image",                  0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f},
1779         {       -1, 0, ""       }
1780 };
1781 static bNodeSocketType cmp_node_sephsva_out[]= {
1782         {       SOCK_VALUE, 0, "H",                     0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
1783         {       SOCK_VALUE, 0, "S",                     0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
1784         {       SOCK_VALUE, 0, "V",                     0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
1785         {       SOCK_VALUE, 0, "A",                     0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
1786         {       -1, 0, ""       }
1787 };
1788
1789 static void do_sephsva(bNode *node, float *out, float *in)
1790 {
1791         float h, s, v;
1792         
1793         rgb_to_hsv(in[0], in[1], in[2], &h, &s, &v);
1794         
1795         out[0]= h;
1796         out[1]= s;
1797         out[2]= v;
1798         out[3]= in[3];
1799 }
1800
1801 static void node_composit_exec_sephsva(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
1802 {
1803         /* stack order out: bw channels */
1804         /* stack order in: col */
1805
1806         /* input no image? then only color operation */
1807         if(in[0]->data==NULL) {
1808                 float h, s, v;
1809         
1810                 rgb_to_hsv(in[0]->vec[0], in[0]->vec[1], in[0]->vec[2], &h, &s, &v);
1811                 
1812                 out[0]->vec[0] = h;
1813                 out[1]->vec[0] = s;
1814                 out[2]->vec[0] = v;
1815                 out[3]->vec[0] = in[0]->vec[3];
1816         }
1817         else if ((out[0]->hasoutput) || (out[1]->hasoutput) || (out[2]->hasoutput) || (out[3]->hasoutput)) {
1818                 /* make output size of input image */
1819                 CompBuf *cbuf= in[0]->data;
1820
1821                 CompBuf *stackbuf= alloc_compbuf(cbuf->x, cbuf->y, CB_RGBA, 1); // allocs
1822
1823                 /* convert the RGB stackbuf to an HSV representation */
1824                 composit1_pixel_processor(node, stackbuf, in[0]->data, in[0]->vec, do_sephsva, CB_RGBA);
1825
1826                 /* separate each of those channels */
1827                 if(out[0]->hasoutput)
1828                         out[0]->data= valbuf_from_rgbabuf(stackbuf, CHAN_R);
1829                 if(out[1]->hasoutput)
1830                         out[1]->data= valbuf_from_rgbabuf(stackbuf, CHAN_G);
1831                 if(out[2]->hasoutput)
1832                         out[2]->data= valbuf_from_rgbabuf(stackbuf, CHAN_B);
1833                 if(out[3]->hasoutput)
1834                         out[3]->data= valbuf_from_rgbabuf(stackbuf, CHAN_A);
1835                         
1836                 free_compbuf(stackbuf);
1837         }
1838 }
1839
1840 static bNodeType cmp_node_sephsva= {
1841         /* type code   */       CMP_NODE_SEPHSVA,
1842         /* name        */       "Separate HSVA",
1843         /* width+range */       80, 40, 140,
1844         /* class+opts  */       NODE_CLASS_CONVERTOR, 0,
1845         /* input sock  */       cmp_node_sephsva_in,
1846         /* output sock */       cmp_node_sephsva_out,
1847         /* storage     */       "",
1848         /* execfunc    */       node_composit_exec_sephsva
1849         
1850 };
1851
1852 /* **************** SET ALPHA ******************** */
1853 static bNodeSocketType cmp_node_setalpha_in[]= {
1854         {       SOCK_RGBA, 1, "Image",                  0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
1855         {       SOCK_VALUE, 1, "Alpha",                 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
1856         {       -1, 0, ""       }
1857 };
1858 static bNodeSocketType cmp_node_setalpha_out[]= {
1859         {       SOCK_RGBA, 0, "Image",  0.0f, 0.0f, 1.0f, 1.0f, -1.0f, 1.0f},
1860         {       -1, 0, ""       }
1861 };
1862
1863 static void node_composit_exec_setalpha(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
1864 {
1865         /* stack order out: RGBA image */
1866         /* stack order in: col, alpha */
1867         
1868         /* input no image? then only color operation */
1869         if(in[0]->data==NULL) {
1870                 out[0]->vec[0] = in[0]->vec[0];
1871                 out[0]->vec[1] = in[0]->vec[1];
1872                 out[0]->vec[2] = in[0]->vec[2];
1873                 out[0]->vec[3] = in[1]->vec[0];
1874         }
1875         else {
1876                 /* make output size of input image */
1877                 CompBuf *cbuf= in[0]->data;
1878                 CompBuf *stackbuf= alloc_compbuf(cbuf->x, cbuf->y, CB_RGBA, 1); // allocs
1879                 
1880                 if(in[1]->data==NULL && in[1]->vec[0]==1.0f) {
1881                         /* pass on image */
1882                         composit1_pixel_processor(node, stackbuf, in[0]->data, in[0]->vec, do_copy_rgb, CB_RGBA);
1883                 }
1884                 else {
1885                         /* send an compbuf or a value to set as alpha - composit2_pixel_processor handles choosing the right one */
1886                         composit2_pixel_processor(node, stackbuf, in[0]->data, in[0]->vec, in[1]->data, in[1]->vec, do_copy_a_rgba, CB_RGBA, CB_VAL);
1887                 }
1888         
1889                 out[0]->data= stackbuf;
1890         }
1891 }
1892
1893 static bNodeType cmp_node_setalpha= {
1894         /* type code   */       CMP_NODE_SETALPHA,
1895         /* name        */       "Set Alpha",
1896         /* width+range */       120, 40, 140,
1897         /* class+opts  */       NODE_CLASS_CONVERTOR, NODE_OPTIONS,
1898         /* input sock  */       cmp_node_setalpha_in,
1899         /* output sock */       cmp_node_setalpha_out,
1900         /* storage     */       "",
1901         /* execfunc    */       node_composit_exec_setalpha
1902         
1903 };
1904
1905 /* **************** ALPHAOVER ******************** */
1906 static bNodeSocketType cmp_node_alphaover_in[]= {
1907         {       SOCK_VALUE, 0, "Fac",                   1.0f, 0.0f, 1.0f, 1.0f, 0.0f, 1.0f},
1908         {       SOCK_RGBA, 1, "Image",                  0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f},
1909         {       SOCK_RGBA, 1, "Image",                  0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f},
1910         {       -1, 0, ""       }
1911 };
1912 static bNodeSocketType cmp_node_alphaover_out[]= {
1913         {       SOCK_RGBA, 0, "Image",                  0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
1914         {       -1, 0, ""       }
1915 };
1916
1917 static void do_alphaover_premul(bNode *node, float *out, float *src, float *over, float fac)
1918 {
1919         
1920         if(over[3]<=0.0f) {
1921                 QUATCOPY(out, src);
1922         }
1923         else if(fac==1.0f && over[3]>=1.0f) {
1924                 QUATCOPY(out, over);
1925         }
1926         else {
1927                 float mul= 1.0f - fac*over[3];
1928
1929                 out[0]= (mul*src[0]) + fac*over[0];
1930                 out[1]= (mul*src[1]) + fac*over[1];
1931                 out[2]= (mul*src[2]) + fac*over[2];
1932                 out[3]= (mul*src[3]) + fac*over[3];
1933         }       
1934 }
1935
1936 /* result will be still premul, but the over part is premulled */
1937 static void do_alphaover_key(bNode *node, float *out, float *src, float *over, float fac)
1938 {
1939         
1940         if(over[3]<=0.0f) {
1941                 QUATCOPY(out, src);
1942         }
1943         else if(fac==1.0f && over[3]>=1.0f) {
1944                 QUATCOPY(out, over);
1945         }
1946         else {
1947                 float premul= fac*over[3];
1948                 float mul= 1.0f - premul;
1949
1950                 out[0]= (mul*src[0]) + premul*over[0];
1951                 out[1]= (mul*src[1]) + premul*over[1];
1952                 out[2]= (mul*src[2]) + premul*over[2];
1953                 out[3]= (mul*src[3]) + fac*over[3];
1954         }
1955 }
1956
1957
1958 static void node_composit_exec_alphaover(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
1959 {
1960         /* stack order in: col col */
1961         /* stack order out: col */
1962         if(out[0]->hasoutput==0) 
1963                 return;
1964         
1965         /* input no image? then only color operation */
1966         if(in[1]->data==NULL) {
1967                 do_alphaover_premul(node, out[0]->vec, in[1]->vec, in[2]->vec, in[0]->vec[0]);
1968         }
1969         else {
1970                 /* make output size of input image */
1971                 CompBuf *cbuf= in[1]->data;
1972                 CompBuf *stackbuf= alloc_compbuf(cbuf->x, cbuf->y, CB_RGBA, 1); // allocs
1973                 
1974                 if(node->custom1)
1975                         composit3_pixel_processor(node, stackbuf, in[1]->data, in[1]->vec, in[2]->data, in[2]->vec, in[0]->data, in[0]->vec[0], do_alphaover_key, CB_RGBA, CB_RGBA, CB_VAL);
1976                 else
1977                         composit3_pixel_processor(node, stackbuf, in[1]->data, in[1]->vec, in[2]->data, in[2]->vec, in[0]->data, in[0]->vec[0], do_alphaover_premul, CB_RGBA, CB_RGBA, CB_VAL);
1978                 
1979                 out[0]->data= stackbuf;
1980         }
1981 }
1982
1983 /* custom1: convert 'over' to premul */
1984 static bNodeType cmp_node_alphaover= {
1985         /* type code   */       CMP_NODE_ALPHAOVER,
1986         /* name        */       "AlphaOver",
1987         /* width+range */       80, 40, 120,
1988         /* class+opts  */       NODE_CLASS_OP_COLOR, NODE_OPTIONS,
1989         /* input sock  */       cmp_node_alphaover_in,
1990         /* output sock */       cmp_node_alphaover_out,
1991         /* storage     */       "",
1992         /* execfunc    */       node_composit_exec_alphaover
1993         
1994 };
1995
1996 /* **************** Z COMBINE ******************** */
1997 static bNodeSocketType cmp_node_zcombine_in[]= {
1998         {       SOCK_RGBA, 1, "Image",          0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f},
1999         {       SOCK_VALUE, 1, "Z",                     0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f},
2000         {       SOCK_RGBA, 1, "Image",          0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f},
2001         {       SOCK_VALUE, 1, "Z",                     0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f},
2002         {       -1, 0, ""       }
2003 };
2004 static bNodeSocketType cmp_node_zcombine_out[]= {
2005         {       SOCK_RGBA, 0, "Image",          0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
2006         {       SOCK_VALUE, 1, "Z",                     0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f},
2007         {       -1, 0, ""       }
2008 };
2009
2010 static void do_zcombine(bNode *node, float *out, float *src1, float *z1, float *src2, float *z2)
2011 {
2012         if(*z1 <= *z2) {
2013                 QUATCOPY(out, src1);
2014         }
2015         else {
2016                 QUATCOPY(out, src2);
2017         }
2018 }
2019
2020 static void node_composit_exec_zcombine(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
2021 {
2022         /* stack order in: col z col z */
2023         /* stack order out: col z */
2024         if(out[0]->hasoutput==0) 
2025                 return;
2026         
2027         /* no input no image do nothing now */
2028         if(in[0]->data==NULL || in[1]->data==NULL || in[2]->data==NULL || in[3]->data==NULL) {
2029                 return;
2030         }
2031         else {
2032                 /* make output size of first input image */
2033                 CompBuf *cbuf= in[0]->data;
2034                 CompBuf *stackbuf= alloc_compbuf(cbuf->x, cbuf->y, CB_RGBA, 1); // allocs
2035                 
2036                 composit4_pixel_processor(node, stackbuf, in[0]->data, in[0]->vec, in[1]->data, in[1]->vec, in[2]->data, in[2]->vec, 
2037                                                                    in[3]->data, in[3]->vec, do_zcombine, CB_RGBA, CB_VAL, CB_RGBA, CB_VAL);
2038                 
2039                 out[0]->data= stackbuf;
2040         }
2041 }
2042
2043 static bNodeType cmp_node_zcombine= {
2044         /* type code   */       CMP_NODE_ZCOMBINE,
2045         /* name        */       "Z Combine",
2046         /* width+range */       80, 40, 120,
2047         /* class+opts  */       NODE_CLASS_OP_COLOR, NODE_OPTIONS,
2048         /* input sock  */       cmp_node_zcombine_in,
2049         /* output sock */       cmp_node_zcombine_out,
2050         /* storage     */       "",
2051         /* execfunc    */       node_composit_exec_zcombine
2052         
2053 };
2054
2055 /* **************** MAP VALUE ******************** */
2056 static bNodeSocketType cmp_node_map_value_in[]= {
2057         {       SOCK_VALUE, 1, "Value",                 1.0f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f},
2058         {       -1, 0, ""       }
2059 };
2060 static bNodeSocketType cmp_node_map_value_out[]= {
2061         {       SOCK_VALUE, 0, "Value",                 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
2062         {       -1, 0, ""       }
2063 };
2064
2065 static void do_map_value(bNode *node, float *out, float *src)
2066 {
2067         TexMapping *texmap= node->storage;
2068         
2069         out[0]= (src[0] + texmap->loc[0])*texmap->size[0];
2070         if(texmap->flag & TEXMAP_CLIP_MIN)
2071                 if(out[0]<texmap->min[0])
2072                         out[0]= texmap->min[0];
2073         if(texmap->flag & TEXMAP_CLIP_MAX)
2074                 if(out[0]>texmap->max[0])
2075                         out[0]= texmap->max[0];
2076 }
2077
2078 static void node_composit_exec_map_value(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
2079 {
2080         /* stack order in: valbuf */
2081         /* stack order out: valbuf */
2082         if(out[0]->hasoutput==0) return;
2083         
2084         /* input no image? then only value operation */
2085         if(in[0]->data==NULL) {
2086                 do_map_value(node, out[0]->vec, in[0]->vec);
2087         }
2088         else {
2089                 /* make output size of input image */
2090                 CompBuf *cbuf= in[0]->data;
2091                 CompBuf *stackbuf= alloc_compbuf(cbuf->x, cbuf->y, CB_VAL, 1); // allocs
2092                 
2093                 composit1_pixel_processor(node, stackbuf, in[0]->data, in[0]->vec, do_map_value, CB_VAL);
2094                 
2095                 out[0]->data= stackbuf;
2096         }
2097 }
2098
2099 static bNodeType cmp_node_map_value= {
2100         /* type code   */       CMP_NODE_MAP_VALUE,
2101         /* name        */       "Map Value",
2102         /* width+range */       100, 60, 150,
2103         /* class+opts  */       NODE_CLASS_OP_VECTOR, NODE_OPTIONS,
2104         /* input sock  */       cmp_node_map_value_in,
2105         /* output sock */       cmp_node_map_value_out,
2106         /* storage     */       "TexMapping",
2107         /* execfunc    */       node_composit_exec_map_value
2108         
2109 };
2110
2111 /* **************** BLUR ******************** */
2112 static bNodeSocketType cmp_node_blur_in[]= {
2113         {       SOCK_RGBA, 1, "Image",                  0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f},
2114         {       SOCK_VALUE, 1, "Size",                  1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
2115         {       -1, 0, ""       }
2116 };
2117 static bNodeSocketType cmp_node_blur_out[]= {
2118         {       SOCK_RGBA, 0, "Image",                  0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
2119         {       -1, 0, ""       }
2120 };
2121
2122 static float *make_gausstab(int filtertype, int rad)
2123 {
2124         float *gausstab, sum, val;
2125         int i, n;
2126         
2127         n = 2 * rad + 1;
2128         
2129         gausstab = (float *) MEM_mallocT(n * sizeof(float), "gauss");
2130         
2131         sum = 0.0f;
2132         for (i = -rad; i <= rad; i++) {
2133                 val= RE_filter_value(filtertype, (float)i/(float)rad);
2134                 sum += val;
2135                 gausstab[i+rad] = val;
2136         }
2137         
2138         sum= 1.0f/sum;
2139         for(i=0; i<n; i++)
2140                 gausstab[i]*= sum;
2141         
2142         return gausstab;
2143 }
2144
2145 static float *make_bloomtab(int rad)
2146 {
2147         float *bloomtab, val;
2148         int i, n;
2149         
2150         n = 2 * rad + 1;
2151         
2152         bloomtab = (float *) MEM_mallocT(n * sizeof(float), "bloom");
2153         
2154         for (i = -rad; i <= rad; i++) {
2155                 val = pow(1.0 - fabs((float)i)/((float)rad), 4.0);
2156                 bloomtab[i+rad] = val;
2157         }
2158         
2159         return bloomtab;
2160 }
2161
2162 /* both input images of same type, either 4 or 1 channel */
2163 static void blur_single_image(CompBuf *new, CompBuf *img, float scale, NodeBlurData *nbd)
2164 {
2165         CompBuf *work;
2166         register float sum, val;
2167         float rval, gval, bval, aval;
2168         float *gausstab, *gausstabcent;
2169         int rad, imgx= img->x, imgy= img->y;
2170         int x, y, pix= img->type;
2171         int i, bigstep;
2172         float *src, *dest;
2173
2174         /* helper image */
2175         work= alloc_compbuf(imgx, imgy, img->type, 1); // allocs
2176         
2177         /* horizontal */
2178         rad = scale*(float)nbd->sizex;
2179         if(rad>imgx/2)
2180                 rad= imgx/2;
2181         else if(rad<1) 
2182                 rad= 1;
2183
2184         gausstab= make_gausstab(nbd->filtertype, rad);
2185         gausstabcent= gausstab+rad;
2186         
2187         for (y = 0; y < imgy; y++) {
2188                 float *srcd= img->rect + pix*(y*img->x);
2189                 
2190                 dest = work->rect + pix*(y * img->x);
2191                 
2192                 for (x = 0; x < imgx ; x++) {
2193                         int minr= x-rad<0?-x:-rad;
2194                         int maxr= x+rad>imgx?imgx-x:rad;
2195                         
2196                         src= srcd + pix*(x+minr);
2197                         
2198                         sum= gval = rval= bval= aval= 0.0f;
2199                         for (i= minr; i < maxr; i++) {
2200                                 val= gausstabcent[i];
2201                                 sum+= val;
2202                                 rval += val * (*src++);
2203                                 if(pix==4) {
2204                                         gval += val * (*src++);
2205                                         bval += val * (*src++);
2206                                         aval += val * (*src++);
2207                                 }
2208                         }
2209                         sum= 1.0f/sum;
2210                         *dest++ = rval*sum;
2211                         if(pix==4) {
2212                                 *dest++ = gval*sum;
2213                                 *dest++ = bval*sum;
2214                                 *dest++ = aval*sum;
2215                         }
2216                 }
2217         }
2218         
2219         /* vertical */
2220         MEM_freeT(gausstab);
2221         
2222         rad = scale*(float)nbd->sizey;
2223         if(rad>imgy/2)
2224                 rad= imgy/2;
2225         else if(rad<1) 
2226                 rad= 1;
2227
2228         gausstab= make_gausstab(nbd->filtertype, rad);
2229         gausstabcent= gausstab+rad;
2230         
2231         bigstep = pix*imgx;
2232         for (x = 0; x < imgx; x++) {
2233                 float *srcd= work->rect + pix*x;
2234                 
2235                 dest = new->rect + pix*x;
2236                 
2237                 for (y = 0; y < imgy ; y++) {
2238                         int minr= y-rad<0?-y:-rad;
2239                         int maxr= y+rad>imgy?imgy-y:rad;
2240                         
2241                         src= srcd + bigstep*(y+minr);
2242                         
2243                         sum= gval = rval= bval= aval= 0.0f;
2244                         for (i= minr; i < maxr; i++) {
2245                                 val= gausstabcent[i];
2246                                 sum+= val;
2247                                 rval += val * src[0];
2248                                 if(pix==4) {
2249                                         gval += val * src[1];
2250                                         bval += val * src[2];
2251                                         aval += val * src[3];
2252                                 }
2253                                 src += bigstep;
2254                         }
2255                         sum= 1.0f/sum;
2256                         dest[0] = rval*sum;
2257                         if(pix==4) {
2258                                 dest[1] = gval*sum;
2259                                 dest[2] = bval*sum;
2260                                 dest[3] = aval*sum;
2261                         }
2262                         dest+= bigstep;
2263                 }
2264         }
2265         
2266         free_compbuf(work);
2267         MEM_freeT(gausstab);
2268 }
2269
2270 /* reference has to be mapped 0-1, and equal in size */
2271 static void bloom_with_reference(CompBuf *new, CompBuf *img, CompBuf *ref, float fac, NodeBlurData *nbd)
2272 {
2273         CompBuf *wbuf;
2274         register float val;
2275         float radxf, radyf;
2276         float **maintabs;
2277         float *gausstabx, *gausstabcenty;
2278         float *gausstaby, *gausstabcentx;
2279         int radx, rady, imgx= img->x, imgy= img->y;
2280         int x, y;
2281         int i, j;
2282         float *src, *dest, *wb;
2283         
2284         wbuf= alloc_compbuf(imgx, imgy, CB_VAL, 1);
2285 //      memset(wbuf->rect, sizeof(float)*imgx*imgy, 0);
2286         
2287         /* horizontal */
2288         radx = (float)nbd->sizex;
2289         if(radx>imgx/2)
2290                 radx= imgx/2;
2291         else if(radx<1) 
2292                 radx= 1;
2293         
2294         /* vertical */
2295         rady = (float)nbd->sizey;
2296         if(rady>imgy/2)
2297                 rady= imgy/2;
2298         else if(rady<1) 
2299                 rady= 1;
2300         
2301         x= MAX2(radx, rady);
2302         maintabs= MEM_mallocT(x*sizeof(void *), "gauss array");
2303         for(i= 0; i<x; i++)
2304                 maintabs[i]= make_bloomtab(i+1);
2305                 
2306         /* vars to store before we go */
2307 //      refd= ref->rect;
2308         src= img->rect;
2309         
2310 //      memset(new->rect, 4*imgx*imgy, 0);
2311         
2312         radxf= (float)radx;
2313         radyf= (float)rady;
2314         
2315         for (y = 0; y < imgy; y++) {
2316                 for (x = 0; x < imgx ; x++, src+=4) {//, refd++) {
2317                         
2318 //                      int refradx= (int)(refd[0]*radxf);
2319 //                      int refrady= (int)(refd[0]*radyf);
2320                         
2321                         int refradx= (int)(radxf*0.3f*src[3]*(src[0]+src[1]+src[2]));
2322                         int refrady= (int)(radyf*0.3f*src[3]*(src[0]+src[1]+src[2]));
2323                         
2324                         if(refradx>radx) refradx= radx;
2325                         else if(refradx<1) refradx= 1;
2326                         if(refrady>rady) refrady= rady;
2327                         else if(refrady<1) refrady= 1;
2328                         
2329                         if(refradx==1 && refrady==1) {
2330                                 wb= wbuf->rect + ( y*imgx + x);
2331                                 dest= new->rect + 4*( y*imgx + x);
2332                                 wb[0]+= 1.0f;
2333                                 dest[0] += src[0];
2334                                 dest[1] += src[1];
2335                                 dest[2] += src[2];
2336                                 dest[3] += src[3];
2337                         }
2338                         else {
2339                                 int minxr= x-refradx<0?-x:-refradx;
2340                                 int maxxr= x+refradx>imgx?imgx-x:refradx;
2341                                 int minyr= y-refrady<0?-y:-refrady;
2342                                 int maxyr= y+refrady>imgy?imgy-y:refrady;
2343                                 
2344                                 float *destd= new->rect + 4*( (y + minyr)*imgx + x + minxr);
2345                                 float *wbufd= wbuf->rect + ( (y + minyr)*imgx + x + minxr);
2346                                 
2347                                 gausstabx= maintabs[refradx-1];
2348                                 gausstabcentx= gausstabx+refradx;
2349                                 gausstaby= maintabs[refrady-1];
2350                                 gausstabcenty= gausstaby+refrady;
2351                                 
2352                                 for (i= minyr; i < maxyr; i++, destd+= 4*imgx, wbufd+= imgx) {
2353                                         dest= destd;
2354                                         wb= wbufd;
2355                                         for (j= minxr; j < maxxr; j++, dest+=4, wb++) {
2356                                                 
2357                                                 val= gausstabcenty[i]*gausstabcentx[j];
2358                                                 wb[0]+= val;
2359                                                 dest[0] += val * src[0];
2360                                                 dest[1] += val * src[1];
2361                                                 dest[2] += val * src[2];
2362                                                 dest[3] += val * src[3];
2363                                         }
2364                                 }
2365                         }
2366                 }
2367         }
2368         
2369         x= imgx*imgy;
2370         dest= new->rect;
2371         wb= wbuf->rect;
2372         while(x--) {
2373                 val= 1.0f/wb[0];
2374                 dest[0]*= val;
2375                 dest[1]*= val;
2376                 dest[2]*= val;
2377                 dest[3]*= val;
2378                 wb++;
2379                 dest+= 4;
2380         }
2381         
2382         free_compbuf(wbuf);
2383         
2384         x= MAX2(radx, rady);
2385         for(i= 0; i<x; i++)
2386                 MEM_freeT(maintabs[i]);
2387         MEM_freeT(maintabs);
2388         
2389 }
2390
2391 /* only accepts RGBA buffers */
2392 static void gamma_correct_compbuf(CompBuf *img, int inversed)
2393 {
2394         float *drect;
2395         int x;
2396         
2397         if(img->type!=CB_RGBA) return;
2398         
2399         drect= img->rect;
2400         if(inversed) {
2401                 for(x=img->x*img->y; x>0; x--, drect+=4) {
2402                         if(drect[0]>0.0f) drect[0]= sqrt(drect[0]); else drect[0]= 0.0f;
2403                         if(drect[1]>0.0f) drect[1]= sqrt(drect[1]); else drect[1]= 0.0f;
2404                         if(drect[2]>0.0f) drect[2]= sqrt(drect[2]); else drect[2]= 0.0f;
2405                 }
2406         }
2407         else {
2408                 for(x=img->x*img->y; x>0; x--, drect+=4) {
2409                         if(drect[0]>0.0f) drect[0]*= drect[0]; else drect[0]= 0.0f;
2410                         if(drect[1]>0.0f) drect[1]*= drect[1]; else drect[1]= 0.0f;
2411                         if(drect[2]>0.0f) drect[2]*= drect[2]; else drect[2]= 0.0f;
2412                 }
2413         }
2414 }
2415 #if 0
2416 static float hexagon_filter(float fi, float fj)
2417 {
2418         fi= fabs(fi);
2419         fj= fabs(fj);
2420         
2421         if(fj>0.33f) {
2422                 fj= (fj-0.33f)/0.66f;
2423                 if(fi+fj>1.0f)
2424                         return 0.0f;
2425                 else
2426                         return 1.0f;
2427         }
2428         else return 1.0f;
2429 }
2430 #endif
2431
2432 /* uses full filter, no horizontal/vertical optimize possible */
2433 /* both images same type, either 1 or 4 channels */
2434 static void bokeh_single_image(CompBuf *new, CompBuf *img, float fac, NodeBlurData *nbd)
2435 {
2436         register float val;
2437         float radxf, radyf;
2438         float *gausstab, *dgauss;
2439         int radx, rady, imgx= img->x, imgy= img->y;
2440         int x, y, pix= img->type;
2441         int i, j;
2442         float *src= NULL, *dest, *srcd= NULL;
2443         
2444         /* horizontal */
2445         radx = fac*(float)nbd->sizex;
2446         if(radx>imgx/2)
2447                 radx= imgx/2;
2448         else if(radx<1) 
2449                 radx= 1;
2450         
2451         /* vertical */
2452         rady = fac*(float)nbd->sizey;
2453         if(rady>imgy/2)
2454                 rady= imgy/2;
2455         else if(rady<1) 
2456                 rady= 1;
2457         
2458         radxf= (float)radx;
2459         radyf= (float)rady;
2460         
2461         /* create a full filter image */
2462         gausstab= MEM_mallocT(sizeof(float)*radx*rady*4, "filter tab");
2463         dgauss= gausstab;
2464         val= 0.0f;
2465         for(j=-rady; j<rady; j++) {
2466                 for(i=-radx; i<radx; i++, dgauss++) {
2467                         float fj= (float)j/radyf;
2468                         float fi= (float)i/radxf;
2469                         float dist= sqrt(fj*fj + fi*fi);
2470                         
2471 //                      *dgauss= hexagon_filter(fi, fj);
2472                         *dgauss= RE_filter_value(nbd->filtertype, 2.0f*dist - 1.0f);
2473
2474                         val+= *dgauss;
2475                 }
2476         }
2477         val= 1.0f/val;
2478         for(j= 4*radx*rady -1; j>=0; j--)
2479                 gausstab[j]*= val;
2480         
2481 //      memset(new->rect, 4*imgx*imgy, 0);
2482         
2483         for (y = -rady+1; y < imgy+rady-1; y++) {
2484                 
2485                 if(y<=0) srcd= img->rect;
2486                 else if(y<imgy) srcd+= pix*imgx;
2487                 else srcd= img->rect + pix*(imgy-1)*imgx;
2488                         
2489                 for (x = -radx+1; x < imgx+radx-1 ; x++) {
2490                         int minxr= x-radx<0?-x:-radx;
2491                         int maxxr= x+radx>imgx?imgx-x:radx;
2492                         int minyr= y-rady<0?-y:-rady;
2493                         int maxyr= y+rady>imgy?imgy-y:rady;
2494                         
2495                         float *destd= new->rect + pix*( (y + minyr)*imgx + x + minxr);
2496                         float *dgausd= gausstab + (minyr+rady)*2*radx + minxr+radx;
2497                         
2498                         if(x<=0) src= srcd;
2499                         else if(x<imgx) src+= pix;
2500                         else src= srcd + pix*(imgx-1);
2501                         
2502                         for (i= minyr; i < maxyr; i++, destd+= pix*imgx, dgausd+= 2*radx) {
2503                                 dest= destd;
2504                                 dgauss= dgausd;
2505                                 for (j= minxr; j < maxxr; j++, dest+=pix, dgauss++) {
2506                                         val= *dgauss;
2507                                         if(val!=0.0f) {
2508                                                 dest[0] += val * src[0];
2509                                                 if(pix>1) {
2510                                                         dest[1] += val * src[1];
2511                                                         dest[2] += val * src[2];
2512                                                         dest[3] += val * src[3];
2513                                                 }
2514                                         }
2515                                 }
2516                         }
2517                 }
2518         }
2519         
2520         MEM_freeT(gausstab);
2521 }
2522
2523
2524 /* reference has to be mapped 0-1, and equal in size */
2525 static void blur_with_reference(CompBuf *new, CompBuf *img, CompBuf *ref, NodeBlurData *nbd)
2526 {
2527         CompBuf *blurbuf, *ref_use;
2528         register float sum, val;
2529         float rval, gval, bval, aval, radxf, radyf;
2530         float **maintabs;
2531         float *gausstabx, *gausstabcenty;
2532         float *gausstaby, *gausstabcentx;
2533         int radx, rady, imgx= img->x, imgy= img->y;
2534         int x, y, pix= img->type;
2535         int i, j;
2536         float *src, *dest, *refd, *blurd;
2537
2538         if(ref->x!=img->x && ref->y!=img->y)
2539                 return;
2540         
2541         ref_use= typecheck_compbuf(ref, CB_VAL);
2542         
2543         /* trick is; we blur the reference image... but only works with clipped values*/
2544         blurbuf= alloc_compbuf(imgx, imgy, CB_VAL, 1);
2545         blurd= blurbuf->rect;
2546         refd= ref_use->rect;
2547         for(x= imgx*imgy; x>0; x--, refd++, blurd++) {
2548                 if(refd[0]<0.0f) blurd[0]= 0.0f;
2549                 else if(refd[0]>1.0f) blurd[0]= 1.0f;
2550                 else blurd[0]= refd[0];
2551         }
2552         
2553         blur_single_image(blurbuf, blurbuf, 1.0f, nbd);
2554         
2555         /* horizontal */
2556         radx = (float)nbd->sizex;
2557         if(radx>imgx/2)
2558                 radx= imgx/2;
2559         else if(radx<1) 
2560                 radx= 1;
2561         
2562         /* vertical */
2563         rady = (float)nbd->sizey;
2564         if(rady>imgy/2)
2565                 rady= imgy/2;
2566         else if(rady<1) 
2567                 rady= 1;
2568         
2569         x= MAX2(radx, rady);
2570         maintabs= MEM_mallocT(x*sizeof(void *), "gauss array");
2571         for(i= 0; i<x; i++)
2572                 maintabs[i]= make_gausstab(nbd->filtertype, i+1);
2573         
2574         refd= blurbuf->rect;
2575         dest= new->rect;
2576         radxf= (float)radx;
2577         radyf= (float)rady;
2578         
2579         for (y = 0; y < imgy; y++) {
2580                 for (x = 0; x < imgx ; x++, dest+=pix, refd++) {
2581                         int refradx= (int)(refd[0]*radxf);
2582                         int refrady= (int)(refd[0]*radyf);
2583                         
2584                         if(refradx>radx) refradx= radx;
2585                         else if(refradx<1) refradx= 1;
2586                         if(refrady>rady) refrady= rady;
2587                         else if(refrady<1) refrady= 1;
2588
2589                         if(refradx==1 && refrady==1) {
2590                                 src= img->rect + pix*( y*imgx + x);
2591                                 if(pix==1)
2592                                         dest[0]= src[0];
2593                                 else
2594                                         QUATCOPY(dest, src);
2595                         }
2596                         else {
2597                                 int minxr= x-refradx<0?-x:-refradx;
2598                                 int maxxr= x+refradx>imgx?imgx-x:refradx;
2599                                 int minyr= y-refrady<0?-y:-refrady;
2600                                 int maxyr= y+refrady>imgy?imgy-y:refrady;
2601         
2602                                 float *srcd= img->rect + pix*( (y + minyr)*imgx + x + minxr);
2603                                 
2604                                 gausstabx= maintabs[refradx-1];
2605                                 gausstabcentx= gausstabx+refradx;
2606                                 gausstaby= maintabs[refrady-1];
2607                                 gausstabcenty= gausstaby+refrady;
2608
2609                                 sum= gval = rval= bval= aval= 0.0f;
2610                                 
2611                                 for (i= minyr; i < maxyr; i++, srcd+= pix*imgx) {
2612                                         src= srcd;
2613                                         for (j= minxr; j < maxxr; j++, src+=pix) {
2614                                         
2615                                                 val= gausstabcenty[i]*gausstabcentx[j];
2616                                                 sum+= val;
2617                                                 rval += val * src[0];
2618                                                 if(pix>1) {
2619                                                         gval += val * src[1];
2620                                                         bval += val * src[2];
2621                                                         aval += val * src[3];
2622                                                 }
2623                                         }
2624                                 }
2625                                 sum= 1.0f/sum;
2626                                 dest[0] = rval*sum;
2627                                 if(pix>1) {
2628                                         dest[1] = gval*sum;
2629                                         dest[2] = bval*sum;
2630                                         dest[3] = aval*sum;
2631                                 }
2632                         }
2633                 }
2634         }
2635         
2636         free_compbuf(blurbuf);
2637         
2638         x= MAX2(radx, rady);
2639         for(i= 0; i<x; i++)
2640                 MEM_freeT(maintabs[i]);
2641         MEM_freeT(maintabs);
2642         
2643         if(ref_use!=ref)
2644                 free_compbuf(ref_use);
2645 }
2646
2647
2648
2649 static void node_composit_exec_blur(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
2650 {
2651         CompBuf *new, *img= in[0]->data;
2652         
2653         if(img==NULL || img->type==CB_VEC3 || out[0]->hasoutput==0)
2654                 return;
2655         
2656         /* if fac input, we do it different */
2657         if(in[1]->data) {
2658                 
2659                 /* make output size of input image */
2660                 new= alloc_compbuf(img->x, img->y, img->type, 1); // allocs
2661                 
2662                 blur_with_reference(new, img, in[1]->data, node->storage);
2663                 
2664                 out[0]->data= new;
2665         }
2666         else {
2667                 if(in[1]->vec[0]==0.0f) {
2668                         /* pass on image */
2669                         new= alloc_compbuf(img->x, img->y, img->type, 0);
2670                         new->rect= img->rect;
2671                 }
2672                 else {
2673                         NodeBlurData *nbd= node->storage;
2674                         CompBuf *gammabuf;
2675                         
2676                         /* make output size of input image */
2677                         new= alloc_compbuf(img->x, img->y, img->type, 1); // allocs
2678                         
2679                         if(nbd->gamma) {
2680                                 gammabuf= dupalloc_compbuf(img);
2681                                 gamma_correct_compbuf(gammabuf, 0);
2682                         }
2683                         else gammabuf= img;
2684                         
2685                         if(nbd->bokeh)
2686                                 bokeh_single_image(new, gammabuf, in[1]->vec[0], nbd);
2687                         else if(1)
2688                                 blur_single_image(new, gammabuf, in[1]->vec[0], nbd);
2689                         else    /* bloom experimental... */
2690                                 bloom_with_reference(new, gammabuf, NULL, in[1]->vec[0], nbd);
2691                         
2692                         if(nbd->gamma) {
2693                                 gamma_correct_compbuf(new, 1);
2694                                 free_compbuf(gammabuf);
2695                         }
2696                 }
2697                 out[0]->data= new;
2698         }
2699 }
2700         
2701
2702 static bNodeType cmp_node_blur= {
2703         /* type code   */       CMP_NODE_BLUR,
2704         /* name        */       "Blur",
2705         /* width+range */       120, 80, 200,
2706         /* class+opts  */       NODE_CLASS_OP_FILTER, NODE_OPTIONS,
2707         /* input sock  */       cmp_node_blur_in,
2708         /* output sock */       cmp_node_blur_out,
2709         /* storage     */       "NodeBlurData",
2710         /* execfunc    */       node_composit_exec_blur
2711         
2712 };
2713
2714 /* **************** VECTOR BLUR ******************** */
2715 static bNodeSocketType cmp_node_vecblur_in[]= {
2716         {       SOCK_RGBA, 1, "Image",                  0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f},
2717         {       SOCK_VALUE, 1, "Z",                     0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
2718         {       SOCK_VECTOR, 1, "Speed",                        0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
2719         {       -1, 0, ""       }
2720 };
2721 static bNodeSocketType cmp_node_vecblur_out[]= {
2722         {       SOCK_RGBA, 0, "Image",                  0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
2723         {       -1, 0, ""       }
2724 };
2725
2726
2727
2728 static void node_composit_exec_vecblur(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
2729 {
2730         NodeBlurData *nbd= node->storage;
2731         CompBuf *new, *img= in[0]->data, *vecbuf= in[2]->data, *zbuf= in[1]->data;
2732         
2733         if(img==NULL || vecbuf==NULL || zbuf==NULL || out[0]->hasoutput==0)
2734                 return;
2735         if(vecbuf->x!=img->x || vecbuf->y!=img->y) {
2736                 printf("ERROR: cannot do different sized vecbuf yet\n");
2737                 return;
2738         }
2739         if(vecbuf->type!=CB_VEC4) {
2740                 printf("ERROR: input should be vecbuf\n");
2741                 return;
2742         }
2743         if(zbuf->type!=CB_VAL) {
2744                 printf("ERROR: input should be zbuf\n");
2745                 return;
2746         }
2747         if(zbuf->x!=img->x || zbuf->y!=img->y) {
2748                 printf("ERROR: cannot do different sized zbuf yet\n");
2749                 return;
2750         }
2751         
2752         new= dupalloc_compbuf(img);
2753         
2754         /* call special zbuffer version */
2755         RE_zbuf_accumulate_vecblur(nbd, img->x, img->y, new->rect, img->rect, vecbuf->rect, zbuf->rect);
2756         
2757         out[0]->data= new;
2758 }
2759
2760 /* custom1: itterations, custom2: maxspeed (0 = nolimit) */
2761 static bNodeType cmp_node_vecblur= {
2762         /* type code   */       CMP_NODE_VECBLUR,
2763         /* name        */       "Vector Blur",
2764         /* width+range */       120, 80, 200,
2765         /* class+opts  */       NODE_CLASS_OP_FILTER, NODE_OPTIONS,
2766         /* input sock  */       cmp_node_vecblur_in,
2767         /* output sock */       cmp_node_vecblur_out,
2768         /* storage     */       "NodeBlurData",
2769         /* execfunc    */       node_composit_exec_vecblur
2770         
2771 };
2772
2773 /* **************** Translate  ******************** */
2774
2775 static bNodeSocketType cmp_node_translate_in[]= {
2776         {       SOCK_RGBA, 1, "Image",                  0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f},
2777         {       SOCK_VALUE, 0, "X",     0.0f, 0.0f, 0.0f, 0.0f, -10000.0f, 10000.0f},
2778         {       SOCK_VALUE, 0, "Y",     0.0f, 0.0f, 0.0f, 0.0f, -10000.0f, 10000.0f},
2779         {       -1, 0, ""       }
2780 };
2781 static bNodeSocketType cmp_node_translate_out[]= {
2782         {       SOCK_RGBA, 0, "Image",                  0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
2783         {       -1, 0, ""       }
2784 };
2785
2786 static void node_composit_exec_translate(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
2787 {
2788         if(in[0]->data) {
2789                 CompBuf *cbuf= in[0]->data;
2790                 CompBuf *stackbuf= alloc_compbuf(cbuf->x, cbuf->y, cbuf->type, 0); // no alloc
2791         
2792                 stackbuf->xof= (int)floor(in[1]->vec[0]);
2793                 stackbuf->yof= (int)floor(in[2]->vec[0]);
2794                 
2795                 stackbuf->rect= cbuf->rect;
2796                 out[0]->data= stackbuf;
2797         }
2798 }
2799
2800 static bNodeType cmp_node_translate= {
2801         /* type code   */       CMP_NODE_TRANSLATE,
2802         /* name        */       "Translate",
2803         /* width+range */       140, 100, 320,
2804         /* class+opts  */       NODE_CLASS_CONVERTOR, NODE_OPTIONS,
2805         /* input sock  */       cmp_node_translate_in,
2806         /* output sock */       cmp_node_translate_out,
2807         /* storage     */       "",
2808         /* execfunc    */       node_composit_exec_translate
2809 };
2810
2811
2812 /* ****************** types array for all shaders ****************** */
2813
2814 bNodeType *node_all_composit[]= {
2815         &node_group_typeinfo,
2816         &cmp_node_composite,
2817         &cmp_node_viewer,
2818         &cmp_node_output_file,
2819         &cmp_node_rresult,
2820         &cmp_node_image,
2821         &cmp_node_curve_rgb,
2822         &cmp_node_mix_rgb,
2823         &cmp_node_hue_sat,
2824         &cmp_node_alphaover,
2825         &cmp_node_value,
2826         &cmp_node_rgb,
2827         &cmp_node_normal,
2828         &cmp_node_curve_vec,
2829         &cmp_node_time,
2830         &cmp_node_filter,
2831         &cmp_node_blur,
2832         &cmp_node_vecblur,
2833         &cmp_node_map_value,
2834         &cmp_node_valtorgb,
2835         &cmp_node_rgbtobw,
2836         &cmp_node_seprgba,
2837         &cmp_node_sephsva,
2838         &cmp_node_setalpha,
2839         &cmp_node_texture,
2840         &cmp_node_translate,
2841         &cmp_node_zcombine,
2842         NULL
2843 };
2844
2845 /* ******************* parse ************ */
2846
2847
2848 /* called from render pipeline, to tag render input and output */
2849 void ntreeCompositTagRender(bNodeTree *ntree)
2850 {
2851         bNode *node;
2852         
2853         if(ntree==NULL) return;
2854         
2855         for(node= ntree->nodes.first; node; node= node->next) {
2856                 if( ELEM(node->type, CMP_NODE_R_RESULT, CMP_NODE_COMPOSITE))
2857                         NodeTagChanged(ntree, node);
2858         }
2859 }
2860
2861 /* tags nodes that have animation capabilities */
2862 void ntreeCompositTagAnimated(bNodeTree *ntree)
2863 {
2864         bNode *node;
2865         
2866         if(ntree==NULL) return;
2867         
2868         for(node= ntree->nodes.first; node; node= node->next) {
2869                 if(node->type==CMP_NODE_IMAGE) {
2870                         /* no actual test yet... */
2871                         if(node->storage)
2872                                 NodeTagChanged(ntree, node);
2873                 }
2874                 else if(node->type==CMP_NODE_TIME)
2875                         NodeTagChanged(ntree, node);
2876         }
2877 }
2878
2879
2880 /* called from image window preview */
2881 void ntreeCompositTagGenerators(bNodeTree *ntree)
2882 {
2883         bNode *node;
2884         
2885         if(ntree==NULL) return;
2886         
2887         for(node= ntree->nodes.first; node; node= node->next) {
2888                 if( ELEM(node->type, CMP_NODE_R_RESULT, CMP_NODE_IMAGE))
2889                         NodeTagChanged(ntree, node);
2890         }
2891 }
2892
2893