60cf84c7f929470fd7b4cf877ada23f397c84325
[blender-staging.git] / source / blender / blenkernel / intern / node_composite.c
1 /**
2  * $Id$
3  *
4  * ***** BEGIN GPL LICENSE BLOCK *****
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (at your option) any later version. 
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software Foundation,
18  * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
19  *
20  * The Original Code is Copyright (C) 2006 Blender Foundation.
21  * All rights reserved.
22  *
23  * The Original Code is: all of this file.
24  *
25  * Contributor(s): none yet.
26  *
27  * ***** END GPL LICENSE BLOCK *****
28  */
29
30 #include <stdlib.h>
31 #include <string.h>
32 #include <math.h>
33
34 #include "DNA_ID.h"
35 #include "DNA_image_types.h"
36 #include "DNA_node_types.h"
37 #include "DNA_material_types.h"
38 #include "DNA_scene_types.h"
39 #include "DNA_texture_types.h"
40 #include "DNA_vec_types.h"
41
42 #include "BKE_blender.h"
43 #include "BKE_colortools.h"
44 #include "BKE_global.h"
45 #include "BKE_image.h"
46 #include "BKE_node.h"
47 #include "BKE_material.h"
48 #include "BKE_texture.h"
49 #include "BKE_utildefines.h"
50
51 #include "BLI_arithb.h"
52 #include "BLI_blenlib.h"
53 #include "BLI_threads.h"
54
55 #include "IMB_imbuf.h"
56 #include "IMB_imbuf_types.h"
57
58 #include "RE_pipeline.h"
59
60 /* *************************** operations support *************************** */
61
62 /* general signal that's in output sockets, and goes over the wires */
63 typedef struct CompBuf {
64         float *rect;
65         int x, y;
66         short type, malloc;
67         rcti disprect;          /* cropped part of image */
68         int xof, yof;           /* relative to center of target image */
69 } CompBuf;
70
71 /* defines also used for pixel size */
72 #define CB_RGBA         4
73 #define CB_VEC3         3
74 #define CB_VEC2         2
75 #define CB_VAL          1
76
77 static CompBuf *alloc_compbuf(int sizex, int sizey, int type, int alloc)
78 {
79         CompBuf *cbuf= MEM_callocT(sizeof(CompBuf), "compbuf");
80         
81         cbuf->x= sizex;
82         cbuf->y= sizey;
83         cbuf->type= type;
84         if(alloc) {
85                 if(cbuf->type==CB_RGBA)
86                         cbuf->rect= MEM_mallocT(4*sizeof(float)*sizex*sizey, "compbuf RGBA rect");
87                 else if(cbuf->type==CB_VEC3)
88                         cbuf->rect= MEM_mallocT(3*sizeof(float)*sizex*sizey, "compbuf Vector3 rect");
89                 else if(cbuf->type==CB_VEC2)
90                         cbuf->rect= MEM_mallocT(2*sizeof(float)*sizex*sizey, "compbuf Vector2 rect");
91                 else
92                         cbuf->rect= MEM_mallocT(sizeof(float)*sizex*sizey, "compbuf Fac rect");
93                 cbuf->malloc= 1;
94         }
95         cbuf->disprect.xmin= 0;
96         cbuf->disprect.ymin= 0;
97         cbuf->disprect.xmax= sizex;
98         cbuf->disprect.ymax= sizey;
99         
100         return cbuf;
101 }
102
103 static CompBuf *dupalloc_compbuf(CompBuf *cbuf)
104 {
105         CompBuf *dupbuf= alloc_compbuf(cbuf->x, cbuf->y, cbuf->type, 1);
106         memcpy(dupbuf->rect, cbuf->rect, cbuf->type*sizeof(float)*cbuf->x*cbuf->y);
107         return dupbuf;
108 }
109
110 void free_compbuf(CompBuf *cbuf)
111 {
112         if(cbuf->malloc && cbuf->rect)
113                 MEM_freeT(cbuf->rect);
114         MEM_freeT(cbuf);
115 }
116
117 void print_compbuf(char *str, CompBuf *cbuf)
118 {
119         printf("Compbuf %s %d %d %p\n", str, cbuf->x, cbuf->y, cbuf->rect);
120         
121 }
122
123
124
125 #if 0
126 /* on first call, disprect should be initialized to 'out', then you can call this on all 'src' images */
127 static void get_overlap_rct(CompBuf *out, CompBuf *src, rcti *disprect)
128 {
129         rcti rect;
130         /* output center is considered (0,0) */
131         
132         if(src==NULL) return;
133         
134         /* translate src into output space */
135         rect= src->disprect;
136         BLI_translate_rcti(&rect, out->xof-src->xof, out->xof-src->xof);
137         /* intersect rect with current disprect */
138         
139         BLI_isect_rcti(&rect, disprect, disprect);
140 }
141
142 static void get_scanline_rcti(CompBuf *out, rcti *disprect, CompBuf *src, rcti *srcrect)
143 {
144         int xof, yof;
145         
146         /* translate src into output space */
147         xof= out->xof-src->xof;
148         yof= out->xof-src->xof;
149         
150         srcrect->xmin= disprect->xmin + xof;
151         srcrect->ymin= disprect->ymin + yof;
152         srcrect->xmax= disprect->xmax + xof;
153         srcrect->ymax= disprect->ymax + yof;
154 }
155 #endif
156
157 /* Pixel-to-Pixel operation, 1 Image in, 1 out */
158 static void composit1_pixel_processor(bNode *node, CompBuf *out, CompBuf *src_buf, float *src_col,
159                                                                           void (*func)(bNode *, float *, float *))
160 {
161         float *outfp, *srcfp, *out_data, *src_data;
162         int outx, outy;
163         int srcx, srcy;
164         int out_pix, out_stride, src_stride, src_pix, x, y;
165         
166         outx= out->x;
167         outy= out->y;
168         out_pix= out->type;
169         out_stride= out->x;
170         out_data= out->rect;
171         
172         /* handle case when input is constant color */
173         if(src_buf==NULL) {
174                 srcx= outx; srcy= outy;
175                 src_stride= 0;
176                 src_pix= 0;
177                 src_data= src_col;
178         }
179         else {
180                 srcx= src_buf->x;
181                 srcy= src_buf->y;
182                 src_stride= srcx;
183                 src_pix= src_buf->type;
184                 src_data= src_buf->rect;
185         }
186         
187         outx= MIN2(outx, srcx);
188         outy= MIN2(outy, srcy);
189
190         for(y=0; y<outy; y++) {
191                 /* set scanlines on right location */
192                 srcfp= src_data + src_pix*y*src_stride;
193                 outfp= out_data + out_pix*y*out_stride;
194                         
195                 for(x=0; x<outx; x++) {
196                         func(node, outfp, srcfp);
197                         srcfp += src_pix;
198                         outfp += out_pix;
199                 }
200         }
201 }
202
203 /* Pixel-to-Pixel operation, 2 Images in, 1 out */
204 static void composit2_pixel_processor(bNode *node, CompBuf *out, CompBuf *src_buf, float *src_col,
205                                                                           CompBuf *fac_buf, float *fac, void (*func)(bNode *, float *, float *, float *))
206 {
207         float *outfp, *srcfp, *src_data, *facfp, *fac_data;
208         int outx= out->x, outy= out->y;
209         int srcx, srcy, facx, facy;
210         int out_pix, src_stride, src_pix, fac_stride, fac_pix, x, y;
211         
212         out_pix= out->type;
213         
214         /* handle case when input is constant color */
215         if(src_buf==NULL) {
216                 srcx= outx; srcy= outy;
217                 src_stride= 0;
218                 src_pix= 0;
219                 src_data= src_col;
220         }
221         else {
222                 srcx= src_buf->x;
223                 srcy= src_buf->y;
224                 src_stride= srcx;
225                 src_pix= src_buf->type;
226                 src_data= src_buf->rect;
227         }
228         
229         /* factor buf or constant? */
230         if(fac_buf==NULL) {
231                 facx= outx; facy= outy;
232                 fac_stride= 0;
233                 fac_pix= 0;
234                 fac_data= fac;
235         }
236         else {
237                 facx= fac_buf->x;
238                 facy= fac_buf->y;
239                 fac_stride= facx;
240                 fac_pix= fac_buf->type;
241                 fac_data= fac_buf->rect;
242         }
243         
244         if(fac_data==NULL) {
245                 printf("fac buffer error, node %s\n", node->name);
246                 return;
247         }
248         
249         facx= MIN2(facx, srcx);
250         facy= MIN2(facy, srcy);
251         
252 #if 0   
253         if(src_buf) {
254                 rcti disprect;
255                 
256                 disprect= out->disprect;
257                 get_overlap_rct(out, src_buf, &disprect);
258                 printf("%s\n", node->name);
259                 printf("union %d %d %d %d\n", disprect.xmin,disprect.ymin,disprect.xmax,disprect.ymax);
260         }
261         /* new approach */
262         outfp= out->rect_float + src.ymin*outx + ;
263         for(y=src.ymin; y<src.ymax; y++) {
264                 
265                 /* all operators available */
266                 if(y>=disp.ymin && y<disp.ymax) {
267                         srcfp= src_data + (src_stride*(y+scrc.ymin) + src.xmin);
268                         facfp= fac_data + (fac_stride*(y+fac.ymin) + fac.xmin);
269                         
270                         for(x= src.xmin; x<src.xmax; x++) {
271                                 if(x>=disp.xmin && x<disp.xmax) {
272                                         
273                                         srcfp+= src_pix;
274                                         facfp+= fac_pix;
275                                 }
276                                 else {
277                                         /* copy src1 */
278                                 }
279                         }
280                 }
281                 else {
282                         /* copy src1 */
283                         srcfp= src_data + (src_stride*(y+scrc.ymin) + src.xmin);
284                         
285                         QUATCOPY(outfp, srcfp);
286                 }
287         }       
288 #endif
289         
290         outfp= out->rect;
291         for(y=0; y<outy; y++) {
292                 /* set source scanline on right location */
293                 srcfp= src_data + src_pix*y*src_stride;
294                 facfp= fac_data + fac_pix*y*fac_stride;
295                 
296                 for(x=0; x<outx; x++, outfp+=out_pix) {
297                         if(x<facx && y<facy)
298                                 func(node, outfp, srcfp, facfp);
299                         srcfp += src_pix;
300                         facfp += fac_pix;
301                 }
302         }
303 }
304
305 /* Pixel-to-Pixel operation, 3 Images in, 1 out */
306 static void composit3_pixel_processor(bNode *node, CompBuf *out, CompBuf *src1_buf, float *src1_col, CompBuf *src2_buf, float *src2_col, 
307                                                                           CompBuf *fac_buf, float fac, void (*func)(bNode *, float *, float *, float *, float))
308 {
309         float *outfp, *src1fp, *src2fp, *facfp, *src1_data, *src2_data, *fac_data;
310         int outx= out->x, outy= out->y;
311         int src1x, src1y, src2x, src2y, facx, facy;
312         int src1_stride, src1_pix, src2_stride, src2_pix, fac_stride, fac_pix, x, y;
313
314         /* handle case when input has constant color */
315         if(src1_buf==NULL) {
316                 src1x= outx; src1y= outy;
317                 src1_stride= 0;
318                 src1_pix= 0;
319                 src1_data= src1_col;
320         }
321         else {
322                 src1x= src1_buf->x;
323                 src1y= src1_buf->y;
324                 src1_stride= src1x;
325                 src1_pix= src1_buf->type;
326                 src1_data= src1_buf->rect;
327         }
328         
329         if(src2_buf==NULL) {
330                 src2x= outx; src2y= outy;
331                 src2_stride= 0;
332                 src2_pix= 0;
333                 src2_data= src2_col;
334         }
335         else {
336                 src2x= src2_buf->x;
337                 src2y= src2_buf->y;
338                 src2_stride= src2x;
339                 src2_pix= src2_buf->type;
340                 src2_data= src2_buf->rect;
341         }
342         
343         /* factor buf or constant? */
344         if(fac_buf==NULL) {
345                 facx= outx; facy= outy;
346                 fac_stride= 0;
347                 fac_pix= 0;
348                 fac_data= &fac;
349         }
350         else {
351                 facx= fac_buf->x;
352                 facy= fac_buf->y;
353                 fac_stride= facx;
354                 fac_pix= 1;
355                 fac_data= fac_buf->rect;
356         }
357         
358         facx= MIN3(facx, src1x, src2x);
359         facy= MIN3(facy, src1y, src2y);
360         
361         outfp= out->rect;
362         for(y=0; y<outy; y++) {
363                 
364                 /* set source scanlines on right location */
365                 src1fp= src1_data + src1_pix*y*src1_stride;
366                 src2fp= src2_data + src2_pix*y*src2_stride;
367                 facfp= fac_data + y*fac_stride;
368                 
369                 for(x=0; x<outx; x++, outfp+=4) {
370                         if(x<facx && y<facy)
371                                 func(node, outfp, src1fp, src2fp, *facfp);
372                         src1fp+= src1_pix;
373                         src2fp+= src2_pix;
374                         facfp+= fac_pix;
375                 }
376         }
377 }
378
379 /*  */
380 static CompBuf *alphabuf_from_rgbabuf(CompBuf *cbuf)
381 {
382         CompBuf *valbuf= alloc_compbuf(cbuf->x, cbuf->y, CB_VAL, 1);
383         float *valf, *rectf;
384         int tot;
385         
386         valf= valbuf->rect;
387         rectf= cbuf->rect + 3;
388         for(tot= cbuf->x*cbuf->y; tot>0; tot--, valf++, rectf+=4)
389                 *valf= *rectf;
390         
391         return valbuf;
392 }
393
394 static void generate_preview(bNode *node, CompBuf *stackbuf)
395 {
396         bNodePreview *preview= node->preview;
397         
398         if(preview) {
399                 ImBuf *ibuf= IMB_allocImBuf(stackbuf->x, stackbuf->y, 32, 0, 0);        /* empty */
400                 
401                 if(stackbuf->x > stackbuf->y) {
402                         preview->xsize= 140;
403                         preview->ysize= (140*stackbuf->y)/stackbuf->x;
404                 }
405                 else {
406                         preview->ysize= 140;
407                         preview->xsize= (140*stackbuf->x)/stackbuf->y;
408                 }
409                 ibuf->rect_float= stackbuf->rect;
410                 ibuf= IMB_scalefastImBuf(ibuf, preview->xsize, preview->ysize);
411                 
412                 /* this ensures free-imbuf does the right stuff */
413                 SWAP(float *, ibuf->rect_float, node->preview->rect);
414                 
415                 IMB_freeImBuf(ibuf);
416         }
417 }
418
419 /* ******************************************************** */
420 /* ********* Composit Node type definitions ***************** */
421 /* ******************************************************** */
422
423 /* SocketType syntax: 
424    socket type, max connections (0 is no limit), name, 4 values for default, 2 values for range */
425
426 /* Verification rule: If name changes, a saved socket and its links will be removed! Type changes are OK */
427
428 /* **************** VIEWER ******************** */
429 static bNodeSocketType cmp_node_viewer_in[]= {
430         {       SOCK_RGBA, 1, "Image",          0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
431         {       SOCK_VALUE, 1, "Alpha",         1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
432         {       SOCK_VALUE, 1, "Z",             1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
433         {       -1, 0, ""       }
434 };
435
436 static void do_copy_rgba(bNode *node, float *out, float *in)
437 {
438         QUATCOPY(out, in);
439 }
440 static void do_copy_rgb(bNode *node, float *out, float *in)
441 {
442         VECCOPY(out, in);
443         out[3]= 1.0f;
444 }
445 static void do_copy_rg(bNode *node, float *out, float *in)
446 {
447         out[0]= in[0];
448         out[1]= in[1];
449         out[2]= 0.0f;
450         out[3]= 1.0f;
451 }
452 static void do_copy_value(bNode *node, float *out, float *in)
453 {
454         out[0]= in[0];
455 }
456 static void do_copy_a_rgba(bNode *node, float *out, float *in, float *fac)
457 {
458         VECCOPY(out, in);
459         out[3]= *fac;
460 }
461
462 static void node_composit_exec_viewer(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
463 {
464         /* image assigned to output */
465         /* stack order input sockets: col, alpha, z */
466         
467         if(node->id && (node->flag & NODE_DO_OUTPUT)) { /* only one works on out */
468                 Image *ima= (Image *)node->id;
469                 CompBuf *cbuf, *inbuf= in[0]->data;
470                 int rectx, recty;
471                 
472                 /* scene size? */
473                 if(1) {
474                         RenderData *rd= data;
475
476                         /* re-create output, derive size from scene */
477                         rectx= (rd->size*rd->xsch)/100;
478                         recty= (rd->size*rd->ysch)/100;
479                         
480                         if(ima->ibuf) IMB_freeImBuf(ima->ibuf);
481                         ima->ibuf= IMB_allocImBuf(rectx, recty, 32, IB_rectfloat, 0); // do alloc
482                         
483                         cbuf= alloc_compbuf(rectx, recty, CB_RGBA, 0);  // no alloc
484                         cbuf->rect= ima->ibuf->rect_float;
485
486                         /* when no alpha, we can simply copy */
487                         if(in[1]->data==NULL) {
488                                 void (*func)(bNode *, float *, float *);
489                                 
490                                 if(inbuf==NULL || inbuf->type==CB_RGBA) func= do_copy_rgba;
491                                 else if(inbuf->type==CB_VEC3) func= do_copy_rgb;
492                                 else if(inbuf->type==CB_VEC2) func= do_copy_rg;
493                                 else func= do_copy_value;
494                                 
495                                 composit1_pixel_processor(node, cbuf, inbuf, in[0]->vec, func);
496                         }
497                         else
498                                 composit2_pixel_processor(node, cbuf, inbuf, in[0]->vec, in[1]->data, in[1]->vec, do_copy_a_rgba);
499                         
500                         if(in[2]->data) {
501                                 CompBuf *zbuf= alloc_compbuf(rectx, recty, CB_VAL, 0);
502                                 addzbuffloatImBuf(ima->ibuf);
503                                 zbuf->rect= ima->ibuf->zbuf_float;
504                                 composit1_pixel_processor(node, zbuf, in[2]->data, in[2]->vec, do_copy_value);
505                                 free_compbuf(zbuf);
506                         }
507
508                         generate_preview(node, cbuf);
509                         free_compbuf(cbuf);
510                 }
511                 else { /* test */
512                         if(ima->ibuf) IMB_freeImBuf(ima->ibuf);
513                         ima->ibuf= IMB_allocImBuf(rectx, recty, 32, 0, 0); // do alloc
514                         ima->ibuf->mall= IB_rectfloat;
515                         cbuf= in[0]->data;
516                         ima->ibuf->rect_float= cbuf->rect;
517                         ima->ibuf->x= cbuf->x;
518                         ima->ibuf->y= cbuf->y;
519                         cbuf->rect= NULL;
520                 }
521
522         }       /* lets make only previews when not done yet, so activating doesnt update */
523         else if(in[0]->data && node->preview && node->preview->rect==NULL) {
524                 CompBuf *cbuf, *inbuf= in[0]->data;
525                 
526                 if(inbuf->type!=CB_RGBA) {
527                         void (*func)(bNode *, float *, float *);
528                         
529                         if(inbuf->type==CB_VEC3) func= do_copy_rgb;
530                         else if(inbuf->type==CB_VEC2) func= do_copy_rg;
531                         else func= do_copy_value;
532                         
533                         cbuf= alloc_compbuf(inbuf->x, inbuf->y, CB_RGBA, 1);
534                         composit1_pixel_processor(node, cbuf, inbuf, in[0]->vec, func);
535                         generate_preview(node, cbuf);
536                         free_compbuf(cbuf);
537                 }
538                 else
539                         generate_preview(node, inbuf);
540         }
541 }
542
543 static bNodeType cmp_node_viewer= {
544         /* type code   */       CMP_NODE_VIEWER,
545         /* name        */       "Viewer",
546         /* width+range */       80, 60, 200,
547         /* class+opts  */       NODE_CLASS_OUTPUT, NODE_PREVIEW,
548         /* input sock  */       cmp_node_viewer_in,
549         /* output sock */       NULL,
550         /* storage     */       "",
551         /* execfunc    */       node_composit_exec_viewer
552         
553 };
554
555 /* **************** COMPOSITE ******************** */
556 static bNodeSocketType cmp_node_composite_in[]= {
557         {       SOCK_RGBA, 1, "Image",          0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
558         {       SOCK_VALUE, 1, "Alpha",         1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
559         {       SOCK_VALUE, 1, "Z",                     1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
560         {       -1, 0, ""       }
561 };
562
563 /* applies to render pipeline */
564 static void node_composit_exec_composite(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
565 {
566         /* image assigned to output */
567         /* stack order input sockets: col, alpha, z */
568         
569         if(node->flag & NODE_DO_OUTPUT) {       /* only one works on out */
570                 RenderData *rd= data;
571                 if(rd->scemode & R_DOCOMP) {
572                         RenderResult *rr= RE_GetResult(RE_GetRender("Render"));
573                         if(rr) {
574                                 CompBuf *outbuf, *zbuf=NULL;
575                                 
576                                 if(rr->rectf) 
577                                         MEM_freeT(rr->rectf);
578                                 outbuf= alloc_compbuf(rr->rectx, rr->recty, CB_RGBA, 1);
579                                 
580                                 if(in[1]->data==NULL)
581                                         composit1_pixel_processor(node, outbuf, in[0]->data, in[0]->vec, do_copy_rgba);
582                                 else
583                                         composit2_pixel_processor(node, outbuf, in[0]->data, in[0]->vec, in[1]->data, in[1]->vec, do_copy_a_rgba);
584                                 
585                                 if(in[2]->data) {
586                                         if(rr->rectz) 
587                                                 MEM_freeT(rr->rectz);
588                                         zbuf= alloc_compbuf(rr->rectx, rr->recty, CB_VAL, 1);
589                                         composit1_pixel_processor(node, zbuf, in[2]->data, in[2]->vec, do_copy_value);
590                                         rr->rectz= zbuf->rect;
591                                         zbuf->malloc= 0;
592                                         free_compbuf(zbuf);
593                                 }
594                                 generate_preview(node, outbuf);
595                                 
596                                 /* we give outbuf to rr... */
597                                 rr->rectf= outbuf->rect;
598                                 outbuf->malloc= 0;
599                                 free_compbuf(outbuf);
600                                 
601                                 return;
602                         }
603                 }
604         }
605         if(in[0]->data)
606                 generate_preview(node, in[0]->data);
607 }
608
609 static bNodeType cmp_node_composite= {
610         /* type code   */       CMP_NODE_COMPOSITE,
611         /* name        */       "Composite",
612         /* width+range */       80, 60, 200,
613         /* class+opts  */       NODE_CLASS_OUTPUT, NODE_PREVIEW,
614         /* input sock  */       cmp_node_composite_in,
615         /* output sock */       NULL,
616         /* storage     */       "",
617         /* execfunc    */       node_composit_exec_composite
618         
619 };
620
621 /* **************** OUTPUT FILE ******************** */
622 static bNodeSocketType cmp_node_output_file_in[]= {
623         {       SOCK_RGBA, 1, "Image",          0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
624         {       SOCK_VALUE, 1, "Alpha",         1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
625         {       -1, 0, ""       }
626 };
627
628
629 static void node_composit_exec_output_file(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
630 {
631         /* image assigned to output */
632         /* stack order input sockets: col, alpha */
633         
634         if(node->id && (node->flag & NODE_DO_OUTPUT)) { /* only one works on out */
635         }
636         else if(in[0]->data)
637                 generate_preview(node, in[0]->data);
638 }
639
640 static bNodeType cmp_node_output_file= {
641         /* type code   */       CMP_NODE_OUTPUT_FILE,
642         /* name        */       "File Output",
643         /* width+range */       80, 60, 200,
644         /* class+opts  */       NODE_CLASS_FILE, NODE_PREVIEW,
645         /* input sock  */       cmp_node_output_file_in,
646         /* output sock */       NULL,
647         /* storage     */       "",
648         /* execfunc    */       node_composit_exec_output_file
649         
650 };
651
652 /* **************** IMAGE ******************** */
653 static bNodeSocketType cmp_node_image_out[]= {
654         {       SOCK_RGBA, 0, "Image",          0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
655         {       SOCK_VALUE, 0, "Alpha",         1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
656         {       SOCK_VALUE, 0, "Z",                     1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
657         {       -1, 0, ""       }
658 };
659
660 static int calcimanr(int cfra, NodeImageAnim *nia)
661 {
662         
663         if(nia->frames==0) return nia->nr;
664         
665         cfra= cfra - nia->sfra;
666         
667         /* cyclic */
668         if(nia->cyclic)
669                 cfra= (cfra % nia->frames);
670         else if(cfra>=nia->frames)
671                 cfra= nia->frames-1;
672         else if(cfra<0)
673                 cfra= 0;
674         
675         cfra+= nia->nr;
676         
677         if(cfra<1) cfra= 1;
678         
679         return cfra;
680 }
681
682
683 static void animated_image(bNode *node, int cfra)
684 {
685         Image *ima;
686         NodeImageAnim *nia;
687         int imanr;
688         unsigned short numlen;
689         char name[FILE_MAXDIR+FILE_MAXFILE], head[FILE_MAXDIR+FILE_MAXFILE], tail[FILE_MAXDIR+FILE_MAXFILE];
690         
691         ima= (Image *)node->id;
692         nia= node->storage;
693         
694         if(nia && nia->frames && ima && ima->name) {    /* frames */
695                 strcpy(name, ima->name);
696                 
697                 imanr= calcimanr(cfra, nia);
698                 if(imanr!=ima->lastframe) {
699                         ima->lastframe= imanr;
700                         
701                         BLI_stringdec(name, head, tail, &numlen);
702                         BLI_stringenc(name, head, tail, numlen, imanr);
703                         
704                         ima= add_image(name);
705                         
706                         if(ima) {
707                                 ima->flag |= IMA_FROMANIM;
708                                 if(node->id) node->id->us--;
709                                 node->id= (ID *)ima;
710                                 
711                                 ima->ok= 1;
712                         }
713                 }
714         }
715 }
716
717
718 static void node_composit_exec_image(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
719 {
720         RenderData *rd= data;
721         
722         /* image assigned to output */
723         /* stack order input sockets: col, alpha */
724         if(node->id) {
725                 Image *ima;
726                 CompBuf *stackbuf;
727                 
728                 /* animated image? */
729                 if(node->storage)
730                         animated_image(node, rd->cfra);
731                 
732                 ima= (Image *)node->id;
733                 
734                 /* test if image is OK */
735                 if(ima->ok==0) return;
736                 
737                 if(ima->ibuf==NULL) {
738                         
739                         load_image(ima, IB_rect, G.sce, rd->cfra);      /* G.sce is current .blend path */
740                         if(ima->ibuf==NULL) {
741                                 ima->ok= 0;
742                                 return;
743                         }
744                 }
745                 if(ima->ibuf->rect_float==NULL)
746                         IMB_float_from_rect(ima->ibuf);
747                 
748                 /* we put imbuf copy on stack, cbuf knows rect is from other ibuf when freed! */
749                 stackbuf= alloc_compbuf(ima->ibuf->x, ima->ibuf->y, CB_RGBA, 0);
750                 stackbuf->rect= ima->ibuf->rect_float;
751                 
752                 /* put ibuf on stack */ 
753                 out[0]->data= stackbuf;
754                 
755                 if(out[1]->hasoutput)
756                         out[1]->data= alphabuf_from_rgbabuf(stackbuf);
757                 
758                 if(out[2]->hasoutput && ima->ibuf->zbuf_float) {
759                         CompBuf *zbuf= alloc_compbuf(ima->ibuf->x, ima->ibuf->y, CB_VAL, 0);
760                         zbuf->rect= ima->ibuf->zbuf_float;
761                         out[2]->data= zbuf;
762                 }
763                 
764                 generate_preview(node, stackbuf);
765         }       
766 }
767
768 /* uses node->storage to indicate animated image */
769
770 static bNodeType cmp_node_image= {
771         /* type code   */       CMP_NODE_IMAGE,
772         /* name        */       "Image",
773         /* width+range */       120, 80, 300,
774         /* class+opts  */       NODE_CLASS_GENERATOR, NODE_PREVIEW|NODE_OPTIONS,
775         /* input sock  */       NULL,
776         /* output sock */       cmp_node_image_out,
777         /* storage     */       "NodeImageAnim",
778         /* execfunc    */       node_composit_exec_image
779         
780 };
781
782 /* **************** RENDER RESULT ******************** */
783
784 /* output socket defines */
785 #define RRES_OUT_IMAGE  0
786 #define RRES_OUT_ALPHA  1
787 #define RRES_OUT_Z              2
788 #define RRES_OUT_NOR    3
789 #define RRES_OUT_VEC    4
790 #define RRES_OUT_COL    5
791 #define RRES_OUT_DIFF   6
792 #define RRES_OUT_SPEC   7
793 #define RRES_OUT_SHAD   8
794 #define RRES_OUT_AO             9
795 #define RRES_OUT_RAY    10
796
797 static bNodeSocketType cmp_node_rresult_out[]= {
798         {       SOCK_RGBA, 0, "Image",          0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
799         {       SOCK_VALUE, 0, "Alpha",         1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
800         {       SOCK_VALUE, 0, "Z",                     1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
801         {       SOCK_VECTOR, 0, "Normal",       0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
802         {       SOCK_VECTOR, 0, "Speed",        1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
803 //      {       SOCK_RGBA, 0, "Color",          0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
804 //      {       SOCK_RGBA, 0, "Diffuse",        0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
805 //      {       SOCK_RGBA, 0, "Specular",       0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
806 //      {       SOCK_RGBA, 0, "Shadow",         0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
807 //      {       SOCK_RGBA, 0, "AO",                     0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
808 //      {       SOCK_RGBA, 0, "Ray",            0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
809         {       -1, 0, ""       }
810 };
811
812 static CompBuf *compbuf_from_pass(RenderLayer *rl, int rectx, int recty, int passcode)
813 {
814         float *fp= RE_RenderLayerGetPass(rl, passcode);
815         if(fp) {
816                 CompBuf *buf;
817                 int buftype= CB_VEC3;
818                 
819                 if(passcode==SCE_PASS_Z)
820                         buftype= CB_VAL;
821                 else if(passcode==SCE_PASS_VECTOR)
822                         buftype= CB_VEC2;
823                 else if(passcode==SCE_PASS_RGBA)
824                         buftype= CB_RGBA;
825                         
826                 buf= alloc_compbuf(rectx, recty, buftype, 0);
827                 buf->rect= fp;
828                 return buf;
829         }
830         return NULL;
831 }
832
833 static void node_composit_exec_rresult(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
834 {
835         RenderResult *rr= RE_GetResult(RE_GetRender("Render"));
836         
837         if(rr) {
838                 RenderLayer *rl= BLI_findlink(&rr->layers, node->custom1);
839                 if(rl) {
840                         CompBuf *stackbuf;
841                         
842                         /* we put render rect on stack, cbuf knows rect is from other ibuf when freed! */
843                         stackbuf= alloc_compbuf(rr->rectx, rr->recty, CB_RGBA, 0);
844                         stackbuf->rect= rl->rectf;
845                         
846                         /* put on stack */      
847                         out[RRES_OUT_IMAGE]->data= stackbuf;
848                         
849                         if(out[RRES_OUT_ALPHA]->hasoutput)
850                                 out[RRES_OUT_ALPHA]->data= alphabuf_from_rgbabuf(stackbuf);
851                         if(out[RRES_OUT_Z]->hasoutput)
852                                 out[RRES_OUT_Z]->data= compbuf_from_pass(rl, rr->rectx, rr->recty, SCE_PASS_Z);
853                         if(out[RRES_OUT_VEC]->hasoutput)
854                                 out[RRES_OUT_VEC]->data= compbuf_from_pass(rl, rr->rectx, rr->recty, SCE_PASS_VECTOR);
855                         if(out[RRES_OUT_NOR]->hasoutput)
856                                 out[RRES_OUT_NOR]->data= compbuf_from_pass(rl, rr->rectx, rr->recty, SCE_PASS_NORMAL);
857 /*                      
858                         if(out[RRES_OUT_COL]->hasoutput)
859                                 out[RRES_OUT_COL]->data= compbuf_from_pass(rl, rr->rectx, rr->recty, SCE_PASS_RGBA);
860                         if(out[RRES_OUT_DIFF]->hasoutput)
861                                 out[RRES_OUT_DIFF]->data= compbuf_from_pass(rl, rr->rectx, rr->recty, SCE_PASS_DIFFUSE);
862                         if(out[RRES_OUT_SPEC]->hasoutput)
863                                 out[RRES_OUT_SPEC]->data= compbuf_from_pass(rl, rr->rectx, rr->recty, SCE_PASS_SPEC);
864                         if(out[RRES_OUT_SHAD]->hasoutput)
865                                 out[RRES_OUT_SHAD]->data= compbuf_from_pass(rl, rr->rectx, rr->recty, SCE_PASS_SHADOW);
866                         if(out[RRES_OUT_AO]->hasoutput)
867                                 out[RRES_OUT_AO]->data= compbuf_from_pass(rl, rr->rectx, rr->recty, SCE_PASS_AO);
868                         if(out[RRES_OUT_RAY]->hasoutput)
869                                 out[RRES_OUT_RAY]->data= compbuf_from_pass(rl, rr->rectx, rr->recty, SCE_PASS_RAY);
870 */                      
871                         generate_preview(node, stackbuf);
872                 }
873         }       
874 }
875
876 /* custom1 = render layer in use */
877 static bNodeType cmp_node_rresult= {
878         /* type code   */       CMP_NODE_R_RESULT,
879         /* name        */       "Render Result",
880         /* width+range */       120, 80, 300,
881         /* class+opts  */       NODE_CLASS_GENERATOR, NODE_PREVIEW|NODE_OPTIONS,
882         /* input sock  */       NULL,
883         /* output sock */       cmp_node_rresult_out,
884         /* storage     */       "",
885         /* execfunc    */       node_composit_exec_rresult
886         
887 };
888
889 /* **************** NORMAL  ******************** */
890 static bNodeSocketType cmp_node_normal_in[]= {
891         {       SOCK_VECTOR, 1, "Normal",       0.0f, 0.0f, 0.0f, 1.0f, -1.0f, 1.0f},
892         {       -1, 0, ""       }
893 };
894
895 static bNodeSocketType cmp_node_normal_out[]= {
896         {       SOCK_VECTOR, 0, "Normal",       0.0f, 0.0f, 1.0f, 1.0f, -1.0f, 1.0f},
897         {       SOCK_VALUE, 0, "Dot",           1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
898         {       -1, 0, ""       }
899 };
900
901 static void do_normal(bNode *node, float *out, float *in)
902 {
903         bNodeSocket *sock= node->outputs.first;
904         float *nor= sock->ns.vec;
905         
906         /* render normals point inside... the widget points outside */
907         out[0]= -INPR(nor, in);
908 }
909
910 /* generates normal, does dot product */
911 static void node_composit_exec_normal(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
912 {
913         bNodeSocket *sock= node->outputs.first;
914         /* stack order input:  normal */
915         /* stack order output: normal, value */
916         
917         /* input no image? then only vector op */
918         if(in[0]->data==NULL) {
919                 VECCOPY(out[0]->vec, sock->ns.vec);
920                 /* render normals point inside... the widget points outside */
921                 out[1]->vec[0]= -INPR(out[0]->vec, in[0]->vec);
922         }
923         else if(out[1]->hasoutput) {
924                 /* make output size of input image */
925                 CompBuf *cbuf= in[0]->data;
926                 CompBuf *stackbuf= alloc_compbuf(cbuf->x, cbuf->y, CB_VAL, 1); // allocs
927                 
928                 composit1_pixel_processor(node, stackbuf, in[0]->data, NULL, do_normal);
929                 
930                 out[1]->data= stackbuf;
931         }
932         
933         
934 }
935
936 static bNodeType cmp_node_normal= {
937         /* type code   */       CMP_NODE_NORMAL,
938         /* name        */       "Normal",
939         /* width+range */       100, 60, 200,
940         /* class+opts  */       NODE_CLASS_OPERATOR, NODE_OPTIONS,
941         /* input sock  */       cmp_node_normal_in,
942         /* output sock */       cmp_node_normal_out,
943         /* storage     */       "",
944         /* execfunc    */       node_composit_exec_normal
945         
946 };
947
948 /* **************** CURVE VEC  ******************** */
949 static bNodeSocketType cmp_node_curve_vec_in[]= {
950         {       SOCK_VECTOR, 1, "Vector",       0.0f, 0.0f, 0.0f, 1.0f, -1.0f, 1.0f},
951         {       -1, 0, ""       }
952 };
953
954 static bNodeSocketType cmp_node_curve_vec_out[]= {
955         {       SOCK_VECTOR, 0, "Vector",       0.0f, 0.0f, 1.0f, 1.0f, -1.0f, 1.0f},
956         {       -1, 0, ""       }
957 };
958
959 static void node_composit_exec_curve_vec(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
960 {
961         /* stack order input:  vec */
962         /* stack order output: vec */
963         
964         curvemapping_evaluate_premulRGBF(node->storage, out[0]->vec, in[0]->vec);
965 }
966
967 static bNodeType cmp_node_curve_vec= {
968         /* type code   */       CMP_NODE_CURVE_VEC,
969         /* name        */       "Vector Curves",
970         /* width+range */       200, 140, 320,
971         /* class+opts  */       NODE_CLASS_OPERATOR, NODE_OPTIONS,
972         /* input sock  */       cmp_node_curve_vec_in,
973         /* output sock */       cmp_node_curve_vec_out,
974         /* storage     */       "CurveMapping",
975         /* execfunc    */       node_composit_exec_curve_vec
976         
977 };
978
979 /* **************** CURVE RGB  ******************** */
980 static bNodeSocketType cmp_node_curve_rgb_in[]= {
981         {       SOCK_VALUE, 1, "Fac",   1.0f, 0.0f, 0.0f, 1.0f, -1.0f, 1.0f},
982         {       SOCK_RGBA, 1, "Image",  0.0f, 0.0f, 0.0f, 1.0f, -1.0f, 1.0f},
983         {       -1, 0, ""       }
984 };
985
986 static bNodeSocketType cmp_node_curve_rgb_out[]= {
987         {       SOCK_RGBA, 0, "Image",  0.0f, 0.0f, 1.0f, 1.0f, -1.0f, 1.0f},
988         {       -1, 0, ""       }
989 };
990
991 static void do_curves(bNode *node, float *out, float *in)
992 {
993         curvemapping_evaluateRGBF(node->storage, out, in);
994         out[3]= in[3];
995 }
996
997 static void do_curves_fac(bNode *node, float *out, float *in, float *fac)
998 {
999         
1000         if(*fac>=1.0)
1001                 curvemapping_evaluateRGBF(node->storage, out, in);
1002         else if(*fac<=0.0) {
1003                 VECCOPY(out, in);
1004         }
1005         else {
1006                 float col[4], mfac= 1.0f-*fac;
1007                 curvemapping_evaluateRGBF(node->storage, col, in);
1008                 out[0]= mfac*in[0] + *fac*col[0];
1009                 out[1]= mfac*in[1] + *fac*col[1];
1010                 out[2]= mfac*in[2] + *fac*col[2];
1011         }
1012         out[3]= in[3];
1013 }
1014
1015 static void node_composit_exec_curve_rgb(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
1016 {
1017         /* stack order input:  vec */
1018         /* stack order output: vec */
1019         
1020         if(out[0]->hasoutput==0)
1021                 return;
1022
1023         /* input no image? then only color operation */
1024         if(in[1]->data==NULL) {
1025                 curvemapping_evaluateRGBF(node->storage, out[0]->vec, in[1]->vec);
1026         }
1027         else {
1028                 /* make output size of input image */
1029                 CompBuf *cbuf= in[1]->data;
1030                 CompBuf *stackbuf= alloc_compbuf(cbuf->x, cbuf->y, CB_RGBA, 1); // allocs
1031                 
1032                 curvemapping_premultiply(node->storage, 0);
1033                 if(in[0]->data)
1034                         composit2_pixel_processor(node, stackbuf, in[1]->data, in[1]->vec, in[0]->data, in[0]->vec, do_curves_fac);
1035                 else
1036                         composit1_pixel_processor(node, stackbuf, in[1]->data, NULL, do_curves);
1037                 curvemapping_premultiply(node->storage, 1);
1038                 
1039                 out[0]->data= stackbuf;
1040         }
1041         
1042 }
1043
1044 static bNodeType cmp_node_curve_rgb= {
1045         /* type code   */       CMP_NODE_CURVE_RGB,
1046         /* name        */       "RGB Curves",
1047         /* width+range */       200, 140, 320,
1048         /* class+opts  */       NODE_CLASS_OPERATOR, NODE_OPTIONS,
1049         /* input sock  */       cmp_node_curve_rgb_in,
1050         /* output sock */       cmp_node_curve_rgb_out,
1051         /* storage     */       "CurveMapping",
1052         /* execfunc    */       node_composit_exec_curve_rgb
1053         
1054 };
1055
1056 /* **************** VALUE ******************** */
1057 static bNodeSocketType cmp_node_value_out[]= {
1058         {       SOCK_VALUE, 0, "Value",         0.5f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
1059         {       -1, 0, ""       }
1060 };
1061
1062 static void node_composit_exec_value(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
1063 {
1064         bNodeSocket *sock= node->outputs.first;
1065         
1066         out[0]->vec[0]= sock->ns.vec[0];
1067 }
1068
1069 static bNodeType cmp_node_value= {
1070         /* type code   */       CMP_NODE_VALUE,
1071         /* name        */       "Value",
1072         /* width+range */       80, 40, 120,
1073         /* class+opts  */       NODE_CLASS_GENERATOR, NODE_OPTIONS,
1074         /* input sock  */       NULL,
1075         /* output sock */       cmp_node_value_out,
1076         /* storage     */       "", 
1077         /* execfunc    */       node_composit_exec_value
1078         
1079 };
1080
1081 /* **************** RGB ******************** */
1082 static bNodeSocketType cmp_node_rgb_out[]= {
1083         {       SOCK_RGBA, 0, "RGBA",                   0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f},
1084         {       -1, 0, ""       }
1085 };
1086
1087 static void node_composit_exec_rgb(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
1088 {
1089         bNodeSocket *sock= node->outputs.first;
1090         
1091         VECCOPY(out[0]->vec, sock->ns.vec);
1092 }
1093
1094 static bNodeType cmp_node_rgb= {
1095         /* type code   */       CMP_NODE_RGB,
1096         /* name        */       "RGB",
1097         /* width+range */       100, 60, 140,
1098         /* class+opts  */       NODE_CLASS_GENERATOR, NODE_OPTIONS,
1099         /* input sock  */       NULL,
1100         /* output sock */       cmp_node_rgb_out,
1101         /* storage     */       "",
1102         /* execfunc    */       node_composit_exec_rgb
1103         
1104 };
1105
1106 /* **************** MIX RGB ******************** */
1107 static bNodeSocketType cmp_node_mix_rgb_in[]= {
1108         {       SOCK_VALUE, 1, "Fac",                   0.5f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
1109         {       SOCK_RGBA, 1, "Image",                  0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f},
1110         {       SOCK_RGBA, 1, "Image",                  0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f},
1111         {       -1, 0, ""       }
1112 };
1113 static bNodeSocketType cmp_node_mix_rgb_out[]= {
1114         {       SOCK_RGBA, 0, "Image",                  0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
1115         {       -1, 0, ""       }
1116 };
1117
1118 static void do_mix_rgb(bNode *node, float *out, float *in1, float *in2, float fac)
1119 {
1120         float col[3];
1121         
1122         VECCOPY(col, in1);
1123         ramp_blend(node->custom1, col, col+1, col+2, fac, in2);
1124         VECCOPY(out, col);
1125         out[3]= in1[3];
1126 }
1127
1128 static void node_composit_exec_mix_rgb(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
1129 {
1130         /* stack order in: fac, Image, Image */
1131         /* stack order out: Image */
1132         float fac= in[0]->vec[0];
1133         
1134         CLAMP(fac, 0.0f, 1.0f);
1135         
1136         /* input no image? then only color operation */
1137         if(in[1]->data==NULL && in[2]->data==NULL) {
1138                 do_mix_rgb(node, out[0]->vec, in[1]->vec, in[2]->vec, fac);
1139         }
1140         else {
1141                 /* make output size of first available input image */
1142                 CompBuf *cbuf= in[1]->data?in[1]->data:in[2]->data;
1143                 CompBuf *stackbuf= alloc_compbuf(cbuf->x, cbuf->y, CB_RGBA, 1); // allocs
1144                 
1145                 composit3_pixel_processor(node, stackbuf, in[1]->data, in[1]->vec, in[2]->data, in[2]->vec, in[0]->data, fac, do_mix_rgb);
1146                 
1147                 out[0]->data= stackbuf;
1148         }
1149 }
1150
1151 /* custom1 = mix type */
1152 static bNodeType cmp_node_mix_rgb= {
1153         /* type code   */       CMP_NODE_MIX_RGB,
1154         /* name        */       "Mix",
1155         /* width+range */       80, 40, 120,
1156         /* class+opts  */       NODE_CLASS_OPERATOR, NODE_OPTIONS,
1157         /* input sock  */       cmp_node_mix_rgb_in,
1158         /* output sock */       cmp_node_mix_rgb_out,
1159         /* storage     */       "", 
1160         /* execfunc    */       node_composit_exec_mix_rgb
1161         
1162 };
1163
1164 /* **************** FILTER  ******************** */
1165 static bNodeSocketType cmp_node_filter_in[]= {
1166         {       SOCK_VALUE, 1, "Fac",                   1.0f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f},
1167         {       SOCK_RGBA, 1, "Image",                  0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f},
1168         {       -1, 0, ""       }
1169 };
1170 static bNodeSocketType cmp_node_filter_out[]= {
1171         {       SOCK_RGBA, 0, "Image",                  0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
1172         {       -1, 0, ""       }
1173 };
1174
1175 static void do_filter_edge(CompBuf *out, CompBuf *in, float *filter, float fac)
1176 {
1177         float *row1, *row2, *row3;
1178         float *fp, f1, f2, mfac= 1.0f-fac;
1179         int rowlen, x, y, c;
1180         
1181         rowlen= in->x;
1182         
1183         if(in->type==CB_RGBA) {
1184                 
1185                 for(y=2; y<in->y; y++) {
1186                         /* setup rows */
1187                         row1= in->rect + 4*(y-2)*rowlen;
1188                         row2= row1 + 4*rowlen;
1189                         row3= row2 + 4*rowlen;
1190                         fp= out->rect + 4*(y-1)*rowlen + 4;
1191                         
1192                         for(x=2; x<rowlen; x++) {
1193                                 for(c=0; c<3; c++) {
1194                                         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];
1195                                         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];
1196                                         fp[0]= mfac*row2[4] + fac*sqrt(f1*f1 + f2*f2);
1197                                         fp++; row1++; row2++; row3++;
1198                                 }
1199                                 fp[0]= row2[4];
1200                                 /* no alpha... will clear it completely */
1201                                 fp++; row1++; row2++; row3++;
1202                         }
1203                 }
1204         }       
1205 }
1206
1207 static void do_filter3(CompBuf *out, CompBuf *in, float *filter, float fac)
1208 {
1209         float *row1, *row2, *row3;
1210         float *fp, mfac= 1.0f-fac;
1211         int rowlen, x, y, c;
1212         int pixlen= in->type;
1213         
1214         rowlen= in->x;
1215         
1216         for(y=2; y<in->y; y++) {
1217                 /* setup rows */
1218                 row1= in->rect + pixlen*(y-2)*rowlen;
1219                 row2= row1 + pixlen*rowlen;
1220                 row3= row2 + pixlen*rowlen;
1221                 
1222                 fp= out->rect + pixlen*(y-1)*rowlen;
1223                 QUATCOPY(fp, row2);
1224                 fp+= pixlen;
1225                 
1226                 for(x=2; x<rowlen; x++) {
1227                         for(c=0; c<pixlen; c++) {
1228                                 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]);
1229                                 fp++; row1++; row2++; row3++;
1230                         }
1231                 }
1232         }
1233 }
1234
1235 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};
1236
1237 static void node_composit_exec_filter(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
1238 {
1239         float sharp[9]= {-1,-1,-1,-1,9,-1,-1,-1,-1};
1240         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};
1241         float sobel[9]= {1,2,1,0,0,0,-1,-2,-1};
1242         float prewitt[9]= {1,1,1,0,0,0,-1,-1,-1};
1243         float kirsch[9]= {5,5,5,-3,-3,-3,-2,-2,-2};
1244         float shadow[9]= {1,2,1,0,1,0,-1,-2,-1};
1245         
1246         /* stack order in: Image */
1247         /* stack order out: Image */
1248         
1249         if(in[1]->data) {
1250                 /* make output size of first available input image */
1251                 CompBuf *cbuf= in[1]->data;
1252                 CompBuf *stackbuf= alloc_compbuf(cbuf->x, cbuf->y, CB_RGBA, 1); // allocs
1253                 
1254                 switch(node->custom1) {
1255                         case CMP_FILT_SOFT:
1256                                 do_filter3(stackbuf, cbuf, soft, in[0]->vec[0]);
1257                                 break;
1258                         case CMP_FILT_SHARP:
1259                                 do_filter3(stackbuf, cbuf, sharp, in[0]->vec[0]);
1260                                 break;
1261                         case CMP_FILT_LAPLACE:
1262                                 do_filter3(stackbuf, cbuf, laplace, in[0]->vec[0]);
1263                                 break;
1264                         case CMP_FILT_SOBEL:
1265                                 do_filter_edge(stackbuf, cbuf, sobel, in[0]->vec[0]);
1266                                 break;
1267                         case CMP_FILT_PREWITT:
1268                                 do_filter_edge(stackbuf, cbuf, prewitt, in[0]->vec[0]);
1269                                 break;
1270                         case CMP_FILT_KIRSCH:
1271                                 do_filter_edge(stackbuf, cbuf, kirsch, in[0]->vec[0]);
1272                                 break;
1273                         case CMP_FILT_SHADOW:
1274                                 do_filter3(stackbuf, cbuf, shadow, in[0]->vec[0]);
1275                                 break;
1276                 }
1277                         
1278                 out[0]->data= stackbuf;
1279         }
1280 }
1281
1282 /* custom1 = filter type */
1283 static bNodeType cmp_node_filter= {
1284         /* type code   */       CMP_NODE_FILTER,
1285         /* name        */       "Filter",
1286         /* width+range */       80, 40, 120,
1287         /* class+opts  */       NODE_CLASS_OPERATOR, NODE_OPTIONS,
1288         /* input sock  */       cmp_node_filter_in,
1289         /* output sock */       cmp_node_filter_out,
1290         /* storage     */       "", 
1291         /* execfunc    */       node_composit_exec_filter
1292         
1293 };
1294
1295
1296 /* **************** VALTORGB ******************** */
1297 static bNodeSocketType cmp_node_valtorgb_in[]= {
1298         {       SOCK_VALUE, 1, "Fac",                   0.5f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
1299         {       -1, 0, ""       }
1300 };
1301 static bNodeSocketType cmp_node_valtorgb_out[]= {
1302         {       SOCK_RGBA, 0, "Image",                  0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
1303         {       SOCK_VALUE, 0, "Alpha",                 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
1304         {       -1, 0, ""       }
1305 };
1306
1307 static void do_colorband_composit(bNode *node, float *out, float *in)
1308 {
1309         do_colorband(node->storage, in[0], out);
1310 }
1311
1312 static void node_composit_exec_valtorgb(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
1313 {
1314         /* stack order in: fac */
1315         /* stack order out: col, alpha */
1316         
1317         if(node->storage) {
1318                 /* input no image? then only color operation */
1319                 if(in[0]->data==NULL) {
1320                         do_colorband(node->storage, in[0]->vec[0], out[0]->vec);
1321                 }
1322                 else {
1323                         /* make output size of input image */
1324                         CompBuf *cbuf= in[0]->data;
1325                         CompBuf *stackbuf= alloc_compbuf(cbuf->x, cbuf->y, CB_RGBA, 1); // allocs
1326                         
1327                         composit1_pixel_processor(node, stackbuf, in[0]->data, NULL, do_colorband_composit);
1328                         
1329                         out[0]->data= stackbuf;
1330                         
1331                         if(out[1]->hasoutput)
1332                                 out[1]->data= alphabuf_from_rgbabuf(stackbuf);
1333
1334                 }
1335         }
1336 }
1337
1338 static bNodeType cmp_node_valtorgb= {
1339         /* type code   */       CMP_NODE_VALTORGB,
1340         /* name        */       "ColorRamp",
1341         /* width+range */       240, 200, 300,
1342         /* class+opts  */       NODE_CLASS_OPERATOR, NODE_OPTIONS,
1343         /* input sock  */       cmp_node_valtorgb_in,
1344         /* output sock */       cmp_node_valtorgb_out,
1345         /* storage     */       "ColorBand",
1346         /* execfunc    */       node_composit_exec_valtorgb
1347         
1348 };
1349
1350
1351 /* **************** RGBTOBW ******************** */
1352 static bNodeSocketType cmp_node_rgbtobw_in[]= {
1353         {       SOCK_RGBA, 1, "Image",                  0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f},
1354         {       -1, 0, ""       }
1355 };
1356 static bNodeSocketType cmp_node_rgbtobw_out[]= {
1357         {       SOCK_VALUE, 0, "Val",                   0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
1358         {       -1, 0, ""       }
1359 };
1360
1361 static void do_rgbtobw(bNode *node, float *out, float *in)
1362 {
1363         out[0]= in[0]*0.35f + in[1]*0.45f + in[2]*0.2f;
1364 }
1365
1366 static void node_composit_exec_rgbtobw(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
1367 {
1368         /* stack order out: bw */
1369         /* stack order in: col */
1370         
1371         /* input no image? then only color operation */
1372         if(in[0]->data==NULL) {
1373                 out[0]->vec[0]= in[0]->vec[0]*0.35f + in[0]->vec[1]*0.45f + in[0]->vec[2]*0.2f;
1374         }
1375         else {
1376                 /* make output size of input image */
1377                 CompBuf *cbuf= in[0]->data;
1378                 CompBuf *stackbuf= alloc_compbuf(cbuf->x, cbuf->y, CB_VAL, 1); // allocs
1379                 
1380                 composit1_pixel_processor(node, stackbuf, in[0]->data, NULL, do_rgbtobw);
1381                 
1382                 out[0]->data= stackbuf;
1383         }
1384 }
1385
1386 static bNodeType cmp_node_rgbtobw= {
1387         /* type code   */       CMP_NODE_RGBTOBW,
1388         /* name        */       "RGB to BW",
1389         /* width+range */       80, 40, 120,
1390         /* class+opts  */       NODE_CLASS_OPERATOR, 0,
1391         /* input sock  */       cmp_node_rgbtobw_in,
1392         /* output sock */       cmp_node_rgbtobw_out,
1393         /* storage     */       "",
1394         /* execfunc    */       node_composit_exec_rgbtobw
1395         
1396 };
1397
1398 /* **************** ALPHAOVER ******************** */
1399 static bNodeSocketType cmp_node_alphaover_in[]= {
1400         {       SOCK_RGBA, 1, "Image",                  0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f},
1401         {       SOCK_RGBA, 1, "Image",                  0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f},
1402         {       -1, 0, ""       }
1403 };
1404 static bNodeSocketType cmp_node_alphaover_out[]= {
1405         {       SOCK_RGBA, 0, "Image",                  0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
1406         {       -1, 0, ""       }
1407 };
1408
1409 static void do_alphaover(bNode *node, float *out, float *src, float *dest)
1410 {
1411         float mul= 1.0f - dest[3];
1412         
1413         if(mul<=0.0f) {
1414                 QUATCOPY(out, dest);
1415         }
1416         else {
1417                 out[0]= (mul*src[0]) + dest[0];
1418                 out[1]= (mul*src[1]) + dest[1];
1419                 out[2]= (mul*src[2]) + dest[2];
1420                 out[3]= (mul*src[3]) + dest[3];
1421         }       
1422 }
1423
1424 static void node_composit_exec_alphaover(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
1425 {
1426         /* stack order in: col col */
1427         /* stack order out: col */
1428         
1429         /* input no image? then only color operation */
1430         if(in[0]->data==NULL) {
1431                 do_alphaover(node, out[0]->vec, in[0]->vec, in[1]->vec);
1432         }
1433         else {
1434                 /* make output size of input image */
1435                 CompBuf *cbuf= in[0]->data;
1436                 CompBuf *stackbuf= alloc_compbuf(cbuf->x, cbuf->y, CB_RGBA, 1); // allocs
1437                 
1438                 composit2_pixel_processor(node, stackbuf, in[0]->data, in[0]->vec, in[1]->data, in[1]->vec, do_alphaover);
1439                 
1440                 out[0]->data= stackbuf;
1441         }
1442 }
1443
1444 static bNodeType cmp_node_alphaover= {
1445         /* type code   */       CMP_NODE_ALPHAOVER,
1446         /* name        */       "AlphaOver",
1447         /* width+range */       80, 40, 120,
1448         /* class+opts  */       NODE_CLASS_OPERATOR, 0,
1449         /* input sock  */       cmp_node_alphaover_in,
1450         /* output sock */       cmp_node_alphaover_out,
1451         /* storage     */       "",
1452         /* execfunc    */       node_composit_exec_alphaover
1453         
1454 };
1455
1456 /* **************** MAP VALUE ******************** */
1457 static bNodeSocketType cmp_node_map_value_in[]= {
1458         {       SOCK_VALUE, 1, "Value",                 1.0f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f},
1459         {       -1, 0, ""       }
1460 };
1461 static bNodeSocketType cmp_node_map_value_out[]= {
1462         {       SOCK_VALUE, 0, "Value",                 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
1463         {       -1, 0, ""       }
1464 };
1465
1466 static void do_map_value(bNode *node, float *out, float *src)
1467 {
1468         TexMapping *texmap= node->storage;
1469         
1470         out[0]= (src[0] + texmap->loc[0])*texmap->size[0];
1471         if(texmap->flag & TEXMAP_CLIP_MIN)
1472                 if(out[0]<texmap->min[0])
1473                         out[0]= texmap->min[0];
1474         if(texmap->flag & TEXMAP_CLIP_MAX)
1475                 if(out[0]>texmap->max[0])
1476                         out[0]= texmap->max[0];
1477 }
1478
1479 static void node_composit_exec_map_value(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
1480 {
1481         /* stack order in: col col */
1482         /* stack order out: col */
1483         
1484         /* input no image? then only value operation */
1485         if(in[0]->data==NULL) {
1486                 do_map_value(node, out[0]->vec, in[0]->vec);
1487         }
1488         else {
1489                 /* make output size of input image */
1490                 CompBuf *cbuf= in[0]->data;
1491                 CompBuf *stackbuf= alloc_compbuf(cbuf->x, cbuf->y, CB_VAL, 1); // allocs
1492                 
1493                 composit1_pixel_processor(node, stackbuf, in[0]->data, in[0]->vec, do_map_value);
1494                 
1495                 out[0]->data= stackbuf;
1496         }
1497 }
1498
1499 static bNodeType cmp_node_map_value= {
1500         /* type code   */       CMP_NODE_MAP_VALUE,
1501         /* name        */       "Map Value",
1502         /* width+range */       100, 60, 150,
1503         /* class+opts  */       NODE_CLASS_OPERATOR, NODE_OPTIONS,
1504         /* input sock  */       cmp_node_map_value_in,
1505         /* output sock */       cmp_node_map_value_out,
1506         /* storage     */       "TexMapping",
1507         /* execfunc    */       node_composit_exec_map_value
1508         
1509 };
1510
1511 /* **************** BLUR ******************** */
1512 static bNodeSocketType cmp_node_blur_in[]= {
1513         {       SOCK_RGBA, 1, "Image",                  0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f},
1514         {       SOCK_VALUE, 1, "Size",                  1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
1515         {       -1, 0, ""       }
1516 };
1517 static bNodeSocketType cmp_node_blur_out[]= {
1518         {       SOCK_RGBA, 0, "Image",                  0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
1519         {       -1, 0, ""       }
1520 };
1521
1522 static float *make_gausstab(int filtertype, int rad)
1523 {
1524         float *gausstab, sum, val;
1525         int i, n;
1526         
1527         n = 2 * rad + 1;
1528         
1529         gausstab = (float *) MEM_mallocT(n * sizeof(float), "gauss");
1530         
1531         sum = 0.0f;
1532         for (i = -rad; i <= rad; i++) {
1533                 val= RE_filter_value(filtertype, (float)i/(float)rad);
1534                 sum += val;
1535                 gausstab[i+rad] = val;
1536         }
1537         
1538         sum= 1.0f/sum;
1539         for(i=0; i<n; i++)
1540                 gausstab[i]*= sum;
1541         
1542         return gausstab;
1543 }
1544
1545 static float *make_bloomtab(int rad)
1546 {
1547         float *bloomtab, val;
1548         int i, n;
1549         
1550         n = 2 * rad + 1;
1551         
1552         bloomtab = (float *) MEM_mallocT(n * sizeof(float), "bloom");
1553         
1554         for (i = -rad; i <= rad; i++) {
1555                 val = pow(1.0 - fabs((float)i)/((float)rad), 4.0);
1556                 bloomtab[i+rad] = val;
1557         }
1558         
1559         return bloomtab;
1560 }
1561
1562 static void blur_single_image(CompBuf *new, CompBuf *img, float scale, NodeBlurData *nbd)
1563 {
1564         CompBuf *work;
1565         register float sum, val;
1566         float rval, gval, bval, aval;
1567         float *gausstab, *gausstabcent;
1568         int rad, imgx= img->x, imgy= img->y;
1569         int x, y, pix= img->type;
1570         int i, bigstep;
1571         float *src, *dest;
1572
1573         /* helper image */
1574         work= alloc_compbuf(imgx, imgy, img->type, 1); // allocs
1575         
1576         /* horizontal */
1577         rad = scale*(float)nbd->sizex;
1578         if(rad>imgx/2)
1579                 rad= imgx/2;
1580         else if(rad<1) 
1581                 rad= 1;
1582
1583         gausstab= make_gausstab(nbd->filtertype, rad);
1584         gausstabcent= gausstab+rad;
1585         
1586         for (y = 0; y < imgy; y++) {
1587                 float *srcd= img->rect + pix*(y*img->x);
1588                 
1589                 dest = work->rect + pix*(y * img->x);
1590                 
1591                 for (x = 0; x < imgx ; x++) {
1592                         int minr= x-rad<0?-x:-rad;
1593                         int maxr= x+rad>imgx?imgx-x:rad;
1594                         
1595                         src= srcd + pix*(x+minr);
1596                         
1597                         sum= gval = rval= bval= aval= 0.0f;
1598                         for (i= minr; i < maxr; i++) {
1599                                 val= gausstabcent[i];
1600                                 sum+= val;
1601                                 rval += val * (*src++);
1602                                 if(pix==4) {
1603                                         gval += val * (*src++);
1604                                         bval += val * (*src++);
1605                                         aval += val * (*src++);
1606                                 }
1607                         }
1608                         sum= 1.0f/sum;
1609                         *dest++ = rval*sum;
1610                         if(pix==4) {
1611                                 *dest++ = gval*sum;
1612                                 *dest++ = bval*sum;
1613                                 *dest++ = aval*sum;
1614                         }
1615                 }
1616         }
1617         
1618         /* vertical */
1619         MEM_freeT(gausstab);
1620         
1621         rad = scale*(float)nbd->sizey;
1622         if(rad>imgy/2)
1623                 rad= imgy/2;
1624         else if(rad<1) 
1625                 rad= 1;
1626
1627         gausstab= make_gausstab(nbd->filtertype, rad);
1628         gausstabcent= gausstab+rad;
1629         
1630         bigstep = pix*imgx;
1631         for (x = 0; x < imgx; x++) {
1632                 float *srcd= work->rect + pix*x;
1633                 
1634                 dest = new->rect + pix*x;
1635                 
1636                 for (y = 0; y < imgy ; y++) {
1637                         int minr= y-rad<0?-y:-rad;
1638                         int maxr= y+rad>imgy?imgy-y:rad;
1639                         
1640                         src= srcd + bigstep*(y+minr);
1641                         
1642                         sum= gval = rval= bval= aval= 0.0f;
1643                         for (i= minr; i < maxr; i++) {
1644                                 val= gausstabcent[i];
1645                                 sum+= val;
1646                                 rval += val * src[0];
1647                                 if(pix==4) {
1648                                         gval += val * src[1];
1649                                         bval += val * src[2];
1650                                         aval += val * src[3];
1651                                 }
1652                                 src += bigstep;
1653                         }
1654                         sum= 1.0f/sum;
1655                         dest[0] = rval*sum;
1656                         if(pix==4) {
1657                                 dest[1] = gval*sum;
1658                                 dest[2] = bval*sum;
1659                                 dest[3] = aval*sum;
1660                         }
1661                         dest+= bigstep;
1662                 }
1663         }
1664         
1665         free_compbuf(work);
1666         MEM_freeT(gausstab);
1667 }
1668
1669 /* reference has to be mapped 0-1, and equal in size */
1670 static void bloom_with_reference(CompBuf *new, CompBuf *img, CompBuf *ref, float fac, NodeBlurData *nbd)
1671 {
1672         CompBuf *wbuf;
1673         register float val;
1674         float radxf, radyf;
1675         float **maintabs;
1676         float *gausstabx, *gausstabcenty;
1677         float *gausstaby, *gausstabcentx;
1678         int radx, rady, imgx= img->x, imgy= img->y;
1679         int x, y;
1680         int i, j;
1681         float *src, *dest, *wb;
1682         
1683         wbuf= alloc_compbuf(imgx, imgy, CB_VAL, 1);
1684         memset(wbuf->rect, sizeof(float)*imgx*imgy, 0);
1685         
1686         /* horizontal */
1687         radx = (float)nbd->sizex;
1688         if(radx>imgx/2)
1689                 radx= imgx/2;
1690         else if(radx<1) 
1691                 radx= 1;
1692         
1693         /* vertical */
1694         rady = (float)nbd->sizey;
1695         if(rady>imgy/2)
1696                 rady= imgy/2;
1697         else if(rady<1) 
1698                 rady= 1;
1699         
1700         x= MAX2(radx, rady);
1701         maintabs= MEM_mallocT(x*sizeof(void *), "gauss array");
1702         for(i= 0; i<x; i++)
1703                 maintabs[i]= make_bloomtab(i+1);
1704                 
1705         /* vars to store before we go */
1706 //      refd= ref->rect;
1707         src= img->rect;
1708         
1709         memset(new->rect, 4*imgx*imgy, 0);
1710         
1711         radxf= (float)radx;
1712         radyf= (float)rady;
1713         
1714         for (y = 0; y < imgy; y++) {
1715                 for (x = 0; x < imgx ; x++, src+=4) {//, refd++) {
1716                         
1717 //                      int refradx= (int)(refd[0]*radxf);
1718 //                      int refrady= (int)(refd[0]*radyf);
1719                         
1720                         int refradx= (int)(radxf*0.3f*src[3]*(src[0]+src[1]+src[2]));
1721                         int refrady= (int)(radyf*0.3f*src[3]*(src[0]+src[1]+src[2]));
1722                         
1723                         if(refradx>radx) refradx= radx;
1724                         else if(refradx<1) refradx= 1;
1725                         if(refrady>rady) refrady= rady;
1726                         else if(refrady<1) refrady= 1;
1727                         
1728                         if(refradx==1 && refrady==1) {
1729                                 wb= wbuf->rect + ( y*imgx + x);
1730                                 dest= new->rect + 4*( y*imgx + x);
1731                                 wb[0]+= 1.0f;
1732                                 dest[0] += src[0];
1733                                 dest[1] += src[1];
1734                                 dest[2] += src[2];
1735                                 dest[3] += src[3];
1736                         }
1737                         else {
1738                                 int minxr= x-refradx<0?-x:-refradx;
1739                                 int maxxr= x+refradx>imgx?imgx-x:refradx;
1740                                 int minyr= y-refrady<0?-y:-refrady;
1741                                 int maxyr= y+refrady>imgy?imgy-y:refrady;
1742                                 
1743                                 float *destd= new->rect + 4*( (y + minyr)*imgx + x + minxr);
1744                                 float *wbufd= wbuf->rect + ( (y + minyr)*imgx + x + minxr);
1745                                 
1746                                 gausstabx= maintabs[refradx-1];
1747                                 gausstabcentx= gausstabx+refradx;
1748                                 gausstaby= maintabs[refrady-1];
1749                                 gausstabcenty= gausstaby+refrady;
1750                                 
1751                                 for (i= minyr; i < maxyr; i++, destd+= 4*imgx, wbufd+= imgx) {
1752                                         dest= destd;
1753                                         wb= wbufd;
1754                                         for (j= minxr; j < maxxr; j++, dest+=4, wb++) {
1755                                                 
1756                                                 val= gausstabcenty[i]*gausstabcentx[j];
1757                                                 wb[0]+= val;
1758                                                 dest[0] += val * src[0];
1759                                                 dest[1] += val * src[1];
1760                                                 dest[2] += val * src[2];
1761                                                 dest[3] += val * src[3];
1762                                         }
1763                                 }
1764                         }
1765                 }
1766         }
1767         
1768         x= imgx*imgy;
1769         dest= new->rect;
1770         wb= wbuf->rect;
1771         while(x--) {
1772                 val= 1.0f/wb[0];
1773                 dest[0]*= val;
1774                 dest[1]*= val;
1775                 dest[2]*= val;
1776                 dest[3]*= val;
1777                 wb++;
1778                 dest+= 4;
1779         }
1780         
1781         free_compbuf(wbuf);
1782         
1783         x= MAX2(radx, rady);
1784         for(i= 0; i<x; i++)
1785                 MEM_freeT(maintabs[i]);
1786         MEM_freeT(maintabs);
1787         
1788 }
1789
1790 static void gamma_correct_compbuf(CompBuf *img, int inversed)
1791 {
1792         float *drect;
1793         int x;
1794         
1795         drect= img->rect;
1796         if(inversed) {
1797                 for(x=img->x*img->y; x>0; x--, drect+=4) {
1798                         if(drect[0]>0.0f) drect[0]= sqrt(drect[0]); else drect[0]= 0.0f;
1799                         if(drect[1]>0.0f) drect[1]= sqrt(drect[1]); else drect[1]= 0.0f;
1800                         if(drect[2]>0.0f) drect[2]= sqrt(drect[2]); else drect[2]= 0.0f;
1801                 }
1802         }
1803         else {
1804                 for(x=img->x*img->y; x>0; x--, drect+=4) {
1805                         if(drect[0]>0.0f) drect[0]*= drect[0]; else drect[0]= 0.0f;
1806                         if(drect[1]>0.0f) drect[1]*= drect[1]; else drect[1]= 0.0f;
1807                         if(drect[2]>0.0f) drect[2]*= drect[2]; else drect[2]= 0.0f;
1808                 }
1809         }
1810 }
1811 #if 0
1812 static float hexagon_filter(float fi, float fj)
1813 {
1814         fi= fabs(fi);
1815         fj= fabs(fj);
1816         
1817         if(fj>0.33f) {
1818                 fj= (fj-0.33f)/0.66f;
1819                 if(fi+fj>1.0f)
1820                         return 0.0f;
1821                 else
1822                         return 1.0f;
1823         }
1824         else return 1.0f;
1825 }
1826 #endif
1827 /* uses full filter, no horizontal/vertical optimize possible */
1828 static void bokeh_single_image(CompBuf *new, CompBuf *img, float fac, NodeBlurData *nbd)
1829 {
1830         register float val;
1831         float radxf, radyf;
1832         float *gausstab, *dgauss;
1833         int radx, rady, imgx= img->x, imgy= img->y;
1834         int x, y;
1835         int i, j;
1836         float *src, *dest;
1837         
1838         /* horizontal */
1839         radx = fac*(float)nbd->sizex;
1840         if(radx>imgx/2)
1841                 radx= imgx/2;
1842         else if(radx<1) 
1843                 radx= 1;
1844         
1845         /* vertical */
1846         rady = fac*(float)nbd->sizey;
1847         if(rady>imgy/2)
1848                 rady= imgy/2;
1849         else if(rady<1) 
1850                 rady= 1;
1851         
1852         radxf= (float)radx;
1853         radyf= (float)rady;
1854         
1855         /* create a full filter image */
1856         gausstab= MEM_mallocT(sizeof(float)*radx*rady*4, "filter tab");
1857         dgauss= gausstab;
1858         val= 0.0f;
1859         for(j=-rady; j<rady; j++) {
1860                 for(i=-radx; i<radx; i++, dgauss++) {
1861                         float fj= (float)j/radyf;
1862                         float fi= (float)i/radxf;
1863                         float dist= sqrt(fj*fj + fi*fi);
1864                         
1865 //                      *dgauss= hexagon_filter(fi, fj);
1866                         *dgauss= RE_filter_value(nbd->filtertype, 2.0f*dist - 1.0f);
1867
1868                         val+= *dgauss;
1869                 }
1870         }
1871         val= 1.0f/val;
1872         for(j= 4*radx*rady -1; j>=0; j--)
1873                 gausstab[j]*= val;
1874         
1875         
1876         /* vars to store before we go */
1877         //      refd= ref->rect;
1878         src= img->rect;
1879         
1880         memset(new->rect, 4*imgx*imgy, 0);
1881         
1882         for (y = 0; y < imgy; y++) {
1883                 for (x = 0; x < imgx ; x++, src+=4) {//, refd++) {
1884                         int minxr= x-radx<0?-x:-radx;
1885                         int maxxr= x+radx>imgx?imgx-x:radx;
1886                         int minyr= y-rady<0?-y:-rady;
1887                         int maxyr= y+rady>imgy?imgy-y:rady;
1888                         
1889                         float *destd= new->rect + 4*( (y + minyr)*imgx + x + minxr);
1890                         
1891                         float *dgausd= gausstab + (minyr+rady)*2*radx + minxr+radx;
1892                         
1893                         for (i= minyr; i < maxyr; i++, destd+= 4*imgx, dgausd+= 2*radx) {
1894                                 dest= destd;
1895                                 dgauss= dgausd;
1896                                 for (j= minxr; j < maxxr; j++, dest+=4, dgauss++) {
1897                                         
1898                                         val= *dgauss;
1899                                         dest[0] += val * src[0];
1900                                         dest[1] += val * src[1];
1901                                         dest[2] += val * src[2];
1902                                         dest[3] += val * src[3];
1903                                 }
1904                         }
1905                 }
1906         }
1907         
1908         MEM_freeT(gausstab);
1909 }
1910
1911
1912 /* reference has to be mapped 0-1, and equal in size */
1913 static void blur_with_reference(CompBuf *new, CompBuf *img, CompBuf *ref, NodeBlurData *nbd)
1914 {
1915         CompBuf *blurbuf;
1916         register float sum, val;
1917         float rval, gval, bval, aval, radxf, radyf;
1918         float **maintabs;
1919         float *gausstabx, *gausstabcenty;
1920         float *gausstaby, *gausstabcentx;
1921         int radx, rady, imgx= img->x, imgy= img->y;
1922         int x, y;
1923         int i, j;
1924         float *src, *dest, *refd, *blurd;
1925
1926         /* trick is; we blur the reference image... but only works with clipped values*/
1927         blurbuf= alloc_compbuf(imgx, imgy, CB_VAL, 1);
1928         blurd= blurbuf->rect;
1929         refd= ref->rect;
1930         for(x= imgx*imgy; x>0; x--, refd++, blurd++) {
1931                 if(refd[0]<0.0f) blurd[0]= 0.0f;
1932                 else if(refd[0]>1.0f) blurd[0]= 1.0f;
1933                 else blurd[0]= refd[0];
1934         }
1935         
1936         blur_single_image(blurbuf, blurbuf, 1.0f, nbd);
1937         
1938         /* horizontal */
1939         radx = (float)nbd->sizex;
1940         if(radx>imgx/2)
1941                 radx= imgx/2;
1942         else if(radx<1) 
1943                 radx= 1;
1944         
1945         /* vertical */
1946         rady = (float)nbd->sizey;
1947         if(rady>imgy/2)
1948                 rady= imgy/2;
1949         else if(rady<1) 
1950                 rady= 1;
1951         
1952         x= MAX2(radx, rady);
1953         maintabs= MEM_mallocT(x*sizeof(void *), "gauss array");
1954         for(i= 0; i<x; i++)
1955                 maintabs[i]= make_gausstab(nbd->filtertype, i+1);
1956         
1957         refd= blurbuf->rect;
1958         dest= new->rect;
1959         radxf= (float)radx;
1960         radyf= (float)rady;
1961         
1962         for (y = 0; y < imgy; y++) {
1963                 for (x = 0; x < imgx ; x++, dest+=4, refd++) {
1964                         int refradx= (int)(refd[0]*radxf);
1965                         int refrady= (int)(refd[0]*radyf);
1966                         
1967                         if(refradx>radx) refradx= radx;
1968                         else if(refradx<1) refradx= 1;
1969                         if(refrady>rady) refrady= rady;
1970                         else if(refrady<1) refrady= 1;
1971
1972                         if(refradx==1 && refrady==1) {
1973                                 src= img->rect + 4*( y*imgx + x);
1974                                 QUATCOPY(dest, src);
1975                         }
1976                         else {
1977                                 int minxr= x-refradx<0?-x:-refradx;
1978                                 int maxxr= x+refradx>imgx?imgx-x:refradx;
1979                                 int minyr= y-refrady<0?-y:-refrady;
1980                                 int maxyr= y+refrady>imgy?imgy-y:refrady;
1981         
1982                                 float *srcd= img->rect + 4*( (y + minyr)*imgx + x + minxr);
1983                                 
1984                                 gausstabx= maintabs[refradx-1];
1985                                 gausstabcentx= gausstabx+refradx;
1986                                 gausstaby= maintabs[refrady-1];
1987                                 gausstabcenty= gausstaby+refrady;
1988
1989                                 sum= gval = rval= bval= aval= 0.0f;
1990                                 
1991                                 for (i= minyr; i < maxyr; i++, srcd+= 4*imgx) {
1992                                         src= srcd;
1993                                         for (j= minxr; j < maxxr; j++, src+=4) {
1994                                         
1995                                                 val= gausstabcenty[i]*gausstabcentx[j];
1996                                                 sum+= val;
1997                                                 rval += val * src[0];
1998                                                 gval += val * src[1];
1999                                                 bval += val * src[2];
2000                                                 aval += val * src[3];
2001                                         }
2002                                 }
2003                                 sum= 1.0f/sum;
2004                                 dest[0] = rval*sum;
2005                                 dest[1] = gval*sum;
2006                                 dest[2] = bval*sum;
2007                                 dest[3] = aval*sum;
2008                         }
2009                 }
2010         }
2011         
2012         free_compbuf(blurbuf);
2013         
2014         x= MAX2(radx, rady);
2015         for(i= 0; i<x; i++)
2016                 MEM_freeT(maintabs[i]);
2017         MEM_freeT(maintabs);
2018         
2019 }
2020
2021
2022
2023 static void node_composit_exec_blur(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
2024 {
2025         CompBuf *new, *img= in[0]->data;
2026         
2027         if(img==NULL || out[0]->hasoutput==0)
2028                 return;
2029         
2030         /* if fac input, we do it different */
2031         if(in[1]->data) {
2032                 
2033                 /* test fitness if reference */
2034                 
2035                 /* make output size of input image */
2036                 new= alloc_compbuf(img->x, img->y, CB_RGBA, 1); // allocs
2037                 
2038                 blur_with_reference(new, img, in[1]->data, node->storage);
2039                 
2040                 out[0]->data= new;
2041         }
2042         else {
2043                 if(in[1]->vec[0]==0.0f) {
2044                         /* pass on image */
2045                         new= alloc_compbuf(img->x, img->y, img->type, 0);
2046                         new->rect= img->rect;
2047                 }
2048                 else {
2049                         NodeBlurData *nbd= node->storage;
2050                         CompBuf *gammabuf;
2051                         
2052                         /* make output size of input image */
2053                         new= alloc_compbuf(img->x, img->y, img->type, 1); // allocs
2054                         
2055                         if(nbd->gamma) {
2056                                 gammabuf= dupalloc_compbuf(img);
2057                                 gamma_correct_compbuf(gammabuf, 0);
2058                         }
2059                         else gammabuf= img;
2060                         
2061                         if(nbd->bokeh)
2062                                 bokeh_single_image(new, gammabuf, in[1]->vec[0], nbd);
2063                         else if(1)
2064                                 blur_single_image(new, gammabuf, in[1]->vec[0], nbd);
2065                         else    /* bloom experimental... */
2066                                 bloom_with_reference(new, gammabuf, NULL, in[1]->vec[0], nbd);
2067                         
2068                         if(nbd->gamma) {
2069                                 gamma_correct_compbuf(new, 1);
2070                                 free_compbuf(gammabuf);
2071                         }
2072                 }
2073                 out[0]->data= new;
2074         }
2075 }
2076         
2077
2078 static bNodeType cmp_node_blur= {
2079         /* type code   */       CMP_NODE_BLUR,
2080         /* name        */       "Blur",
2081         /* width+range */       120, 80, 200,
2082         /* class+opts  */       NODE_CLASS_OPERATOR, NODE_OPTIONS,
2083         /* input sock  */       cmp_node_blur_in,
2084         /* output sock */       cmp_node_blur_out,
2085         /* storage     */       "NodeBlurData",
2086         /* execfunc    */       node_composit_exec_blur
2087         
2088 };
2089
2090 /* **************** VECTOR BLUR ******************** */
2091 static bNodeSocketType cmp_node_vecblur_in[]= {
2092         {       SOCK_RGBA, 1, "Image",                  0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f},
2093         {       SOCK_VECTOR, 1, "Vec",                  0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
2094         {       -1, 0, ""       }
2095 };
2096 static bNodeSocketType cmp_node_vecblur_out[]= {
2097         {       SOCK_RGBA, 0, "Image",                  0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
2098         {       -1, 0, ""       }
2099 };
2100
2101 static void node_composit_exec_vecblur(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
2102 {
2103         NodeBlurData nbd;
2104         CompBuf *new, *img= in[0]->data, *vecbuf= in[1]->data, *wbuf;
2105         float *vect, *dest;
2106         int x, y;
2107         
2108         if(img==NULL || vecbuf==NULL || out[0]->hasoutput==0)
2109                 return;
2110         if(vecbuf->x!=img->x || vecbuf->y!=img->y) {
2111                 printf("cannot do different sized vecbuf yet\n");
2112                 return;
2113         }
2114         if(vecbuf->type!=CB_VEC2) {
2115                 printf("input should be vecbuf\n");
2116                 return;
2117         }
2118         
2119         /* make weights version of vectors */
2120         wbuf= alloc_compbuf(img->x, img->y, CB_VAL, 1); // allocs
2121         dest= wbuf->rect;
2122         vect= vecbuf->rect;
2123         for(y=0; y<img->y; y++) {
2124                 for(x=0; x<img->x; x++, dest++, vect+=2) {
2125                         *dest= 0.02f*sqrt(vect[0]*vect[0] + vect[1]*vect[1]);
2126                         if(*dest>1.0f) *dest= 1.0f;
2127                 }
2128         }
2129         
2130         /* make output size of input image */
2131         new= alloc_compbuf(img->x, img->y, CB_RGBA, 1); // allocs
2132         
2133         nbd.sizex= 100; nbd.sizey= 100; nbd.filtertype= R_FILTER_GAUSS;
2134         blur_with_reference(new, img, wbuf, &nbd);
2135         
2136         free_compbuf(wbuf);
2137         out[0]->data= new;
2138 }
2139
2140 static bNodeType cmp_node_vecblur= {
2141         /* type code   */       CMP_NODE_VECBLUR,
2142         /* name        */       "Vector Blur",
2143         /* width+range */       120, 80, 200,
2144         /* class+opts  */       NODE_CLASS_OPERATOR, NODE_OPTIONS,
2145         /* input sock  */       cmp_node_vecblur_in,
2146         /* output sock */       cmp_node_vecblur_out,
2147         /* storage     */       "",
2148         /* execfunc    */       node_composit_exec_vecblur
2149         
2150 };
2151
2152
2153 /* ****************** types array for all shaders ****************** */
2154
2155 bNodeType *node_all_composit[]= {
2156         &node_group_typeinfo,
2157         &cmp_node_viewer,
2158         &cmp_node_composite,
2159         &cmp_node_output_file,
2160         &cmp_node_value,
2161         &cmp_node_rgb,
2162         &cmp_node_mix_rgb,
2163         &cmp_node_filter,
2164         &cmp_node_valtorgb,
2165         &cmp_node_rgbtobw,
2166         &cmp_node_normal,
2167         &cmp_node_curve_vec,
2168         &cmp_node_curve_rgb,
2169         &cmp_node_image,
2170         &cmp_node_rresult,
2171         &cmp_node_alphaover,
2172         &cmp_node_blur,
2173         &cmp_node_vecblur,
2174         &cmp_node_map_value,
2175         NULL
2176 };
2177
2178 /* ******************* parse ************ */
2179
2180 /* helper call to detect if theres a render-result node */
2181 int ntreeCompositNeedsRender(bNodeTree *ntree)
2182 {
2183         bNode *node;
2184         
2185         if(ntree==NULL) return 1;
2186         
2187         for(node= ntree->nodes.first; node; node= node->next) {
2188                 if(node->type==CMP_NODE_R_RESULT)
2189                         return 1;
2190         }
2191         return 0;
2192 }
2193
2194 /* called from render pipeline, to tag render input and output */
2195 void ntreeCompositTagRender(bNodeTree *ntree)
2196 {
2197         bNode *node;
2198         
2199         if(ntree==NULL) return;
2200         
2201         for(node= ntree->nodes.first; node; node= node->next) {
2202                 if( ELEM(node->type, CMP_NODE_R_RESULT, CMP_NODE_COMPOSITE))
2203                         NodeTagChanged(ntree, node);
2204         }
2205 }
2206
2207 /* tags nodes that have animation capabilities */
2208 void ntreeCompositTagAnimated(bNodeTree *ntree)
2209 {
2210         bNode *node;
2211         
2212         if(ntree==NULL) return;
2213         
2214         for(node= ntree->nodes.first; node; node= node->next) {
2215                 if(node->type==CMP_NODE_IMAGE) {
2216                         /* no actual test yet... */
2217                         if(node->storage)
2218                                 NodeTagChanged(ntree, node);
2219                 }
2220         }
2221 }