More work on render stuff!
[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;
836         
837         if(node->id && node->id!=&G.scene->id)
838                 rr= RE_GetResult(RE_GetRender(node->id->name+2));
839         else
840                 rr= RE_GetResult(RE_GetRender("Render"));
841                 
842         if(rr) {
843                 RenderLayer *rl= BLI_findlink(&rr->layers, node->custom1);
844                 if(rl) {
845                         CompBuf *stackbuf;
846                         
847                         /* we put render rect on stack, cbuf knows rect is from other ibuf when freed! */
848                         stackbuf= alloc_compbuf(rr->rectx, rr->recty, CB_RGBA, 0);
849                         stackbuf->rect= rl->rectf;
850                         
851                         /* put on stack */      
852                         out[RRES_OUT_IMAGE]->data= stackbuf;
853                         
854                         if(out[RRES_OUT_ALPHA]->hasoutput)
855                                 out[RRES_OUT_ALPHA]->data= alphabuf_from_rgbabuf(stackbuf);
856                         if(out[RRES_OUT_Z]->hasoutput)
857                                 out[RRES_OUT_Z]->data= compbuf_from_pass(rl, rr->rectx, rr->recty, SCE_PASS_Z);
858                         if(out[RRES_OUT_VEC]->hasoutput)
859                                 out[RRES_OUT_VEC]->data= compbuf_from_pass(rl, rr->rectx, rr->recty, SCE_PASS_VECTOR);
860                         if(out[RRES_OUT_NOR]->hasoutput)
861                                 out[RRES_OUT_NOR]->data= compbuf_from_pass(rl, rr->rectx, rr->recty, SCE_PASS_NORMAL);
862 /*                      
863                         if(out[RRES_OUT_COL]->hasoutput)
864                                 out[RRES_OUT_COL]->data= compbuf_from_pass(rl, rr->rectx, rr->recty, SCE_PASS_RGBA);
865                         if(out[RRES_OUT_DIFF]->hasoutput)
866                                 out[RRES_OUT_DIFF]->data= compbuf_from_pass(rl, rr->rectx, rr->recty, SCE_PASS_DIFFUSE);
867                         if(out[RRES_OUT_SPEC]->hasoutput)
868                                 out[RRES_OUT_SPEC]->data= compbuf_from_pass(rl, rr->rectx, rr->recty, SCE_PASS_SPEC);
869                         if(out[RRES_OUT_SHAD]->hasoutput)
870                                 out[RRES_OUT_SHAD]->data= compbuf_from_pass(rl, rr->rectx, rr->recty, SCE_PASS_SHADOW);
871                         if(out[RRES_OUT_AO]->hasoutput)
872                                 out[RRES_OUT_AO]->data= compbuf_from_pass(rl, rr->rectx, rr->recty, SCE_PASS_AO);
873                         if(out[RRES_OUT_RAY]->hasoutput)
874                                 out[RRES_OUT_RAY]->data= compbuf_from_pass(rl, rr->rectx, rr->recty, SCE_PASS_RAY);
875 */                      
876                         generate_preview(node, stackbuf);
877                 }
878         }       
879 }
880
881 /* custom1 = render layer in use */
882 static bNodeType cmp_node_rresult= {
883         /* type code   */       CMP_NODE_R_RESULT,
884         /* name        */       "Render Result",
885         /* width+range */       120, 80, 300,
886         /* class+opts  */       NODE_CLASS_GENERATOR, NODE_PREVIEW|NODE_OPTIONS,
887         /* input sock  */       NULL,
888         /* output sock */       cmp_node_rresult_out,
889         /* storage     */       "",
890         /* execfunc    */       node_composit_exec_rresult
891         
892 };
893
894 /* **************** NORMAL  ******************** */
895 static bNodeSocketType cmp_node_normal_in[]= {
896         {       SOCK_VECTOR, 1, "Normal",       0.0f, 0.0f, 0.0f, 1.0f, -1.0f, 1.0f},
897         {       -1, 0, ""       }
898 };
899
900 static bNodeSocketType cmp_node_normal_out[]= {
901         {       SOCK_VECTOR, 0, "Normal",       0.0f, 0.0f, 1.0f, 1.0f, -1.0f, 1.0f},
902         {       SOCK_VALUE, 0, "Dot",           1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
903         {       -1, 0, ""       }
904 };
905
906 static void do_normal(bNode *node, float *out, float *in)
907 {
908         bNodeSocket *sock= node->outputs.first;
909         float *nor= sock->ns.vec;
910         
911         /* render normals point inside... the widget points outside */
912         out[0]= -INPR(nor, in);
913 }
914
915 /* generates normal, does dot product */
916 static void node_composit_exec_normal(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
917 {
918         bNodeSocket *sock= node->outputs.first;
919         /* stack order input:  normal */
920         /* stack order output: normal, value */
921         
922         /* input no image? then only vector op */
923         if(in[0]->data==NULL) {
924                 VECCOPY(out[0]->vec, sock->ns.vec);
925                 /* render normals point inside... the widget points outside */
926                 out[1]->vec[0]= -INPR(out[0]->vec, in[0]->vec);
927         }
928         else if(out[1]->hasoutput) {
929                 /* make output size of input image */
930                 CompBuf *cbuf= in[0]->data;
931                 CompBuf *stackbuf= alloc_compbuf(cbuf->x, cbuf->y, CB_VAL, 1); // allocs
932                 
933                 composit1_pixel_processor(node, stackbuf, in[0]->data, NULL, do_normal);
934                 
935                 out[1]->data= stackbuf;
936         }
937         
938         
939 }
940
941 static bNodeType cmp_node_normal= {
942         /* type code   */       CMP_NODE_NORMAL,
943         /* name        */       "Normal",
944         /* width+range */       100, 60, 200,
945         /* class+opts  */       NODE_CLASS_OPERATOR, NODE_OPTIONS,
946         /* input sock  */       cmp_node_normal_in,
947         /* output sock */       cmp_node_normal_out,
948         /* storage     */       "",
949         /* execfunc    */       node_composit_exec_normal
950         
951 };
952
953 /* **************** CURVE VEC  ******************** */
954 static bNodeSocketType cmp_node_curve_vec_in[]= {
955         {       SOCK_VECTOR, 1, "Vector",       0.0f, 0.0f, 0.0f, 1.0f, -1.0f, 1.0f},
956         {       -1, 0, ""       }
957 };
958
959 static bNodeSocketType cmp_node_curve_vec_out[]= {
960         {       SOCK_VECTOR, 0, "Vector",       0.0f, 0.0f, 1.0f, 1.0f, -1.0f, 1.0f},
961         {       -1, 0, ""       }
962 };
963
964 static void node_composit_exec_curve_vec(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
965 {
966         /* stack order input:  vec */
967         /* stack order output: vec */
968         
969         curvemapping_evaluate_premulRGBF(node->storage, out[0]->vec, in[0]->vec);
970 }
971
972 static bNodeType cmp_node_curve_vec= {
973         /* type code   */       CMP_NODE_CURVE_VEC,
974         /* name        */       "Vector Curves",
975         /* width+range */       200, 140, 320,
976         /* class+opts  */       NODE_CLASS_OPERATOR, NODE_OPTIONS,
977         /* input sock  */       cmp_node_curve_vec_in,
978         /* output sock */       cmp_node_curve_vec_out,
979         /* storage     */       "CurveMapping",
980         /* execfunc    */       node_composit_exec_curve_vec
981         
982 };
983
984 /* **************** CURVE RGB  ******************** */
985 static bNodeSocketType cmp_node_curve_rgb_in[]= {
986         {       SOCK_VALUE, 1, "Fac",   1.0f, 0.0f, 0.0f, 1.0f, -1.0f, 1.0f},
987         {       SOCK_RGBA, 1, "Image",  0.0f, 0.0f, 0.0f, 1.0f, -1.0f, 1.0f},
988         {       -1, 0, ""       }
989 };
990
991 static bNodeSocketType cmp_node_curve_rgb_out[]= {
992         {       SOCK_RGBA, 0, "Image",  0.0f, 0.0f, 1.0f, 1.0f, -1.0f, 1.0f},
993         {       -1, 0, ""       }
994 };
995
996 static void do_curves(bNode *node, float *out, float *in)
997 {
998         curvemapping_evaluateRGBF(node->storage, out, in);
999         out[3]= in[3];
1000 }
1001
1002 static void do_curves_fac(bNode *node, float *out, float *in, float *fac)
1003 {
1004         
1005         if(*fac>=1.0)
1006                 curvemapping_evaluateRGBF(node->storage, out, in);
1007         else if(*fac<=0.0) {
1008                 VECCOPY(out, in);
1009         }
1010         else {
1011                 float col[4], mfac= 1.0f-*fac;
1012                 curvemapping_evaluateRGBF(node->storage, col, in);
1013                 out[0]= mfac*in[0] + *fac*col[0];
1014                 out[1]= mfac*in[1] + *fac*col[1];
1015                 out[2]= mfac*in[2] + *fac*col[2];
1016         }
1017         out[3]= in[3];
1018 }
1019
1020 static void node_composit_exec_curve_rgb(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
1021 {
1022         /* stack order input:  vec */
1023         /* stack order output: vec */
1024         
1025         if(out[0]->hasoutput==0)
1026                 return;
1027
1028         /* input no image? then only color operation */
1029         if(in[1]->data==NULL) {
1030                 curvemapping_evaluateRGBF(node->storage, out[0]->vec, in[1]->vec);
1031         }
1032         else {
1033                 /* make output size of input image */
1034                 CompBuf *cbuf= in[1]->data;
1035                 CompBuf *stackbuf= alloc_compbuf(cbuf->x, cbuf->y, CB_RGBA, 1); // allocs
1036                 
1037                 curvemapping_premultiply(node->storage, 0);
1038                 if(in[0]->data)
1039                         composit2_pixel_processor(node, stackbuf, in[1]->data, in[1]->vec, in[0]->data, in[0]->vec, do_curves_fac);
1040                 else
1041                         composit1_pixel_processor(node, stackbuf, in[1]->data, NULL, do_curves);
1042                 curvemapping_premultiply(node->storage, 1);
1043                 
1044                 out[0]->data= stackbuf;
1045         }
1046         
1047 }
1048
1049 static bNodeType cmp_node_curve_rgb= {
1050         /* type code   */       CMP_NODE_CURVE_RGB,
1051         /* name        */       "RGB Curves",
1052         /* width+range */       200, 140, 320,
1053         /* class+opts  */       NODE_CLASS_OPERATOR, NODE_OPTIONS,
1054         /* input sock  */       cmp_node_curve_rgb_in,
1055         /* output sock */       cmp_node_curve_rgb_out,
1056         /* storage     */       "CurveMapping",
1057         /* execfunc    */       node_composit_exec_curve_rgb
1058         
1059 };
1060
1061 /* **************** VALUE ******************** */
1062 static bNodeSocketType cmp_node_value_out[]= {
1063         {       SOCK_VALUE, 0, "Value",         0.5f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
1064         {       -1, 0, ""       }
1065 };
1066
1067 static void node_composit_exec_value(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
1068 {
1069         bNodeSocket *sock= node->outputs.first;
1070         
1071         out[0]->vec[0]= sock->ns.vec[0];
1072 }
1073
1074 static bNodeType cmp_node_value= {
1075         /* type code   */       CMP_NODE_VALUE,
1076         /* name        */       "Value",
1077         /* width+range */       80, 40, 120,
1078         /* class+opts  */       NODE_CLASS_GENERATOR, NODE_OPTIONS,
1079         /* input sock  */       NULL,
1080         /* output sock */       cmp_node_value_out,
1081         /* storage     */       "", 
1082         /* execfunc    */       node_composit_exec_value
1083         
1084 };
1085
1086 /* **************** RGB ******************** */
1087 static bNodeSocketType cmp_node_rgb_out[]= {
1088         {       SOCK_RGBA, 0, "RGBA",                   0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f},
1089         {       -1, 0, ""       }
1090 };
1091
1092 static void node_composit_exec_rgb(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
1093 {
1094         bNodeSocket *sock= node->outputs.first;
1095         
1096         VECCOPY(out[0]->vec, sock->ns.vec);
1097 }
1098
1099 static bNodeType cmp_node_rgb= {
1100         /* type code   */       CMP_NODE_RGB,
1101         /* name        */       "RGB",
1102         /* width+range */       100, 60, 140,
1103         /* class+opts  */       NODE_CLASS_GENERATOR, NODE_OPTIONS,
1104         /* input sock  */       NULL,
1105         /* output sock */       cmp_node_rgb_out,
1106         /* storage     */       "",
1107         /* execfunc    */       node_composit_exec_rgb
1108         
1109 };
1110
1111 /* **************** MIX RGB ******************** */
1112 static bNodeSocketType cmp_node_mix_rgb_in[]= {
1113         {       SOCK_VALUE, 1, "Fac",                   0.5f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
1114         {       SOCK_RGBA, 1, "Image",                  0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f},
1115         {       SOCK_RGBA, 1, "Image",                  0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f},
1116         {       -1, 0, ""       }
1117 };
1118 static bNodeSocketType cmp_node_mix_rgb_out[]= {
1119         {       SOCK_RGBA, 0, "Image",                  0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
1120         {       -1, 0, ""       }
1121 };
1122
1123 static void do_mix_rgb(bNode *node, float *out, float *in1, float *in2, float fac)
1124 {
1125         float col[3];
1126         
1127         VECCOPY(col, in1);
1128         ramp_blend(node->custom1, col, col+1, col+2, fac, in2);
1129         VECCOPY(out, col);
1130         out[3]= in1[3];
1131 }
1132
1133 static void node_composit_exec_mix_rgb(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
1134 {
1135         /* stack order in: fac, Image, Image */
1136         /* stack order out: Image */
1137         float fac= in[0]->vec[0];
1138         
1139         CLAMP(fac, 0.0f, 1.0f);
1140         
1141         /* input no image? then only color operation */
1142         if(in[1]->data==NULL && in[2]->data==NULL) {
1143                 do_mix_rgb(node, out[0]->vec, in[1]->vec, in[2]->vec, fac);
1144         }
1145         else {
1146                 /* make output size of first available input image */
1147                 CompBuf *cbuf= in[1]->data?in[1]->data:in[2]->data;
1148                 CompBuf *stackbuf= alloc_compbuf(cbuf->x, cbuf->y, CB_RGBA, 1); // allocs
1149                 
1150                 composit3_pixel_processor(node, stackbuf, in[1]->data, in[1]->vec, in[2]->data, in[2]->vec, in[0]->data, fac, do_mix_rgb);
1151                 
1152                 out[0]->data= stackbuf;
1153         }
1154 }
1155
1156 /* custom1 = mix type */
1157 static bNodeType cmp_node_mix_rgb= {
1158         /* type code   */       CMP_NODE_MIX_RGB,
1159         /* name        */       "Mix",
1160         /* width+range */       80, 40, 120,
1161         /* class+opts  */       NODE_CLASS_OPERATOR, NODE_OPTIONS,
1162         /* input sock  */       cmp_node_mix_rgb_in,
1163         /* output sock */       cmp_node_mix_rgb_out,
1164         /* storage     */       "", 
1165         /* execfunc    */       node_composit_exec_mix_rgb
1166         
1167 };
1168
1169 /* **************** FILTER  ******************** */
1170 static bNodeSocketType cmp_node_filter_in[]= {
1171         {       SOCK_VALUE, 1, "Fac",                   1.0f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f},
1172         {       SOCK_RGBA, 1, "Image",                  0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f},
1173         {       -1, 0, ""       }
1174 };
1175 static bNodeSocketType cmp_node_filter_out[]= {
1176         {       SOCK_RGBA, 0, "Image",                  0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
1177         {       -1, 0, ""       }
1178 };
1179
1180 static void do_filter_edge(CompBuf *out, CompBuf *in, float *filter, float fac)
1181 {
1182         float *row1, *row2, *row3;
1183         float *fp, f1, f2, mfac= 1.0f-fac;
1184         int rowlen, x, y, c;
1185         
1186         rowlen= in->x;
1187         
1188         if(in->type==CB_RGBA) {
1189                 
1190                 for(y=2; y<in->y; y++) {
1191                         /* setup rows */
1192                         row1= in->rect + 4*(y-2)*rowlen;
1193                         row2= row1 + 4*rowlen;
1194                         row3= row2 + 4*rowlen;
1195                         fp= out->rect + 4*(y-1)*rowlen + 4;
1196                         
1197                         for(x=2; x<rowlen; x++) {
1198                                 for(c=0; c<3; c++) {
1199                                         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];
1200                                         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];
1201                                         fp[0]= mfac*row2[4] + fac*sqrt(f1*f1 + f2*f2);
1202                                         fp++; row1++; row2++; row3++;
1203                                 }
1204                                 fp[0]= row2[4];
1205                                 /* no alpha... will clear it completely */
1206                                 fp++; row1++; row2++; row3++;
1207                         }
1208                 }
1209         }       
1210 }
1211
1212 static void do_filter3(CompBuf *out, CompBuf *in, float *filter, float fac)
1213 {
1214         float *row1, *row2, *row3;
1215         float *fp, mfac= 1.0f-fac;
1216         int rowlen, x, y, c;
1217         int pixlen= in->type;
1218         
1219         rowlen= in->x;
1220         
1221         for(y=2; y<in->y; y++) {
1222                 /* setup rows */
1223                 row1= in->rect + pixlen*(y-2)*rowlen;
1224                 row2= row1 + pixlen*rowlen;
1225                 row3= row2 + pixlen*rowlen;
1226                 
1227                 fp= out->rect + pixlen*(y-1)*rowlen;
1228                 QUATCOPY(fp, row2);
1229                 fp+= pixlen;
1230                 
1231                 for(x=2; x<rowlen; x++) {
1232                         for(c=0; c<pixlen; c++) {
1233                                 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]);
1234                                 fp++; row1++; row2++; row3++;
1235                         }
1236                 }
1237         }
1238 }
1239
1240 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};
1241
1242 static void node_composit_exec_filter(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
1243 {
1244         float sharp[9]= {-1,-1,-1,-1,9,-1,-1,-1,-1};
1245         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};
1246         float sobel[9]= {1,2,1,0,0,0,-1,-2,-1};
1247         float prewitt[9]= {1,1,1,0,0,0,-1,-1,-1};
1248         float kirsch[9]= {5,5,5,-3,-3,-3,-2,-2,-2};
1249         float shadow[9]= {1,2,1,0,1,0,-1,-2,-1};
1250         
1251         /* stack order in: Image */
1252         /* stack order out: Image */
1253         
1254         if(in[1]->data) {
1255                 /* make output size of first available input image */
1256                 CompBuf *cbuf= in[1]->data;
1257                 CompBuf *stackbuf= alloc_compbuf(cbuf->x, cbuf->y, CB_RGBA, 1); // allocs
1258                 
1259                 switch(node->custom1) {
1260                         case CMP_FILT_SOFT:
1261                                 do_filter3(stackbuf, cbuf, soft, in[0]->vec[0]);
1262                                 break;
1263                         case CMP_FILT_SHARP:
1264                                 do_filter3(stackbuf, cbuf, sharp, in[0]->vec[0]);
1265                                 break;
1266                         case CMP_FILT_LAPLACE:
1267                                 do_filter3(stackbuf, cbuf, laplace, in[0]->vec[0]);
1268                                 break;
1269                         case CMP_FILT_SOBEL:
1270                                 do_filter_edge(stackbuf, cbuf, sobel, in[0]->vec[0]);
1271                                 break;
1272                         case CMP_FILT_PREWITT:
1273                                 do_filter_edge(stackbuf, cbuf, prewitt, in[0]->vec[0]);
1274                                 break;
1275                         case CMP_FILT_KIRSCH:
1276                                 do_filter_edge(stackbuf, cbuf, kirsch, in[0]->vec[0]);
1277                                 break;
1278                         case CMP_FILT_SHADOW:
1279                                 do_filter3(stackbuf, cbuf, shadow, in[0]->vec[0]);
1280                                 break;
1281                 }
1282                         
1283                 out[0]->data= stackbuf;
1284         }
1285 }
1286
1287 /* custom1 = filter type */
1288 static bNodeType cmp_node_filter= {
1289         /* type code   */       CMP_NODE_FILTER,
1290         /* name        */       "Filter",
1291         /* width+range */       80, 40, 120,
1292         /* class+opts  */       NODE_CLASS_OPERATOR, NODE_OPTIONS,
1293         /* input sock  */       cmp_node_filter_in,
1294         /* output sock */       cmp_node_filter_out,
1295         /* storage     */       "", 
1296         /* execfunc    */       node_composit_exec_filter
1297         
1298 };
1299
1300
1301 /* **************** VALTORGB ******************** */
1302 static bNodeSocketType cmp_node_valtorgb_in[]= {
1303         {       SOCK_VALUE, 1, "Fac",                   0.5f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
1304         {       -1, 0, ""       }
1305 };
1306 static bNodeSocketType cmp_node_valtorgb_out[]= {
1307         {       SOCK_RGBA, 0, "Image",                  0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
1308         {       SOCK_VALUE, 0, "Alpha",                 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
1309         {       -1, 0, ""       }
1310 };
1311
1312 static void do_colorband_composit(bNode *node, float *out, float *in)
1313 {
1314         do_colorband(node->storage, in[0], out);
1315 }
1316
1317 static void node_composit_exec_valtorgb(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
1318 {
1319         /* stack order in: fac */
1320         /* stack order out: col, alpha */
1321         
1322         if(node->storage) {
1323                 /* input no image? then only color operation */
1324                 if(in[0]->data==NULL) {
1325                         do_colorband(node->storage, in[0]->vec[0], out[0]->vec);
1326                 }
1327                 else {
1328                         /* make output size of input image */
1329                         CompBuf *cbuf= in[0]->data;
1330                         CompBuf *stackbuf= alloc_compbuf(cbuf->x, cbuf->y, CB_RGBA, 1); // allocs
1331                         
1332                         composit1_pixel_processor(node, stackbuf, in[0]->data, NULL, do_colorband_composit);
1333                         
1334                         out[0]->data= stackbuf;
1335                         
1336                         if(out[1]->hasoutput)
1337                                 out[1]->data= alphabuf_from_rgbabuf(stackbuf);
1338
1339                 }
1340         }
1341 }
1342
1343 static bNodeType cmp_node_valtorgb= {
1344         /* type code   */       CMP_NODE_VALTORGB,
1345         /* name        */       "ColorRamp",
1346         /* width+range */       240, 200, 300,
1347         /* class+opts  */       NODE_CLASS_OPERATOR, NODE_OPTIONS,
1348         /* input sock  */       cmp_node_valtorgb_in,
1349         /* output sock */       cmp_node_valtorgb_out,
1350         /* storage     */       "ColorBand",
1351         /* execfunc    */       node_composit_exec_valtorgb
1352         
1353 };
1354
1355
1356 /* **************** RGBTOBW ******************** */
1357 static bNodeSocketType cmp_node_rgbtobw_in[]= {
1358         {       SOCK_RGBA, 1, "Image",                  0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f},
1359         {       -1, 0, ""       }
1360 };
1361 static bNodeSocketType cmp_node_rgbtobw_out[]= {
1362         {       SOCK_VALUE, 0, "Val",                   0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
1363         {       -1, 0, ""       }
1364 };
1365
1366 static void do_rgbtobw(bNode *node, float *out, float *in)
1367 {
1368         out[0]= in[0]*0.35f + in[1]*0.45f + in[2]*0.2f;
1369 }
1370
1371 static void node_composit_exec_rgbtobw(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
1372 {
1373         /* stack order out: bw */
1374         /* stack order in: col */
1375         
1376         /* input no image? then only color operation */
1377         if(in[0]->data==NULL) {
1378                 out[0]->vec[0]= in[0]->vec[0]*0.35f + in[0]->vec[1]*0.45f + in[0]->vec[2]*0.2f;
1379         }
1380         else {
1381                 /* make output size of input image */
1382                 CompBuf *cbuf= in[0]->data;
1383                 CompBuf *stackbuf= alloc_compbuf(cbuf->x, cbuf->y, CB_VAL, 1); // allocs
1384                 
1385                 composit1_pixel_processor(node, stackbuf, in[0]->data, NULL, do_rgbtobw);
1386                 
1387                 out[0]->data= stackbuf;
1388         }
1389 }
1390
1391 static bNodeType cmp_node_rgbtobw= {
1392         /* type code   */       CMP_NODE_RGBTOBW,
1393         /* name        */       "RGB to BW",
1394         /* width+range */       80, 40, 120,
1395         /* class+opts  */       NODE_CLASS_OPERATOR, 0,
1396         /* input sock  */       cmp_node_rgbtobw_in,
1397         /* output sock */       cmp_node_rgbtobw_out,
1398         /* storage     */       "",
1399         /* execfunc    */       node_composit_exec_rgbtobw
1400         
1401 };
1402
1403 /* **************** ALPHAOVER ******************** */
1404 static bNodeSocketType cmp_node_alphaover_in[]= {
1405         {       SOCK_RGBA, 1, "Image",                  0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f},
1406         {       SOCK_RGBA, 1, "Image",                  0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f},
1407         {       -1, 0, ""       }
1408 };
1409 static bNodeSocketType cmp_node_alphaover_out[]= {
1410         {       SOCK_RGBA, 0, "Image",                  0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
1411         {       -1, 0, ""       }
1412 };
1413
1414 static void do_alphaover(bNode *node, float *out, float *src, float *over)
1415 {
1416         
1417         if(over[3]<=0.0f) {
1418                 QUATCOPY(out, src);
1419         }
1420         else if(over[3]>=1.0f) {
1421                 QUATCOPY(out, over);
1422         }
1423         else {
1424                 float mul= 1.0f - over[3];
1425                 
1426                 /* handle case where backdrop has no alpha, but still color */
1427                 if(src[0]==0.0f) {
1428                         out[0]= over[0];
1429                         out[1]= (mul*src[1]) + over[1];
1430                         out[2]= (mul*src[2]) + over[2];
1431                         out[3]= (mul*src[3]) + over[3];
1432                 }
1433                 else {
1434                         out[0]= (mul*src[0]) + over[0];
1435                         out[1]= (mul*src[1]) + over[1];
1436                         out[2]= (mul*src[2]) + over[2];
1437                         out[3]= (mul*src[3]) + over[3];
1438                 }
1439         }       
1440 }
1441
1442 static void node_composit_exec_alphaover(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
1443 {
1444         /* stack order in: col col */
1445         /* stack order out: col */
1446         
1447         /* input no image? then only color operation */
1448         if(in[0]->data==NULL) {
1449                 do_alphaover(node, out[0]->vec, in[0]->vec, in[1]->vec);
1450         }
1451         else {
1452                 /* make output size of input image */
1453                 CompBuf *cbuf= in[0]->data;
1454                 CompBuf *stackbuf= alloc_compbuf(cbuf->x, cbuf->y, CB_RGBA, 1); // allocs
1455                 
1456                 composit2_pixel_processor(node, stackbuf, in[0]->data, in[0]->vec, in[1]->data, in[1]->vec, do_alphaover);
1457                 
1458                 out[0]->data= stackbuf;
1459         }
1460 }
1461
1462 static bNodeType cmp_node_alphaover= {
1463         /* type code   */       CMP_NODE_ALPHAOVER,
1464         /* name        */       "AlphaOver",
1465         /* width+range */       80, 40, 120,
1466         /* class+opts  */       NODE_CLASS_OPERATOR, 0,
1467         /* input sock  */       cmp_node_alphaover_in,
1468         /* output sock */       cmp_node_alphaover_out,
1469         /* storage     */       "",
1470         /* execfunc    */       node_composit_exec_alphaover
1471         
1472 };
1473
1474 /* **************** MAP VALUE ******************** */
1475 static bNodeSocketType cmp_node_map_value_in[]= {
1476         {       SOCK_VALUE, 1, "Value",                 1.0f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f},
1477         {       -1, 0, ""       }
1478 };
1479 static bNodeSocketType cmp_node_map_value_out[]= {
1480         {       SOCK_VALUE, 0, "Value",                 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
1481         {       -1, 0, ""       }
1482 };
1483
1484 static void do_map_value(bNode *node, float *out, float *src)
1485 {
1486         TexMapping *texmap= node->storage;
1487         
1488         out[0]= (src[0] + texmap->loc[0])*texmap->size[0];
1489         if(texmap->flag & TEXMAP_CLIP_MIN)
1490                 if(out[0]<texmap->min[0])
1491                         out[0]= texmap->min[0];
1492         if(texmap->flag & TEXMAP_CLIP_MAX)
1493                 if(out[0]>texmap->max[0])
1494                         out[0]= texmap->max[0];
1495 }
1496
1497 static void node_composit_exec_map_value(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
1498 {
1499         /* stack order in: col col */
1500         /* stack order out: col */
1501         
1502         /* input no image? then only value operation */
1503         if(in[0]->data==NULL) {
1504                 do_map_value(node, out[0]->vec, in[0]->vec);
1505         }
1506         else {
1507                 /* make output size of input image */
1508                 CompBuf *cbuf= in[0]->data;
1509                 CompBuf *stackbuf= alloc_compbuf(cbuf->x, cbuf->y, CB_VAL, 1); // allocs
1510                 
1511                 composit1_pixel_processor(node, stackbuf, in[0]->data, in[0]->vec, do_map_value);
1512                 
1513                 out[0]->data= stackbuf;
1514         }
1515 }
1516
1517 static bNodeType cmp_node_map_value= {
1518         /* type code   */       CMP_NODE_MAP_VALUE,
1519         /* name        */       "Map Value",
1520         /* width+range */       100, 60, 150,
1521         /* class+opts  */       NODE_CLASS_OPERATOR, NODE_OPTIONS,
1522         /* input sock  */       cmp_node_map_value_in,
1523         /* output sock */       cmp_node_map_value_out,
1524         /* storage     */       "TexMapping",
1525         /* execfunc    */       node_composit_exec_map_value
1526         
1527 };
1528
1529 /* **************** BLUR ******************** */
1530 static bNodeSocketType cmp_node_blur_in[]= {
1531         {       SOCK_RGBA, 1, "Image",                  0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f},
1532         {       SOCK_VALUE, 1, "Size",                  1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
1533         {       -1, 0, ""       }
1534 };
1535 static bNodeSocketType cmp_node_blur_out[]= {
1536         {       SOCK_RGBA, 0, "Image",                  0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
1537         {       -1, 0, ""       }
1538 };
1539
1540 static float *make_gausstab(int filtertype, int rad)
1541 {
1542         float *gausstab, sum, val;
1543         int i, n;
1544         
1545         n = 2 * rad + 1;
1546         
1547         gausstab = (float *) MEM_mallocT(n * sizeof(float), "gauss");
1548         
1549         sum = 0.0f;
1550         for (i = -rad; i <= rad; i++) {
1551                 val= RE_filter_value(filtertype, (float)i/(float)rad);
1552                 sum += val;
1553                 gausstab[i+rad] = val;
1554         }
1555         
1556         sum= 1.0f/sum;
1557         for(i=0; i<n; i++)
1558                 gausstab[i]*= sum;
1559         
1560         return gausstab;
1561 }
1562
1563 static float *make_bloomtab(int rad)
1564 {
1565         float *bloomtab, val;
1566         int i, n;
1567         
1568         n = 2 * rad + 1;
1569         
1570         bloomtab = (float *) MEM_mallocT(n * sizeof(float), "bloom");
1571         
1572         for (i = -rad; i <= rad; i++) {
1573                 val = pow(1.0 - fabs((float)i)/((float)rad), 4.0);
1574                 bloomtab[i+rad] = val;
1575         }
1576         
1577         return bloomtab;
1578 }
1579
1580 static void blur_single_image(CompBuf *new, CompBuf *img, float scale, NodeBlurData *nbd)
1581 {
1582         CompBuf *work;
1583         register float sum, val;
1584         float rval, gval, bval, aval;
1585         float *gausstab, *gausstabcent;
1586         int rad, imgx= img->x, imgy= img->y;
1587         int x, y, pix= img->type;
1588         int i, bigstep;
1589         float *src, *dest;
1590
1591         /* helper image */
1592         work= alloc_compbuf(imgx, imgy, img->type, 1); // allocs
1593         
1594         /* horizontal */
1595         rad = scale*(float)nbd->sizex;
1596         if(rad>imgx/2)
1597                 rad= imgx/2;
1598         else if(rad<1) 
1599                 rad= 1;
1600
1601         gausstab= make_gausstab(nbd->filtertype, rad);
1602         gausstabcent= gausstab+rad;
1603         
1604         for (y = 0; y < imgy; y++) {
1605                 float *srcd= img->rect + pix*(y*img->x);
1606                 
1607                 dest = work->rect + pix*(y * img->x);
1608                 
1609                 for (x = 0; x < imgx ; x++) {
1610                         int minr= x-rad<0?-x:-rad;
1611                         int maxr= x+rad>imgx?imgx-x:rad;
1612                         
1613                         src= srcd + pix*(x+minr);
1614                         
1615                         sum= gval = rval= bval= aval= 0.0f;
1616                         for (i= minr; i < maxr; i++) {
1617                                 val= gausstabcent[i];
1618                                 sum+= val;
1619                                 rval += val * (*src++);
1620                                 if(pix==4) {
1621                                         gval += val * (*src++);
1622                                         bval += val * (*src++);
1623                                         aval += val * (*src++);
1624                                 }
1625                         }
1626                         sum= 1.0f/sum;
1627                         *dest++ = rval*sum;
1628                         if(pix==4) {
1629                                 *dest++ = gval*sum;
1630                                 *dest++ = bval*sum;
1631                                 *dest++ = aval*sum;
1632                         }
1633                 }
1634         }
1635         
1636         /* vertical */
1637         MEM_freeT(gausstab);
1638         
1639         rad = scale*(float)nbd->sizey;
1640         if(rad>imgy/2)
1641                 rad= imgy/2;
1642         else if(rad<1) 
1643                 rad= 1;
1644
1645         gausstab= make_gausstab(nbd->filtertype, rad);
1646         gausstabcent= gausstab+rad;
1647         
1648         bigstep = pix*imgx;
1649         for (x = 0; x < imgx; x++) {
1650                 float *srcd= work->rect + pix*x;
1651                 
1652                 dest = new->rect + pix*x;
1653                 
1654                 for (y = 0; y < imgy ; y++) {
1655                         int minr= y-rad<0?-y:-rad;
1656                         int maxr= y+rad>imgy?imgy-y:rad;
1657                         
1658                         src= srcd + bigstep*(y+minr);
1659                         
1660                         sum= gval = rval= bval= aval= 0.0f;
1661                         for (i= minr; i < maxr; i++) {
1662                                 val= gausstabcent[i];
1663                                 sum+= val;
1664                                 rval += val * src[0];
1665                                 if(pix==4) {
1666                                         gval += val * src[1];
1667                                         bval += val * src[2];
1668                                         aval += val * src[3];
1669                                 }
1670                                 src += bigstep;
1671                         }
1672                         sum= 1.0f/sum;
1673                         dest[0] = rval*sum;
1674                         if(pix==4) {
1675                                 dest[1] = gval*sum;
1676                                 dest[2] = bval*sum;
1677                                 dest[3] = aval*sum;
1678                         }
1679                         dest+= bigstep;
1680                 }
1681         }
1682         
1683         free_compbuf(work);
1684         MEM_freeT(gausstab);
1685 }
1686
1687 /* reference has to be mapped 0-1, and equal in size */
1688 static void bloom_with_reference(CompBuf *new, CompBuf *img, CompBuf *ref, float fac, NodeBlurData *nbd)
1689 {
1690         CompBuf *wbuf;
1691         register float val;
1692         float radxf, radyf;
1693         float **maintabs;
1694         float *gausstabx, *gausstabcenty;
1695         float *gausstaby, *gausstabcentx;
1696         int radx, rady, imgx= img->x, imgy= img->y;
1697         int x, y;
1698         int i, j;
1699         float *src, *dest, *wb;
1700         
1701         wbuf= alloc_compbuf(imgx, imgy, CB_VAL, 1);
1702         memset(wbuf->rect, sizeof(float)*imgx*imgy, 0);
1703         
1704         /* horizontal */
1705         radx = (float)nbd->sizex;
1706         if(radx>imgx/2)
1707                 radx= imgx/2;
1708         else if(radx<1) 
1709                 radx= 1;
1710         
1711         /* vertical */
1712         rady = (float)nbd->sizey;
1713         if(rady>imgy/2)
1714                 rady= imgy/2;
1715         else if(rady<1) 
1716                 rady= 1;
1717         
1718         x= MAX2(radx, rady);
1719         maintabs= MEM_mallocT(x*sizeof(void *), "gauss array");
1720         for(i= 0; i<x; i++)
1721                 maintabs[i]= make_bloomtab(i+1);
1722                 
1723         /* vars to store before we go */
1724 //      refd= ref->rect;
1725         src= img->rect;
1726         
1727         memset(new->rect, 4*imgx*imgy, 0);
1728         
1729         radxf= (float)radx;
1730         radyf= (float)rady;
1731         
1732         for (y = 0; y < imgy; y++) {
1733                 for (x = 0; x < imgx ; x++, src+=4) {//, refd++) {
1734                         
1735 //                      int refradx= (int)(refd[0]*radxf);
1736 //                      int refrady= (int)(refd[0]*radyf);
1737                         
1738                         int refradx= (int)(radxf*0.3f*src[3]*(src[0]+src[1]+src[2]));
1739                         int refrady= (int)(radyf*0.3f*src[3]*(src[0]+src[1]+src[2]));
1740                         
1741                         if(refradx>radx) refradx= radx;
1742                         else if(refradx<1) refradx= 1;
1743                         if(refrady>rady) refrady= rady;
1744                         else if(refrady<1) refrady= 1;
1745                         
1746                         if(refradx==1 && refrady==1) {
1747                                 wb= wbuf->rect + ( y*imgx + x);
1748                                 dest= new->rect + 4*( y*imgx + x);
1749                                 wb[0]+= 1.0f;
1750                                 dest[0] += src[0];
1751                                 dest[1] += src[1];
1752                                 dest[2] += src[2];
1753                                 dest[3] += src[3];
1754                         }
1755                         else {
1756                                 int minxr= x-refradx<0?-x:-refradx;
1757                                 int maxxr= x+refradx>imgx?imgx-x:refradx;
1758                                 int minyr= y-refrady<0?-y:-refrady;
1759                                 int maxyr= y+refrady>imgy?imgy-y:refrady;
1760                                 
1761                                 float *destd= new->rect + 4*( (y + minyr)*imgx + x + minxr);
1762                                 float *wbufd= wbuf->rect + ( (y + minyr)*imgx + x + minxr);
1763                                 
1764                                 gausstabx= maintabs[refradx-1];
1765                                 gausstabcentx= gausstabx+refradx;
1766                                 gausstaby= maintabs[refrady-1];
1767                                 gausstabcenty= gausstaby+refrady;
1768                                 
1769                                 for (i= minyr; i < maxyr; i++, destd+= 4*imgx, wbufd+= imgx) {
1770                                         dest= destd;
1771                                         wb= wbufd;
1772                                         for (j= minxr; j < maxxr; j++, dest+=4, wb++) {
1773                                                 
1774                                                 val= gausstabcenty[i]*gausstabcentx[j];
1775                                                 wb[0]+= val;
1776                                                 dest[0] += val * src[0];
1777                                                 dest[1] += val * src[1];
1778                                                 dest[2] += val * src[2];
1779                                                 dest[3] += val * src[3];
1780                                         }
1781                                 }
1782                         }
1783                 }
1784         }
1785         
1786         x= imgx*imgy;
1787         dest= new->rect;
1788         wb= wbuf->rect;
1789         while(x--) {
1790                 val= 1.0f/wb[0];
1791                 dest[0]*= val;
1792                 dest[1]*= val;
1793                 dest[2]*= val;
1794                 dest[3]*= val;
1795                 wb++;
1796                 dest+= 4;
1797         }
1798         
1799         free_compbuf(wbuf);
1800         
1801         x= MAX2(radx, rady);
1802         for(i= 0; i<x; i++)
1803                 MEM_freeT(maintabs[i]);
1804         MEM_freeT(maintabs);
1805         
1806 }
1807
1808 static void gamma_correct_compbuf(CompBuf *img, int inversed)
1809 {
1810         float *drect;
1811         int x;
1812         
1813         drect= img->rect;
1814         if(inversed) {
1815                 for(x=img->x*img->y; x>0; x--, drect+=4) {
1816                         if(drect[0]>0.0f) drect[0]= sqrt(drect[0]); else drect[0]= 0.0f;
1817                         if(drect[1]>0.0f) drect[1]= sqrt(drect[1]); else drect[1]= 0.0f;
1818                         if(drect[2]>0.0f) drect[2]= sqrt(drect[2]); else drect[2]= 0.0f;
1819                 }
1820         }
1821         else {
1822                 for(x=img->x*img->y; x>0; x--, drect+=4) {
1823                         if(drect[0]>0.0f) drect[0]*= drect[0]; else drect[0]= 0.0f;
1824                         if(drect[1]>0.0f) drect[1]*= drect[1]; else drect[1]= 0.0f;
1825                         if(drect[2]>0.0f) drect[2]*= drect[2]; else drect[2]= 0.0f;
1826                 }
1827         }
1828 }
1829 #if 0
1830 static float hexagon_filter(float fi, float fj)
1831 {
1832         fi= fabs(fi);
1833         fj= fabs(fj);
1834         
1835         if(fj>0.33f) {
1836                 fj= (fj-0.33f)/0.66f;
1837                 if(fi+fj>1.0f)
1838                         return 0.0f;
1839                 else
1840                         return 1.0f;
1841         }
1842         else return 1.0f;
1843 }
1844 #endif
1845 /* uses full filter, no horizontal/vertical optimize possible */
1846 static void bokeh_single_image(CompBuf *new, CompBuf *img, float fac, NodeBlurData *nbd)
1847 {
1848         register float val;
1849         float radxf, radyf;
1850         float *gausstab, *dgauss;
1851         int radx, rady, imgx= img->x, imgy= img->y;
1852         int x, y;
1853         int i, j;
1854         float *src, *dest;
1855         
1856         /* horizontal */
1857         radx = fac*(float)nbd->sizex;
1858         if(radx>imgx/2)
1859                 radx= imgx/2;
1860         else if(radx<1) 
1861                 radx= 1;
1862         
1863         /* vertical */
1864         rady = fac*(float)nbd->sizey;
1865         if(rady>imgy/2)
1866                 rady= imgy/2;
1867         else if(rady<1) 
1868                 rady= 1;
1869         
1870         radxf= (float)radx;
1871         radyf= (float)rady;
1872         
1873         /* create a full filter image */
1874         gausstab= MEM_mallocT(sizeof(float)*radx*rady*4, "filter tab");
1875         dgauss= gausstab;
1876         val= 0.0f;
1877         for(j=-rady; j<rady; j++) {
1878                 for(i=-radx; i<radx; i++, dgauss++) {
1879                         float fj= (float)j/radyf;
1880                         float fi= (float)i/radxf;
1881                         float dist= sqrt(fj*fj + fi*fi);
1882                         
1883 //                      *dgauss= hexagon_filter(fi, fj);
1884                         *dgauss= RE_filter_value(nbd->filtertype, 2.0f*dist - 1.0f);
1885
1886                         val+= *dgauss;
1887                 }
1888         }
1889         val= 1.0f/val;
1890         for(j= 4*radx*rady -1; j>=0; j--)
1891                 gausstab[j]*= val;
1892         
1893         
1894         /* vars to store before we go */
1895         //      refd= ref->rect;
1896         src= img->rect;
1897         
1898         memset(new->rect, 4*imgx*imgy, 0);
1899         
1900         for (y = 0; y < imgy; y++) {
1901                 for (x = 0; x < imgx ; x++, src+=4) {//, refd++) {
1902                         int minxr= x-radx<0?-x:-radx;
1903                         int maxxr= x+radx>imgx?imgx-x:radx;
1904                         int minyr= y-rady<0?-y:-rady;
1905                         int maxyr= y+rady>imgy?imgy-y:rady;
1906                         
1907                         float *destd= new->rect + 4*( (y + minyr)*imgx + x + minxr);
1908                         
1909                         float *dgausd= gausstab + (minyr+rady)*2*radx + minxr+radx;
1910                         
1911                         for (i= minyr; i < maxyr; i++, destd+= 4*imgx, dgausd+= 2*radx) {
1912                                 dest= destd;
1913                                 dgauss= dgausd;
1914                                 for (j= minxr; j < maxxr; j++, dest+=4, dgauss++) {
1915                                         
1916                                         val= *dgauss;
1917                                         dest[0] += val * src[0];
1918                                         dest[1] += val * src[1];
1919                                         dest[2] += val * src[2];
1920                                         dest[3] += val * src[3];
1921                                 }
1922                         }
1923                 }
1924         }
1925         
1926         MEM_freeT(gausstab);
1927 }
1928
1929
1930 /* reference has to be mapped 0-1, and equal in size */
1931 static void blur_with_reference(CompBuf *new, CompBuf *img, CompBuf *ref, NodeBlurData *nbd)
1932 {
1933         CompBuf *blurbuf;
1934         register float sum, val;
1935         float rval, gval, bval, aval, radxf, radyf;
1936         float **maintabs;
1937         float *gausstabx, *gausstabcenty;
1938         float *gausstaby, *gausstabcentx;
1939         int radx, rady, imgx= img->x, imgy= img->y;
1940         int x, y;
1941         int i, j;
1942         float *src, *dest, *refd, *blurd;
1943
1944         /* trick is; we blur the reference image... but only works with clipped values*/
1945         blurbuf= alloc_compbuf(imgx, imgy, CB_VAL, 1);
1946         blurd= blurbuf->rect;
1947         refd= ref->rect;
1948         for(x= imgx*imgy; x>0; x--, refd++, blurd++) {
1949                 if(refd[0]<0.0f) blurd[0]= 0.0f;
1950                 else if(refd[0]>1.0f) blurd[0]= 1.0f;
1951                 else blurd[0]= refd[0];
1952         }
1953         
1954         blur_single_image(blurbuf, blurbuf, 1.0f, nbd);
1955         
1956         /* horizontal */
1957         radx = (float)nbd->sizex;
1958         if(radx>imgx/2)
1959                 radx= imgx/2;
1960         else if(radx<1) 
1961                 radx= 1;
1962         
1963         /* vertical */
1964         rady = (float)nbd->sizey;
1965         if(rady>imgy/2)
1966                 rady= imgy/2;
1967         else if(rady<1) 
1968                 rady= 1;
1969         
1970         x= MAX2(radx, rady);
1971         maintabs= MEM_mallocT(x*sizeof(void *), "gauss array");
1972         for(i= 0; i<x; i++)
1973                 maintabs[i]= make_gausstab(nbd->filtertype, i+1);
1974         
1975         refd= blurbuf->rect;
1976         dest= new->rect;
1977         radxf= (float)radx;
1978         radyf= (float)rady;
1979         
1980         for (y = 0; y < imgy; y++) {
1981                 for (x = 0; x < imgx ; x++, dest+=4, refd++) {
1982                         int refradx= (int)(refd[0]*radxf);
1983                         int refrady= (int)(refd[0]*radyf);
1984                         
1985                         if(refradx>radx) refradx= radx;
1986                         else if(refradx<1) refradx= 1;
1987                         if(refrady>rady) refrady= rady;
1988                         else if(refrady<1) refrady= 1;
1989
1990                         if(refradx==1 && refrady==1) {
1991                                 src= img->rect + 4*( y*imgx + x);
1992                                 QUATCOPY(dest, src);
1993                         }
1994                         else {
1995                                 int minxr= x-refradx<0?-x:-refradx;
1996                                 int maxxr= x+refradx>imgx?imgx-x:refradx;
1997                                 int minyr= y-refrady<0?-y:-refrady;
1998                                 int maxyr= y+refrady>imgy?imgy-y:refrady;
1999         
2000                                 float *srcd= img->rect + 4*( (y + minyr)*imgx + x + minxr);
2001                                 
2002                                 gausstabx= maintabs[refradx-1];
2003                                 gausstabcentx= gausstabx+refradx;
2004                                 gausstaby= maintabs[refrady-1];
2005                                 gausstabcenty= gausstaby+refrady;
2006
2007                                 sum= gval = rval= bval= aval= 0.0f;
2008                                 
2009                                 for (i= minyr; i < maxyr; i++, srcd+= 4*imgx) {
2010                                         src= srcd;
2011                                         for (j= minxr; j < maxxr; j++, src+=4) {
2012                                         
2013                                                 val= gausstabcenty[i]*gausstabcentx[j];
2014                                                 sum+= val;
2015                                                 rval += val * src[0];
2016                                                 gval += val * src[1];
2017                                                 bval += val * src[2];
2018                                                 aval += val * src[3];
2019                                         }
2020                                 }
2021                                 sum= 1.0f/sum;
2022                                 dest[0] = rval*sum;
2023                                 dest[1] = gval*sum;
2024                                 dest[2] = bval*sum;
2025                                 dest[3] = aval*sum;
2026                         }
2027                 }
2028         }
2029         
2030         free_compbuf(blurbuf);
2031         
2032         x= MAX2(radx, rady);
2033         for(i= 0; i<x; i++)
2034                 MEM_freeT(maintabs[i]);
2035         MEM_freeT(maintabs);
2036         
2037 }
2038
2039
2040
2041 static void node_composit_exec_blur(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
2042 {
2043         CompBuf *new, *img= in[0]->data;
2044         
2045         if(img==NULL || out[0]->hasoutput==0)
2046                 return;
2047         
2048         /* if fac input, we do it different */
2049         if(in[1]->data) {
2050                 
2051                 /* test fitness if reference */
2052                 
2053                 /* make output size of input image */
2054                 new= alloc_compbuf(img->x, img->y, CB_RGBA, 1); // allocs
2055                 
2056                 blur_with_reference(new, img, in[1]->data, node->storage);
2057                 
2058                 out[0]->data= new;
2059         }
2060         else {
2061                 if(in[1]->vec[0]==0.0f) {
2062                         /* pass on image */
2063                         new= alloc_compbuf(img->x, img->y, img->type, 0);
2064                         new->rect= img->rect;
2065                 }
2066                 else {
2067                         NodeBlurData *nbd= node->storage;
2068                         CompBuf *gammabuf;
2069                         
2070                         /* make output size of input image */
2071                         new= alloc_compbuf(img->x, img->y, img->type, 1); // allocs
2072                         
2073                         if(nbd->gamma) {
2074                                 gammabuf= dupalloc_compbuf(img);
2075                                 gamma_correct_compbuf(gammabuf, 0);
2076                         }
2077                         else gammabuf= img;
2078                         
2079                         if(nbd->bokeh)
2080                                 bokeh_single_image(new, gammabuf, in[1]->vec[0], nbd);
2081                         else if(1)
2082                                 blur_single_image(new, gammabuf, in[1]->vec[0], nbd);
2083                         else    /* bloom experimental... */
2084                                 bloom_with_reference(new, gammabuf, NULL, in[1]->vec[0], nbd);
2085                         
2086                         if(nbd->gamma) {
2087                                 gamma_correct_compbuf(new, 1);
2088                                 free_compbuf(gammabuf);
2089                         }
2090                 }
2091                 out[0]->data= new;
2092         }
2093 }
2094         
2095
2096 static bNodeType cmp_node_blur= {
2097         /* type code   */       CMP_NODE_BLUR,
2098         /* name        */       "Blur",
2099         /* width+range */       120, 80, 200,
2100         /* class+opts  */       NODE_CLASS_OPERATOR, NODE_OPTIONS,
2101         /* input sock  */       cmp_node_blur_in,
2102         /* output sock */       cmp_node_blur_out,
2103         /* storage     */       "NodeBlurData",
2104         /* execfunc    */       node_composit_exec_blur
2105         
2106 };
2107
2108 /* **************** VECTOR BLUR ******************** */
2109 static bNodeSocketType cmp_node_vecblur_in[]= {
2110         {       SOCK_RGBA, 1, "Image",                  0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f},
2111         {       SOCK_VECTOR, 1, "Vec",                  0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
2112         {       -1, 0, ""       }
2113 };
2114 static bNodeSocketType cmp_node_vecblur_out[]= {
2115         {       SOCK_RGBA, 0, "Image",                  0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
2116         {       -1, 0, ""       }
2117 };
2118
2119 static void node_composit_exec_vecblur(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
2120 {
2121         NodeBlurData nbd;
2122         CompBuf *new, *img= in[0]->data, *vecbuf= in[1]->data, *wbuf;
2123         float *vect, *dest;
2124         int x, y;
2125         
2126         if(img==NULL || vecbuf==NULL || out[0]->hasoutput==0)
2127                 return;
2128         if(vecbuf->x!=img->x || vecbuf->y!=img->y) {
2129                 printf("cannot do different sized vecbuf yet\n");
2130                 return;
2131         }
2132         if(vecbuf->type!=CB_VEC2) {
2133                 printf("input should be vecbuf\n");
2134                 return;
2135         }
2136         
2137         /* make weights version of vectors */
2138         wbuf= alloc_compbuf(img->x, img->y, CB_VAL, 1); // allocs
2139         dest= wbuf->rect;
2140         vect= vecbuf->rect;
2141         for(y=0; y<img->y; y++) {
2142                 for(x=0; x<img->x; x++, dest++, vect+=2) {
2143                         *dest= 0.02f*sqrt(vect[0]*vect[0] + vect[1]*vect[1]);
2144                         if(*dest>1.0f) *dest= 1.0f;
2145                 }
2146         }
2147         
2148         /* make output size of input image */
2149         new= alloc_compbuf(img->x, img->y, CB_RGBA, 1); // allocs
2150         
2151         nbd.sizex= 100; nbd.sizey= 100; nbd.filtertype= R_FILTER_GAUSS;
2152         blur_with_reference(new, img, wbuf, &nbd);
2153         
2154         free_compbuf(wbuf);
2155         out[0]->data= new;
2156 }
2157
2158 static bNodeType cmp_node_vecblur= {
2159         /* type code   */       CMP_NODE_VECBLUR,
2160         /* name        */       "Vector Blur",
2161         /* width+range */       120, 80, 200,
2162         /* class+opts  */       NODE_CLASS_OPERATOR, NODE_OPTIONS,
2163         /* input sock  */       cmp_node_vecblur_in,
2164         /* output sock */       cmp_node_vecblur_out,
2165         /* storage     */       "",
2166         /* execfunc    */       node_composit_exec_vecblur
2167         
2168 };
2169
2170
2171 /* ****************** types array for all shaders ****************** */
2172
2173 bNodeType *node_all_composit[]= {
2174         &node_group_typeinfo,
2175         &cmp_node_viewer,
2176         &cmp_node_composite,
2177         &cmp_node_output_file,
2178         &cmp_node_value,
2179         &cmp_node_rgb,
2180         &cmp_node_mix_rgb,
2181         &cmp_node_filter,
2182         &cmp_node_valtorgb,
2183         &cmp_node_rgbtobw,
2184         &cmp_node_normal,
2185         &cmp_node_curve_vec,
2186         &cmp_node_curve_rgb,
2187         &cmp_node_image,
2188         &cmp_node_rresult,
2189         &cmp_node_alphaover,
2190         &cmp_node_blur,
2191         &cmp_node_vecblur,
2192         &cmp_node_map_value,
2193         NULL
2194 };
2195
2196 /* ******************* parse ************ */
2197
2198
2199 /* called from render pipeline, to tag render input and output */
2200 void ntreeCompositTagRender(bNodeTree *ntree)
2201 {
2202         bNode *node;
2203         
2204         if(ntree==NULL) return;
2205         
2206         for(node= ntree->nodes.first; node; node= node->next) {
2207                 if( ELEM(node->type, CMP_NODE_R_RESULT, CMP_NODE_COMPOSITE))
2208                         NodeTagChanged(ntree, node);
2209         }
2210 }
2211
2212 /* tags nodes that have animation capabilities */
2213 void ntreeCompositTagAnimated(bNodeTree *ntree)
2214 {
2215         bNode *node;
2216         
2217         if(ntree==NULL) return;
2218         
2219         for(node= ntree->nodes.first; node; node= node->next) {
2220                 if(node->type==CMP_NODE_IMAGE) {
2221                         /* no actual test yet... */
2222                         if(node->storage)
2223                                 NodeTagChanged(ntree, node);
2224                 }
2225         }
2226 }