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