Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLukas Toenne <lukas.toenne@googlemail.com>2011-09-06 01:01:50 +0400
committerLukas Toenne <lukas.toenne@googlemail.com>2011-09-06 01:01:50 +0400
commit8e0fe8bff72e2dc2926618577eaffdd3417a8304 (patch)
tree43b933c88cac451518dc68846c1119acacffca4f /source/blender/nodes/composite
parent6e9ff495eb082aeb49e6a1da23a7827d3fcd0fde (diff)
Merged the particles-2010 branch with node improvements into trunk.
This branch adds mostly organizational improvements to the node system by renaming the node folders and files. A couple of internal features have been added too. Detailed information can be found on the wiki page: http://wiki.blender.org/index.php/User:Phonybone/Particles2010
Diffstat (limited to 'source/blender/nodes/composite')
-rw-r--r--source/blender/nodes/composite/node_composite_tree.c811
-rw-r--r--source/blender/nodes/composite/node_composite_util.c1413
-rw-r--r--source/blender/nodes/composite/node_composite_util.h210
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_alphaOver.c163
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_bilateralblur.c271
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_blur.c736
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_brightness.c110
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_channelMatte.c217
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_chromaMatte.c207
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_colorMatte.c143
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_colorSpill.c341
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_colorbalance.c201
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_common.c373
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_composite.c113
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_crop.c129
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_curves.c209
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_defocus.c892
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_diffMatte.c151
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_dilate.c163
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_directionalblur.c146
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_displace.c199
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_distanceMatte.c148
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_filter.c239
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_flip.c106
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_gamma.c90
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_glare.c506
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_hueSatVal.c122
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_huecorrect.c170
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_idMask.c125
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_image.c452
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_invert.c135
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_lensdist.c207
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_levels.c339
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_lummaMatte.c125
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_mapUV.c180
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_mapValue.c103
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_math.c214
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_mixrgb.c99
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_normal.c109
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_normalize.c117
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_outputFile.c127
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_premulkey.c78
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_rgb.c77
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_rotate.c142
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_scale.c134
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_sepcombHSVA.c187
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_sepcombRGBA.c162
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_sepcombYCCA.c313
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_sepcombYUVA.c187
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_setalpha.c89
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_splitViewer.c171
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_texture.c160
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_tonemap.c179
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_translate.c76
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_valToRgb.c152
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_value.c72
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_vecBlur.c113
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_viewer.c148
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_zcombine.c238
59 files changed, 13589 insertions, 0 deletions
diff --git a/source/blender/nodes/composite/node_composite_tree.c b/source/blender/nodes/composite/node_composite_tree.c
new file mode 100644
index 00000000000..1a2fb04be8c
--- /dev/null
+++ b/source/blender/nodes/composite/node_composite_tree.c
@@ -0,0 +1,811 @@
+/**
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2007 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s):
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/nodes/composite/node_composite_tree.c
+ * \ingroup nodes
+ */
+
+
+#include <stdio.h>
+
+#include "DNA_anim_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_node_types.h"
+
+#include "BLI_listbase.h"
+#include "BLI_threads.h"
+
+#include "BKE_animsys.h"
+#include "BKE_colortools.h"
+#include "BKE_fcurve.h"
+#include "BKE_global.h"
+#include "BKE_main.h"
+#include "BKE_node.h"
+#include "BKE_utildefines.h"
+
+#include "node_exec.h"
+#include "node_util.h"
+
+#include "PIL_time.h"
+
+#include "RNA_access.h"
+
+#include "NOD_composite.h"
+#include "node_composite_util.h"
+
+static void foreach_nodetree(Main *main, void *calldata, bNodeTreeCallback func)
+{
+ Scene *sce;
+ for(sce= main->scene.first; sce; sce= sce->id.next) {
+ if(sce->nodetree) {
+ func(calldata, &sce->id, sce->nodetree);
+ }
+ }
+}
+
+static void free_node_cache(bNodeTree *UNUSED(ntree), bNode *node)
+{
+ bNodeSocket *sock;
+
+ for(sock= node->outputs.first; sock; sock= sock->next) {
+ if(sock->cache) {
+ free_compbuf(sock->cache);
+ sock->cache= NULL;
+ }
+ }
+}
+
+static void free_cache(bNodeTree *ntree)
+{
+ bNode *node;
+ for(node= ntree->nodes.first; node; node= node->next)
+ free_node_cache(ntree, node);
+}
+
+static void update_node(bNodeTree *ntree, bNode *node)
+{
+ bNodeSocket *sock;
+
+ for(sock= node->outputs.first; sock; sock= sock->next) {
+ if(sock->cache) {
+ //free_compbuf(sock->cache);
+ //sock->cache= NULL;
+ }
+ }
+ node->need_exec= 1;
+
+ /* individual node update call */
+ if (node->typeinfo->updatefunc)
+ node->typeinfo->updatefunc(ntree, node);
+}
+
+/* local tree then owns all compbufs */
+static void localize(bNodeTree *UNUSED(localtree), bNodeTree *ntree)
+{
+ bNode *node;
+ bNodeSocket *sock;
+
+ for(node= ntree->nodes.first; node; node= node->next) {
+ /* ensure new user input gets handled ok */
+ node->need_exec= 0;
+
+ /* move over the compbufs */
+ /* right after ntreeCopyTree() oldsock pointers are valid */
+
+ if(ELEM(node->type, CMP_NODE_VIEWER, CMP_NODE_SPLITVIEWER)) {
+ if(node->id) {
+ if(node->flag & NODE_DO_OUTPUT)
+ node->new_node->id= (ID *)copy_image((Image *)node->id);
+ else
+ node->new_node->id= NULL;
+ }
+ }
+
+ for(sock= node->outputs.first; sock; sock= sock->next) {
+ sock->new_sock->cache= sock->cache;
+ compbuf_set_node(sock->new_sock->cache, node->new_node);
+
+ sock->cache= NULL;
+ sock->new_sock->new_sock= sock;
+ }
+ }
+}
+
+static void local_sync(bNodeTree *localtree, bNodeTree *ntree)
+{
+ bNode *lnode;
+
+ /* move over the compbufs and previews */
+ for(lnode= localtree->nodes.first; lnode; lnode= lnode->next) {
+ if( (lnode->exec & NODE_READY) && !(lnode->exec & NODE_SKIPPED) ) {
+ if(ntreeNodeExists(ntree, lnode->new_node)) {
+
+ if(lnode->preview && lnode->preview->rect) {
+ nodeFreePreview(lnode->new_node);
+ lnode->new_node->preview= lnode->preview;
+ lnode->preview= NULL;
+ }
+ }
+ }
+ }
+}
+
+static void local_merge(bNodeTree *localtree, bNodeTree *ntree)
+{
+ bNode *lnode;
+ bNodeSocket *lsock;
+
+ /* move over the compbufs and previews */
+ for(lnode= localtree->nodes.first; lnode; lnode= lnode->next) {
+ if(ntreeNodeExists(ntree, lnode->new_node)) {
+ if(ELEM(lnode->type, CMP_NODE_VIEWER, CMP_NODE_SPLITVIEWER)) {
+ if(lnode->id && (lnode->flag & NODE_DO_OUTPUT)) {
+ /* image_merge does sanity check for pointers */
+ BKE_image_merge((Image *)lnode->new_node->id, (Image *)lnode->id);
+ }
+ }
+
+ for(lsock= lnode->outputs.first; lsock; lsock= lsock->next) {
+ if(ntreeOutputExists(lnode->new_node, lsock->new_sock)) {
+ lsock->new_sock->cache= lsock->cache;
+ compbuf_set_node(lsock->new_sock->cache, lnode->new_node);
+ lsock->cache= NULL;
+ lsock->new_sock= NULL;
+ }
+ }
+ }
+ }
+}
+
+bNodeTreeType ntreeType_Composite = {
+ /* type */ NTREE_COMPOSIT,
+ /* idname */ "NTCompositing Nodetree",
+
+ /* node_types */ { NULL, NULL },
+
+ /* free_cache */ free_cache,
+ /* free_node_cache */ free_node_cache,
+ /* foreach_nodetree */ foreach_nodetree,
+ /* localize */ localize,
+ /* local_sync */ local_sync,
+ /* local_merge */ local_merge,
+ /* update */ NULL,
+ /* update_node */ update_node
+};
+
+
+struct bNodeTreeExec *ntreeCompositBeginExecTree(bNodeTree *ntree)
+{
+ bNodeTreeExec *exec;
+ bNode *node;
+ bNodeSocket *sock;
+
+ /* XXX hack: prevent exec data from being generated twice.
+ * this should be handled by the renderer!
+ */
+ if (ntree->execdata)
+ return ntree->execdata;
+
+ /* ensures only a single output node is enabled */
+ ntreeSetOutput(ntree);
+
+ exec = ntree_exec_begin(ntree);
+
+ for(node= exec->nodetree->nodes.first; node; node= node->next) {
+ /* initialize needed for groups */
+ node->exec= 0;
+
+ for(sock= node->outputs.first; sock; sock= sock->next) {
+ bNodeStack *ns= node_get_socket_stack(exec->stack, sock);
+ if(ns && sock->cache) {
+ ns->data= sock->cache;
+ sock->cache= NULL;
+ }
+ }
+ /* cannot initialize them while using in threads */
+ if(ELEM4(node->type, CMP_NODE_TIME, CMP_NODE_CURVE_VEC, CMP_NODE_CURVE_RGB, CMP_NODE_HUECORRECT)) {
+ curvemapping_initialize(node->storage);
+ if(node->type==CMP_NODE_CURVE_RGB)
+ curvemapping_premultiply(node->storage, 0);
+ }
+ }
+
+ /* XXX this should not be necessary, but is still used for cmp/sha/tex nodes,
+ * which only store the ntree pointer. Should be fixed at some point!
+ */
+ ntree->execdata = exec;
+
+ return exec;
+}
+
+void ntreeCompositEndExecTree(bNodeTreeExec *exec)
+{
+ if(exec) {
+ bNodeTree *ntree= exec->nodetree;
+ bNode *node;
+ bNodeStack *ns;
+
+ for(node= exec->nodetree->nodes.first; node; node= node->next) {
+ bNodeSocket *sock;
+
+ for(sock= node->outputs.first; sock; sock= sock->next) {
+ ns = node_get_socket_stack(exec->stack, sock);
+ if(ns && ns->data) {
+ sock->cache= ns->data;
+ ns->data= NULL;
+ }
+ }
+ if(node->type==CMP_NODE_CURVE_RGB)
+ curvemapping_premultiply(node->storage, 1);
+
+ node->need_exec= 0;
+ }
+
+ ntree_exec_end(exec);
+
+ /* XXX clear nodetree backpointer to exec data, same problem as noted in ntreeBeginExecTree */
+ ntree->execdata = NULL;
+ }
+}
+
+/* ***************************** threaded version for execute composite nodes ************* */
+/* these are nodes without input, only giving values */
+/* or nodes with only value inputs */
+static int node_only_value(bNode *node)
+{
+ bNodeSocket *sock;
+
+ if(ELEM3(node->type, CMP_NODE_TIME, CMP_NODE_VALUE, CMP_NODE_RGB))
+ return 1;
+
+ /* doing this for all node types goes wrong. memory free errors */
+ if(node->inputs.first && node->type==CMP_NODE_MAP_VALUE) {
+ int retval= 1;
+ for(sock= node->inputs.first; sock; sock= sock->next) {
+ if(sock->link)
+ retval &= node_only_value(sock->link->fromnode);
+ }
+ return retval;
+ }
+ return 0;
+}
+
+/* not changing info, for thread callback */
+typedef struct ThreadData {
+ bNodeStack *stack;
+ RenderData *rd;
+} ThreadData;
+
+static void *exec_composite_node(void *nodeexec_v)
+{
+ bNodeStack *nsin[MAX_SOCKET]; /* arbitrary... watch this */
+ bNodeStack *nsout[MAX_SOCKET]; /* arbitrary... watch this */
+ bNodeExec *nodeexec= nodeexec_v;
+ bNode *node= nodeexec->node;
+ ThreadData *thd= (ThreadData *)node->threaddata;
+
+ node_get_stack(node, thd->stack, nsin, nsout);
+
+ if((node->flag & NODE_MUTED) && (!node_only_value(node))) {
+ /* viewers we execute, for feedback to user */
+ if(ELEM(node->type, CMP_NODE_VIEWER, CMP_NODE_SPLITVIEWER))
+ node->typeinfo->execfunc(thd->rd, node, nsin, nsout);
+ else
+ node_compo_pass_on(node, nsin, nsout);
+ }
+ else if(node->typeinfo->execfunc)
+ node->typeinfo->execfunc(thd->rd, node, nsin, nsout);
+ else if (node->typeinfo->newexecfunc)
+ node->typeinfo->newexecfunc(thd->rd, 0, node, nodeexec->data, nsin, nsout);
+
+ node->exec |= NODE_READY;
+ return 0;
+}
+
+/* return total of executable nodes, for timecursor */
+static int setExecutableNodes(bNodeTree *ntree, ThreadData *thd)
+{
+ bNodeStack *nsin[MAX_SOCKET]; /* arbitrary... watch this */
+ bNodeStack *nsout[MAX_SOCKET]; /* arbitrary... watch this */
+ bNode *node;
+ bNodeSocket *sock;
+ int totnode= 0, group_edit= 0;
+
+ /* note; do not add a dependency sort here, the stack was created already */
+
+ /* if we are in group edit, viewer nodes get skipped when group has viewer */
+ for(node= ntree->nodes.first; node; node= node->next)
+ if(node->type==NODE_GROUP && (node->flag & NODE_GROUP_EDIT))
+ if(ntreeHasType((bNodeTree *)node->id, CMP_NODE_VIEWER))
+ group_edit= 1;
+
+ for(node= ntree->nodes.first; node; node= node->next) {
+ int a;
+
+ node_get_stack(node, thd->stack, nsin, nsout);
+
+ /* test the outputs */
+ /* skip value-only nodes (should be in type!) */
+ if(!node_only_value(node)) {
+ for(a=0, sock= node->outputs.first; sock; sock= sock->next, a++) {
+ if(nsout[a]->data==NULL && nsout[a]->hasoutput) {
+ node->need_exec= 1;
+ break;
+ }
+ }
+ }
+
+ /* test the inputs */
+ for(a=0, sock= node->inputs.first; sock; sock= sock->next, a++) {
+ /* skip viewer nodes in bg render or group edit */
+ if( ELEM(node->type, CMP_NODE_VIEWER, CMP_NODE_SPLITVIEWER) && (G.background || group_edit))
+ node->need_exec= 0;
+ /* is sock in use? */
+ else if(sock->link) {
+ bNodeLink *link= sock->link;
+
+ /* this is the test for a cyclic case */
+ if(link->fromnode==NULL || link->tonode==NULL);
+ else if(link->fromnode->level >= link->tonode->level && link->tonode->level!=0xFFF) {
+ if(link->fromnode->need_exec) {
+ node->need_exec= 1;
+ break;
+ }
+ }
+ else {
+ node->need_exec= 0;
+ printf("Node %s skipped, cyclic dependency\n", node->name);
+ }
+ }
+ }
+
+ if(node->need_exec) {
+
+ /* free output buffers */
+ for(a=0, sock= node->outputs.first; sock; sock= sock->next, a++) {
+ if(nsout[a]->data) {
+ free_compbuf(nsout[a]->data);
+ nsout[a]->data= NULL;
+ }
+ }
+ totnode++;
+ /* printf("node needs exec %s\n", node->name); */
+
+ /* tag for getExecutableNode() */
+ node->exec= 0;
+ }
+ else {
+ /* tag for getExecutableNode() */
+ node->exec= NODE_READY|NODE_FINISHED|NODE_SKIPPED;
+
+ }
+ }
+
+ /* last step: set the stack values for only-value nodes */
+ /* just does all now, compared to a full buffer exec this is nothing */
+ if(totnode) {
+ for(node= ntree->nodes.first; node; node= node->next) {
+ if(node->need_exec==0 && node_only_value(node)) {
+ if(node->typeinfo->execfunc) {
+ node_get_stack(node, thd->stack, nsin, nsout);
+ node->typeinfo->execfunc(thd->rd, node, nsin, nsout);
+ }
+ }
+ }
+ }
+
+ return totnode;
+}
+
+/* while executing tree, free buffers from nodes that are not needed anymore */
+static void freeExecutableNode(bNodeTree *ntree, bNodeTreeExec *exec)
+{
+ /* node outputs can be freed when:
+ - not a render result or image node
+ - when node outputs go to nodes all being set NODE_FINISHED
+ */
+ bNode *node;
+ bNodeSocket *sock;
+
+ /* set exec flag for finished nodes that might need freed */
+ for(node= ntree->nodes.first; node; node= node->next) {
+ if(node->type!=CMP_NODE_R_LAYERS)
+ if(node->exec & NODE_FINISHED)
+ node->exec |= NODE_FREEBUFS;
+ }
+ /* clear this flag for input links that are not done yet */
+ for(node= ntree->nodes.first; node; node= node->next) {
+ if((node->exec & NODE_FINISHED)==0) {
+ for(sock= node->inputs.first; sock; sock= sock->next)
+ if(sock->link)
+ sock->link->fromnode->exec &= ~NODE_FREEBUFS;
+ }
+ }
+ /* now we can free buffers */
+ for(node= ntree->nodes.first; node; node= node->next) {
+ if(node->exec & NODE_FREEBUFS) {
+ for(sock= node->outputs.first; sock; sock= sock->next) {
+ bNodeStack *ns= node_get_socket_stack(exec->stack, sock);
+ if(ns && ns->data) {
+ free_compbuf(ns->data);
+ ns->data= NULL;
+ // printf("freed buf node %s \n", node->name);
+ }
+ }
+ }
+ }
+}
+
+static bNodeExec *getExecutableNode(bNodeTreeExec *exec)
+{
+ bNodeExec *nodeexec;
+ bNodeSocket *sock;
+ int n;
+
+ for(n=0, nodeexec=exec->nodeexec; n < exec->totnodes; ++n, ++nodeexec) {
+ if(nodeexec->node->exec==0) {
+ /* input sockets should be ready */
+ for(sock= nodeexec->node->inputs.first; sock; sock= sock->next) {
+ if(sock->link && sock->link->fromnode)
+ if((sock->link->fromnode->exec & NODE_READY)==0)
+ break;
+ }
+ if(sock==NULL)
+ return nodeexec;
+ }
+ }
+ return NULL;
+}
+
+/* check if texture nodes need exec or end */
+static void ntree_composite_texnode(bNodeTree *ntree, int init)
+{
+ bNode *node;
+
+ for(node= ntree->nodes.first; node; node= node->next) {
+ if(node->type==CMP_NODE_TEXTURE && node->id) {
+ Tex *tex= (Tex *)node->id;
+ if(tex->nodetree && tex->use_nodes) {
+ /* has internal flag to detect it only does it once */
+ if(init) {
+ if (!tex->nodetree->execdata)
+ tex->nodetree->execdata = ntreeTexBeginExecTree(tex->nodetree);
+ }
+ else
+ ntreeTexEndExecTree(tex->nodetree->execdata);
+ tex->nodetree->execdata = NULL;
+ }
+ }
+ }
+
+}
+
+/* optimized tree execute test for compositing */
+void ntreeCompositExecTree(bNodeTree *ntree, RenderData *rd, int do_preview)
+{
+ bNodeExec *nodeexec;
+ bNode *node;
+ ListBase threads;
+ ThreadData thdata;
+ int totnode, curnode, rendering= 1, n;
+ bNodeTreeExec *exec= NULL;
+
+ if(ntree==NULL) return;
+
+ if(do_preview)
+ ntreeInitPreview(ntree, 0, 0);
+
+ if (!ntree->execdata)
+ exec = ntreeCompositBeginExecTree(ntree);
+ ntree_composite_texnode(ntree, 1);
+
+ /* prevent unlucky accidents */
+ if(G.background)
+ rd->scemode &= ~R_COMP_CROP;
+
+ /* setup callerdata for thread callback */
+ thdata.rd= rd;
+ thdata.stack= exec->stack;
+
+ /* fixed seed, for example noise texture */
+ BLI_srandom(rd->cfra);
+
+ /* sets need_exec tags in nodes */
+ curnode = totnode= setExecutableNodes(ntree, &thdata);
+
+ BLI_init_threads(&threads, exec_composite_node, rd->threads);
+
+ while(rendering) {
+
+ if(BLI_available_threads(&threads)) {
+ nodeexec= getExecutableNode(exec);
+ if(nodeexec) {
+ node = nodeexec->node;
+ if(ntree->progress && totnode)
+ ntree->progress(ntree->prh, (1.0 - curnode/(float)totnode));
+ if(ntree->stats_draw) {
+ char str[64];
+ sprintf(str, "Compositing %d %s", curnode, node->name);
+ ntree->stats_draw(ntree->sdh, str);
+ }
+ curnode--;
+
+ node->threaddata = &thdata;
+ node->exec= NODE_PROCESSING;
+ BLI_insert_thread(&threads, nodeexec);
+ }
+ else
+ PIL_sleep_ms(50);
+ }
+ else
+ PIL_sleep_ms(50);
+
+ rendering= 0;
+ /* test for ESC */
+ if(ntree->test_break && ntree->test_break(ntree->tbh)) {
+ for(node= ntree->nodes.first; node; node= node->next)
+ node->exec |= NODE_READY;
+ }
+
+ /* check for ready ones, and if we need to continue */
+ for(n=0, nodeexec=exec->nodeexec; n < exec->totnodes; ++n, ++nodeexec) {
+ node = nodeexec->node;
+ if(node->exec & NODE_READY) {
+ if((node->exec & NODE_FINISHED)==0) {
+ BLI_remove_thread(&threads, nodeexec); /* this waits for running thread to finish btw */
+ node->exec |= NODE_FINISHED;
+
+ /* freeing unused buffers */
+ if(rd->scemode & R_COMP_FREE)
+ freeExecutableNode(ntree, exec);
+ }
+ }
+ else rendering= 1;
+ }
+ }
+
+ BLI_end_threads(&threads);
+
+ ntreeCompositEndExecTree(exec);
+}
+
+/* *********************************************** */
+
+/* clumsy checking... should do dynamic outputs once */
+static void force_hidden_passes(bNode *node, int passflag)
+{
+ bNodeSocket *sock;
+
+ for(sock= node->outputs.first; sock; sock= sock->next)
+ sock->flag &= ~SOCK_UNAVAIL;
+
+ sock= BLI_findlink(&node->outputs, RRES_OUT_Z);
+ if(!(passflag & SCE_PASS_Z)) sock->flag |= SOCK_UNAVAIL;
+ sock= BLI_findlink(&node->outputs, RRES_OUT_NORMAL);
+ if(!(passflag & SCE_PASS_NORMAL)) sock->flag |= SOCK_UNAVAIL;
+ sock= BLI_findlink(&node->outputs, RRES_OUT_VEC);
+ if(!(passflag & SCE_PASS_VECTOR)) sock->flag |= SOCK_UNAVAIL;
+ sock= BLI_findlink(&node->outputs, RRES_OUT_UV);
+ if(!(passflag & SCE_PASS_UV)) sock->flag |= SOCK_UNAVAIL;
+ sock= BLI_findlink(&node->outputs, RRES_OUT_RGBA);
+ if(!(passflag & SCE_PASS_RGBA)) sock->flag |= SOCK_UNAVAIL;
+ sock= BLI_findlink(&node->outputs, RRES_OUT_DIFF);
+ if(!(passflag & SCE_PASS_DIFFUSE)) sock->flag |= SOCK_UNAVAIL;
+ sock= BLI_findlink(&node->outputs, RRES_OUT_SPEC);
+ if(!(passflag & SCE_PASS_SPEC)) sock->flag |= SOCK_UNAVAIL;
+ sock= BLI_findlink(&node->outputs, RRES_OUT_SHADOW);
+ if(!(passflag & SCE_PASS_SHADOW)) sock->flag |= SOCK_UNAVAIL;
+ sock= BLI_findlink(&node->outputs, RRES_OUT_AO);
+ if(!(passflag & SCE_PASS_AO)) sock->flag |= SOCK_UNAVAIL;
+ sock= BLI_findlink(&node->outputs, RRES_OUT_REFLECT);
+ if(!(passflag & SCE_PASS_REFLECT)) sock->flag |= SOCK_UNAVAIL;
+ sock= BLI_findlink(&node->outputs, RRES_OUT_REFRACT);
+ if(!(passflag & SCE_PASS_REFRACT)) sock->flag |= SOCK_UNAVAIL;
+ sock= BLI_findlink(&node->outputs, RRES_OUT_INDIRECT);
+ if(!(passflag & SCE_PASS_INDIRECT)) sock->flag |= SOCK_UNAVAIL;
+ sock= BLI_findlink(&node->outputs, RRES_OUT_INDEXOB);
+ if(!(passflag & SCE_PASS_INDEXOB)) sock->flag |= SOCK_UNAVAIL;
+ sock= BLI_findlink(&node->outputs, RRES_OUT_INDEXMA);
+ if(!(passflag & SCE_PASS_INDEXMA)) sock->flag |= SOCK_UNAVAIL;
+ sock= BLI_findlink(&node->outputs, RRES_OUT_MIST);
+ if(!(passflag & SCE_PASS_MIST)) sock->flag |= SOCK_UNAVAIL;
+ sock= BLI_findlink(&node->outputs, RRES_OUT_EMIT);
+ if(!(passflag & SCE_PASS_EMIT)) sock->flag |= SOCK_UNAVAIL;
+ sock= BLI_findlink(&node->outputs, RRES_OUT_ENV);
+ if(!(passflag & SCE_PASS_ENVIRONMENT)) sock->flag |= SOCK_UNAVAIL;
+
+}
+
+/* based on rules, force sockets hidden always */
+void ntreeCompositForceHidden(bNodeTree *ntree, Scene *curscene)
+{
+ bNode *node;
+
+ if(ntree==NULL) return;
+
+ for(node= ntree->nodes.first; node; node= node->next) {
+ if( node->type==CMP_NODE_R_LAYERS) {
+ Scene *sce= node->id?(Scene *)node->id:curscene;
+ SceneRenderLayer *srl= BLI_findlink(&sce->r.layers, node->custom1);
+ if(srl)
+ force_hidden_passes(node, srl->passflag);
+ }
+ else if( node->type==CMP_NODE_IMAGE) {
+ Image *ima= (Image *)node->id;
+ if(ima) {
+ if(ima->rr) {
+ ImageUser *iuser= node->storage;
+ RenderLayer *rl= BLI_findlink(&ima->rr->layers, iuser->layer);
+ if(rl)
+ force_hidden_passes(node, rl->passflag);
+ else
+ force_hidden_passes(node, 0);
+ }
+ else if(ima->type!=IMA_TYPE_MULTILAYER) { /* if ->rr not yet read we keep inputs */
+ force_hidden_passes(node, RRES_OUT_Z);
+ }
+ else
+ force_hidden_passes(node, 0);
+ }
+ else
+ force_hidden_passes(node, 0);
+ }
+ }
+
+}
+
+/* called from render pipeline, to tag render input and output */
+/* need to do all scenes, to prevent errors when you re-render 1 scene */
+void ntreeCompositTagRender(Scene *curscene)
+{
+ Scene *sce;
+
+ for(sce= G.main->scene.first; sce; sce= sce->id.next) {
+ if(sce->nodetree) {
+ bNode *node;
+
+ for(node= sce->nodetree->nodes.first; node; node= node->next) {
+ if(node->id==(ID *)curscene || node->type==CMP_NODE_COMPOSITE)
+ NodeTagChanged(sce->nodetree, node);
+ else if(node->type==CMP_NODE_TEXTURE) /* uses scene sizex/sizey */
+ NodeTagChanged(sce->nodetree, node);
+ }
+ }
+ }
+}
+
+static int node_animation_properties(bNodeTree *ntree, bNode *node)
+{
+ bNodeSocket *sock;
+ const ListBase *lb;
+ Link *link;
+ PointerRNA ptr;
+ PropertyRNA *prop;
+
+ /* check to see if any of the node's properties have fcurves */
+ RNA_pointer_create((ID *)ntree, &RNA_Node, node, &ptr);
+ lb = RNA_struct_type_properties(ptr.type);
+
+ for (link=lb->first; link; link=link->next) {
+ int driven, len=1, index;
+ prop = (PropertyRNA *)link;
+
+ if (RNA_property_array_check(prop))
+ len = RNA_property_array_length(&ptr, prop);
+
+ for (index=0; index<len; index++) {
+ if (rna_get_fcurve(&ptr, prop, index, NULL, &driven)) {
+ NodeTagChanged(ntree, node);
+ return 1;
+ }
+ }
+ }
+
+ /* now check node sockets */
+ for (sock = node->inputs.first; sock; sock=sock->next) {
+ int driven, len=1, index;
+
+ RNA_pointer_create((ID *)ntree, &RNA_NodeSocket, sock, &ptr);
+ prop = RNA_struct_find_property(&ptr, "default_value");
+ if (prop) {
+ if (RNA_property_array_check(prop))
+ len = RNA_property_array_length(&ptr, prop);
+
+ for (index=0; index<len; index++) {
+ if (rna_get_fcurve(&ptr, prop, index, NULL, &driven)) {
+ NodeTagChanged(ntree, node);
+ return 1;
+ }
+ }
+ }
+ }
+
+ return 0;
+}
+
+/* tags nodes that have animation capabilities */
+int ntreeCompositTagAnimated(bNodeTree *ntree)
+{
+ bNode *node;
+ int tagged= 0;
+
+ if(ntree==NULL) return 0;
+
+ for(node= ntree->nodes.first; node; node= node->next) {
+
+ tagged = node_animation_properties(ntree, node);
+
+ /* otherwise always tag these node types */
+ if(node->type==CMP_NODE_IMAGE) {
+ Image *ima= (Image *)node->id;
+ if(ima && ELEM(ima->source, IMA_SRC_MOVIE, IMA_SRC_SEQUENCE)) {
+ NodeTagChanged(ntree, node);
+ tagged= 1;
+ }
+ }
+ else if(node->type==CMP_NODE_TIME) {
+ NodeTagChanged(ntree, node);
+ tagged= 1;
+ }
+ /* here was tag render layer, but this is called after a render, so re-composites fail */
+ else if(node->type==NODE_GROUP) {
+ if( ntreeCompositTagAnimated((bNodeTree *)node->id) ) {
+ NodeTagChanged(ntree, node);
+ }
+ }
+ }
+
+ return tagged;
+}
+
+
+/* called from image window preview */
+void ntreeCompositTagGenerators(bNodeTree *ntree)
+{
+ bNode *node;
+
+ if(ntree==NULL) return;
+
+ for(node= ntree->nodes.first; node; node= node->next) {
+ if( ELEM(node->type, CMP_NODE_R_LAYERS, CMP_NODE_IMAGE))
+ NodeTagChanged(ntree, node);
+ }
+}
+
+/* XXX after render animation system gets a refresh, this call allows composite to end clean */
+void ntreeClearTags(bNodeTree *ntree)
+{
+ bNode *node;
+
+ if(ntree==NULL) return;
+
+ for(node= ntree->nodes.first; node; node= node->next) {
+ node->need_exec= 0;
+ if(node->type==NODE_GROUP)
+ ntreeClearTags((bNodeTree *)node->id);
+ }
+}
diff --git a/source/blender/nodes/composite/node_composite_util.c b/source/blender/nodes/composite/node_composite_util.c
new file mode 100644
index 00000000000..f7759775af0
--- /dev/null
+++ b/source/blender/nodes/composite/node_composite_util.c
@@ -0,0 +1,1413 @@
+/*
+ * $Id: CMP_util.c 36536 2011-05-07 13:27:27Z lukastoenne $
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2006 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/nodes/composite/node_composite_util.c
+ * \ingroup nodes
+ */
+
+
+#include "node_composite_util.h"
+
+CompBuf *alloc_compbuf(int sizex, int sizey, int type, int alloc)
+{
+ CompBuf *cbuf= MEM_callocN(sizeof(CompBuf), "compbuf");
+
+ cbuf->x= sizex;
+ cbuf->y= sizey;
+ cbuf->xrad= sizex/2;
+ cbuf->yrad= sizey/2;
+
+ cbuf->type= type;
+ if(alloc) {
+ if(cbuf->type==CB_RGBA)
+ cbuf->rect= MEM_mapallocN(4*sizeof(float)*sizex*sizey, "compbuf RGBA rect");
+ else if(cbuf->type==CB_VEC3)
+ cbuf->rect= MEM_mapallocN(3*sizeof(float)*sizex*sizey, "compbuf Vector3 rect");
+ else if(cbuf->type==CB_VEC2)
+ cbuf->rect= MEM_mapallocN(2*sizeof(float)*sizex*sizey, "compbuf Vector2 rect");
+ else
+ cbuf->rect= MEM_mapallocN(sizeof(float)*sizex*sizey, "compbuf Fac rect");
+ cbuf->malloc= 1;
+ }
+ cbuf->disprect.xmin= 0;
+ cbuf->disprect.ymin= 0;
+ cbuf->disprect.xmax= sizex;
+ cbuf->disprect.ymax= sizey;
+
+ return cbuf;
+}
+
+CompBuf *dupalloc_compbuf(CompBuf *cbuf)
+{
+ CompBuf *dupbuf= alloc_compbuf(cbuf->x, cbuf->y, cbuf->type, 1);
+ if(dupbuf) {
+ memcpy(dupbuf->rect, cbuf->rect, cbuf->type*sizeof(float)*cbuf->x*cbuf->y);
+
+ dupbuf->xof= cbuf->xof;
+ dupbuf->yof= cbuf->yof;
+ }
+ return dupbuf;
+}
+
+/* instead of reference counting, we create a list */
+CompBuf *pass_on_compbuf(CompBuf *cbuf)
+{
+ CompBuf *dupbuf= (cbuf)? alloc_compbuf(cbuf->x, cbuf->y, cbuf->type, 0): NULL;
+ CompBuf *lastbuf;
+
+ if(dupbuf) {
+ dupbuf->rect= cbuf->rect;
+ dupbuf->xof= cbuf->xof;
+ dupbuf->yof= cbuf->yof;
+ dupbuf->malloc= 0;
+
+ /* get last buffer in list, and append dupbuf */
+ for(lastbuf= cbuf; lastbuf; lastbuf= lastbuf->next)
+ if(lastbuf->next==NULL)
+ break;
+ lastbuf->next= dupbuf;
+ dupbuf->prev= lastbuf;
+ }
+ return dupbuf;
+}
+
+
+void free_compbuf(CompBuf *cbuf)
+{
+ /* check referencing, then remove from list and set malloc tag */
+ if(cbuf->prev || cbuf->next) {
+ if(cbuf->prev)
+ cbuf->prev->next= cbuf->next;
+ if(cbuf->next)
+ cbuf->next->prev= cbuf->prev;
+ if(cbuf->malloc) {
+ if(cbuf->prev)
+ cbuf->prev->malloc= 1;
+ else
+ cbuf->next->malloc= 1;
+ cbuf->malloc= 0;
+ }
+ }
+
+ if(cbuf->malloc && cbuf->rect)
+ MEM_freeN(cbuf->rect);
+
+ MEM_freeN(cbuf);
+}
+
+void print_compbuf(char *str, CompBuf *cbuf)
+{
+ printf("Compbuf %s %d %d %p\n", str, cbuf->x, cbuf->y, (void *)cbuf->rect);
+
+}
+
+void compbuf_set_node(CompBuf *cbuf, bNode *node)
+{
+ if (cbuf) cbuf->node = node;
+}
+
+/* used for disabling node (similar code in node_draw.c for disable line and node_edit for untangling nodes) */
+void node_compo_pass_on(bNode *node, bNodeStack **nsin, bNodeStack **nsout)
+{
+ CompBuf *valbuf= NULL, *colbuf= NULL, *vecbuf= NULL;
+ bNodeSocket *sock;
+ int a;
+
+ /* connect the first value buffer in with first value out */
+ /* connect the first RGBA buffer in with first RGBA out */
+
+ /* test the inputs */
+ for(a=0, sock= node->inputs.first; sock; sock= sock->next, a++) {
+ if(nsin[a]->data) {
+ CompBuf *cbuf= nsin[a]->data;
+ if(cbuf->type==1 && valbuf==NULL) valbuf= cbuf;
+ if(cbuf->type==3 && vecbuf==NULL) vecbuf= cbuf;
+ if(cbuf->type==4 && colbuf==NULL) colbuf= cbuf;
+ }
+ }
+
+ /* outputs */
+ if(valbuf || colbuf || vecbuf) {
+ for(a=0, sock= node->outputs.first; sock; sock= sock->next, a++) {
+ if(nsout[a]->hasoutput) {
+ if(sock->type==SOCK_FLOAT && valbuf) {
+ nsout[a]->data= pass_on_compbuf(valbuf);
+ valbuf= NULL;
+ }
+ if(sock->type==SOCK_VECTOR && vecbuf) {
+ nsout[a]->data= pass_on_compbuf(vecbuf);
+ vecbuf= NULL;
+ }
+ if(sock->type==SOCK_RGBA && colbuf) {
+ nsout[a]->data= pass_on_compbuf(colbuf);
+ colbuf= NULL;
+ }
+ }
+ }
+ }
+}
+
+
+CompBuf *get_cropped_compbuf(rcti *drect, float *rectf, int rectx, int recty, int type)
+{
+ CompBuf *cbuf;
+ rcti disprect= *drect;
+ float *outfp;
+ int dx, y;
+
+ if(disprect.xmax>rectx) disprect.xmax= rectx;
+ if(disprect.ymax>recty) disprect.ymax= recty;
+ if(disprect.xmin>= disprect.xmax) return NULL;
+ if(disprect.ymin>= disprect.ymax) return NULL;
+
+ cbuf= alloc_compbuf(disprect.xmax-disprect.xmin, disprect.ymax-disprect.ymin, type, 1);
+ outfp= cbuf->rect;
+ rectf += type*(disprect.ymin*rectx + disprect.xmin);
+ dx= type*cbuf->x;
+ for(y=cbuf->y; y>0; y--, outfp+=dx, rectf+=type*rectx)
+ memcpy(outfp, rectf, sizeof(float)*dx);
+
+ return cbuf;
+}
+
+CompBuf *scalefast_compbuf(CompBuf *inbuf, int newx, int newy)
+{
+ CompBuf *outbuf;
+ float *rectf, *newrectf, *rf;
+ int x, y, c, pixsize= inbuf->type;
+ int ofsx, ofsy, stepx, stepy;
+
+ if(inbuf->x==newx && inbuf->y==newy)
+ return dupalloc_compbuf(inbuf);
+
+ outbuf= alloc_compbuf(newx, newy, inbuf->type, 1);
+ newrectf= outbuf->rect;
+
+ stepx = (65536.0 * (inbuf->x - 1.0) / (newx - 1.0)) + 0.5;
+ stepy = (65536.0 * (inbuf->y - 1.0) / (newy - 1.0)) + 0.5;
+ ofsy = 32768;
+
+ for (y = newy; y > 0 ; y--){
+ rectf = inbuf->rect;
+ rectf += pixsize * (ofsy >> 16) * inbuf->x;
+
+ ofsy += stepy;
+ ofsx = 32768;
+
+ for (x = newx ; x>0 ; x--) {
+
+ rf= rectf + pixsize*(ofsx >> 16);
+ for(c=0; c<pixsize; c++)
+ newrectf[c] = rf[c];
+
+ newrectf+= pixsize;
+
+ ofsx += stepx;
+ }
+ }
+
+ return outbuf;
+}
+
+void typecheck_compbuf_color(float *out, float *in, int outtype, int intype)
+{
+ if(intype == outtype) {
+ memcpy(out, in, sizeof(float)*outtype);
+ }
+ else if(outtype==CB_VAL) {
+ if(intype==CB_VEC2) {
+ *out= 0.5f*(in[0]+in[1]);
+ }
+ else if(intype==CB_VEC3) {
+ *out= 0.333333f*(in[0]+in[1]+in[2]);
+ }
+ else if(intype==CB_RGBA) {
+ *out= in[0]*0.35f + in[1]*0.45f + in[2]*0.2f;
+ }
+ }
+ else if(outtype==CB_VEC2) {
+ if(intype==CB_VAL) {
+ out[0]= in[0];
+ out[1]= in[0];
+ }
+ else if(intype==CB_VEC3) {
+ out[0]= in[0];
+ out[1]= in[1];
+ }
+ else if(intype==CB_RGBA) {
+ out[0]= in[0];
+ out[1]= in[1];
+ }
+ }
+ else if(outtype==CB_VEC3) {
+ if(intype==CB_VAL) {
+ out[0]= in[0];
+ out[1]= in[0];
+ out[2]= in[0];
+ }
+ else if(intype==CB_VEC2) {
+ out[0]= in[0];
+ out[1]= in[1];
+ out[2]= 0.0f;
+ }
+ else if(intype==CB_RGBA) {
+ out[0]= in[0];
+ out[1]= in[1];
+ out[2]= in[2];
+ }
+ }
+ else if(outtype==CB_RGBA) {
+ if(intype==CB_VAL) {
+ out[0]= in[0];
+ out[1]= in[0];
+ out[2]= in[0];
+ out[3]= 1.0f;
+ }
+ else if(intype==CB_VEC2) {
+ out[0]= in[0];
+ out[1]= in[1];
+ out[2]= 0.0f;
+ out[3]= 1.0f;
+ }
+ else if(intype==CB_VEC3) {
+ out[0]= in[0];
+ out[1]= in[1];
+ out[2]= in[2];
+ out[3]= 1.0f;
+ }
+ }
+}
+
+CompBuf *typecheck_compbuf(CompBuf *inbuf, int type)
+{
+ if(inbuf && inbuf->type!=type) {
+ CompBuf *outbuf;
+ float *inrf, *outrf;
+ int x;
+
+ outbuf= alloc_compbuf(inbuf->x, inbuf->y, type, 1);
+
+ /* warning note: xof and yof are applied in pixelprocessor, but should be copied otherwise? */
+ outbuf->xof= inbuf->xof;
+ outbuf->yof= inbuf->yof;
+
+ if(inbuf->rect_procedural) {
+ outbuf->rect_procedural= inbuf->rect_procedural;
+ VECCOPY(outbuf->procedural_size, inbuf->procedural_size);
+ VECCOPY(outbuf->procedural_offset, inbuf->procedural_offset);
+ outbuf->procedural_type= inbuf->procedural_type;
+ outbuf->node= inbuf->node;
+ return outbuf;
+ }
+
+ inrf= inbuf->rect;
+ outrf= outbuf->rect;
+ x= inbuf->x*inbuf->y;
+
+ if(type==CB_VAL) {
+ if(inbuf->type==CB_VEC2) {
+ for(; x>0; x--, outrf+= 1, inrf+= 2)
+ *outrf= 0.5f*(inrf[0]+inrf[1]);
+ }
+ else if(inbuf->type==CB_VEC3) {
+ for(; x>0; x--, outrf+= 1, inrf+= 3)
+ *outrf= 0.333333f*(inrf[0]+inrf[1]+inrf[2]);
+ }
+ else if(inbuf->type==CB_RGBA) {
+ for(; x>0; x--, outrf+= 1, inrf+= 4)
+ *outrf= inrf[0]*0.35f + inrf[1]*0.45f + inrf[2]*0.2f;
+ }
+ }
+ else if(type==CB_VEC2) {
+ if(inbuf->type==CB_VAL) {
+ for(; x>0; x--, outrf+= 2, inrf+= 1) {
+ outrf[0]= inrf[0];
+ outrf[1]= inrf[0];
+ }
+ }
+ else if(inbuf->type==CB_VEC3) {
+ for(; x>0; x--, outrf+= 2, inrf+= 3) {
+ outrf[0]= inrf[0];
+ outrf[1]= inrf[1];
+ }
+ }
+ else if(inbuf->type==CB_RGBA) {
+ for(; x>0; x--, outrf+= 2, inrf+= 4) {
+ outrf[0]= inrf[0];
+ outrf[1]= inrf[1];
+ }
+ }
+ }
+ else if(type==CB_VEC3) {
+ if(inbuf->type==CB_VAL) {
+ for(; x>0; x--, outrf+= 3, inrf+= 1) {
+ outrf[0]= inrf[0];
+ outrf[1]= inrf[0];
+ outrf[2]= inrf[0];
+ }
+ }
+ else if(inbuf->type==CB_VEC2) {
+ for(; x>0; x--, outrf+= 3, inrf+= 2) {
+ outrf[0]= inrf[0];
+ outrf[1]= inrf[1];
+ outrf[2]= 0.0f;
+ }
+ }
+ else if(inbuf->type==CB_RGBA) {
+ for(; x>0; x--, outrf+= 3, inrf+= 4) {
+ outrf[0]= inrf[0];
+ outrf[1]= inrf[1];
+ outrf[2]= inrf[2];
+ }
+ }
+ }
+ else if(type==CB_RGBA) {
+ if(inbuf->type==CB_VAL) {
+ for(; x>0; x--, outrf+= 4, inrf+= 1) {
+ outrf[0]= inrf[0];
+ outrf[1]= inrf[0];
+ outrf[2]= inrf[0];
+ outrf[3]= 1.0f;
+ }
+ }
+ else if(inbuf->type==CB_VEC2) {
+ for(; x>0; x--, outrf+= 4, inrf+= 2) {
+ outrf[0]= inrf[0];
+ outrf[1]= inrf[1];
+ outrf[2]= 0.0f;
+ outrf[3]= 1.0f;
+ }
+ }
+ else if(inbuf->type==CB_VEC3) {
+ for(; x>0; x--, outrf+= 4, inrf+= 3) {
+ outrf[0]= inrf[0];
+ outrf[1]= inrf[1];
+ outrf[2]= inrf[2];
+ outrf[3]= 1.0f;
+ }
+ }
+ }
+
+ return outbuf;
+ }
+ return inbuf;
+}
+
+static float *compbuf_get_pixel(CompBuf *cbuf, float *defcol, float *use, int x, int y, int xrad, int yrad)
+{
+ if(cbuf) {
+ if(cbuf->rect_procedural) {
+ cbuf->rect_procedural(cbuf, use, (float)x/(float)xrad, (float)y/(float)yrad);
+ return use;
+ }
+ else {
+ static float col[4]= {0.0f, 0.0f, 0.0f, 0.0f};
+
+ /* map coords */
+ x-= cbuf->xof;
+ y-= cbuf->yof;
+
+ if(y<-cbuf->yrad || y>= -cbuf->yrad+cbuf->y) return col;
+ if(x<-cbuf->xrad || x>= -cbuf->xrad+cbuf->x) return col;
+
+ return cbuf->rect + cbuf->type*( (cbuf->yrad+y)*cbuf->x + (cbuf->xrad+x) );
+ }
+ }
+ else return defcol;
+}
+
+/* **************************************************** */
+
+/* Pixel-to-Pixel operation, 1 Image in, 1 out */
+void composit1_pixel_processor(bNode *node, CompBuf *out, CompBuf *src_buf, float *src_col,
+ void (*func)(bNode *, float *, float *),
+ int src_type)
+{
+ CompBuf *src_use;
+ float *outfp=out->rect, *srcfp;
+ float color[4]; /* local color if compbuf is procedural */
+ int xrad, yrad, x, y;
+
+ src_use= typecheck_compbuf(src_buf, src_type);
+
+ xrad= out->xrad;
+ yrad= out->yrad;
+
+ for(y= -yrad; y<-yrad+out->y; y++) {
+ for(x= -xrad; x<-xrad+out->x; x++, outfp+=out->type) {
+ srcfp= compbuf_get_pixel(src_use, src_col, color, x, y, xrad, yrad);
+ func(node, outfp, srcfp);
+ }
+ }
+
+ if(src_use!=src_buf)
+ free_compbuf(src_use);
+}
+
+/* Pixel-to-Pixel operation, 2 Images in, 1 out */
+void composit2_pixel_processor(bNode *node, CompBuf *out, CompBuf *src_buf, float *src_col,
+ CompBuf *fac_buf, float *fac, void (*func)(bNode *, float *, float *, float *),
+ int src_type, int fac_type)
+{
+ CompBuf *src_use, *fac_use;
+ float *outfp=out->rect, *srcfp, *facfp;
+ float color[4]; /* local color if compbuf is procedural */
+ int xrad, yrad, x, y;
+
+ src_use= typecheck_compbuf(src_buf, src_type);
+ fac_use= typecheck_compbuf(fac_buf, fac_type);
+
+ xrad= out->xrad;
+ yrad= out->yrad;
+
+ for(y= -yrad; y<-yrad+out->y; y++) {
+ for(x= -xrad; x<-xrad+out->x; x++, outfp+=out->type) {
+ srcfp= compbuf_get_pixel(src_use, src_col, color, x, y, xrad, yrad);
+ facfp= compbuf_get_pixel(fac_use, fac, color, x, y, xrad, yrad);
+
+ func(node, outfp, srcfp, facfp);
+ }
+ }
+ if(src_use!=src_buf)
+ free_compbuf(src_use);
+ if(fac_use!=fac_buf)
+ free_compbuf(fac_use);
+}
+
+/* Pixel-to-Pixel operation, 3 Images in, 1 out */
+void composit3_pixel_processor(bNode *node, CompBuf *out, CompBuf *src1_buf, float *src1_col, CompBuf *src2_buf, float *src2_col,
+ CompBuf *fac_buf, float *fac, void (*func)(bNode *, float *, float *, float *, float *),
+ int src1_type, int src2_type, int fac_type)
+{
+ CompBuf *src1_use, *src2_use, *fac_use;
+ float *outfp=out->rect, *src1fp, *src2fp, *facfp;
+ float color[4]; /* local color if compbuf is procedural */
+ int xrad, yrad, x, y;
+
+ src1_use= typecheck_compbuf(src1_buf, src1_type);
+ src2_use= typecheck_compbuf(src2_buf, src2_type);
+ fac_use= typecheck_compbuf(fac_buf, fac_type);
+
+ xrad= out->xrad;
+ yrad= out->yrad;
+
+ for(y= -yrad; y<-yrad+out->y; y++) {
+ for(x= -xrad; x<-xrad+out->x; x++, outfp+=out->type) {
+ src1fp= compbuf_get_pixel(src1_use, src1_col, color, x, y, xrad, yrad);
+ src2fp= compbuf_get_pixel(src2_use, src2_col, color, x, y, xrad, yrad);
+ facfp= compbuf_get_pixel(fac_use, fac, color, x, y, xrad, yrad);
+
+ func(node, outfp, src1fp, src2fp, facfp);
+ }
+ }
+
+ if(src1_use!=src1_buf)
+ free_compbuf(src1_use);
+ if(src2_use!=src2_buf)
+ free_compbuf(src2_use);
+ if(fac_use!=fac_buf)
+ free_compbuf(fac_use);
+}
+
+/* Pixel-to-Pixel operation, 4 Images in, 1 out */
+void composit4_pixel_processor(bNode *node, CompBuf *out, CompBuf *src1_buf, float *src1_col, CompBuf *fac1_buf, float *fac1,
+ CompBuf *src2_buf, float *src2_col, CompBuf *fac2_buf, float *fac2,
+ void (*func)(bNode *, float *, float *, float *, float *, float *),
+ int src1_type, int fac1_type, int src2_type, int fac2_type)
+{
+ CompBuf *src1_use, *src2_use, *fac1_use, *fac2_use;
+ float *outfp=out->rect, *src1fp, *src2fp, *fac1fp, *fac2fp;
+ float color[4]; /* local color if compbuf is procedural */
+ int xrad, yrad, x, y;
+
+ src1_use= typecheck_compbuf(src1_buf, src1_type);
+ src2_use= typecheck_compbuf(src2_buf, src2_type);
+ fac1_use= typecheck_compbuf(fac1_buf, fac1_type);
+ fac2_use= typecheck_compbuf(fac2_buf, fac2_type);
+
+ xrad= out->xrad;
+ yrad= out->yrad;
+
+ for(y= -yrad; y<-yrad+out->y; y++) {
+ for(x= -xrad; x<-xrad+out->x; x++, outfp+=out->type) {
+ src1fp= compbuf_get_pixel(src1_use, src1_col, color, x, y, xrad, yrad);
+ src2fp= compbuf_get_pixel(src2_use, src2_col, color, x, y, xrad, yrad);
+ fac1fp= compbuf_get_pixel(fac1_use, fac1, color, x, y, xrad, yrad);
+ fac2fp= compbuf_get_pixel(fac2_use, fac2, color, x, y, xrad, yrad);
+
+ func(node, outfp, src1fp, fac1fp, src2fp, fac2fp);
+ }
+ }
+
+ if(src1_use!=src1_buf)
+ free_compbuf(src1_use);
+ if(src2_use!=src2_buf)
+ free_compbuf(src2_use);
+ if(fac1_use!=fac1_buf)
+ free_compbuf(fac1_use);
+ if(fac2_use!=fac2_buf)
+ free_compbuf(fac2_use);
+}
+
+
+CompBuf *valbuf_from_rgbabuf(CompBuf *cbuf, int channel)
+{
+ CompBuf *valbuf= alloc_compbuf(cbuf->x, cbuf->y, CB_VAL, 1);
+ float *valf, *rectf;
+ int tot;
+
+ /* warning note: xof and yof are applied in pixelprocessor, but should be copied otherwise? */
+ valbuf->xof= cbuf->xof;
+ valbuf->yof= cbuf->yof;
+
+ valf= valbuf->rect;
+
+ /* defaults to returning alpha channel */
+ if ((channel < CHAN_R) || (channel > CHAN_A)) channel = CHAN_A;
+
+ rectf= cbuf->rect + channel;
+
+ for(tot= cbuf->x*cbuf->y; tot>0; tot--, valf++, rectf+=4)
+ *valf= *rectf;
+
+ return valbuf;
+}
+
+static CompBuf *generate_procedural_preview(CompBuf *cbuf, int newx, int newy)
+{
+ CompBuf *outbuf;
+ float *outfp;
+ int xrad, yrad, x, y;
+
+ outbuf= alloc_compbuf(newx, newy, CB_RGBA, 1);
+
+ outfp= outbuf->rect;
+ xrad= outbuf->xrad;
+ yrad= outbuf->yrad;
+
+ for(y= -yrad; y<-yrad+outbuf->y; y++)
+ for(x= -xrad; x<-xrad+outbuf->x; x++, outfp+=outbuf->type)
+ cbuf->rect_procedural(cbuf, outfp, (float)x/(float)xrad, (float)y/(float)yrad);
+
+ return outbuf;
+}
+
+void generate_preview(void *data, bNode *node, CompBuf *stackbuf)
+{
+ RenderData *rd= data;
+ bNodePreview *preview= node->preview;
+ int xsize, ysize;
+ int color_manage= rd->color_mgt_flag & R_COLOR_MANAGEMENT;
+ unsigned char *rect;
+
+ if(preview && stackbuf) {
+ CompBuf *cbuf, *stackbuf_use;
+
+ if(stackbuf->rect==NULL && stackbuf->rect_procedural==NULL) return;
+
+ stackbuf_use= typecheck_compbuf(stackbuf, CB_RGBA);
+
+ if(stackbuf->x > stackbuf->y) {
+ xsize= 140;
+ ysize= (140*stackbuf->y)/stackbuf->x;
+ }
+ else {
+ ysize= 140;
+ xsize= (140*stackbuf->x)/stackbuf->y;
+ }
+
+ if(stackbuf_use->rect_procedural)
+ cbuf= generate_procedural_preview(stackbuf_use, xsize, ysize);
+ else
+ cbuf= scalefast_compbuf(stackbuf_use, xsize, ysize);
+
+ /* convert to byte for preview */
+ rect= MEM_callocN(sizeof(unsigned char)*4*xsize*ysize, "bNodePreview.rect");
+
+ if(color_manage)
+ floatbuf_to_srgb_byte(cbuf->rect, rect, 0, xsize, 0, ysize, xsize);
+ else
+ floatbuf_to_byte(cbuf->rect, rect, 0, xsize, 0, ysize, xsize);
+
+ free_compbuf(cbuf);
+ if(stackbuf_use!=stackbuf)
+ free_compbuf(stackbuf_use);
+
+ BLI_lock_thread(LOCK_PREVIEW);
+
+ if(preview->rect)
+ MEM_freeN(preview->rect);
+ preview->xsize= xsize;
+ preview->ysize= ysize;
+ preview->rect= rect;
+
+ BLI_unlock_thread(LOCK_PREVIEW);
+ }
+}
+
+void do_rgba_to_yuva(bNode *UNUSED(node), float *out, float *in)
+{
+ rgb_to_yuv(in[0],in[1],in[2], &out[0], &out[1], &out[2]);
+ out[3]=in[3];
+}
+
+void do_rgba_to_hsva(bNode *UNUSED(node), float *out, float *in)
+{
+ rgb_to_hsv(in[0],in[1],in[2], &out[0], &out[1], &out[2]);
+ out[3]=in[3];
+}
+
+void do_rgba_to_ycca(bNode *UNUSED(node), float *out, float *in)
+{
+ rgb_to_ycc(in[0],in[1],in[2], &out[0], &out[1], &out[2], BLI_YCC_ITU_BT601);
+ out[3]=in[3];
+}
+
+void do_yuva_to_rgba(bNode *UNUSED(node), float *out, float *in)
+{
+ yuv_to_rgb(in[0],in[1],in[2], &out[0], &out[1], &out[2]);
+ out[3]=in[3];
+}
+
+void do_hsva_to_rgba(bNode *UNUSED(node), float *out, float *in)
+{
+ hsv_to_rgb(in[0],in[1],in[2], &out[0], &out[1], &out[2]);
+ out[3]=in[3];
+}
+
+void do_ycca_to_rgba(bNode *UNUSED(node), float *out, float *in)
+{
+ ycc_to_rgb(in[0],in[1],in[2], &out[0], &out[1], &out[2], BLI_YCC_ITU_BT601);
+ out[3]=in[3];
+}
+
+void do_copy_rgba(bNode *UNUSED(node), float *out, float *in)
+{
+ QUATCOPY(out, in);
+}
+
+void do_copy_rgb(bNode *UNUSED(node), float *out, float *in)
+{
+ VECCOPY(out, in);
+ out[3]= 1.0f;
+}
+
+void do_copy_value(bNode *UNUSED(node), float *out, float *in)
+{
+ out[0]= in[0];
+}
+
+void do_copy_a_rgba(bNode *UNUSED(node), float *out, float *in, float *fac)
+{
+ VECCOPY(out, in);
+ out[3]= *fac;
+}
+
+/* only accepts RGBA buffers */
+void gamma_correct_compbuf(CompBuf *img, int inversed)
+{
+ float *drect;
+ int x;
+
+ if(img->type!=CB_RGBA) return;
+
+ drect= img->rect;
+ if(inversed) {
+ for(x=img->x*img->y; x>0; x--, drect+=4) {
+ if(drect[0]>0.0f) drect[0]= sqrt(drect[0]); else drect[0]= 0.0f;
+ if(drect[1]>0.0f) drect[1]= sqrt(drect[1]); else drect[1]= 0.0f;
+ if(drect[2]>0.0f) drect[2]= sqrt(drect[2]); else drect[2]= 0.0f;
+ }
+ }
+ else {
+ for(x=img->x*img->y; x>0; x--, drect+=4) {
+ if(drect[0]>0.0f) drect[0]*= drect[0]; else drect[0]= 0.0f;
+ if(drect[1]>0.0f) drect[1]*= drect[1]; else drect[1]= 0.0f;
+ if(drect[2]>0.0f) drect[2]*= drect[2]; else drect[2]= 0.0f;
+ }
+ }
+}
+
+void premul_compbuf(CompBuf *img, int inversed)
+{
+ float *drect;
+ int x;
+
+ if(img->type!=CB_RGBA) return;
+
+ drect= img->rect;
+ if(inversed) {
+ for(x=img->x*img->y; x>0; x--, drect+=4) {
+ if(fabs(drect[3]) < 1e-5f) {
+ drect[0]= 0.0f;
+ drect[1]= 0.0f;
+ drect[2]= 0.0f;
+ }
+ else {
+ drect[0] /= drect[3];
+ drect[1] /= drect[3];
+ drect[2] /= drect[3];
+ }
+ }
+ }
+ else {
+ for(x=img->x*img->y; x>0; x--, drect+=4) {
+ drect[0] *= drect[3];
+ drect[1] *= drect[3];
+ drect[2] *= drect[3];
+ }
+ }
+}
+
+
+
+/*
+ * 2D Fast Hartley Transform, used for convolution
+ */
+
+typedef float fREAL;
+
+// returns next highest power of 2 of x, as well it's log2 in L2
+static unsigned int nextPow2(unsigned int x, unsigned int* L2)
+{
+ unsigned int pw, x_notpow2 = x & (x-1);
+ *L2 = 0;
+ while (x>>=1) ++(*L2);
+ pw = 1 << (*L2);
+ if (x_notpow2) { (*L2)++; pw<<=1; }
+ return pw;
+}
+
+//------------------------------------------------------------------------------
+
+// from FXT library by Joerg Arndt, faster in order bitreversal
+// use: r = revbin_upd(r, h) where h = N>>1
+static unsigned int revbin_upd(unsigned int r, unsigned int h)
+{
+ while (!((r^=h)&h)) h >>= 1;
+ return r;
+}
+//------------------------------------------------------------------------------
+static void FHT(fREAL* data, unsigned int M, unsigned int inverse)
+{
+ double tt, fc, dc, fs, ds, a = M_PI;
+ fREAL t1, t2;
+ int n2, bd, bl, istep, k, len = 1 << M, n = 1;
+
+ int i, j = 0;
+ unsigned int Nh = len >> 1;
+ for (i=1;i<(len-1);++i) {
+ j = revbin_upd(j, Nh);
+ if (j>i) {
+ t1 = data[i];
+ data[i] = data[j];
+ data[j] = t1;
+ }
+ }
+
+ do {
+ fREAL* data_n = &data[n];
+
+ istep = n << 1;
+ for (k=0; k<len; k+=istep) {
+ t1 = data_n[k];
+ data_n[k] = data[k] - t1;
+ data[k] += t1;
+ }
+
+ n2 = n >> 1;
+ if (n>2) {
+ fc = dc = cos(a);
+ fs = ds = sqrt(1.0 - fc*fc); //sin(a);
+ bd = n-2;
+ for (bl=1; bl<n2; bl++) {
+ fREAL* data_nbd = &data_n[bd];
+ fREAL* data_bd = &data[bd];
+ for (k=bl; k<len; k+=istep) {
+ t1 = fc*data_n[k] + fs*data_nbd[k];
+ t2 = fs*data_n[k] - fc*data_nbd[k];
+ data_n[k] = data[k] - t1;
+ data_nbd[k] = data_bd[k] - t2;
+ data[k] += t1;
+ data_bd[k] += t2;
+ }
+ tt = fc*dc - fs*ds;
+ fs = fs*dc + fc*ds;
+ fc = tt;
+ bd -= 2;
+ }
+ }
+
+ if (n>1) {
+ for (k=n2; k<len; k+=istep) {
+ t1 = data_n[k];
+ data_n[k] = data[k] - t1;
+ data[k] += t1;
+ }
+ }
+
+ n = istep;
+ a *= 0.5;
+ } while (n<len);
+
+ if (inverse) {
+ fREAL sc = (fREAL)1 / (fREAL)len;
+ for (k=0; k<len; ++k)
+ data[k] *= sc;
+ }
+}
+//------------------------------------------------------------------------------
+/* 2D Fast Hartley Transform, Mx/My -> log2 of width/height,
+ nzp -> the row where zero pad data starts,
+ inverse -> see above */
+static void FHT2D(fREAL *data, unsigned int Mx, unsigned int My,
+ unsigned int nzp, unsigned int inverse)
+{
+ unsigned int i, j, Nx, Ny, maxy;
+ fREAL t;
+
+ Nx = 1 << Mx;
+ Ny = 1 << My;
+
+ // rows (forward transform skips 0 pad data)
+ maxy = inverse ? Ny : nzp;
+ for (j=0; j<maxy; ++j)
+ FHT(&data[Nx*j], Mx, inverse);
+
+ // transpose data
+ if (Nx==Ny) { // square
+ for (j=0; j<Ny; ++j)
+ for (i=j+1; i<Nx; ++i) {
+ unsigned int op = i + (j << Mx), np = j + (i << My);
+ t=data[op], data[op]=data[np], data[np]=t;
+ }
+ }
+ else { // rectangular
+ unsigned int k, Nym = Ny-1, stm = 1 << (Mx + My);
+ for (i=0; stm>0; i++) {
+ #define pred(k) (((k & Nym) << Mx) + (k >> My))
+ for (j=pred(i); j>i; j=pred(j));
+ if (j < i) continue;
+ for (k=i, j=pred(i); j!=i; k=j, j=pred(j), stm--)
+ { t=data[j], data[j]=data[k], data[k]=t; }
+ #undef pred
+ stm--;
+ }
+ }
+ // swap Mx/My & Nx/Ny
+ i = Nx, Nx = Ny, Ny = i;
+ i = Mx, Mx = My, My = i;
+
+ // now columns == transposed rows
+ for (j=0; j<Ny; ++j)
+ FHT(&data[Nx*j], Mx, inverse);
+
+ // finalize
+ for (j=0; j<=(Ny >> 1); j++) {
+ unsigned int jm = (Ny - j) & (Ny-1);
+ unsigned int ji = j << Mx;
+ unsigned int jmi = jm << Mx;
+ for (i=0; i<=(Nx >> 1); i++) {
+ unsigned int im = (Nx - i) & (Nx-1);
+ fREAL A = data[ji + i];
+ fREAL B = data[jmi + i];
+ fREAL C = data[ji + im];
+ fREAL D = data[jmi + im];
+ fREAL E = (fREAL)0.5*((A + D) - (B + C));
+ data[ji + i] = A - E;
+ data[jmi + i] = B + E;
+ data[ji + im] = C + E;
+ data[jmi + im] = D - E;
+ }
+ }
+
+}
+
+//------------------------------------------------------------------------------
+
+/* 2D convolution calc, d1 *= d2, M/N - > log2 of width/height */
+static void fht_convolve(fREAL* d1, fREAL* d2, unsigned int M, unsigned int N)
+{
+ fREAL a, b;
+ unsigned int i, j, k, L, mj, mL;
+ unsigned int m = 1 << M, n = 1 << N;
+ unsigned int m2 = 1 << (M-1), n2 = 1 << (N-1);
+ unsigned int mn2 = m << (N-1);
+
+ d1[0] *= d2[0];
+ d1[mn2] *= d2[mn2];
+ d1[m2] *= d2[m2];
+ d1[m2 + mn2] *= d2[m2 + mn2];
+ for (i=1; i<m2; i++) {
+ k = m - i;
+ a = d1[i]*d2[i] - d1[k]*d2[k];
+ b = d1[k]*d2[i] + d1[i]*d2[k];
+ d1[i] = (b + a)*(fREAL)0.5;
+ d1[k] = (b - a)*(fREAL)0.5;
+ a = d1[i + mn2]*d2[i + mn2] - d1[k + mn2]*d2[k + mn2];
+ b = d1[k + mn2]*d2[i + mn2] + d1[i + mn2]*d2[k + mn2];
+ d1[i + mn2] = (b + a)*(fREAL)0.5;
+ d1[k + mn2] = (b - a)*(fREAL)0.5;
+ }
+ for (j=1; j<n2; j++) {
+ L = n - j;
+ mj = j << M;
+ mL = L << M;
+ a = d1[mj]*d2[mj] - d1[mL]*d2[mL];
+ b = d1[mL]*d2[mj] + d1[mj]*d2[mL];
+ d1[mj] = (b + a)*(fREAL)0.5;
+ d1[mL] = (b - a)*(fREAL)0.5;
+ a = d1[m2 + mj]*d2[m2 + mj] - d1[m2 + mL]*d2[m2 + mL];
+ b = d1[m2 + mL]*d2[m2 + mj] + d1[m2 + mj]*d2[m2 + mL];
+ d1[m2 + mj] = (b + a)*(fREAL)0.5;
+ d1[m2 + mL] = (b - a)*(fREAL)0.5;
+ }
+ for (i=1; i<m2; i++) {
+ k = m - i;
+ for (j=1; j<n2; j++) {
+ L = n - j;
+ mj = j << M;
+ mL = L << M;
+ a = d1[i + mj]*d2[i + mj] - d1[k + mL]*d2[k + mL];
+ b = d1[k + mL]*d2[i + mj] + d1[i + mj]*d2[k + mL];
+ d1[i + mj] = (b + a)*(fREAL)0.5;
+ d1[k + mL] = (b - a)*(fREAL)0.5;
+ a = d1[i + mL]*d2[i + mL] - d1[k + mj]*d2[k + mj];
+ b = d1[k + mj]*d2[i + mL] + d1[i + mL]*d2[k + mj];
+ d1[i + mL] = (b + a)*(fREAL)0.5;
+ d1[k + mj] = (b - a)*(fREAL)0.5;
+ }
+ }
+}
+
+//------------------------------------------------------------------------------
+
+void convolve(CompBuf* dst, CompBuf* in1, CompBuf* in2)
+{
+ fREAL *data1, *data2, *fp;
+ unsigned int w2, h2, hw, hh, log2_w, log2_h;
+ fRGB wt, *colp;
+ int x, y, ch;
+ int xbl, ybl, nxb, nyb, xbsz, ybsz;
+ int in2done = 0;
+
+ CompBuf* rdst = alloc_compbuf(in1->x, in1->y, in1->type, 1);
+
+ // convolution result width & height
+ w2 = 2*in2->x - 1;
+ h2 = 2*in2->y - 1;
+ // FFT pow2 required size & log2
+ w2 = nextPow2(w2, &log2_w);
+ h2 = nextPow2(h2, &log2_h);
+
+ // alloc space
+ data1 = (fREAL*)MEM_callocN(3*w2*h2*sizeof(fREAL), "convolve_fast FHT data1");
+ data2 = (fREAL*)MEM_callocN(w2*h2*sizeof(fREAL), "convolve_fast FHT data2");
+
+ // normalize convolutor
+ wt[0] = wt[1] = wt[2] = 0.f;
+ for (y=0; y<in2->y; y++) {
+ colp = (fRGB*)&in2->rect[y*in2->x*in2->type];
+ for (x=0; x<in2->x; x++)
+ fRGB_add(wt, colp[x]);
+ }
+ if (wt[0] != 0.f) wt[0] = 1.f/wt[0];
+ if (wt[1] != 0.f) wt[1] = 1.f/wt[1];
+ if (wt[2] != 0.f) wt[2] = 1.f/wt[2];
+ for (y=0; y<in2->y; y++) {
+ colp = (fRGB*)&in2->rect[y*in2->x*in2->type];
+ for (x=0; x<in2->x; x++)
+ fRGB_colormult(colp[x], wt);
+ }
+
+ // copy image data, unpacking interleaved RGBA into separate channels
+ // only need to calc data1 once
+
+ // block add-overlap
+ hw = in2->x >> 1;
+ hh = in2->y >> 1;
+ xbsz = (w2 + 1) - in2->x;
+ ybsz = (h2 + 1) - in2->y;
+ nxb = in1->x / xbsz;
+ if (in1->x % xbsz) nxb++;
+ nyb = in1->y / ybsz;
+ if (in1->y % ybsz) nyb++;
+ for (ybl=0; ybl<nyb; ybl++) {
+ for (xbl=0; xbl<nxb; xbl++) {
+
+ // each channel one by one
+ for (ch=0; ch<3; ch++) {
+ fREAL* data1ch = &data1[ch*w2*h2];
+
+ // only need to calc fht data from in2 once, can re-use for every block
+ if (!in2done) {
+ // in2, channel ch -> data1
+ for (y=0; y<in2->y; y++) {
+ fp = &data1ch[y*w2];
+ colp = (fRGB*)&in2->rect[y*in2->x*in2->type];
+ for (x=0; x<in2->x; x++)
+ fp[x] = colp[x][ch];
+ }
+ }
+
+ // in1, channel ch -> data2
+ memset(data2, 0, w2*h2*sizeof(fREAL));
+ for (y=0; y<ybsz; y++) {
+ int yy = ybl*ybsz + y;
+ if (yy >= in1->y) continue;
+ fp = &data2[y*w2];
+ colp = (fRGB*)&in1->rect[yy*in1->x*in1->type];
+ for (x=0; x<xbsz; x++) {
+ int xx = xbl*xbsz + x;
+ if (xx >= in1->x) continue;
+ fp[x] = colp[xx][ch];
+ }
+ }
+
+ // forward FHT
+ // zero pad data start is different for each == height+1
+ if (!in2done) FHT2D(data1ch, log2_w, log2_h, in2->y+1, 0);
+ FHT2D(data2, log2_w, log2_h, in2->y+1, 0);
+
+ // FHT2D transposed data, row/col now swapped
+ // convolve & inverse FHT
+ fht_convolve(data2, data1ch, log2_h, log2_w);
+ FHT2D(data2, log2_h, log2_w, 0, 1);
+ // data again transposed, so in order again
+
+ // overlap-add result
+ for (y=0; y<(int)h2; y++) {
+ const int yy = ybl*ybsz + y - hh;
+ if ((yy < 0) || (yy >= in1->y)) continue;
+ fp = &data2[y*w2];
+ colp = (fRGB*)&rdst->rect[yy*in1->x*in1->type];
+ for (x=0; x<(int)w2; x++) {
+ const int xx = xbl*xbsz + x - hw;
+ if ((xx < 0) || (xx >= in1->x)) continue;
+ colp[xx][ch] += fp[x];
+ }
+ }
+
+ }
+ in2done = 1;
+ }
+ }
+
+ MEM_freeN(data2);
+ MEM_freeN(data1);
+ memcpy(dst->rect, rdst->rect, sizeof(float)*dst->x*dst->y*dst->type);
+ free_compbuf(rdst);
+}
+
+
+/*
+ *
+ * Utility functions qd_* should probably be intergrated better with other functions here.
+ *
+ */
+// sets fcol to pixelcolor at (x, y)
+void qd_getPixel(CompBuf* src, int x, int y, float* col)
+{
+ if(src->rect_procedural) {
+ float bc[4];
+ src->rect_procedural(src, bc, (float)x/(float)src->xrad, (float)y/(float)src->yrad);
+
+ switch(src->type){
+ /* these fallthrough to get all the channels */
+ case CB_RGBA: col[3]=bc[3];
+ case CB_VEC3: col[2]=bc[2];
+ case CB_VEC2: col[1]=bc[1];
+ case CB_VAL: col[0]=bc[0];
+ }
+ }
+ else if ((x >= 0) && (x < src->x) && (y >= 0) && (y < src->y)) {
+ float* bc = &src->rect[(x + y*src->x)*src->type];
+ switch(src->type){
+ /* these fallthrough to get all the channels */
+ case CB_RGBA: col[3]=bc[3];
+ case CB_VEC3: col[2]=bc[2];
+ case CB_VEC2: col[1]=bc[1];
+ case CB_VAL: col[0]=bc[0];
+ }
+ }
+ else {
+ switch(src->type){
+ /* these fallthrough to get all the channels */
+ case CB_RGBA: col[3]=0.0;
+ case CB_VEC3: col[2]=0.0;
+ case CB_VEC2: col[1]=0.0;
+ case CB_VAL: col[0]=0.0;
+ }
+ }
+}
+
+// sets pixel (x, y) to color col
+void qd_setPixel(CompBuf* src, int x, int y, float* col)
+{
+ if ((x >= 0) && (x < src->x) && (y >= 0) && (y < src->y)) {
+ float* bc = &src->rect[(x + y*src->x)*src->type];
+ switch(src->type){
+ /* these fallthrough to get all the channels */
+ case CB_RGBA: bc[3]=col[3];
+ case CB_VEC3: bc[2]=col[2];
+ case CB_VEC2: bc[1]=col[1];
+ case CB_VAL: bc[0]=col[0];
+ }
+ }
+}
+
+// adds fcol to pixelcolor (x, y)
+void qd_addPixel(CompBuf* src, int x, int y, float* col)
+{
+ if ((x >= 0) && (x < src->x) && (y >= 0) && (y < src->y)) {
+ float* bc = &src->rect[(x + y*src->x)*src->type];
+ bc[0] += col[0], bc[1] += col[1], bc[2] += col[2];
+ }
+}
+
+// multiplies pixel by factor value f
+void qd_multPixel(CompBuf* src, int x, int y, float f)
+{
+ if ((x >= 0) && (x < src->x) && (y >= 0) && (y < src->y)) {
+ float* bc = &src->rect[(x + y*src->x)*src->type];
+ bc[0] *= f, bc[1] *= f, bc[2] *= f;
+ }
+}
+
+// bilinear interpolation with wraparound
+void qd_getPixelLerpWrap(CompBuf* src, float u, float v, float* col)
+{
+ const float ufl = floor(u), vfl = floor(v);
+ const int nx = (int)ufl % src->x, ny = (int)vfl % src->y;
+ const int x1 = (nx < 0) ? (nx + src->x) : nx;
+ const int y1 = (ny < 0) ? (ny + src->y) : ny;
+ const int x2 = (x1 + 1) % src->x, y2 = (y1 + 1) % src->y;
+ const float* c00 = &src->rect[(x1 + y1*src->x)*src->type];
+ const float* c10 = &src->rect[(x2 + y1*src->x)*src->type];
+ const float* c01 = &src->rect[(x1 + y2*src->x)*src->type];
+ const float* c11 = &src->rect[(x2 + y2*src->x)*src->type];
+ const float uf = u - ufl, vf = v - vfl;
+ const float w00=(1.f-uf)*(1.f-vf), w10=uf*(1.f-vf), w01=(1.f-uf)*vf, w11=uf*vf;
+ col[0] = w00*c00[0] + w10*c10[0] + w01*c01[0] + w11*c11[0];
+ if (src->type != CB_VAL) {
+ col[1] = w00*c00[1] + w10*c10[1] + w01*c01[1] + w11*c11[1];
+ col[2] = w00*c00[2] + w10*c10[2] + w01*c01[2] + w11*c11[2];
+ col[3] = w00*c00[3] + w10*c10[3] + w01*c01[3] + w11*c11[3];
+ }
+}
+
+// as above, without wrap around
+void qd_getPixelLerp(CompBuf* src, float u, float v, float* col)
+{
+ const float ufl = floor(u), vfl = floor(v);
+ const int x1 = (int)ufl, y1 = (int)vfl;
+ const int x2 = (int)ceil(u), y2 = (int)ceil(v);
+ if ((x2 >= 0) && (y2 >= 0) && (x1 < src->x) && (y1 < src->y)) {
+ const float B[4] = {0,0,0,0};
+ const int ox1 = (x1 < 0), oy1 = (y1 < 0), ox2 = (x2 >= src->x), oy2 = (y2 >= src->y);
+ const float* c00 = (ox1 || oy1) ? B : &src->rect[(x1 + y1*src->x)*src->type];
+ const float* c10 = (ox2 || oy1) ? B : &src->rect[(x2 + y1*src->x)*src->type];
+ const float* c01 = (ox1 || oy2) ? B : &src->rect[(x1 + y2*src->x)*src->type];
+ const float* c11 = (ox2 || oy2) ? B : &src->rect[(x2 + y2*src->x)*src->type];
+ const float uf = u - ufl, vf = v - vfl;
+ const float w00=(1.f-uf)*(1.f-vf), w10=uf*(1.f-vf), w01=(1.f-uf)*vf, w11=uf*vf;
+ col[0] = w00*c00[0] + w10*c10[0] + w01*c01[0] + w11*c11[0];
+ if (src->type != CB_VAL) {
+ col[1] = w00*c00[1] + w10*c10[1] + w01*c01[1] + w11*c11[1];
+ col[2] = w00*c00[2] + w10*c10[2] + w01*c01[2] + w11*c11[2];
+ col[3] = w00*c00[3] + w10*c10[3] + w01*c01[3] + w11*c11[3];
+ }
+ }
+ else col[0] = col[1] = col[2] = col[3] = 0.f;
+}
+
+// as above, sampling only one channel
+void qd_getPixelLerpChan(CompBuf* src, float u, float v, int chan, float* out)
+{
+ const float ufl = floor(u), vfl = floor(v);
+ const int x1 = (int)ufl, y1 = (int)vfl;
+ const int x2 = (int)ceil(u), y2 = (int)ceil(v);
+ if (chan >= src->type) chan = 0;
+ if ((x2 >= 0) && (y2 >= 0) && (x1 < src->x) && (y1 < src->y)) {
+ const float B[4] = {0,0,0,0};
+ const int ox1 = (x1 < 0), oy1 = (y1 < 0), ox2 = (x2 >= src->x), oy2 = (y2 >= src->y);
+ const float* c00 = (ox1 || oy1) ? B : &src->rect[(x1 + y1*src->x)*src->type + chan];
+ const float* c10 = (ox2 || oy1) ? B : &src->rect[(x2 + y1*src->x)*src->type + chan];
+ const float* c01 = (ox1 || oy2) ? B : &src->rect[(x1 + y2*src->x)*src->type + chan];
+ const float* c11 = (ox2 || oy2) ? B : &src->rect[(x2 + y2*src->x)*src->type + chan];
+ const float uf = u - ufl, vf = v - vfl;
+ const float w00=(1.f-uf)*(1.f-vf), w10=uf*(1.f-vf), w01=(1.f-uf)*vf, w11=uf*vf;
+ out[0] = w00*c00[0] + w10*c10[0] + w01*c01[0] + w11*c11[0];
+ }
+ else *out = 0.f;
+}
+
+
+CompBuf* qd_downScaledCopy(CompBuf* src, int scale)
+{
+ CompBuf* fbuf;
+ if (scale <= 1)
+ fbuf = dupalloc_compbuf(src);
+ else {
+ int nw = src->x/scale, nh = src->y/scale;
+ if ((2*(src->x % scale)) > scale) nw++;
+ if ((2*(src->y % scale)) > scale) nh++;
+ fbuf = alloc_compbuf(nw, nh, src->type, 1);
+ {
+ int x, y, xx, yy, sx, sy, mx, my;
+ float colsum[4] = {0.0f, 0.0f, 0.0f, 0.0f};
+ float fscale = 1.f/(float)(scale*scale);
+ for (y=0; y<nh; y++) {
+ fRGB* fcolp = (fRGB*)&fbuf->rect[y*fbuf->x*fbuf->type];
+ yy = y*scale;
+ my = yy + scale;
+ if (my > src->y) my = src->y;
+ for (x=0; x<nw; x++) {
+ xx = x*scale;
+ mx = xx + scale;
+ if (mx > src->x) mx = src->x;
+ colsum[0] = colsum[1] = colsum[2] = 0.f;
+ for (sy=yy; sy<my; sy++) {
+ fRGB* scolp = (fRGB*)&src->rect[sy*src->x*src->type];
+ for (sx=xx; sx<mx; sx++)
+ fRGB_add(colsum, scolp[sx]);
+ }
+ fRGB_mult(colsum, fscale);
+ fRGB_copy(fcolp[x], colsum);
+ }
+ }
+ }
+ }
+ return fbuf;
+}
+
+// fast g.blur, per channel
+// xy var. bits 1 & 2 ca be used to blur in x or y direction separately
+void IIR_gauss(CompBuf* src, float sigma, int chan, int xy)
+{
+ double q, q2, sc, cf[4], tsM[9], tsu[3], tsv[3];
+ double *X, *Y, *W;
+ int i, x, y, sz;
+
+ // <0.5 not valid, though can have a possibly useful sort of sharpening effect
+ if (sigma < 0.5) return;
+
+ if ((xy < 1) || (xy > 3)) xy = 3;
+
+ // XXX The YVV macro defined below explicitely expects sources of at least 3x3 pixels,
+ // so just skiping blur along faulty direction if src's def is below that limit!
+ if (src->x < 3) xy &= ~(int) 1;
+ if (src->y < 3) xy &= ~(int) 2;
+ if (xy < 1) return;
+
+ // see "Recursive Gabor Filtering" by Young/VanVliet
+ // all factors here in double.prec. Required, because for single.prec it seems to blow up if sigma > ~200
+ if (sigma >= 3.556)
+ q = 0.9804*(sigma - 3.556) + 2.5091;
+ else // sigma >= 0.5
+ q = (0.0561*sigma + 0.5784)*sigma - 0.2568;
+ q2 = q*q;
+ sc = (1.1668 + q)*(3.203729649 + (2.21566 + q)*q);
+ // no gabor filtering here, so no complex multiplies, just the regular coefs.
+ // all negated here, so as not to have to recalc Triggs/Sdika matrix
+ cf[1] = q*(5.788961737 + (6.76492 + 3.0*q)*q)/ sc;
+ cf[2] = -q2*(3.38246 + 3.0*q)/sc;
+ // 0 & 3 unchanged
+ cf[3] = q2*q/sc;
+ cf[0] = 1.0 - cf[1] - cf[2] - cf[3];
+
+ // Triggs/Sdika border corrections,
+ // it seems to work, not entirely sure if it is actually totally correct,
+ // Besides J.M.Geusebroek's anigauss.c (see http://www.science.uva.nl/~mark),
+ // found one other implementation by Cristoph Lampert,
+ // but neither seem to be quite the same, result seems to be ok sofar anyway.
+ // Extra scale factor here to not have to do it in filter,
+ // though maybe this had something to with the precision errors
+ sc = cf[0]/((1.0 + cf[1] - cf[2] + cf[3])*(1.0 - cf[1] - cf[2] - cf[3])*(1.0 + cf[2] + (cf[1] - cf[3])*cf[3]));
+ tsM[0] = sc*(-cf[3]*cf[1] + 1.0 - cf[3]*cf[3] - cf[2]);
+ tsM[1] = sc*((cf[3] + cf[1])*(cf[2] + cf[3]*cf[1]));
+ tsM[2] = sc*(cf[3]*(cf[1] + cf[3]*cf[2]));
+ tsM[3] = sc*(cf[1] + cf[3]*cf[2]);
+ tsM[4] = sc*(-(cf[2] - 1.0)*(cf[2] + cf[3]*cf[1]));
+ tsM[5] = sc*(-(cf[3]*cf[1] + cf[3]*cf[3] + cf[2] - 1.0)*cf[3]);
+ tsM[6] = sc*(cf[3]*cf[1] + cf[2] + cf[1]*cf[1] - cf[2]*cf[2]);
+ tsM[7] = sc*(cf[1]*cf[2] + cf[3]*cf[2]*cf[2] - cf[1]*cf[3]*cf[3] - cf[3]*cf[3]*cf[3] - cf[3]*cf[2] + cf[3]);
+ tsM[8] = sc*(cf[3]*(cf[1] + cf[3]*cf[2]));
+
+#define YVV(L)\
+{\
+ W[0] = cf[0]*X[0] + cf[1]*X[0] + cf[2]*X[0] + cf[3]*X[0];\
+ W[1] = cf[0]*X[1] + cf[1]*W[0] + cf[2]*X[0] + cf[3]*X[0];\
+ W[2] = cf[0]*X[2] + cf[1]*W[1] + cf[2]*W[0] + cf[3]*X[0];\
+ for (i=3; i<L; i++)\
+ W[i] = cf[0]*X[i] + cf[1]*W[i-1] + cf[2]*W[i-2] + cf[3]*W[i-3];\
+ tsu[0] = W[L-1] - X[L-1];\
+ tsu[1] = W[L-2] - X[L-1];\
+ tsu[2] = W[L-3] - X[L-1];\
+ tsv[0] = tsM[0]*tsu[0] + tsM[1]*tsu[1] + tsM[2]*tsu[2] + X[L-1];\
+ tsv[1] = tsM[3]*tsu[0] + tsM[4]*tsu[1] + tsM[5]*tsu[2] + X[L-1];\
+ tsv[2] = tsM[6]*tsu[0] + tsM[7]*tsu[1] + tsM[8]*tsu[2] + X[L-1];\
+ Y[L-1] = cf[0]*W[L-1] + cf[1]*tsv[0] + cf[2]*tsv[1] + cf[3]*tsv[2];\
+ Y[L-2] = cf[0]*W[L-2] + cf[1]*Y[L-1] + cf[2]*tsv[0] + cf[3]*tsv[1];\
+ Y[L-3] = cf[0]*W[L-3] + cf[1]*Y[L-2] + cf[2]*Y[L-1] + cf[3]*tsv[0];\
+ for (i=L-4; i>=0; i--)\
+ Y[i] = cf[0]*W[i] + cf[1]*Y[i+1] + cf[2]*Y[i+2] + cf[3]*Y[i+3];\
+}
+
+ // intermediate buffers
+ sz = MAX2(src->x, src->y);
+ X = MEM_callocN(sz*sizeof(double), "IIR_gauss X buf");
+ Y = MEM_callocN(sz*sizeof(double), "IIR_gauss Y buf");
+ W = MEM_callocN(sz*sizeof(double), "IIR_gauss W buf");
+ if (xy & 1) { // H
+ for (y=0; y<src->y; ++y) {
+ const int yx = y*src->x;
+ for (x=0; x<src->x; ++x)
+ X[x] = src->rect[(x + yx)*src->type + chan];
+ YVV(src->x);
+ for (x=0; x<src->x; ++x)
+ src->rect[(x + yx)*src->type + chan] = Y[x];
+ }
+ }
+ if (xy & 2) { // V
+ for (x=0; x<src->x; ++x) {
+ for (y=0; y<src->y; ++y)
+ X[y] = src->rect[(x + y*src->x)*src->type + chan];
+ YVV(src->y);
+ for (y=0; y<src->y; ++y)
+ src->rect[(x + y*src->x)*src->type + chan] = Y[y];
+ }
+ }
+
+ MEM_freeN(X);
+ MEM_freeN(W);
+ MEM_freeN(Y);
+#undef YVV
+}
+
diff --git a/source/blender/nodes/composite/node_composite_util.h b/source/blender/nodes/composite/node_composite_util.h
new file mode 100644
index 00000000000..e3158b2a286
--- /dev/null
+++ b/source/blender/nodes/composite/node_composite_util.h
@@ -0,0 +1,210 @@
+/*
+ * $Id: CMP_util.h 35562 2011-03-15 20:10:32Z lukastoenne $
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2006 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/nodes/composite/node_composite_util.h
+ * \ingroup nodes
+ */
+
+
+#ifndef NODE_COMPOSITE_UTIL_H_
+#define NODE_COMPOSITE_UTIL_H_
+
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_camera_types.h" /* qdn: defocus node, need camera info */
+#include "DNA_color_types.h"
+#include "DNA_ID.h"
+#include "DNA_image_types.h"
+#include "DNA_material_types.h"
+#include "DNA_node_types.h"
+#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_texture_types.h"
+
+#include "BLI_math.h"
+#include "BLI_blenlib.h"
+#include "BLI_rand.h"
+#include "BLI_threads.h"
+#include "BLI_utildefines.h"
+#include "BLI_utildefines.h"
+
+#include "BKE_blender.h"
+#include "BKE_colortools.h"
+#include "BKE_global.h"
+#include "BKE_image.h"
+#include "BKE_main.h"
+#include "BKE_material.h"
+#include "BKE_node.h"
+#include "BKE_texture.h"
+
+#include "BKE_library.h"
+#include "BKE_object.h"
+
+#include "node_util.h"
+
+#include "IMB_imbuf_types.h"
+#include "IMB_imbuf.h"
+
+#include "RE_pipeline.h"
+#include "RE_shader_ext.h"
+#include "RE_render_ext.h"
+
+/* *************************** operations support *************************** */
+
+/* general signal that's in output sockets, and goes over the wires */
+typedef struct CompBuf {
+ float *rect;
+ int x, y, xrad, yrad;
+ short type, malloc;
+ rcti disprect; /* cropped part of image */
+ int xof, yof; /* relative to center of target image */
+
+ void (*rect_procedural)(struct CompBuf *, float *, float, float);
+ float procedural_size[3], procedural_offset[3];
+ int procedural_type;
+ bNode *node; /* only in use for procedural bufs */
+
+ struct CompBuf *next, *prev; /* for pass-on, works nicer than reference counting */
+} CompBuf;
+
+/* defines also used for pixel size */
+#define CB_RGBA 4
+#define CB_VEC4 4
+#define CB_VEC3 3
+#define CB_VEC2 2
+#define CB_VAL 1
+
+/* defines for RGBA channels */
+#define CHAN_R 0
+#define CHAN_G 1
+#define CHAN_B 2
+#define CHAN_A 3
+
+
+
+CompBuf *alloc_compbuf(int sizex, int sizey, int type, int alloc);
+CompBuf *dupalloc_compbuf(CompBuf *cbuf);
+CompBuf *pass_on_compbuf(CompBuf *cbuf);
+void free_compbuf(CompBuf *cbuf);
+void print_compbuf(char *str, CompBuf *cbuf);
+void compbuf_set_node(struct CompBuf *cbuf, struct bNode *node);
+void node_compo_pass_on(struct bNode *node, struct bNodeStack **nsin, struct bNodeStack **nsout);
+
+CompBuf *get_cropped_compbuf(rcti *drect, float *rectf, int rectx, int recty, int type);
+CompBuf *scalefast_compbuf(CompBuf *inbuf, int newx, int newy);
+CompBuf *typecheck_compbuf(CompBuf *inbuf, int type);
+void typecheck_compbuf_color(float *out, float *in, int outtype, int intype);
+
+/* **************************************************** */
+
+/* Pixel-to-Pixel operation, 1 Image in, 1 out */
+void composit1_pixel_processor(bNode *node, CompBuf *out, CompBuf *src_buf, float *src_col,
+ void (*func)(bNode *, float *, float *),
+ int src_type);
+/* Pixel-to-Pixel operation, 2 Images in, 1 out */
+void composit2_pixel_processor(bNode *node, CompBuf *out, CompBuf *src_buf, float *src_col,
+ CompBuf *fac_buf, float *fac, void (*func)(bNode *, float *, float *, float *),
+ int src_type, int fac_type);
+
+/* Pixel-to-Pixel operation, 3 Images in, 1 out */
+void composit3_pixel_processor(bNode *node, CompBuf *out, CompBuf *src1_buf, float *src1_col, CompBuf *src2_buf, float *src2_col,
+ CompBuf *fac_buf, float *fac, void (*func)(bNode *, float *, float *, float *, float *),
+ int src1_type, int src2_type, int fac_type);
+
+/* Pixel-to-Pixel operation, 4 Images in, 1 out */
+void composit4_pixel_processor(bNode *node, CompBuf *out, CompBuf *src1_buf, float *src1_col, CompBuf *fac1_buf, float *fac1,
+ CompBuf *src2_buf, float *src2_col, CompBuf *fac2_buf, float *fac2,
+ void (*func)(bNode *, float *, float *, float *, float *, float *),
+ int src1_type, int fac1_type, int src2_type, int fac2_type);
+
+CompBuf *valbuf_from_rgbabuf(CompBuf *cbuf, int channel);
+void generate_preview(void *data, bNode *node, CompBuf *stackbuf);
+
+void do_copy_rgba(bNode *node, float *out, float *in);
+void do_copy_rgb(bNode *node, float *out, float *in);
+void do_copy_value(bNode *node, float *out, float *in);
+void do_copy_a_rgba(bNode *node, float *out, float *in, float *fac);
+
+void do_rgba_to_yuva(bNode *node, float *out, float *in);
+void do_rgba_to_hsva(bNode *node, float *out, float *in);
+void do_rgba_to_ycca(bNode *node, float *out, float *in);
+void do_yuva_to_rgba(bNode *node, float *out, float *in);
+void do_hsva_to_rgba(bNode *node, float *out, float *in);
+void do_ycca_to_rgba(bNode *node, float *out, float *in);
+
+void gamma_correct_compbuf(CompBuf *img, int inversed);
+void premul_compbuf(CompBuf *img, int inversed);
+void convolve(CompBuf* dst, CompBuf* in1, CompBuf* in2);
+
+extern void node_ID_title_cb(void *node_v, void *unused_v);
+
+
+/* utility functions used by glare, tonemap and lens distortion */
+/* soms macros for color handling */
+typedef float fRGB[4];
+/* clear color */
+#define fRGB_clear(c) { c[0]=c[1]=c[2]=0.f; }
+/* copy c2 to c1 */
+#define fRGB_copy(c1, c2) { c1[0]=c2[0]; c1[1]=c2[1]; c1[2]=c2[2]; c1[3]=c2[3]; }
+/* add c2 to c1 */
+#define fRGB_add(c1, c2) { c1[0]+=c2[0]; c1[1]+=c2[1]; c1[2]+=c2[2]; }
+/* subtract c2 from c1 */
+#define fRGB_sub(c1, c2) { c1[0]-=c2[0]; c1[1]-=c2[1]; c1[2]-=c2[2]; }
+/* multiply c by float value s */
+#define fRGB_mult(c, s) { c[0]*=s; c[1]*=s; c[2]*=s; }
+/* multiply c2 by s and add to c1 */
+#define fRGB_madd(c1, c2, s) { c1[0]+=c2[0]*s; c1[1]+=c2[1]*s; c1[2]+=c2[2]*s; }
+/* multiply c2 by color c1 */
+#define fRGB_colormult(c, cs) { c[0]*=cs[0]; c[1]*=cs[1]; c[2]*=cs[2]; }
+/* multiply c2 by color c3 and add to c1 */
+#define fRGB_colormadd(c1, c2, c3) { c1[0]+=c2[0]*c3[0]; c1[1]+=c2[1]*c3[1]; c1[2]+=c2[2]*c3[2]; }
+/* multiply c2 by color rgb, rgb as separate arguments */
+#define fRGB_rgbmult(c, r, g, b) { c[0]*=(r); c[1]*=(g); c[2]*=(b); }
+/* swap colors c1 & c2 */
+#define fRGB_swap(c1, c2) { float _t=c1[0]; c1[0]=c2[0]; c2[0]=_t;\
+ _t=c1[1]; c1[1]=c2[1]; c2[1]=_t;\
+ _t=c1[2]; c1[2]=c2[2]; c2[2]=_t;\
+ _t=c1[3]; c1[3]=c2[3]; c3[3]=_t;}
+
+void qd_getPixel(CompBuf* src, int x, int y, float* col);
+void qd_setPixel(CompBuf* src, int x, int y, float* col);
+void qd_addPixel(CompBuf* src, int x, int y, float* col);
+void qd_multPixel(CompBuf* src, int x, int y, float f);
+void qd_getPixelLerpWrap(CompBuf* src, float u, float v, float* col);
+void qd_getPixelLerp(CompBuf* src, float u, float v, float* col);
+void qd_getPixelLerpChan(CompBuf* src, float u, float v, int chan, float* out);
+CompBuf* qd_downScaledCopy(CompBuf* src, int scale);
+void IIR_gauss(CompBuf* src, float sigma, int chan, int xy);
+/* end utility funcs */
+
+#endif
diff --git a/source/blender/nodes/composite/nodes/node_composite_alphaOver.c b/source/blender/nodes/composite/nodes/node_composite_alphaOver.c
new file mode 100644
index 00000000000..400bdd92b6f
--- /dev/null
+++ b/source/blender/nodes/composite/nodes/node_composite_alphaOver.c
@@ -0,0 +1,163 @@
+/*
+ * $Id: CMP_alphaOver.c 36593 2011-05-10 11:19:26Z lukastoenne $
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2006 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/nodes/composite/nodes/node_composite_alphaOver.c
+ * \ingroup cmpnodes
+ */
+
+
+#include "node_composite_util.h"
+
+/* **************** ALPHAOVER ******************** */
+static bNodeSocketTemplate cmp_node_alphaover_in[]= {
+ { SOCK_FLOAT, 1, "Fac", 1.0f, 0.0f, 1.0f, 1.0f, 0.0f, 1.0f, PROP_FACTOR},
+ { SOCK_RGBA, 1, "Image", 0.8f, 0.8f, 0.8f, 1.0f},
+ { SOCK_RGBA, 1, "Image", 0.8f, 0.8f, 0.8f, 1.0f},
+ { -1, 0, "" }
+};
+static bNodeSocketTemplate cmp_node_alphaover_out[]= {
+ { SOCK_RGBA, 0, "Image"},
+ { -1, 0, "" }
+};
+
+static void do_alphaover_premul(bNode *UNUSED(node), float *out, float *src, float *over, float *fac)
+{
+
+ if(over[3]<=0.0f) {
+ QUATCOPY(out, src);
+ }
+ else if(fac[0]==1.0f && over[3]>=1.0f) {
+ QUATCOPY(out, over);
+ }
+ else {
+ float mul= 1.0f - fac[0]*over[3];
+
+ out[0]= (mul*src[0]) + fac[0]*over[0];
+ out[1]= (mul*src[1]) + fac[0]*over[1];
+ out[2]= (mul*src[2]) + fac[0]*over[2];
+ out[3]= (mul*src[3]) + fac[0]*over[3];
+ }
+}
+
+/* result will be still premul, but the over part is premulled */
+static void do_alphaover_key(bNode *UNUSED(node), float *out, float *src, float *over, float *fac)
+{
+
+ if(over[3]<=0.0f) {
+ QUATCOPY(out, src);
+ }
+ else if(fac[0]==1.0f && over[3]>=1.0f) {
+ QUATCOPY(out, over);
+ }
+ else {
+ float premul= fac[0]*over[3];
+ float mul= 1.0f - premul;
+
+ out[0]= (mul*src[0]) + premul*over[0];
+ out[1]= (mul*src[1]) + premul*over[1];
+ out[2]= (mul*src[2]) + premul*over[2];
+ out[3]= (mul*src[3]) + fac[0]*over[3];
+ }
+}
+
+/* result will be still premul, but the over part is premulled */
+static void do_alphaover_mixed(bNode *node, float *out, float *src, float *over, float *fac)
+{
+
+ if(over[3]<=0.0f) {
+ QUATCOPY(out, src);
+ }
+ else if(fac[0]==1.0f && over[3]>=1.0f) {
+ QUATCOPY(out, over);
+ }
+ else {
+ NodeTwoFloats *ntf= node->storage;
+ float addfac= 1.0f - ntf->x + over[3]*ntf->x;
+ float premul= fac[0]*addfac;
+ float mul= 1.0f - fac[0]*over[3];
+
+ out[0]= (mul*src[0]) + premul*over[0];
+ out[1]= (mul*src[1]) + premul*over[1];
+ out[2]= (mul*src[2]) + premul*over[2];
+ out[3]= (mul*src[3]) + fac[0]*over[3];
+ }
+}
+
+
+
+
+static void node_composit_exec_alphaover(void *UNUSED(data), bNode *node, bNodeStack **in, bNodeStack **out)
+{
+ /* stack order in: col col */
+ /* stack order out: col */
+ if(out[0]->hasoutput==0)
+ return;
+
+ /* input no image? then only color operation */
+ if(in[1]->data==NULL && in[2]->data==NULL) {
+ do_alphaover_premul(node, out[0]->vec, in[1]->vec, in[2]->vec, in[0]->vec);
+ }
+ else {
+ /* make output size of input image */
+ CompBuf *cbuf= in[1]->data?in[1]->data:in[2]->data;
+ CompBuf *stackbuf= alloc_compbuf(cbuf->x, cbuf->y, CB_RGBA, 1); /* allocs */
+ NodeTwoFloats *ntf= node->storage;
+
+ if(ntf->x != 0.0f)
+ composit3_pixel_processor(node, stackbuf, in[1]->data, in[1]->vec, in[2]->data, in[2]->vec, in[0]->data, in[0]->vec, do_alphaover_mixed, CB_RGBA, CB_RGBA, CB_VAL);
+ else if(node->custom1)
+ composit3_pixel_processor(node, stackbuf, in[1]->data, in[1]->vec, in[2]->data, in[2]->vec, in[0]->data, in[0]->vec, do_alphaover_key, CB_RGBA, CB_RGBA, CB_VAL);
+ else
+ composit3_pixel_processor(node, stackbuf, in[1]->data, in[1]->vec, in[2]->data, in[2]->vec, in[0]->data, in[0]->vec, do_alphaover_premul, CB_RGBA, CB_RGBA, CB_VAL);
+
+ out[0]->data= stackbuf;
+ }
+}
+
+static void node_alphaover_init(bNodeTree *UNUSED(ntree), bNode* node, bNodeTemplate *UNUSED(ntemp))
+{
+ node->storage= MEM_callocN(sizeof(NodeTwoFloats), "NodeTwoFloats");
+}
+
+void register_node_type_cmp_alphaover(ListBase *lb)
+{
+ static bNodeType ntype;
+
+ node_type_base(&ntype, CMP_NODE_ALPHAOVER, "AlphaOver", NODE_CLASS_OP_COLOR, NODE_OPTIONS);
+ node_type_socket_templates(&ntype, cmp_node_alphaover_in, cmp_node_alphaover_out);
+ node_type_size(&ntype, 80, 40, 120);
+ node_type_init(&ntype, node_alphaover_init);
+ node_type_storage(&ntype, "NodeTwoFloats", node_free_standard_storage, node_copy_standard_storage);
+ node_type_exec(&ntype, node_composit_exec_alphaover);
+
+ nodeRegisterType(lb, &ntype);
+}
+
+
+
diff --git a/source/blender/nodes/composite/nodes/node_composite_bilateralblur.c b/source/blender/nodes/composite/nodes/node_composite_bilateralblur.c
new file mode 100644
index 00000000000..e7a9ee12ca1
--- /dev/null
+++ b/source/blender/nodes/composite/nodes/node_composite_bilateralblur.c
@@ -0,0 +1,271 @@
+/*
+ *
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2006 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): Vilem Novak
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/nodes/composite/nodes/node_composite_bilateralblur.c
+ * \ingroup cmpnodes
+ */
+
+#include "node_composite_util.h"
+
+/* **************** BILATERALBLUR ******************** */
+static bNodeSocketTemplate cmp_node_bilateralblur_in[]= {
+ { SOCK_RGBA, 1, "Image", 0.8f, 0.8f, 0.8f, 1.0f},
+ { SOCK_RGBA, 1, "Determinator", 0.8f, 0.8f, 0.8f, 1.0f},
+ { -1, 0, "" }
+};
+
+static bNodeSocketTemplate cmp_node_bilateralblur_out[]= {
+ { SOCK_RGBA, 0, "Image"},
+ { -1, 0, "" }
+};
+
+#define INIT_C3\
+ mean0 = 1; mean1[0] = src[0];mean1[1] = src[1];mean1[2] = src[2];mean1[3] = src[3];
+
+/* finds color distances */
+#define COLOR_DISTANCE_C3(c1, c2)\
+ ((c1[0] - c2[0])*(c1[0] - c2[0]) + \
+ (c1[1] - c2[1])*(c1[1] - c2[1]) + \
+ (c1[2] - c2[2])*(c1[2] - c2[2]) + \
+ (c1[3] - c2[3])*(c1[3] - c2[3]))
+
+/* this is the main kernel function for comparing color distances
+ and adding them weighted to the final color */
+#define KERNEL_ELEMENT_C3(k)\
+ temp_color = src + deltas[k];\
+ ref_color = ref + deltas[k];\
+ w = weight_tab[k] + COLOR_DISTANCE_C3(ref, ref_color )*i2sigma_color;\
+ w = 1./(w*w + 1); \
+ mean0 += w;\
+ mean1[0] += temp_color[0]*w; \
+ mean1[1] += temp_color[1]*w; \
+ mean1[2] += temp_color[2]*w; \
+ mean1[3] += temp_color[3]*w;
+
+/* write blurred values to image */
+#define UPDATE_OUTPUT_C3\
+ mean0 = 1./mean0;\
+ dest[x*pix + 0] = mean1[0]*mean0; \
+ dest[x*pix + 1] = mean1[1]*mean0; \
+ dest[x*pix + 2] = mean1[2]*mean0; \
+ dest[x*pix + 3] = mean1[3]*mean0;
+
+/* initializes deltas for fast access to neighbour pixels */
+#define INIT_3X3_DELTAS( deltas, step, nch ) \
+ ((deltas)[0] = (nch), (deltas)[1] = -(step) + (nch), \
+ (deltas)[2] = -(step), (deltas)[3] = -(step) - (nch), \
+ (deltas)[4] = -(nch), (deltas)[5] = (step) - (nch), \
+ (deltas)[6] = (step), (deltas)[7] = (step) + (nch));
+
+
+/* code of this node was heavily inspired by the smooth function of opencv library.
+The main change is an optional image input */
+static void node_composit_exec_bilateralblur(void *UNUSED(data), bNode *node, bNodeStack **in, bNodeStack **out)
+{
+ NodeBilateralBlurData *nbbd= node->storage;
+ CompBuf *new, *source, *img= in[0]->data , *refimg= in[1]->data;
+ double mean0, w, i2sigma_color, i2sigma_space;
+ double mean1[4];
+ double weight_tab[8];
+ float *src, *dest, *ref, *temp_color, *ref_color;
+ float sigma_color, sigma_space;
+ int imgx, imgy, x, y, pix, i, step;
+ int deltas[8];
+ short found_determinator= 0;
+
+ if(img == NULL || out[0]->hasoutput == 0)
+ return;
+
+ if(img->type != CB_RGBA) {
+ img= typecheck_compbuf(in[0]->data, CB_RGBA);
+ }
+
+ imgx= img->x;
+ imgy= img->y;
+ pix= img->type;
+ step= pix * imgx;
+
+ if(refimg) {
+ if(refimg->x == imgx && refimg->y == imgy) {
+ if(ELEM3(refimg->type, CB_VAL, CB_VEC2, CB_VEC3)) {
+ refimg= typecheck_compbuf(in[1]->data, CB_RGBA);
+ found_determinator= 1;
+ }
+ }
+ }
+ else {
+ refimg= img;
+ }
+
+ /* allocs */
+ source= dupalloc_compbuf(img);
+ new= alloc_compbuf(imgx, imgy, pix, 1);
+
+ /* accept image offsets from other nodes */
+ new->xof= img->xof;
+ new->yof= img->yof;
+
+ /* bilateral code properties */
+ sigma_color= nbbd->sigma_color;
+ sigma_space= nbbd->sigma_space;
+
+ i2sigma_color= 1. / (sigma_color * sigma_color);
+ i2sigma_space= 1. / (sigma_space * sigma_space);
+
+ INIT_3X3_DELTAS(deltas, step, pix);
+
+ weight_tab[0] = weight_tab[2] = weight_tab[4] = weight_tab[6] = i2sigma_space;
+ weight_tab[1] = weight_tab[3] = weight_tab[5] = weight_tab[7] = i2sigma_space * 2;
+
+ /* iterations */
+ for(i= 0; i < nbbd->iter; i++) {
+ src= source->rect;
+ ref= refimg->rect;
+ dest= new->rect;
+ /*goes through image, there are more loops for 1st/last line and all other lines*/
+ /*kernel element accumulates surrounding colors, which are then written with the update_output function*/
+ for(x= 0; x < imgx; x++, src+= pix, ref+= pix) {
+ INIT_C3;
+
+ KERNEL_ELEMENT_C3(6);
+
+ if(x > 0) {
+ KERNEL_ELEMENT_C3(5);
+ KERNEL_ELEMENT_C3(4);
+ }
+
+ if(x < imgx - 1) {
+ KERNEL_ELEMENT_C3(7);
+ KERNEL_ELEMENT_C3(0);
+ }
+
+ UPDATE_OUTPUT_C3;
+ }
+
+ dest+= step;
+
+ for(y= 1; y < imgy - 1; y++, dest+= step, src+= pix, ref+= pix) {
+ x= 0;
+
+ INIT_C3;
+
+ KERNEL_ELEMENT_C3(0);
+ KERNEL_ELEMENT_C3(1);
+ KERNEL_ELEMENT_C3(2);
+ KERNEL_ELEMENT_C3(6);
+ KERNEL_ELEMENT_C3(7);
+
+ UPDATE_OUTPUT_C3;
+
+ src+= pix;
+ ref+= pix;
+
+ for(x= 1; x < imgx - 1; x++, src+= pix, ref+= pix) {
+ INIT_C3;
+
+ KERNEL_ELEMENT_C3(0);
+ KERNEL_ELEMENT_C3(1);
+ KERNEL_ELEMENT_C3(2);
+ KERNEL_ELEMENT_C3(3);
+ KERNEL_ELEMENT_C3(4);
+ KERNEL_ELEMENT_C3(5);
+ KERNEL_ELEMENT_C3(6);
+ KERNEL_ELEMENT_C3(7);
+
+ UPDATE_OUTPUT_C3;
+ }
+
+ INIT_C3;
+
+ KERNEL_ELEMENT_C3(2);
+ KERNEL_ELEMENT_C3(3);
+ KERNEL_ELEMENT_C3(4);
+ KERNEL_ELEMENT_C3(5);
+ KERNEL_ELEMENT_C3(6);
+
+ UPDATE_OUTPUT_C3;
+ }
+
+ for(x= 0; x < imgx; x++, src+= pix, ref+= pix) {
+ INIT_C3;
+
+ KERNEL_ELEMENT_C3(2);
+
+ if(x > 0) {
+ KERNEL_ELEMENT_C3(3);
+ KERNEL_ELEMENT_C3(4);
+ }
+ if(x < imgx - 1) {
+ KERNEL_ELEMENT_C3(1);
+ KERNEL_ELEMENT_C3(0);
+ }
+
+ UPDATE_OUTPUT_C3;
+ }
+
+ if(node->exec & NODE_BREAK) break;
+
+ SWAP(CompBuf, *source, *new);
+ }
+
+ if(img != in[0]->data)
+ free_compbuf(img);
+
+ if(found_determinator == 1) {
+ if(refimg != in[1]->data)
+ free_compbuf(refimg);
+ }
+
+ out[0]->data= source;
+
+ free_compbuf(new);
+}
+
+static void node_composit_init_bilateralblur(bNodeTree *UNUSED(ntree), bNode* node, bNodeTemplate *UNUSED(ntemp))
+{
+ NodeBilateralBlurData *nbbd= MEM_callocN(sizeof(NodeBilateralBlurData), "node bilateral blur data");
+ node->storage= nbbd;
+ nbbd->sigma_color= 0.3;
+ nbbd->sigma_space= 5.0;
+}
+
+void register_node_type_cmp_bilateralblur(ListBase *lb)
+{
+ static bNodeType ntype;
+
+ node_type_base(&ntype, CMP_NODE_BILATERALBLUR, "Bilateral Blur", NODE_CLASS_OP_FILTER, NODE_OPTIONS);
+ node_type_socket_templates(&ntype, cmp_node_bilateralblur_in, cmp_node_bilateralblur_out);
+ node_type_size(&ntype, 150, 120, 200);
+ node_type_init(&ntype, node_composit_init_bilateralblur);
+ node_type_storage(&ntype, "NodeBilateralBlurData", node_free_standard_storage, node_copy_standard_storage);
+ node_type_exec(&ntype, node_composit_exec_bilateralblur);
+
+ nodeRegisterType(lb, &ntype);
+}
+
diff --git a/source/blender/nodes/composite/nodes/node_composite_blur.c b/source/blender/nodes/composite/nodes/node_composite_blur.c
new file mode 100644
index 00000000000..7b1a9623845
--- /dev/null
+++ b/source/blender/nodes/composite/nodes/node_composite_blur.c
@@ -0,0 +1,736 @@
+/*
+ * $Id: CMP_blur.c 36593 2011-05-10 11:19:26Z lukastoenne $
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2006 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): Campbell Barton, Alfredo de Greef, David Millan Escriva,
+ * Juho Vepsäläinen
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/nodes/composite/nodes/node_composite_blur.c
+ * \ingroup cmpnodes
+ */
+
+
+#include "node_composite_util.h"
+
+/* **************** BLUR ******************** */
+static bNodeSocketTemplate cmp_node_blur_in[]= {
+ { SOCK_RGBA, 1, "Image", 0.8f, 0.8f, 0.8f, 1.0f},
+ { SOCK_FLOAT, 1, "Size", 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR},
+ { -1, 0, "" }
+};
+static bNodeSocketTemplate cmp_node_blur_out[]= {
+ { SOCK_RGBA, 0, "Image"},
+ { -1, 0, "" }
+};
+
+static float *make_gausstab(int filtertype, int rad)
+{
+ float *gausstab, sum, val;
+ int i, n;
+
+ n = 2 * rad + 1;
+
+ gausstab = (float *) MEM_mallocN(n * sizeof(float), "gauss");
+
+ sum = 0.0f;
+ for (i = -rad; i <= rad; i++) {
+ val= RE_filter_value(filtertype, (float)i/(float)rad);
+ sum += val;
+ gausstab[i+rad] = val;
+ }
+
+ sum= 1.0f/sum;
+ for(i=0; i<n; i++)
+ gausstab[i]*= sum;
+
+ return gausstab;
+}
+
+static float *make_bloomtab(int rad)
+{
+ float *bloomtab, val;
+ int i, n;
+
+ n = 2 * rad + 1;
+
+ bloomtab = (float *) MEM_mallocN(n * sizeof(float), "bloom");
+
+ for (i = -rad; i <= rad; i++) {
+ val = pow(1.0 - fabs((float)i)/((float)rad), 4.0);
+ bloomtab[i+rad] = val;
+ }
+
+ return bloomtab;
+}
+
+/* both input images of same type, either 4 or 1 channel */
+static void blur_single_image(bNode *node, CompBuf *new, CompBuf *img, float scale)
+{
+ NodeBlurData *nbd= node->storage;
+ CompBuf *work;
+ register float sum, val;
+ float rval, gval, bval, aval;
+ float *gausstab, *gausstabcent;
+ int rad, imgx= img->x, imgy= img->y;
+ int x, y, pix= img->type;
+ int i, bigstep;
+ float *src, *dest;
+
+ /* helper image */
+ work= alloc_compbuf(imgx, imgy, img->type, 1); /* allocs */
+
+ /* horizontal */
+ if(nbd->sizex == 0) {
+ memcpy(work->rect, img->rect, sizeof(float) * img->type * imgx * imgy);
+ }
+ else {
+ rad = scale*(float)nbd->sizex;
+ if(rad>imgx/2)
+ rad= imgx/2;
+ else if(rad<1)
+ rad= 1;
+
+ gausstab= make_gausstab(nbd->filtertype, rad);
+ gausstabcent= gausstab+rad;
+
+ for (y = 0; y < imgy; y++) {
+ float *srcd= img->rect + pix*(y*img->x);
+
+ dest = work->rect + pix*(y * img->x);
+
+ for (x = 0; x < imgx ; x++) {
+ int minr= x-rad<0?-x:-rad;
+ int maxr= x+rad>imgx?imgx-x:rad;
+
+ src= srcd + pix*(x+minr);
+
+ sum= gval = rval= bval= aval= 0.0f;
+ for (i= minr; i < maxr; i++) {
+ val= gausstabcent[i];
+ sum+= val;
+ rval += val * (*src++);
+ if(pix==4) {
+ gval += val * (*src++);
+ bval += val * (*src++);
+ aval += val * (*src++);
+ }
+ }
+ sum= 1.0f/sum;
+ *dest++ = rval*sum;
+ if(pix==4) {
+ *dest++ = gval*sum;
+ *dest++ = bval*sum;
+ *dest++ = aval*sum;
+ }
+ }
+ if(node->exec & NODE_BREAK)
+ break;
+ }
+
+ /* vertical */
+ MEM_freeN(gausstab);
+ }
+
+ if(nbd->sizey == 0) {
+ memcpy(new->rect, work->rect, sizeof(float) * img->type * imgx * imgy);
+ }
+ else {
+ rad = scale*(float)nbd->sizey;
+ if(rad>imgy/2)
+ rad= imgy/2;
+ else if(rad<1)
+ rad= 1;
+
+ gausstab= make_gausstab(nbd->filtertype, rad);
+ gausstabcent= gausstab+rad;
+
+ bigstep = pix*imgx;
+ for (x = 0; x < imgx; x++) {
+ float *srcd= work->rect + pix*x;
+
+ dest = new->rect + pix*x;
+
+ for (y = 0; y < imgy ; y++) {
+ int minr= y-rad<0?-y:-rad;
+ int maxr= y+rad>imgy?imgy-y:rad;
+
+ src= srcd + bigstep*(y+minr);
+
+ sum= gval = rval= bval= aval= 0.0f;
+ for (i= minr; i < maxr; i++) {
+ val= gausstabcent[i];
+ sum+= val;
+ rval += val * src[0];
+ if(pix==4) {
+ gval += val * src[1];
+ bval += val * src[2];
+ aval += val * src[3];
+ }
+ src += bigstep;
+ }
+ sum= 1.0f/sum;
+ dest[0] = rval*sum;
+ if(pix==4) {
+ dest[1] = gval*sum;
+ dest[2] = bval*sum;
+ dest[3] = aval*sum;
+ }
+ dest+= bigstep;
+ }
+ if(node->exec & NODE_BREAK)
+ break;
+ }
+ MEM_freeN(gausstab);
+ }
+
+ free_compbuf(work);
+}
+
+/* reference has to be mapped 0-1, and equal in size */
+static void bloom_with_reference(CompBuf *new, CompBuf *img, CompBuf *UNUSED(ref), float UNUSED(fac), NodeBlurData *nbd)
+{
+ CompBuf *wbuf;
+ register float val;
+ float radxf, radyf;
+ float **maintabs;
+ float *gausstabx, *gausstabcenty;
+ float *gausstaby, *gausstabcentx;
+ int radx, rady, imgx= img->x, imgy= img->y;
+ int x, y;
+ int i, j;
+ float *src, *dest, *wb;
+
+ wbuf= alloc_compbuf(imgx, imgy, CB_VAL, 1);
+
+ /* horizontal */
+ radx = (float)nbd->sizex;
+ if(radx>imgx/2)
+ radx= imgx/2;
+ else if(radx<1)
+ radx= 1;
+
+ /* vertical */
+ rady = (float)nbd->sizey;
+ if(rady>imgy/2)
+ rady= imgy/2;
+ else if(rady<1)
+ rady= 1;
+
+ x= MAX2(radx, rady);
+ maintabs= MEM_mallocN(x*sizeof(void *), "gauss array");
+ for(i= 0; i<x; i++)
+ maintabs[i]= make_bloomtab(i+1);
+
+ /* vars to store before we go */
+// refd= ref->rect;
+ src= img->rect;
+
+ radxf= (float)radx;
+ radyf= (float)rady;
+
+ for (y = 0; y < imgy; y++) {
+ for (x = 0; x < imgx ; x++, src+=4) {//, refd++) {
+
+// int refradx= (int)(refd[0]*radxf);
+// int refrady= (int)(refd[0]*radyf);
+
+ int refradx= (int)(radxf*0.3f*src[3]*(src[0]+src[1]+src[2]));
+ int refrady= (int)(radyf*0.3f*src[3]*(src[0]+src[1]+src[2]));
+
+ if(refradx>radx) refradx= radx;
+ else if(refradx<1) refradx= 1;
+ if(refrady>rady) refrady= rady;
+ else if(refrady<1) refrady= 1;
+
+ if(refradx==1 && refrady==1) {
+ wb= wbuf->rect + ( y*imgx + x);
+ dest= new->rect + 4*( y*imgx + x);
+ wb[0]+= 1.0f;
+ dest[0] += src[0];
+ dest[1] += src[1];
+ dest[2] += src[2];
+ dest[3] += src[3];
+ }
+ else {
+ int minxr= x-refradx<0?-x:-refradx;
+ int maxxr= x+refradx>imgx?imgx-x:refradx;
+ int minyr= y-refrady<0?-y:-refrady;
+ int maxyr= y+refrady>imgy?imgy-y:refrady;
+
+ float *destd= new->rect + 4*( (y + minyr)*imgx + x + minxr);
+ float *wbufd= wbuf->rect + ( (y + minyr)*imgx + x + minxr);
+
+ gausstabx= maintabs[refradx-1];
+ gausstabcentx= gausstabx+refradx;
+ gausstaby= maintabs[refrady-1];
+ gausstabcenty= gausstaby+refrady;
+
+ for (i= minyr; i < maxyr; i++, destd+= 4*imgx, wbufd+= imgx) {
+ dest= destd;
+ wb= wbufd;
+ for (j= minxr; j < maxxr; j++, dest+=4, wb++) {
+
+ val= gausstabcenty[i]*gausstabcentx[j];
+ wb[0]+= val;
+ dest[0] += val * src[0];
+ dest[1] += val * src[1];
+ dest[2] += val * src[2];
+ dest[3] += val * src[3];
+ }
+ }
+ }
+ }
+ }
+
+ x= imgx*imgy;
+ dest= new->rect;
+ wb= wbuf->rect;
+ while(x--) {
+ val= 1.0f/wb[0];
+ dest[0]*= val;
+ dest[1]*= val;
+ dest[2]*= val;
+ dest[3]*= val;
+ wb++;
+ dest+= 4;
+ }
+
+ free_compbuf(wbuf);
+
+ x= MAX2(radx, rady);
+ for(i= 0; i<x; i++)
+ MEM_freeN(maintabs[i]);
+ MEM_freeN(maintabs);
+
+}
+
+#if 0
+static float hexagon_filter(float fi, float fj)
+{
+ fi= fabs(fi);
+ fj= fabs(fj);
+
+ if(fj>0.33f) {
+ fj= (fj-0.33f)/0.66f;
+ if(fi+fj>1.0f)
+ return 0.0f;
+ else
+ return 1.0f;
+ }
+ else return 1.0f;
+}
+#endif
+
+/* uses full filter, no horizontal/vertical optimize possible */
+/* both images same type, either 1 or 4 channels */
+static void bokeh_single_image(bNode *node, CompBuf *new, CompBuf *img, float fac)
+{
+ NodeBlurData *nbd= node->storage;
+ register float val;
+ float radxf, radyf;
+ float *gausstab, *dgauss;
+ int radx, rady, imgx= img->x, imgy= img->y;
+ int x, y, pix= img->type;
+ int i, j, n;
+ float *src= NULL, *dest, *srcd= NULL;
+
+ /* horizontal */
+ radxf = fac*(float)nbd->sizex;
+ if(radxf>imgx/2.0f)
+ radxf= imgx/2.0f;
+ else if(radxf<1.0f)
+ radxf= 1.0f;
+
+ /* vertical */
+ radyf = fac*(float)nbd->sizey;
+ if(radyf>imgy/2.0f)
+ radyf= imgy/2.0f;
+ else if(radyf<1.0f)
+ radyf= 1.0f;
+
+ radx= ceil(radxf);
+ rady= ceil(radyf);
+
+ n = (2*radx+1)*(2*rady+1);
+
+ /* create a full filter image */
+ gausstab= MEM_mallocN(sizeof(float)*n, "filter tab");
+ dgauss= gausstab;
+ val= 0.0f;
+ for(j=-rady; j<=rady; j++) {
+ for(i=-radx; i<=radx; i++, dgauss++) {
+ float fj= (float)j/radyf;
+ float fi= (float)i/radxf;
+ float dist= sqrt(fj*fj + fi*fi);
+
+ //*dgauss= hexagon_filter(fi, fj);
+ *dgauss= RE_filter_value(nbd->filtertype, dist);
+
+ val+= *dgauss;
+ }
+ }
+
+ if(val!=0.0f) {
+ val= 1.0f/val;
+ for(j= n -1; j>=0; j--)
+ gausstab[j]*= val;
+ }
+ else gausstab[4]= 1.0f;
+
+ for (y = -rady+1; y < imgy+rady-1; y++) {
+
+ if(y<=0) srcd= img->rect;
+ else if(y<imgy) srcd+= pix*imgx;
+ else srcd= img->rect + pix*(imgy-1)*imgx;
+
+ for (x = -radx+1; x < imgx+radx-1 ; x++) {
+ int minxr= x-radx<0?-x:-radx;
+ int maxxr= x+radx>=imgx?imgx-x-1:radx;
+ int minyr= y-rady<0?-y:-rady;
+ int maxyr= y+rady>imgy-1?imgy-y-1:rady;
+
+ float *destd= new->rect + pix*( (y + minyr)*imgx + x + minxr);
+ float *dgausd= gausstab + (minyr+rady)*(2*radx+1) + minxr+radx;
+
+ if(x<=0) src= srcd;
+ else if(x<imgx) src+= pix;
+ else src= srcd + pix*(imgx-1);
+
+ for (i= minyr; i <=maxyr; i++, destd+= pix*imgx, dgausd+= 2*radx + 1) {
+ dest= destd;
+ dgauss= dgausd;
+ for (j= minxr; j <=maxxr; j++, dest+=pix, dgauss++) {
+ val= *dgauss;
+ if(val!=0.0f) {
+ dest[0] += val * src[0];
+ if(pix>1) {
+ dest[1] += val * src[1];
+ dest[2] += val * src[2];
+ dest[3] += val * src[3];
+ }
+ }
+ }
+ }
+ }
+ if(node->exec & NODE_BREAK)
+ break;
+ }
+
+ MEM_freeN(gausstab);
+}
+
+
+/* reference has to be mapped 0-1, and equal in size */
+static void blur_with_reference(bNode *node, CompBuf *new, CompBuf *img, CompBuf *ref)
+{
+ NodeBlurData *nbd= node->storage;
+ CompBuf *blurbuf, *ref_use;
+ register float sum, val;
+ float rval, gval, bval, aval, radxf, radyf;
+ float **maintabs;
+ float *gausstabx, *gausstabcenty;
+ float *gausstaby, *gausstabcentx;
+ int radx, rady, imgx= img->x, imgy= img->y;
+ int x, y, pix= img->type;
+ int i, j;
+ float *src, *dest, *refd, *blurd;
+
+ if(ref->x!=img->x && ref->y!=img->y)
+ return;
+
+ ref_use= typecheck_compbuf(ref, CB_VAL);
+
+ /* trick is; we blur the reference image... but only works with clipped values*/
+ blurbuf= alloc_compbuf(imgx, imgy, CB_VAL, 1);
+ blurd= blurbuf->rect;
+ refd= ref_use->rect;
+ for(x= imgx*imgy; x>0; x--, refd++, blurd++) {
+ if(refd[0]<0.0f) blurd[0]= 0.0f;
+ else if(refd[0]>1.0f) blurd[0]= 1.0f;
+ else blurd[0]= refd[0];
+ }
+
+ blur_single_image(node, blurbuf, blurbuf, 1.0f);
+
+ /* horizontal */
+ radx = (float)nbd->sizex;
+ if(radx>imgx/2)
+ radx= imgx/2;
+ else if(radx<1)
+ radx= 1;
+
+ /* vertical */
+ rady = (float)nbd->sizey;
+ if(rady>imgy/2)
+ rady= imgy/2;
+ else if(rady<1)
+ rady= 1;
+
+ x= MAX2(radx, rady);
+ maintabs= MEM_mallocN(x*sizeof(void *), "gauss array");
+ for(i= 0; i<x; i++)
+ maintabs[i]= make_gausstab(nbd->filtertype, i+1);
+
+ refd= blurbuf->rect;
+ dest= new->rect;
+ radxf= (float)radx;
+ radyf= (float)rady;
+
+ for (y = 0; y < imgy; y++) {
+ for (x = 0; x < imgx ; x++, dest+=pix, refd++) {
+ int refradx= (int)(refd[0]*radxf);
+ int refrady= (int)(refd[0]*radyf);
+
+ if(refradx>radx) refradx= radx;
+ else if(refradx<1) refradx= 1;
+ if(refrady>rady) refrady= rady;
+ else if(refrady<1) refrady= 1;
+
+ if(refradx==1 && refrady==1) {
+ src= img->rect + pix*( y*imgx + x);
+ if(pix==1)
+ dest[0]= src[0];
+ else
+ QUATCOPY(dest, src);
+ }
+ else {
+ int minxr= x-refradx<0?-x:-refradx;
+ int maxxr= x+refradx>imgx?imgx-x:refradx;
+ int minyr= y-refrady<0?-y:-refrady;
+ int maxyr= y+refrady>imgy?imgy-y:refrady;
+
+ float *srcd= img->rect + pix*( (y + minyr)*imgx + x + minxr);
+
+ gausstabx= maintabs[refradx-1];
+ gausstabcentx= gausstabx+refradx;
+ gausstaby= maintabs[refrady-1];
+ gausstabcenty= gausstaby+refrady;
+
+ sum= gval = rval= bval= aval= 0.0f;
+
+ for (i= minyr; i < maxyr; i++, srcd+= pix*imgx) {
+ src= srcd;
+ for (j= minxr; j < maxxr; j++, src+=pix) {
+
+ val= gausstabcenty[i]*gausstabcentx[j];
+ sum+= val;
+ rval += val * src[0];
+ if(pix>1) {
+ gval += val * src[1];
+ bval += val * src[2];
+ aval += val * src[3];
+ }
+ }
+ }
+ sum= 1.0f/sum;
+ dest[0] = rval*sum;
+ if(pix>1) {
+ dest[1] = gval*sum;
+ dest[2] = bval*sum;
+ dest[3] = aval*sum;
+ }
+ }
+ }
+ if(node->exec & NODE_BREAK)
+ break;
+ }
+
+ free_compbuf(blurbuf);
+
+ x= MAX2(radx, rady);
+ for(i= 0; i<x; i++)
+ MEM_freeN(maintabs[i]);
+ MEM_freeN(maintabs);
+
+ if(ref_use!=ref)
+ free_compbuf(ref_use);
+}
+
+static void node_composit_exec_blur(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
+{
+ CompBuf *new, *img= in[0]->data;
+ NodeBlurData *nbd= node->storage;
+
+ if(img==NULL) return;
+
+ /* store image in size that is needed for absolute/relative conversions on ui level */
+ nbd->image_in_width= img->x;
+ nbd->image_in_height= img->y;
+
+ if(out[0]->hasoutput==0) return;
+
+ if(nbd->relative) {
+ if (nbd->aspect==CMP_NODE_BLUR_ASPECT_NONE) {
+ nbd->sizex= (int)(nbd->percentx*0.01f*nbd->image_in_width);
+ nbd->sizey= (int)(nbd->percenty*0.01f*nbd->image_in_height);
+ }
+ else if (nbd->aspect==CMP_NODE_BLUR_ASPECT_Y) {
+ nbd->sizex= (int)(nbd->percentx*0.01f*nbd->image_in_width);
+ nbd->sizey= (int)(nbd->percenty*0.01f*nbd->image_in_width);
+ }
+ else if (nbd->aspect==CMP_NODE_BLUR_ASPECT_X) {
+ nbd->sizex= (int)(nbd->percentx*0.01f*nbd->image_in_height);
+ nbd->sizey= (int)(nbd->percenty*0.01f*nbd->image_in_height);
+ }
+ }
+
+ if (nbd->sizex==0 && nbd->sizey==0) {
+ new= pass_on_compbuf(img);
+ out[0]->data= new;
+ }
+ else if (nbd->filtertype == R_FILTER_FAST_GAUSS) {
+ CompBuf *new, *img = in[0]->data;
+ // TODO: can this be mapped with reference, too?
+ const float sx = ((float)nbd->sizex*in[1]->vec[0])/2.0f, sy = ((float)nbd->sizey*in[1]->vec[0])/2.0f;
+ int c;
+
+ if ((img==NULL) || (out[0]->hasoutput==0)) return;
+
+ if (img->type == CB_VEC2)
+ new = typecheck_compbuf(img, CB_VAL);
+ else if (img->type == CB_VEC3)
+ new = typecheck_compbuf(img, CB_RGBA);
+ else
+ new = dupalloc_compbuf(img);
+
+ if ((sx == sy) && (sx > 0.f)) {
+ for (c=0; c<new->type; ++c)
+ IIR_gauss(new, sx, c, 3);
+ }
+ else {
+ if (sx > 0.f) {
+ for (c=0; c<new->type; ++c)
+ IIR_gauss(new, sx, c, 1);
+ }
+ if (sy > 0.f) {
+ for (c=0; c<new->type; ++c)
+ IIR_gauss(new, sy, c, 2);
+ }
+ }
+ out[0]->data = new;
+
+ } else {
+ /* All non fast gauss blur methods */
+ if(img->type==CB_VEC2 || img->type==CB_VEC3) {
+ img= typecheck_compbuf(in[0]->data, CB_RGBA);
+ }
+
+ /* if fac input, we do it different */
+ if(in[1]->data) {
+ CompBuf *gammabuf;
+
+ /* make output size of input image */
+ new= alloc_compbuf(img->x, img->y, img->type, 1); /* allocs */
+
+ /* accept image offsets from other nodes */
+ new->xof = img->xof;
+ new->yof = img->yof;
+
+ if(nbd->gamma) {
+ gammabuf= dupalloc_compbuf(img);
+ gamma_correct_compbuf(gammabuf, 0);
+ }
+ else gammabuf= img;
+
+ blur_with_reference(node, new, gammabuf, in[1]->data);
+
+ if(nbd->gamma) {
+ gamma_correct_compbuf(new, 1);
+ free_compbuf(gammabuf);
+ }
+ if(node->exec & NODE_BREAK) {
+ free_compbuf(new);
+ new= NULL;
+ }
+ out[0]->data= new;
+ }
+ else {
+
+ if(in[1]->vec[0]<=0.001f) { /* time node inputs can be a tiny value */
+ new= pass_on_compbuf(img);
+ }
+ else {
+ CompBuf *gammabuf;
+
+ /* make output size of input image */
+ new= alloc_compbuf(img->x, img->y, img->type, 1); /* allocs */
+
+ /* accept image offsets from other nodes */
+ new->xof = img->xof;
+ new->yof = img->yof;
+
+ if(nbd->gamma) {
+ gammabuf= dupalloc_compbuf(img);
+ gamma_correct_compbuf(gammabuf, 0);
+ }
+ else gammabuf= img;
+
+ if(nbd->bokeh)
+ bokeh_single_image(node, new, gammabuf, in[1]->vec[0]);
+ else if(1)
+ blur_single_image(node, new, gammabuf, in[1]->vec[0]);
+ else /* bloom experimental... */
+ bloom_with_reference(new, gammabuf, NULL, in[1]->vec[0], nbd);
+
+ if(nbd->gamma) {
+ gamma_correct_compbuf(new, 1);
+ free_compbuf(gammabuf);
+ }
+ if(node->exec & NODE_BREAK) {
+ free_compbuf(new);
+ new= NULL;
+ }
+ }
+ out[0]->data= new;
+ }
+ if(img!=in[0]->data)
+ free_compbuf(img);
+ }
+
+ generate_preview(data, node, out[0]->data);
+}
+
+static void node_composit_init_blur(bNodeTree *UNUSED(ntree), bNode* node, bNodeTemplate *UNUSED(ntemp))
+{
+ node->storage= MEM_callocN(sizeof(NodeBlurData), "node blur data");
+}
+
+void register_node_type_cmp_blur(ListBase *lb)
+{
+ static bNodeType ntype;
+
+ node_type_base(&ntype, CMP_NODE_BLUR, "Blur", NODE_CLASS_OP_FILTER, NODE_PREVIEW|NODE_OPTIONS);
+ node_type_socket_templates(&ntype, cmp_node_blur_in, cmp_node_blur_out);
+ node_type_size(&ntype, 120, 80, 200);
+ node_type_init(&ntype, node_composit_init_blur);
+ node_type_storage(&ntype, "NodeBlurData", node_free_standard_storage, node_copy_standard_storage);
+ node_type_exec(&ntype, node_composit_exec_blur);
+
+ nodeRegisterType(lb, &ntype);
+}
+
+
+
diff --git a/source/blender/nodes/composite/nodes/node_composite_brightness.c b/source/blender/nodes/composite/nodes/node_composite_brightness.c
new file mode 100644
index 00000000000..1a5cf956a52
--- /dev/null
+++ b/source/blender/nodes/composite/nodes/node_composite_brightness.c
@@ -0,0 +1,110 @@
+/*
+* $Id: CMP_brightness.c 36593 2011-05-10 11:19:26Z lukastoenne $
+*
+* ***** BEGIN GPL LICENSE BLOCK *****
+*
+* This program is free software; you can redistribute it and/or
+* modify it under the terms of the GNU General Public License
+* as published by the Free Software Foundation; either version 2
+* of the License, or (at your option) any later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program; if not, write to the Free Software Foundation,
+* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+* The Original Code is Copyright (C) 2006 Blender Foundation.
+* All rights reserved.
+*
+* The Original Code is: all of this file.
+*
+* Contributor(s): none yet.
+*
+* ***** END GPL LICENSE BLOCK *****
+
+*/
+
+/** \file blender/nodes/composite/nodes/node_composite_brightness.c
+ * \ingroup cmpnodes
+ */
+
+
+#include "node_composite_util.h"
+
+
+/* **************** Brigh and contrsast ******************** */
+
+static bNodeSocketTemplate cmp_node_brightcontrast_in[]= {
+ { SOCK_RGBA, 1, "Image", 0.8f, 0.8f, 0.8f, 1.0f},
+ { SOCK_FLOAT, 1, "Bright", 0.0f, 0.0f, 0.0f, 0.0f, -100.0f, 100.0f, PROP_NONE},
+ { SOCK_FLOAT, 1, "Contrast", 0.0f, 0.0f, 0.0f, 0.0f, -100.0f, 100.0f, PROP_NONE},
+ { -1, 0, "" }
+};
+static bNodeSocketTemplate cmp_node_brightcontrast_out[]= {
+ { SOCK_RGBA, 0, "Image"},
+ { -1, 0, "" }
+};
+
+static void do_brightnesscontrast(bNode *UNUSED(node), float *out, float *in, float *in_brightness, float *in_contrast)
+{
+ float i;
+ int c;
+ float a, b, v;
+ float brightness = (*in_brightness) / 100.0f;
+ float contrast = *in_contrast;
+ float delta = contrast / 200.0f;
+ a = 1.0f - delta * 2.0f;
+ /*
+ * The algorithm is by Werner D. Streidt
+ * (http://visca.com/ffactory/archives/5-99/msg00021.html)
+ * Extracted of OpenCV demhist.c
+ */
+ if( contrast > 0 )
+{
+ a = 1.0f / a;
+ b = a * (brightness - delta);
+ }
+ else
+ {
+ delta *= -1;
+ b = a * (brightness + delta);
+ }
+
+ for(c=0; c<3; c++){
+ i = in[c];
+ v = a*i + b;
+ out[c] = v;
+ }
+}
+
+static void node_composit_exec_brightcontrast(void *UNUSED(data), bNode *node, bNodeStack **in, bNodeStack **out)
+{
+ if(out[0]->hasoutput==0)
+ return;
+
+ if(in[0]->data) {
+ CompBuf *stackbuf, *cbuf= typecheck_compbuf(in[0]->data, CB_RGBA);
+ stackbuf= dupalloc_compbuf(cbuf);
+ composit3_pixel_processor(node, stackbuf, in[0]->data, in[0]->vec, in[1]->data, in[1]->vec, in[2]->data, in[2]->vec, do_brightnesscontrast, CB_RGBA, CB_VAL, CB_VAL);
+ out[0]->data = stackbuf;
+ if(cbuf != in[0]->data)
+ free_compbuf(cbuf);
+ }
+}
+
+void register_node_type_cmp_brightcontrast(ListBase *lb)
+{
+ static bNodeType ntype;
+
+ node_type_base(&ntype, CMP_NODE_BRIGHTCONTRAST, "Bright/Contrast", NODE_CLASS_OP_COLOR, NODE_OPTIONS);
+ node_type_socket_templates(&ntype, cmp_node_brightcontrast_in, cmp_node_brightcontrast_out);
+ node_type_size(&ntype, 140, 100, 320);
+ node_type_exec(&ntype, node_composit_exec_brightcontrast);
+
+ nodeRegisterType(lb, &ntype);
+}
+
diff --git a/source/blender/nodes/composite/nodes/node_composite_channelMatte.c b/source/blender/nodes/composite/nodes/node_composite_channelMatte.c
new file mode 100644
index 00000000000..afdbe82aebc
--- /dev/null
+++ b/source/blender/nodes/composite/nodes/node_composite_channelMatte.c
@@ -0,0 +1,217 @@
+/*
+ * $Id: CMP_channelMatte.c 36536 2011-05-07 13:27:27Z lukastoenne $
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2006 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): Bob Holcomb
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/nodes/composite/nodes/node_composite_channelMatte.c
+ * \ingroup cmpnodes
+ */
+
+
+#include "node_composite_util.h"
+
+
+/* ******************* Channel Matte Node ********************************* */
+static bNodeSocketTemplate cmp_node_channel_matte_in[]={
+ {SOCK_RGBA,1,"Image", 0.8f, 0.8f, 0.8f, 1.0f},
+ {-1,0,""}
+};
+
+static bNodeSocketTemplate cmp_node_channel_matte_out[]={
+ {SOCK_RGBA,0,"Image"},
+ {SOCK_FLOAT,0,"Matte"},
+ {-1,0,""}
+};
+
+static void do_normalized_rgba_to_ycca2(bNode *UNUSED(node), float *out, float *in)
+{
+ /*normalize to the range 0.0 to 1.0) */
+ rgb_to_ycc(in[0],in[1],in[2], &out[0], &out[1], &out[2], BLI_YCC_ITU_BT601);
+ out[0]=(out[0])/255.0;
+ out[1]=(out[1])/255.0;
+ out[2]=(out[2])/255.0;
+ out[3]=in[3];
+}
+
+static void do_normalized_ycca_to_rgba2(bNode *UNUSED(node), float *out, float *in)
+{
+ /*un-normalize the normalize from above */
+ in[0]=in[0]*255.0;
+ in[1]=in[1]*255.0;
+ in[2]=in[2]*255.0;
+ ycc_to_rgb(in[0],in[1],in[2], &out[0], &out[1], &out[2], BLI_YCC_ITU_BT601);
+ out[3]=in[3];
+}
+
+
+static void do_channel_matte(bNode *node, float *out, float *in)
+{
+ NodeChroma *c=(NodeChroma *)node->storage;
+ float alpha=0.0;
+
+ switch(c->algorithm) {
+ case 0: { /* Alpha=key_channel-limit channel */
+ int key_channel=node->custom2-1;
+ int limit_channel=c->channel-1;
+ alpha=in[key_channel]-in[limit_channel];
+ break;
+ }
+ case 1: { /* Alpha=G-MAX(R, B) */
+ switch(node->custom2) {
+ case 1: {
+ alpha=in[0]-MAX2(in[1],in[2]);
+ break;
+ }
+ case 2: {
+ alpha=in[1]-MAX2(in[0],in[2]);
+ break;
+ }
+ case 3: {
+ alpha=in[2]-MAX2(in[0],in[1]);
+ break;
+ }
+ default:
+ break;
+ }
+ break;
+ }
+ default:
+ break;
+ }
+
+ /*flip because 0.0 is transparent, not 1.0*/
+ alpha=1-alpha;
+
+ /* test range*/
+ if(alpha>c->t1) {
+ alpha=in[3]; /*whatever it was prior */
+ }
+ else if(alpha<c->t2){
+ alpha=0.0;
+ }
+ else {/*blend */
+ alpha=(alpha-c->t2)/(c->t1-c->t2);
+ }
+
+
+ /* don't make something that was more transparent less transparent */
+ if (alpha<in[3]) {
+ out[3]=alpha;
+ }
+ else {
+ out[3]=in[3];
+ }
+}
+
+static void node_composit_exec_channel_matte(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
+{
+ CompBuf *cbuf;
+ CompBuf *outbuf;
+
+ if(in[0]->hasinput==0) return;
+ if(in[0]->data==NULL) return;
+ if(out[0]->hasoutput==0 && out[1]->hasoutput==0) return;
+
+ cbuf=typecheck_compbuf(in[0]->data, CB_RGBA);
+
+ outbuf=dupalloc_compbuf(cbuf);
+
+ /*convert to colorspace*/
+ switch(node->custom1) {
+ case CMP_NODE_CHANNEL_MATTE_CS_RGB:
+ break;
+ case CMP_NODE_CHANNEL_MATTE_CS_HSV: /*HSV*/
+ composit1_pixel_processor(node, outbuf, cbuf, in[1]->vec, do_rgba_to_hsva, CB_RGBA);
+ break;
+ case CMP_NODE_CHANNEL_MATTE_CS_YUV: /*YUV*/
+ composit1_pixel_processor(node, outbuf, cbuf, in[1]->vec, do_rgba_to_yuva, CB_RGBA);
+ break;
+ case CMP_NODE_CHANNEL_MATTE_CS_YCC: /*YCC*/
+ composit1_pixel_processor(node, outbuf, cbuf, in[1]->vec, do_normalized_rgba_to_ycca2, CB_RGBA);
+ break;
+ default:
+ break;
+ }
+
+ /*use the selected channel information to do the key */
+ composit1_pixel_processor(node, outbuf, outbuf, in[1]->vec, do_channel_matte, CB_RGBA);
+
+ /*convert back to RGB colorspace in place*/
+ switch(node->custom1) {
+ case CMP_NODE_CHANNEL_MATTE_CS_RGB: /*RGB*/
+ break;
+ case CMP_NODE_CHANNEL_MATTE_CS_HSV: /*HSV*/
+ composit1_pixel_processor(node, outbuf, outbuf, in[1]->vec, do_hsva_to_rgba, CB_RGBA);
+ break;
+ case CMP_NODE_CHANNEL_MATTE_CS_YUV: /*YUV*/
+ composit1_pixel_processor(node, outbuf, outbuf, in[1]->vec, do_yuva_to_rgba, CB_RGBA);
+ break;
+ case CMP_NODE_CHANNEL_MATTE_CS_YCC: /*YCC*/
+ composit1_pixel_processor(node, outbuf, outbuf, in[1]->vec, do_normalized_ycca_to_rgba2, CB_RGBA);
+ break;
+ default:
+ break;
+ }
+
+ generate_preview(data, node, outbuf);
+ out[0]->data=outbuf;
+ if(out[1]->hasoutput)
+ out[1]->data=valbuf_from_rgbabuf(outbuf, CHAN_A);
+
+ if(cbuf!=in[0]->data)
+ free_compbuf(cbuf);
+
+}
+
+static void node_composit_init_channel_matte(bNodeTree *UNUSED(ntree), bNode* node, bNodeTemplate *UNUSED(ntemp))
+{
+ NodeChroma *c= MEM_callocN(sizeof(NodeChroma), "node chroma");
+ node->storage=c;
+ c->t1= 1.0f;
+ c->t2= 0.0f;
+ c->t3= 0.0f;
+ c->fsize= 0.0f;
+ c->fstrength= 0.0f;
+ c->algorithm=1; /*max channel limiting */
+ c->channel=1; /* limit by red */
+ node->custom1= 1; /* RGB channel */
+ node->custom2= 2; /* Green Channel */
+}
+
+void register_node_type_cmp_channel_matte(ListBase *lb)
+{
+ static bNodeType ntype;
+
+ node_type_base(&ntype, CMP_NODE_CHANNEL_MATTE, "Channel Key", NODE_CLASS_MATTE, NODE_PREVIEW|NODE_OPTIONS);
+ node_type_socket_templates(&ntype, cmp_node_channel_matte_in, cmp_node_channel_matte_out);
+ node_type_size(&ntype, 200, 80, 250);
+ node_type_init(&ntype, node_composit_init_channel_matte);
+ node_type_storage(&ntype, "NodeChroma", node_free_standard_storage, node_copy_standard_storage);
+ node_type_exec(&ntype, node_composit_exec_channel_matte);
+
+ nodeRegisterType(lb, &ntype);
+}
diff --git a/source/blender/nodes/composite/nodes/node_composite_chromaMatte.c b/source/blender/nodes/composite/nodes/node_composite_chromaMatte.c
new file mode 100644
index 00000000000..db5e6d93856
--- /dev/null
+++ b/source/blender/nodes/composite/nodes/node_composite_chromaMatte.c
@@ -0,0 +1,207 @@
+/*
+ * $Id: CMP_chromaMatte.c 36536 2011-05-07 13:27:27Z lukastoenne $
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2006 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/nodes/composite/nodes/node_composite_chromaMatte.c
+ * \ingroup cmpnodes
+ */
+
+
+#include "node_composite_util.h"
+
+/* ******************* Chroma Key ********************************************************** */
+static bNodeSocketTemplate cmp_node_chroma_in[]={
+ {SOCK_RGBA,1,"Image", 0.8f, 0.8f, 0.8f, 1.0f},
+ {SOCK_RGBA,1,"Key Color", 0.8f, 0.8f, 0.8f, 1.0f},
+ {-1,0,""}
+};
+
+static bNodeSocketTemplate cmp_node_chroma_out[]={
+ {SOCK_RGBA,0,"Image"},
+ {SOCK_FLOAT,0,"Matte"},
+ {-1,0,""}
+};
+
+static void do_rgba_to_ycca_normalized(bNode *UNUSED(node), float *out, float *in)
+{
+ rgb_to_ycc(in[0],in[1],in[2], &out[0], &out[1], &out[2], BLI_YCC_ITU_BT601);
+
+ //normalize to 0..1.0
+ out[0]=out[0]/255.0;
+ out[1]=out[1]/255.0;
+ out[2]=out[2]/255.0;
+
+ //rescale to -1.0..1.0
+ out[0]=(out[0]*2.0)-1.0;
+ out[1]=(out[1]*2.0)-1.0;
+ out[2]=(out[2]*2.0)-1.0;
+
+// out[0]=((out[0])-16)/255.0;
+// out[1]=((out[1])-128)/255.0;
+// out[2]=((out[2])-128)/255.0;
+ out[3]=in[3];
+}
+
+static void do_ycca_to_rgba_normalized(bNode *UNUSED(node), float *out, float *in)
+{
+ /*un-normalize the normalize from above */
+ in[0]=(in[0]+1.0)/2.0;
+ in[1]=(in[1]+1.0)/2.0;
+ in[2]=(in[2]+1.0)/2.0;
+
+ in[0]=(in[0]*255.0);
+ in[1]=(in[1]*255.0);
+ in[2]=(in[2]*255.0);
+
+ // in[0]=(in[0]*255.0)+16;
+// in[1]=(in[1]*255.0)+128;
+// in[2]=(in[2]*255.0)+128;
+ ycc_to_rgb(in[0],in[1],in[2], &out[0], &out[1], &out[2], BLI_YCC_ITU_BT601);
+ out[3]=in[3];
+}
+
+static void do_chroma_key(bNode *node, float *out, float *in)
+{
+ NodeChroma *c;
+ float x, z, alpha;
+ float theta, beta, angle, angle2;
+ float kfg;
+
+ c=node->storage;
+
+ /* Algorithm from book "Video Demistified," does not include the spill reduction part */
+
+ /* find theta, the angle that the color space should be rotated based on key*/
+ theta=atan2(c->key[2], c->key[1]);
+
+ /*rotate the cb and cr into x/z space */
+ x=in[1]*cos(theta)+in[2]*sin(theta);
+ z=in[2]*cos(theta)-in[1]*sin(theta);
+
+ /*if within the acceptance angle */
+ angle=c->t1*M_PI/180.0; /* convert to radians */
+
+ /* if kfg is <0 then the pixel is outside of the key color */
+ kfg=x-(fabs(z)/tan(angle/2.0));
+
+ out[0]=in[0];
+ out[1]=in[1];
+ out[2]=in[2];
+
+ if(kfg>0.0) { /* found a pixel that is within key color */
+ alpha=(1.0-kfg)*(c->fstrength);
+
+ beta=atan2(z,x);
+ angle2=c->t2*M_PI/180.0;
+
+ /* if beta is within the cutoff angle */
+ if(fabs(beta)<(angle2/2.0)) {
+ alpha=0.0;
+ }
+
+ /* don't make something that was more transparent less transparent */
+ if (alpha<in[3]) {
+ out[3]=alpha;
+ }
+ else {
+ out[3]=in[3];
+ }
+ }
+ else { /*pixel is outside key color */
+ out[0]=in[0];
+ out[1]=in[1];
+ out[2]=in[2];
+ out[3]=in[3]; /* make pixel just as transparent as it was before */
+ }
+}
+
+static void node_composit_exec_chroma_matte(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
+{
+ CompBuf *cbuf;
+ CompBuf *chromabuf;
+ NodeChroma *c;
+
+ if(in[0]->hasinput==0) return;
+ if(in[0]->data==NULL) return;
+ if(out[0]->hasoutput==0 && out[1]->hasoutput==0) return;
+
+ cbuf= typecheck_compbuf(in[0]->data, CB_RGBA);
+
+ chromabuf= dupalloc_compbuf(cbuf);
+
+ c=node->storage;
+
+ /*convert rgbbuf to normalized chroma space*/
+ composit1_pixel_processor(node, chromabuf, cbuf, in[0]->vec, do_rgba_to_ycca_normalized, CB_RGBA);
+ /*convert key to normalized chroma color space */
+ do_rgba_to_ycca_normalized(node, c->key, in[1]->vec);
+
+ /*per pixel chroma key*/
+ composit1_pixel_processor(node, chromabuf, chromabuf, in[0]->vec, do_chroma_key, CB_RGBA);
+
+ /*convert back*/
+ composit1_pixel_processor(node, chromabuf, chromabuf, in[0]->vec, do_ycca_to_rgba_normalized, CB_RGBA);
+
+ out[0]->data= chromabuf;
+ if(out[1]->hasoutput)
+ out[1]->data= valbuf_from_rgbabuf(chromabuf, CHAN_A);
+
+ generate_preview(data, node, chromabuf);
+
+ if(cbuf!=in[0]->data)
+ free_compbuf(cbuf);
+}
+
+
+static void node_composit_init_chroma_matte(bNodeTree *UNUSED(ntree), bNode* node, bNodeTemplate *UNUSED(ntemp))
+{
+ NodeChroma *c= MEM_callocN(sizeof(NodeChroma), "node chroma");
+ node->storage= c;
+ c->t1= 30.0f;
+ c->t2= 10.0f;
+ c->t3= 0.0f;
+ c->fsize= 0.0f;
+ c->fstrength= 1.0f;
+}
+
+void register_node_type_cmp_chroma_matte(ListBase *lb)
+{
+ static bNodeType ntype;
+
+ node_type_base(&ntype, CMP_NODE_CHROMA_MATTE, "Chroma Key", NODE_CLASS_MATTE, NODE_PREVIEW|NODE_OPTIONS);
+ node_type_socket_templates(&ntype, cmp_node_chroma_in, cmp_node_chroma_out);
+ node_type_size(&ntype, 200, 80, 300);
+ node_type_init(&ntype, node_composit_init_chroma_matte);
+ node_type_storage(&ntype, "NodeChroma", node_free_standard_storage, node_copy_standard_storage);
+ node_type_exec(&ntype, node_composit_exec_chroma_matte);
+
+ nodeRegisterType(lb, &ntype);
+}
+
+
+
diff --git a/source/blender/nodes/composite/nodes/node_composite_colorMatte.c b/source/blender/nodes/composite/nodes/node_composite_colorMatte.c
new file mode 100644
index 00000000000..7f687240daf
--- /dev/null
+++ b/source/blender/nodes/composite/nodes/node_composite_colorMatte.c
@@ -0,0 +1,143 @@
+/*
+ * $Id: CMP_colorMatte.c 36536 2011-05-07 13:27:27Z lukastoenne $
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2006 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): Bob Holcomb
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/nodes/composite/nodes/node_composite_colorMatte.c
+ * \ingroup cmpnodes
+ */
+
+
+#include "node_composite_util.h"
+
+/* ******************* Color Key ********************************************************** */
+static bNodeSocketTemplate cmp_node_color_in[]={
+ {SOCK_RGBA,1,"Image", 0.8f, 0.8f, 0.8f, 1.0f},
+ {SOCK_RGBA,1,"Key Color", 0.8f, 0.8f, 0.8f, 1.0f},
+ {-1,0,""}
+};
+
+static bNodeSocketTemplate cmp_node_color_out[]={
+ {SOCK_RGBA,0,"Image"},
+ {SOCK_FLOAT,0,"Matte"},
+ {-1,0,""}
+};
+
+static void do_color_key(bNode *node, float *out, float *in)
+{
+ float h_wrap;
+ NodeChroma *c;
+ c=node->storage;
+
+
+ VECCOPY(out, in);
+
+ if(
+ /* do hue last because it needs to wrap, and does some more checks */
+
+ /* sat */ (fabs(in[1]-c->key[1]) < c->t2) &&
+ /* val */ (fabs(in[2]-c->key[2]) < c->t3) &&
+
+ /* multiply by 2 because it wraps on both sides of the hue,
+ * otherwise 0.5 would key all hue's */
+
+ /* hue */ ((h_wrap= 2.0f * fabs(in[0]-c->key[0])) < c->t1 || (2.0f - h_wrap) < c->t1)
+ ) {
+ out[3]=0.0; /*make transparent*/
+ }
+
+ else { /*pixel is outside key color */
+ out[3]=in[3]; /* make pixel just as transparent as it was before */
+ }
+}
+
+static void node_composit_exec_color_matte(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
+{
+ CompBuf *cbuf;
+ CompBuf *colorbuf;
+ NodeChroma *c;
+
+ if(in[0]->hasinput==0) return;
+ if(in[0]->data==NULL) return;
+ if(out[0]->hasoutput==0 && out[1]->hasoutput==0) return;
+
+ cbuf= typecheck_compbuf(in[0]->data, CB_RGBA);
+
+ colorbuf= dupalloc_compbuf(cbuf);
+
+ c=node->storage;
+
+ /*convert rgbbuf to hsv*/
+ composit1_pixel_processor(node, colorbuf, cbuf, in[0]->vec, do_rgba_to_hsva, CB_RGBA);
+
+ /*convert key to hsv*/
+ do_rgba_to_hsva(node, c->key, in[1]->vec);
+
+
+ /*per pixel color key*/
+ composit1_pixel_processor(node, colorbuf, colorbuf, in[0]->vec, do_color_key, CB_RGBA);
+
+ /*convert back*/
+ composit1_pixel_processor(node, colorbuf, colorbuf, in[0]->vec, do_hsva_to_rgba, CB_RGBA);
+
+ out[0]->data= colorbuf;
+ if(out[1]->hasoutput)
+ out[1]->data= valbuf_from_rgbabuf(colorbuf, CHAN_A);
+
+ generate_preview(data, node, colorbuf);
+
+ if(cbuf!=in[0]->data)
+ free_compbuf(cbuf);
+}
+
+static void node_composit_init_color_matte(bNodeTree *UNUSED(ntree), bNode* node, bNodeTemplate *UNUSED(ntemp))
+{
+ NodeChroma *c= MEM_callocN(sizeof(NodeChroma), "node color");
+ node->storage= c;
+ c->t1= 0.01f;
+ c->t2= 0.1f;
+ c->t3= 0.1f;
+ c->fsize= 0.0f;
+ c->fstrength= 1.0f;
+}
+
+void register_node_type_cmp_color_matte(ListBase *lb)
+{
+ static bNodeType ntype;
+
+ node_type_base(&ntype, CMP_NODE_COLOR_MATTE, "Color Key", NODE_CLASS_MATTE, NODE_PREVIEW|NODE_OPTIONS);
+ node_type_socket_templates(&ntype, cmp_node_color_in, cmp_node_color_out);
+ node_type_size(&ntype, 200, 80, 300);
+ node_type_init(&ntype, node_composit_init_color_matte);
+ node_type_storage(&ntype, "NodeChroma", node_free_standard_storage, node_copy_standard_storage);
+ node_type_exec(&ntype, node_composit_exec_color_matte);
+
+ nodeRegisterType(lb, &ntype);
+}
+
+
+
diff --git a/source/blender/nodes/composite/nodes/node_composite_colorSpill.c b/source/blender/nodes/composite/nodes/node_composite_colorSpill.c
new file mode 100644
index 00000000000..18b6d806c82
--- /dev/null
+++ b/source/blender/nodes/composite/nodes/node_composite_colorSpill.c
@@ -0,0 +1,341 @@
+/*
+ * $Id: CMP_colorSpill.c 36593 2011-05-10 11:19:26Z lukastoenne $
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2006 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): Bob Holcomb, Xavier Thomas
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/nodes/composite/nodes/node_composite_colorSpill.c
+ * \ingroup cmpnodes
+ */
+
+
+
+#include "node_composite_util.h"
+
+#define avg(a,b) ((a+b)/2)
+
+/* ******************* Color Spill Supression ********************************* */
+static bNodeSocketTemplate cmp_node_color_spill_in[]={
+ {SOCK_RGBA,1,"Image", 0.8f, 0.8f, 0.8f, 1.0f},
+ {SOCK_FLOAT, 1, "Fac", 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, PROP_FACTOR},
+ {-1,0,""}
+};
+
+static bNodeSocketTemplate cmp_node_color_spill_out[]={
+ {SOCK_RGBA,0,"Image"},
+ {-1,0,""}
+};
+
+static void do_simple_spillmap_red(bNode *node, float* out, float *in)
+{
+ NodeColorspill *ncs;
+ ncs=node->storage;
+ out[0]=in[0]-( ncs->limscale * in[ncs->limchan] );
+}
+
+static void do_simple_spillmap_red_fac(bNode *node, float* out, float *in, float *fac)
+{
+ NodeColorspill *ncs;
+ ncs=node->storage;
+
+ out[0] = *fac * (in[0]-( ncs->limscale * in[ncs->limchan]));
+}
+
+static void do_simple_spillmap_green(bNode *node, float* out, float *in)
+{
+ NodeColorspill *ncs;
+ ncs=node->storage;
+ out[0]=in[1]-( ncs->limscale * in[ncs->limchan] );
+}
+
+static void do_simple_spillmap_green_fac(bNode *node, float* out, float *in, float *fac)
+{
+ NodeColorspill *ncs;
+ ncs=node->storage;
+
+ out[0] = *fac * (in[1]-( ncs->limscale * in[ncs->limchan]));
+}
+
+static void do_simple_spillmap_blue(bNode *node, float* out, float *in)
+{
+ NodeColorspill *ncs;
+ ncs=node->storage;
+ out[0]=in[2]-( ncs->limscale * in[ncs->limchan] );
+}
+
+static void do_simple_spillmap_blue_fac(bNode *node, float* out, float *in, float *fac)
+{
+ NodeColorspill *ncs;
+ ncs=node->storage;
+
+ out[0] = *fac * (in[2]-( ncs->limscale * in[ncs->limchan]));
+}
+
+static void do_average_spillmap_red(bNode *node, float* out, float *in)
+{
+ NodeColorspill *ncs;
+ ncs=node->storage;
+ out[0]=in[0]-(ncs->limscale * avg(in[1], in[2]) );
+}
+
+static void do_average_spillmap_red_fac(bNode *node, float* out, float *in, float *fac)
+{
+ NodeColorspill *ncs;
+ ncs=node->storage;
+
+ out[0] = *fac * (in[0]-(ncs->limscale * avg(in[1], in[2]) ));
+}
+
+static void do_average_spillmap_green(bNode *node, float* out, float *in)
+{
+ NodeColorspill *ncs;
+ ncs=node->storage;
+ out[0]=in[1]-(ncs->limscale * avg(in[0], in[2]) );
+}
+
+static void do_average_spillmap_green_fac(bNode *node, float* out, float *in, float *fac)
+{
+ NodeColorspill *ncs;
+ ncs=node->storage;
+
+ out[0] = *fac * (in[0]-(ncs->limscale * avg(in[0], in[2]) ));
+}
+
+static void do_average_spillmap_blue(bNode *node, float* out, float *in)
+{
+ NodeColorspill *ncs;
+ ncs=node->storage;
+ out[0]=in[2]-(ncs->limscale * avg(in[0], in[1]) );
+}
+
+static void do_average_spillmap_blue_fac(bNode *node, float* out, float *in, float *fac)
+{
+ NodeColorspill *ncs;
+ ncs=node->storage;
+
+ out[0] = *fac * (in[0]-(ncs->limscale * avg(in[0], in[1]) ));
+}
+
+static void do_apply_spillmap_red(bNode *node, float* out, float *in, float *map)
+{
+ NodeColorspill *ncs;
+ ncs=node->storage;
+ if(map[0]>0) {
+ out[0]=in[0]-(ncs->uspillr*map[0]);
+ out[1]=in[1]+(ncs->uspillg*map[0]);
+ out[2]=in[2]+(ncs->uspillb*map[0]);
+ }
+ else {
+ out[0]=in[0];
+ out[1]=in[1];
+ out[2]=in[2];
+ }
+}
+
+static void do_apply_spillmap_green(bNode *node, float* out, float *in, float *map)
+{
+ NodeColorspill *ncs;
+ ncs=node->storage;
+ if(map[0]>0) {
+ out[0]=in[0]+(ncs->uspillr*map[0]);
+ out[1]=in[1]-(ncs->uspillg*map[0]);
+ out[2]=in[2]+(ncs->uspillb*map[0]);
+ }
+ else {
+ out[0]=in[0];
+ out[1]=in[1];
+ out[2]=in[2];
+ }
+}
+
+static void do_apply_spillmap_blue(bNode *node, float* out, float *in, float *map)
+{
+ NodeColorspill *ncs;
+ ncs=node->storage;
+ if(map[0]>0) {
+ out[0]=in[0]+(ncs->uspillr*map[0]);
+ out[1]=in[1]+(ncs->uspillg*map[0]);
+ out[2]=in[2]-(ncs->uspillb*map[0]);
+ }
+ else {
+ out[0]=in[0];
+ out[1]=in[1];
+ out[2]=in[2];
+ }
+}
+
+static void node_composit_exec_color_spill(void *UNUSED(data), bNode *node, bNodeStack **in, bNodeStack **out)
+{
+ /* Originally based on the information from the book "The Art and Science of Digital Composition" and
+ * discussions from vfxtalk.com .*/
+ CompBuf *cbuf;
+ CompBuf *mask;
+ CompBuf *rgbbuf;
+ CompBuf *spillmap;
+ NodeColorspill *ncs;
+ ncs=node->storage;
+
+ /* early out for missing connections */
+ if(out[0]->hasoutput==0 ) return;
+ if(in[0]->hasinput==0) return;
+ if(in[0]->data==NULL) return;
+
+ cbuf=typecheck_compbuf(in[0]->data, CB_RGBA);
+ mask=typecheck_compbuf(in[1]->data, CB_VAL);
+ spillmap=alloc_compbuf(cbuf->x, cbuf->y, CB_VAL, 1);
+ rgbbuf=dupalloc_compbuf(cbuf);
+
+ switch(node->custom1)
+ {
+ case 1: /*red spill*/
+ {
+ switch(node->custom2)
+ {
+ case 0: /* simple limit */
+ {
+ if ((in[1]->data==NULL) && (in[1]->vec[0] >= 1.f)) {
+ composit1_pixel_processor(node, spillmap, cbuf, in[0]->vec, do_simple_spillmap_red, CB_RGBA);
+ } else {
+ composit2_pixel_processor(node, spillmap, cbuf, in[0]->vec, in[1]->data, in[1]->vec, do_simple_spillmap_red_fac, CB_RGBA, CB_VAL);
+ }
+ break;
+ }
+ case 1: /* average limit */
+ {
+ if ((in[1]->data==NULL) && (in[1]->vec[0] >= 1.f)) {
+ composit1_pixel_processor(node, spillmap, cbuf, in[0]->vec, do_average_spillmap_red, CB_RGBA);
+ } else {
+ composit2_pixel_processor(node, spillmap, cbuf, in[0]->vec, in[1]->data, in[1]->vec, do_average_spillmap_red_fac, CB_RGBA, CB_VAL);
+ }
+ break;
+ }
+ }
+ if(ncs->unspill==0) {
+ ncs->uspillr=1.0f;
+ ncs->uspillg=0.0f;
+ ncs->uspillb=0.0f;
+ }
+ composit2_pixel_processor(node, rgbbuf, cbuf, in[0]->vec, spillmap, NULL, do_apply_spillmap_red, CB_RGBA, CB_VAL);
+ break;
+ }
+ case 2: /*green spill*/
+ {
+ switch(node->custom2)
+ {
+ case 0: /* simple limit */
+ {
+ if ((in[1]->data==NULL) && (in[1]->vec[0] >= 1.f)) {
+ composit1_pixel_processor(node, spillmap, cbuf, in[0]->vec, do_simple_spillmap_green, CB_RGBA);
+ } else {
+ composit2_pixel_processor(node, spillmap, cbuf, in[0]->vec, in[1]->data, in[1]->vec, do_simple_spillmap_green_fac, CB_RGBA, CB_VAL);
+ }
+ break;
+ }
+ case 1: /* average limit */
+ {
+ if ((in[1]->data==NULL) && (in[1]->vec[0] >= 1.f)) {
+ composit1_pixel_processor(node, spillmap, cbuf, in[0]->vec, do_average_spillmap_green, CB_RGBA);
+ } else {
+ composit2_pixel_processor(node, spillmap, cbuf, in[0]->vec, in[1]->data, in[1]->vec, do_average_spillmap_green_fac, CB_RGBA, CB_VAL);
+ }
+ break;
+ }
+ }
+ if(ncs->unspill==0) {
+ ncs->uspillr=0.0f;
+ ncs->uspillg=1.0f;
+ ncs->uspillb=0.0f;
+ }
+ composit2_pixel_processor(node, rgbbuf, cbuf, in[0]->vec, spillmap, NULL, do_apply_spillmap_green, CB_RGBA, CB_VAL);
+ break;
+ }
+ case 3: /*blue spill*/
+ {
+ switch(node->custom2)
+ {
+ case 0: /* simple limit */
+ {
+ if ((in[1]->data==NULL) && (in[1]->vec[0] >= 1.f)) {
+ composit1_pixel_processor(node, spillmap, cbuf, in[0]->vec, do_simple_spillmap_blue, CB_RGBA);
+ } else {
+ composit2_pixel_processor(node, spillmap, cbuf, in[0]->vec, in[1]->data, in[1]->vec, do_simple_spillmap_blue_fac, CB_RGBA, CB_VAL);
+ }
+ break;
+ }
+ case 1: /* average limit */
+ {
+ if ((in[1]->data==NULL) && (in[1]->vec[0] >= 1.f)) {
+ composit1_pixel_processor(node, spillmap, cbuf, in[0]->vec, do_average_spillmap_blue, CB_RGBA);
+ } else {
+ composit2_pixel_processor(node, spillmap, cbuf, in[0]->vec, in[1]->data, in[1]->vec, do_average_spillmap_blue_fac, CB_RGBA, CB_VAL);
+ }
+ break;
+ }
+ }
+ if(ncs->unspill==0) {
+ ncs->uspillr=0.0f;
+ ncs->uspillg=0.0f;
+ ncs->uspillb=1.0f;
+ }
+ composit2_pixel_processor(node, rgbbuf, cbuf, in[0]->vec, spillmap, NULL, do_apply_spillmap_blue, CB_RGBA, CB_VAL);
+ break;
+ }
+ default:
+ break;
+ }
+
+ out[0]->data=rgbbuf;
+
+ if(cbuf!=in[0]->data)
+ free_compbuf(cbuf);
+
+ free_compbuf(spillmap);
+}
+
+static void node_composit_init_color_spill(bNodeTree *UNUSED(ntree), bNode* node, bNodeTemplate *UNUSED(ntemp))
+{
+ NodeColorspill *ncs= MEM_callocN(sizeof(NodeColorspill), "node colorspill");
+ node->storage=ncs;
+ node->custom1= 2; /* green channel */
+ node->custom2= 0; /* simple limit algo*/
+ ncs->limchan= 0; /* limit by red */
+ ncs->limscale= 1.0f; /* limit scaling factor */
+ ncs->unspill=0; /* do not use unspill */
+}
+
+void register_node_type_cmp_color_spill(ListBase *lb)
+{
+ static bNodeType ntype;
+
+ node_type_base(&ntype, CMP_NODE_COLOR_SPILL, "Color Spill", NODE_CLASS_MATTE, NODE_OPTIONS);
+ node_type_socket_templates(&ntype, cmp_node_color_spill_in, cmp_node_color_spill_out);
+ node_type_size(&ntype, 140, 80, 200);
+ node_type_init(&ntype, node_composit_init_color_spill);
+ node_type_storage(&ntype, "NodeColorspill", node_free_standard_storage, node_copy_standard_storage);
+ node_type_exec(&ntype, node_composit_exec_color_spill);
+
+ nodeRegisterType(lb, &ntype);
+}
diff --git a/source/blender/nodes/composite/nodes/node_composite_colorbalance.c b/source/blender/nodes/composite/nodes/node_composite_colorbalance.c
new file mode 100644
index 00000000000..7ebceb5c206
--- /dev/null
+++ b/source/blender/nodes/composite/nodes/node_composite_colorbalance.c
@@ -0,0 +1,201 @@
+/*
+ *
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2006 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): Matt Ebb.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/nodes/composite/nodes/node_composite_colorbalance.c
+ * \ingroup cmpnodes
+ */
+
+
+
+#include "node_composite_util.h"
+
+
+/* ******************* Color Balance ********************************* */
+static bNodeSocketTemplate cmp_node_colorbalance_in[]={
+ {SOCK_FLOAT, 1, "Fac", 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, PROP_FACTOR},
+ {SOCK_RGBA,1,"Image", 0.8f, 0.8f, 0.8f, 1.0f},
+ {-1,0,""}
+};
+
+static bNodeSocketTemplate cmp_node_colorbalance_out[]={
+ {SOCK_RGBA,0,"Image"},
+ {-1,0,""}
+};
+
+/* this function implements ASC-CDL according to the spec at http://www.asctech.org/
+ Slope
+ S = in * slope
+ Offset
+ O = S + offset
+ = (in * slope) + offset
+ Power
+ out = Clamp(O) ^ power
+ = Clamp((in * slope) + offset) ^ power
+ */
+DO_INLINE float colorbalance_cdl(float in, float offset, float power, float slope)
+{
+ float x = in * slope + offset;
+
+ /* prevent NaN */
+ CLAMP(x, 0.0, 1.0);
+
+ return powf(x, power);
+}
+
+/* note: lift_lgg is just 2-lift, gamma_inv is 1.0/gamma */
+DO_INLINE float colorbalance_lgg(float in, float lift_lgg, float gamma_inv, float gain)
+{
+ /* 1:1 match with the sequencer with linear/srgb conversions, the conversion isnt pretty
+ * but best keep it this way, sice testing for durian shows a similar calculation
+ * without lin/srgb conversions gives bad results (over-saturated shadows) with colors
+ * slightly below 1.0. some correction can be done but it ends up looking bad for shadows or lighter tones - campbell */
+ float x= (((linearrgb_to_srgb(in) - 1.0f) * lift_lgg) + 1.0f) * gain;
+
+ /* prevent NaN */
+ if (x < 0.f) x = 0.f;
+
+ return powf(srgb_to_linearrgb(x), gamma_inv);
+}
+
+static void do_colorbalance_cdl(bNode *node, float* out, float *in)
+{
+ NodeColorBalance *n= (NodeColorBalance *)node->storage;
+
+ out[0] = colorbalance_cdl(in[0], n->lift[0], n->gamma[0], n->gain[0]);
+ out[1] = colorbalance_cdl(in[1], n->lift[1], n->gamma[1], n->gain[1]);
+ out[2] = colorbalance_cdl(in[2], n->lift[2], n->gamma[2], n->gain[2]);
+ out[3] = in[3];
+}
+
+static void do_colorbalance_cdl_fac(bNode *node, float* out, float *in, float *fac)
+{
+ NodeColorBalance *n= (NodeColorBalance *)node->storage;
+ const float mfac= 1.0f - *fac;
+
+ out[0] = mfac*in[0] + *fac * colorbalance_cdl(in[0], n->lift[0], n->gamma[0], n->gain[0]);
+ out[1] = mfac*in[1] + *fac * colorbalance_cdl(in[1], n->lift[1], n->gamma[1], n->gain[1]);
+ out[2] = mfac*in[2] + *fac * colorbalance_cdl(in[2], n->lift[2], n->gamma[2], n->gain[2]);
+ out[3] = in[3];
+}
+
+static void do_colorbalance_lgg(bNode *node, float* out, float *in)
+{
+ NodeColorBalance *n= (NodeColorBalance *)node->storage;
+
+ out[0] = colorbalance_lgg(in[0], n->lift_lgg[0], n->gamma_inv[0], n->gain[0]);
+ out[1] = colorbalance_lgg(in[1], n->lift_lgg[1], n->gamma_inv[1], n->gain[1]);
+ out[2] = colorbalance_lgg(in[2], n->lift_lgg[2], n->gamma_inv[2], n->gain[2]);
+ out[3] = in[3];
+}
+
+static void do_colorbalance_lgg_fac(bNode *node, float* out, float *in, float *fac)
+{
+ NodeColorBalance *n= (NodeColorBalance *)node->storage;
+ const float mfac= 1.0f - *fac;
+
+ out[0] = mfac*in[0] + *fac * colorbalance_lgg(in[0], n->lift_lgg[0], n->gamma_inv[0], n->gain[0]);
+ out[1] = mfac*in[1] + *fac * colorbalance_lgg(in[1], n->lift_lgg[1], n->gamma_inv[1], n->gain[1]);
+ out[2] = mfac*in[2] + *fac * colorbalance_lgg(in[2], n->lift_lgg[2], n->gamma_inv[2], n->gain[2]);
+ out[3] = in[3];
+}
+
+static void node_composit_exec_colorbalance(void *UNUSED(data), bNode *node, bNodeStack **in, bNodeStack **out)
+{
+ CompBuf *cbuf= in[1]->data;
+ CompBuf *stackbuf;
+
+ /* stack order input: fac, image */
+ /* stack order output: image */
+ if(out[0]->hasoutput==0) return;
+
+ if(in[0]->vec[0] == 0.f && in[0]->data == NULL) {
+ out[0]->data = pass_on_compbuf(cbuf);
+ return;
+ }
+
+ {
+ NodeColorBalance *n= (NodeColorBalance *)node->storage;
+ int c;
+
+ for (c = 0; c < 3; c++) {
+ n->lift_lgg[c] = 2.0f - n->lift[c];
+ n->gamma_inv[c] = (n->gamma[c] != 0.0f) ? 1.0f/n->gamma[c] : 1000000.0f;
+ }
+ }
+
+ if (cbuf) {
+ stackbuf= alloc_compbuf(cbuf->x, cbuf->y, CB_RGBA, 1); /* create output based on image input */
+
+ if (node->custom1 == 0) {
+ /* lift gamma gain */
+ if ((in[0]->data==NULL) && (in[0]->vec[0] >= 1.f)) {
+ composit1_pixel_processor(node, stackbuf, in[1]->data, in[1]->vec, do_colorbalance_lgg, CB_RGBA);
+ }
+ else {
+ composit2_pixel_processor(node, stackbuf, in[1]->data, in[1]->vec, in[0]->data, in[0]->vec, do_colorbalance_lgg_fac, CB_RGBA, CB_VAL);
+ }
+ } else {
+ /* offset/power/slope : ASC-CDL */
+ if ((in[0]->data==NULL) && (in[0]->vec[0] >= 1.f)) {
+ composit1_pixel_processor(node, stackbuf, in[1]->data, in[1]->vec, do_colorbalance_cdl, CB_RGBA);
+ }
+ else {
+ composit2_pixel_processor(node, stackbuf, in[1]->data, in[1]->vec, in[0]->data, in[0]->vec, do_colorbalance_cdl_fac, CB_RGBA, CB_VAL);
+ }
+
+ }
+
+ out[0]->data=stackbuf;
+ }
+}
+
+static void node_composit_init_colorbalance(bNodeTree *UNUSED(ntree), bNode* node, bNodeTemplate *UNUSED(ntemp))
+{
+ NodeColorBalance *n= node->storage= MEM_callocN(sizeof(NodeColorBalance), "node colorbalance");
+
+ n->lift[0] = n->lift[1] = n->lift[2] = 1.0f;
+ n->gamma[0] = n->gamma[1] = n->gamma[2] = 1.0f;
+ n->gain[0] = n->gain[1] = n->gain[2] = 1.0f;
+}
+
+void register_node_type_cmp_colorbalance(ListBase *lb)
+{
+ static bNodeType ntype;
+
+ node_type_base(&ntype, CMP_NODE_COLORBALANCE, "Color Balance", NODE_CLASS_OP_COLOR, NODE_OPTIONS);
+ node_type_socket_templates(&ntype, cmp_node_colorbalance_in, cmp_node_colorbalance_out);
+ node_type_size(&ntype, 400, 200, 400);
+ node_type_init(&ntype, node_composit_init_colorbalance);
+ node_type_storage(&ntype, "NodeColorBalance", node_free_standard_storage, node_copy_standard_storage);
+ node_type_exec(&ntype, node_composit_exec_colorbalance);
+
+ nodeRegisterType(lb, &ntype);
+}
+
+
diff --git a/source/blender/nodes/composite/nodes/node_composite_common.c b/source/blender/nodes/composite/nodes/node_composite_common.c
new file mode 100644
index 00000000000..ab8cf663ef2
--- /dev/null
+++ b/source/blender/nodes/composite/nodes/node_composite_common.c
@@ -0,0 +1,373 @@
+/*
+ * $Id: CMP_blur.c 35562 2011-03-15 20:10:32Z lukastoenne $
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2006 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): Campbell Barton, Alfredo de Greef, David Millan Escriva,
+ * Juho Vepsäläinen
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/nodes/composite/nodes/node_composite_common.c
+ * \ingroup cmpnodes
+ */
+
+
+#include "DNA_node_types.h"
+
+#include "BKE_node.h"
+
+#include "node_composite_util.h"
+#include "node_common.h"
+#include "node_exec.h"
+
+#if 0
+static void PRINT_BUFFERS(bNodeTreeExec *exec)
+{
+ bNodeTree *ntree= exec->nodetree;
+ bNode *node;
+ bNodeSocket *sock;
+ bNodeStack *ns;
+ int i;
+
+ printf("-------------- DEBUG --------------\n");
+ for (sock=ntree->inputs.first, i=0; sock; sock=sock->next, ++i) {
+ ns = node_get_socket_stack(exec->stack, sock);
+ printf("%d. Tree Input %s", i, sock->name);
+ if (ns->external)
+ printf(" (external)");
+ printf(": data=%p\n", ns->data);
+ }
+ for (sock=ntree->outputs.first, i=0; sock; sock=sock->next, ++i) {
+ ns = node_get_socket_stack(exec->stack, sock);
+ printf("%d. Tree Output %s", i, sock->name);
+ if (ns->external)
+ printf(" (external)");
+ printf(": data=%p\n", ns->data);
+ }
+ for (node=ntree->nodes.first; node; node=node->next) {
+ printf("Node %s:\n", node->name);
+ for (sock=node->inputs.first, i=0; sock; sock=sock->next, ++i) {
+ ns = node_get_socket_stack(exec->stack, sock);
+ printf("\t%d. Input %s", i, sock->name);
+ if (ns->external)
+ printf(" (external)");
+ printf(": data=%p\n", ns->data);
+ }
+ for (sock=node->outputs.first, i=0; sock; sock=sock->next, ++i) {
+ ns = node_get_socket_stack(exec->stack, sock);
+ printf("\t%d. Output %s", i, sock->name);
+ if (ns->external)
+ printf(" (external)");
+ printf(": data=%p\n", ns->data);
+ }
+ }
+}
+#endif
+
+static void copy_stack(bNodeStack *to, bNodeStack *from)
+{
+ if (to != from) {
+ copy_v4_v4(to->vec, from->vec);
+ to->data = from->data;
+ to->datatype = from->datatype;
+
+ /* tag as copy to prevent freeing */
+ to->is_copy = 1;
+ }
+}
+
+static void move_stack(bNodeStack *to, bNodeStack *from)
+{
+ if (to != from) {
+ copy_v4_v4(to->vec, from->vec);
+ to->data = from->data;
+ to->datatype = from->datatype;
+ to->is_copy = from->is_copy;
+
+ zero_v4(from->vec);
+ from->data = NULL;
+ from->datatype = 0;
+ from->is_copy = 0;
+ }
+}
+
+/**** GROUP ****/
+
+static void *group_initexec(bNode *node)
+{
+ bNodeTree *ngroup= (bNodeTree*)node->id;
+ bNodeTreeExec *exec;
+ bNodeSocket *sock;
+ bNodeStack *ns;
+
+ /* initialize the internal node tree execution */
+ exec = ntreeCompositBeginExecTree(ngroup);
+
+ /* tag group outputs as external to prevent freeing */
+ for (sock=ngroup->outputs.first; sock; sock=sock->next) {
+ if (!(sock->flag & SOCK_INTERNAL)) {
+ ns = node_get_socket_stack(exec->stack, sock);
+ ns->external = 1;
+ }
+ }
+
+ return exec;
+}
+
+static void group_freeexec(bNode *UNUSED(node), void *nodedata)
+{
+ bNodeTreeExec *gexec= (bNodeTreeExec*)nodedata;
+
+ ntreeCompositEndExecTree(gexec);
+}
+
+/* Copy inputs to the internal stack.
+ * This is a shallow copy, no buffers are duplicated here!
+ */
+static void group_copy_inputs(bNode *node, bNodeStack **in, bNodeStack *gstack)
+{
+ bNodeSocket *sock;
+ bNodeStack *ns;
+ int a;
+ for (sock=node->inputs.first, a=0; sock; sock=sock->next, ++a) {
+ if (sock->groupsock) {
+ ns = node_get_socket_stack(gstack, sock->groupsock);
+ copy_stack(ns, in[a]);
+ }
+ }
+}
+
+/* Copy internal results to the external outputs.
+ */
+static void group_move_outputs(bNode *node, bNodeStack **out, bNodeStack *gstack)
+{
+ bNodeSocket *sock;
+ bNodeStack *ns;
+ int a;
+ for (sock=node->outputs.first, a=0; sock; sock=sock->next, ++a) {
+ if (sock->groupsock) {
+ ns = node_get_socket_stack(gstack, sock->groupsock);
+ move_stack(out[a], ns);
+ }
+ }
+}
+
+/* Free internal buffers */
+static void group_free_internal(bNodeTreeExec *gexec) {
+ bNodeStack *ns;
+ int i;
+
+ for (i=0, ns=gexec->stack; i < gexec->stacksize; ++i, ++ns) {
+ if (!ns->external && !ns->is_copy) {
+ if (ns->data) {
+ free_compbuf(ns->data);
+ ns->data = NULL;
+ }
+ }
+ }
+}
+
+static void group_execute(void *data, int thread, struct bNode *node, void *nodedata, struct bNodeStack **in, struct bNodeStack **out)
+{
+ bNodeTreeExec *exec= (bNodeTreeExec*)nodedata;
+
+ /* XXX same behavior as trunk: all nodes inside group are executed.
+ * it's stupid, but just makes it work. compo redesign will do this better.
+ */
+ {
+ bNode *inode;
+ for (inode=exec->nodetree->nodes.first; inode; inode=inode->next)
+ inode->need_exec = 1;
+ }
+
+ group_copy_inputs(node, in, exec->stack);
+ ntreeExecNodes(exec, data, thread);
+ group_free_internal(exec);
+ group_move_outputs(node, out, exec->stack);
+}
+
+void register_node_type_cmp_group(ListBase *lb)
+{
+ static bNodeType ntype;
+
+ node_type_base(&ntype, NODE_GROUP, "Group", NODE_CLASS_GROUP, NODE_OPTIONS|NODE_CONST_OUTPUT);
+ node_type_socket_templates(&ntype, NULL, NULL);
+ node_type_size(&ntype, 120, 60, 200);
+ node_type_label(&ntype, node_group_label);
+ node_type_init(&ntype, node_group_init);
+ node_type_valid(&ntype, node_group_valid);
+ node_type_template(&ntype, node_group_template);
+ node_type_update(&ntype, NULL, node_group_verify);
+ node_type_group_edit(&ntype, node_group_edit_get, node_group_edit_set, node_group_edit_clear);
+ node_type_exec_new(&ntype, group_initexec, group_freeexec, group_execute);
+
+ nodeRegisterType(lb, &ntype);
+}
+
+
+/**** FOR LOOP ****/
+
+#if 0 /* XXX loop nodes don't work nicely with current trees */
+/* Move the results from the previous iteration back to the input sockets. */
+static void loop_iteration_reset(bNodeTree *ngroup, bNodeStack *gstack)
+{
+ bNodeSocket *gin, *gout;
+ bNodeStack *nsin, *nsout;
+
+ gin = ngroup->inputs.first;
+ gout = ngroup->outputs.first;
+
+ while (gin && gout) {
+ /* skip static (non-looping) sockets */
+ while (gin && !(gin->flag & SOCK_DYNAMIC))
+ gin=gin->next;
+ while (gout && !(gout->flag & SOCK_DYNAMIC))
+ gout=gout->next;
+
+ if (gin && gout) {
+ nsin = node_get_socket_stack(gstack, gin);
+ nsout = node_get_socket_stack(gstack, gout);
+
+ move_stack(nsin, nsout);
+
+ gin=gin->next;
+ gout=gout->next;
+ }
+ }
+}
+
+static void forloop_execute(void *data, int thread, struct bNode *node, void *nodedata, struct bNodeStack **in, struct bNodeStack **out)
+{
+ bNodeTreeExec *exec= (bNodeTreeExec*)nodedata;
+ int totiterations= (int)in[0]->vec[0];
+ bNodeSocket *sock;
+ bNodeStack *ns;
+ int iteration;
+
+ /* XXX same behavior as trunk: all nodes inside group are executed.
+ * it's stupid, but just makes it work. compo redesign will do this better.
+ */
+ {
+ bNode *inode;
+ for (inode=exec->nodetree->nodes.first; inode; inode=inode->next)
+ inode->need_exec = 1;
+ }
+
+ /* "Iteration" socket */
+ sock = exec->nodetree->inputs.first;
+ ns = node_get_socket_stack(exec->stack, sock);
+
+ group_copy_inputs(node, in, exec->stack);
+ for (iteration=0; iteration < totiterations; ++iteration) {
+ /* first input contains current iteration counter */
+ ns->vec[0] = (float)iteration;
+
+ if (iteration > 0)
+ loop_iteration_reset(exec->nodetree, exec->stack);
+ ntreeExecNodes(exec, data, thread);
+ group_free_internal(exec);
+ }
+ group_move_outputs(node, out, exec->stack);
+}
+
+void register_node_type_cmp_forloop(ListBase *lb)
+{
+ static bNodeType ntype;
+
+ node_type_base(&ntype, NODE_FORLOOP, "For", NODE_CLASS_GROUP, NODE_OPTIONS);
+ node_type_socket_templates(&ntype, NULL, NULL);
+ node_type_size(&ntype, 120, 60, 200);
+ node_type_label(&ntype, node_group_label);
+ node_type_init(&ntype, node_forloop_init);
+ node_type_valid(&ntype, node_group_valid);
+ node_type_template(&ntype, node_forloop_template);
+ node_type_update(&ntype, NULL, node_group_verify);
+ node_type_tree(&ntype, node_forloop_init_tree, node_loop_update_tree);
+ node_type_group_edit(&ntype, node_group_edit_get, node_group_edit_set, node_group_edit_clear);
+ node_type_exec_new(&ntype, group_initexec, group_freeexec, forloop_execute);
+
+ nodeRegisterType(lb, &ntype);
+}
+#endif
+
+
+/**** WHILE LOOP ****/
+
+#if 0 /* XXX loop nodes don't work nicely with current trees */
+static void whileloop_execute(void *data, int thread, struct bNode *node, void *nodedata, struct bNodeStack **in, struct bNodeStack **out)
+{
+ bNodeTreeExec *exec= (bNodeTreeExec*)nodedata;
+ int condition= (in[0]->vec[0] > 0.0f);
+ bNodeSocket *sock;
+ bNodeStack *ns;
+ int iteration;
+
+ /* XXX same behavior as trunk: all nodes inside group are executed.
+ * it's stupid, but just makes it work. compo redesign will do this better.
+ */
+ {
+ bNode *inode;
+ for (inode=exec->nodetree->nodes.first; inode; inode=inode->next)
+ inode->need_exec = 1;
+ }
+
+ /* "Condition" socket */
+ sock = exec->nodetree->outputs.first;
+ ns = node_get_socket_stack(exec->stack, sock);
+
+ iteration = 0;
+ group_copy_inputs(node, in, exec->stack);
+ while (condition && iteration < node->custom1) {
+ if (iteration > 0)
+ loop_iteration_reset(exec->nodetree, exec->stack);
+ ntreeExecNodes(exec, data, thread);
+ group_free_internal(exec);
+
+// PRINT_BUFFERS(exec);
+
+ condition = (ns->vec[0] > 0.0f);
+ ++iteration;
+ }
+ group_move_outputs(node, out, exec->stack);
+}
+
+void register_node_type_cmp_whileloop(ListBase *lb)
+{
+ static bNodeType ntype;
+
+ node_type_base(&ntype, NODE_WHILELOOP, "While", NODE_CLASS_GROUP, NODE_OPTIONS);
+ node_type_socket_templates(&ntype, NULL, NULL);
+ node_type_size(&ntype, 120, 60, 200);
+ node_type_label(&ntype, node_group_label);
+ node_type_init(&ntype, node_whileloop_init);
+ node_type_valid(&ntype, node_group_valid);
+ node_type_template(&ntype, node_whileloop_template);
+ node_type_update(&ntype, NULL, node_group_verify);
+ node_type_tree(&ntype, node_whileloop_init_tree, node_loop_update_tree);
+ node_type_group_edit(&ntype, node_group_edit_get, node_group_edit_set, node_group_edit_clear);
+ node_type_exec_new(&ntype, group_initexec, group_freeexec, whileloop_execute);
+
+ nodeRegisterType(lb, &ntype);
+}
+#endif
diff --git a/source/blender/nodes/composite/nodes/node_composite_composite.c b/source/blender/nodes/composite/nodes/node_composite_composite.c
new file mode 100644
index 00000000000..be6246b42d8
--- /dev/null
+++ b/source/blender/nodes/composite/nodes/node_composite_composite.c
@@ -0,0 +1,113 @@
+/*
+ * $Id: CMP_composite.c 36593 2011-05-10 11:19:26Z lukastoenne $
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2006 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/nodes/composite/nodes/node_composite_composite.c
+ * \ingroup cmpnodes
+ */
+
+
+#include "node_composite_util.h"
+
+
+
+/* **************** COMPOSITE ******************** */
+static bNodeSocketTemplate cmp_node_composite_in[]= {
+ { SOCK_RGBA, 1, "Image", 0.0f, 0.0f, 0.0f, 1.0f},
+ { SOCK_FLOAT, 1, "Alpha", 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR},
+ { SOCK_FLOAT, 1, "Z", 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR},
+ { -1, 0, "" }
+};
+
+/* applies to render pipeline */
+static void node_composit_exec_composite(void *data, bNode *node, bNodeStack **in, bNodeStack **UNUSED(out))
+{
+ /* image assigned to output */
+ /* stack order input sockets: col, alpha, z */
+
+ if(node->flag & NODE_DO_OUTPUT) { /* only one works on out */
+ Scene *scene= (Scene *)node->id;
+ RenderData *rd= data;
+
+ if(scene && (rd->scemode & R_DOCOMP)) {
+ Render *re= RE_GetRender(scene->id.name);
+ RenderResult *rr= RE_AcquireResultWrite(re);
+ if(rr) {
+ CompBuf *outbuf, *zbuf=NULL;
+
+ if(rr->rectf)
+ MEM_freeN(rr->rectf);
+ outbuf= alloc_compbuf(rr->rectx, rr->recty, CB_RGBA, 1);
+
+ if(in[1]->data==NULL)
+ composit1_pixel_processor(node, outbuf, in[0]->data, in[0]->vec, do_copy_rgba, CB_RGBA);
+ else
+ composit2_pixel_processor(node, outbuf, in[0]->data, in[0]->vec, in[1]->data, in[1]->vec, do_copy_a_rgba, CB_RGBA, CB_VAL);
+
+ if(in[2]->data) {
+ if(rr->rectz)
+ MEM_freeN(rr->rectz);
+ zbuf= alloc_compbuf(rr->rectx, rr->recty, CB_VAL, 1);
+ composit1_pixel_processor(node, zbuf, in[2]->data, in[2]->vec, do_copy_value, CB_VAL);
+ rr->rectz= zbuf->rect;
+ zbuf->malloc= 0;
+ free_compbuf(zbuf);
+ }
+ generate_preview(data, node, outbuf);
+
+ /* we give outbuf to rr... */
+ rr->rectf= outbuf->rect;
+ outbuf->malloc= 0;
+ free_compbuf(outbuf);
+
+ /* signal for imageviewer to refresh (it converts to byte rects...) */
+ BKE_image_signal(BKE_image_verify_viewer(IMA_TYPE_R_RESULT, "Render Result"), NULL, IMA_SIGNAL_FREE);
+
+ RE_ReleaseResult(re);
+ return;
+ }
+ else
+ RE_ReleaseResult(re);
+ }
+ }
+ if(in[0]->data)
+ generate_preview(data, node, in[0]->data);
+}
+
+void register_node_type_cmp_composite(ListBase *lb)
+{
+ static bNodeType ntype;
+
+ node_type_base(&ntype, CMP_NODE_COMPOSITE, "Composite", NODE_CLASS_OUTPUT, NODE_PREVIEW);
+ node_type_socket_templates(&ntype, cmp_node_composite_in, NULL);
+ node_type_size(&ntype, 80, 60, 200);
+ node_type_exec(&ntype, node_composit_exec_composite);
+
+ nodeRegisterType(lb, &ntype);
+}
+
diff --git a/source/blender/nodes/composite/nodes/node_composite_crop.c b/source/blender/nodes/composite/nodes/node_composite_crop.c
new file mode 100644
index 00000000000..332ecf39616
--- /dev/null
+++ b/source/blender/nodes/composite/nodes/node_composite_crop.c
@@ -0,0 +1,129 @@
+/*
+ *
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2006 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): Juho Vepsäläinen
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/nodes/composite/nodes/node_composite_crop.c
+ * \ingroup cmpnodes
+ */
+
+
+#include "node_composite_util.h"
+
+/* **************** Crop ******************** */
+
+static bNodeSocketTemplate cmp_node_crop_in[]= {
+ { SOCK_RGBA, 1, "Image", 0.8f, 0.8f, 0.8f, 1.0f},
+ { -1, 0, "" }
+};
+static bNodeSocketTemplate cmp_node_crop_out[]= {
+ { SOCK_RGBA, 0, "Image"},
+ { -1, 0, "" }
+};
+
+static void node_composit_exec_crop(void *UNUSED(data), bNode *node, bNodeStack **in, bNodeStack **out)
+{
+ if(in[0]->data) {
+ NodeTwoXYs *ntxy= node->storage;
+ CompBuf *cbuf= in[0]->data;
+ CompBuf *stackbuf;
+ int x, y;
+ float *srcfp, *outfp;
+ rcti outputrect;
+
+ if(node->custom2) {
+ ntxy->x1= cbuf->x* ntxy->fac_x1;
+ ntxy->x2= cbuf->x* ntxy->fac_x2;
+ ntxy->y1= cbuf->y* ntxy->fac_y1;
+ ntxy->y2= cbuf->y* ntxy->fac_y2;
+ }
+
+ /* check input image size */
+ if(cbuf->x <= ntxy->x1 + 1)
+ ntxy->x1= cbuf->x - 1;
+
+ if(cbuf->y <= ntxy->y1 + 1)
+ ntxy->y1= cbuf->y - 1;
+
+ if(cbuf->x <= ntxy->x2 + 1)
+ ntxy->x2= cbuf->x - 1;
+
+ if(cbuf->y <= ntxy->y2 + 1)
+ ntxy->y2= cbuf->y - 1;
+
+ /* figure out the minimums and maximums */
+ outputrect.xmax=MAX2(ntxy->x1, ntxy->x2) + 1;
+ outputrect.xmin=MIN2(ntxy->x1, ntxy->x2);
+ outputrect.ymax=MAX2(ntxy->y1, ntxy->y2) + 1;
+ outputrect.ymin=MIN2(ntxy->y1, ntxy->y2);
+
+ if(node->custom1) {
+ /* this option crops the image size too */
+ stackbuf= get_cropped_compbuf(&outputrect, cbuf->rect, cbuf->x, cbuf->y, cbuf->type);
+ }
+ else {
+ /* this option won't crop the size of the image as well */
+ /* allocate memory for the output image */
+ stackbuf = alloc_compbuf(cbuf->x, cbuf->y, cbuf->type, 1);
+
+ /* select the cropped part of the image and set it to the output */
+ for(y=outputrect.ymin; y<outputrect.ymax; y++){
+ srcfp= cbuf->rect + (y * cbuf->x + outputrect.xmin) * cbuf->type;
+ outfp= stackbuf->rect + (y * stackbuf->x + outputrect.xmin) * stackbuf->type;
+ for(x=outputrect.xmin; x<outputrect.xmax; x++, outfp+= stackbuf->type, srcfp+= cbuf->type)
+ memcpy(outfp, srcfp, sizeof(float)*stackbuf->type);
+ }
+ }
+
+ out[0]->data= stackbuf;
+ }
+}
+
+static void node_composit_init_crop(bNodeTree *UNUSED(ntree), bNode* node, bNodeTemplate *UNUSED(ntemp))
+{
+ NodeTwoXYs *nxy= MEM_callocN(sizeof(NodeTwoXYs), "node xy data");
+ node->storage= nxy;
+ nxy->x1= 0;
+ nxy->x2= 0;
+ nxy->y1= 0;
+ nxy->y2= 0;
+}
+
+void register_node_type_cmp_crop(ListBase *lb)
+{
+ static bNodeType ntype;
+
+ node_type_base(&ntype, CMP_NODE_CROP, "Crop", NODE_CLASS_DISTORT, NODE_OPTIONS);
+ node_type_socket_templates(&ntype, cmp_node_crop_in, cmp_node_crop_out);
+ node_type_size(&ntype, 140, 100, 320);
+ node_type_init(&ntype, node_composit_init_crop);
+ node_type_storage(&ntype, "NodeTwoXYs", node_free_standard_storage, node_copy_standard_storage);
+ node_type_exec(&ntype, node_composit_exec_crop);
+
+ nodeRegisterType(lb, &ntype);
+}
+
diff --git a/source/blender/nodes/composite/nodes/node_composite_curves.c b/source/blender/nodes/composite/nodes/node_composite_curves.c
new file mode 100644
index 00000000000..a830b595321
--- /dev/null
+++ b/source/blender/nodes/composite/nodes/node_composite_curves.c
@@ -0,0 +1,209 @@
+/*
+ * $Id: CMP_curves.c 36593 2011-05-10 11:19:26Z lukastoenne $
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2006 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): Björn C. Schaefer
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/nodes/composite/nodes/node_composite_curves.c
+ * \ingroup cmpnodes
+ */
+
+
+#include "node_composite_util.h"
+
+
+/* **************** CURVE Time ******************** */
+
+/* custom1 = sfra, custom2 = efra */
+static bNodeSocketTemplate cmp_node_time_out[]= {
+ { SOCK_FLOAT, 0, "Fac"},
+ { -1, 0, "" }
+};
+
+static void node_composit_exec_curves_time(void *data, bNode *node, bNodeStack **UNUSED(in), bNodeStack **out)
+{
+ RenderData *rd= data;
+ /* stack order output: fac */
+ float fac= 0.0f;
+
+ if(node->custom1 < node->custom2)
+ fac= (rd->cfra - node->custom1)/(float)(node->custom2-node->custom1);
+
+ fac= curvemapping_evaluateF(node->storage, 0, fac);
+ out[0]->vec[0]= CLAMPIS(fac, 0.0f, 1.0f);
+}
+
+
+static void node_composit_init_curves_time(bNodeTree *UNUSED(ntree), bNode* node, bNodeTemplate *UNUSED(ntemp))
+{
+ node->custom1= 1;
+ node->custom2= 250;
+ node->storage= curvemapping_add(1, 0.0f, 0.0f, 1.0f, 1.0f);
+}
+
+void register_node_type_cmp_curve_time(ListBase *lb)
+{
+ static bNodeType ntype;
+
+ node_type_base(&ntype, CMP_NODE_TIME, "Time", NODE_CLASS_INPUT, NODE_OPTIONS);
+ node_type_socket_templates(&ntype, NULL, cmp_node_time_out);
+ node_type_size(&ntype, 140, 100, 320);
+ node_type_init(&ntype, node_composit_init_curves_time);
+ node_type_storage(&ntype, "CurveMapping", node_free_curves, node_copy_curves);
+ node_type_exec(&ntype, node_composit_exec_curves_time);
+
+ nodeRegisterType(lb, &ntype);
+}
+
+
+
+
+/* **************** CURVE VEC ******************** */
+static bNodeSocketTemplate cmp_node_curve_vec_in[]= {
+ { SOCK_VECTOR, 1, "Vector", 0.0f, 0.0f, 0.0f, 1.0f, -1.0f, 1.0f, PROP_NONE},
+ { -1, 0, "" }
+};
+
+static bNodeSocketTemplate cmp_node_curve_vec_out[]= {
+ { SOCK_VECTOR, 0, "Vector"},
+ { -1, 0, "" }
+};
+
+static void node_composit_exec_curve_vec(void *UNUSED(data), bNode *node, bNodeStack **in, bNodeStack **out)
+{
+ /* stack order input: vec */
+ /* stack order output: vec */
+
+ curvemapping_evaluate_premulRGBF(node->storage, out[0]->vec, in[0]->vec);
+}
+
+static void node_composit_init_curve_vec(bNodeTree *UNUSED(ntree), bNode* node, bNodeTemplate *UNUSED(ntemp))
+{
+ node->storage= curvemapping_add(3, -1.0f, -1.0f, 1.0f, 1.0f);
+}
+
+void register_node_type_cmp_curve_vec(ListBase *lb)
+{
+ static bNodeType ntype;
+
+ node_type_base(&ntype, CMP_NODE_CURVE_VEC, "Vector Curves", NODE_CLASS_OP_VECTOR, NODE_OPTIONS);
+ node_type_socket_templates(&ntype, cmp_node_curve_vec_in, cmp_node_curve_vec_out);
+ node_type_size(&ntype, 200, 140, 320);
+ node_type_init(&ntype, node_composit_init_curve_vec);
+ node_type_storage(&ntype, "CurveMapping", node_free_curves, node_copy_curves);
+ node_type_exec(&ntype, node_composit_exec_curve_vec);
+
+ nodeRegisterType(lb, &ntype);
+}
+
+
+/* **************** CURVE RGB ******************** */
+static bNodeSocketTemplate cmp_node_curve_rgb_in[]= {
+ { SOCK_FLOAT, 1, "Fac", 1.0f, 0.0f, 0.0f, 1.0f, -1.0f, 1.0f, PROP_FACTOR},
+ { SOCK_RGBA, 1, "Image", 0.0f, 0.0f, 0.0f, 1.0f},
+ { SOCK_RGBA, 1, "Black Level", 0.0f, 0.0f, 0.0f, 1.0f},
+ { SOCK_RGBA, 1, "White Level", 1.0f, 1.0f, 1.0f, 1.0f},
+ { -1, 0, "" }
+};
+
+static bNodeSocketTemplate cmp_node_curve_rgb_out[]= {
+ { SOCK_RGBA, 0, "Image"},
+ { -1, 0, "" }
+};
+
+static void do_curves(bNode *node, float *out, float *in)
+{
+ curvemapping_evaluate_premulRGBF(node->storage, out, in);
+ out[3]= in[3];
+}
+
+static void do_curves_fac(bNode *node, float *out, float *in, float *fac)
+{
+
+ if(*fac>=1.0)
+ curvemapping_evaluate_premulRGBF(node->storage, out, in);
+ else if(*fac<=0.0) {
+ VECCOPY(out, in);
+ }
+ else {
+ float col[4], mfac= 1.0f-*fac;
+ curvemapping_evaluate_premulRGBF(node->storage, col, in);
+ out[0]= mfac*in[0] + *fac*col[0];
+ out[1]= mfac*in[1] + *fac*col[1];
+ out[2]= mfac*in[2] + *fac*col[2];
+ }
+ out[3]= in[3];
+}
+
+static void node_composit_exec_curve_rgb(void *UNUSED(data), bNode *node, bNodeStack **in, bNodeStack **out)
+{
+ /* stack order input: fac, image, black level, white level */
+ /* stack order output: image */
+
+ if(out[0]->hasoutput==0)
+ return;
+
+ /* input no image? then only color operation */
+ if(in[1]->data==NULL) {
+ curvemapping_evaluateRGBF(node->storage, out[0]->vec, in[1]->vec);
+ }
+ else {
+ /* make output size of input image */
+ CompBuf *cbuf= in[1]->data;
+ CompBuf *stackbuf= alloc_compbuf(cbuf->x, cbuf->y, CB_RGBA, 1); /* allocs */
+
+ curvemapping_set_black_white(node->storage, in[2]->vec, in[3]->vec);
+
+ if(in[0]->vec[0] == 1.0)
+ composit1_pixel_processor(node, stackbuf, in[1]->data, in[1]->vec, do_curves, CB_RGBA);
+ else
+ composit2_pixel_processor(node, stackbuf, in[1]->data, in[1]->vec, in[0]->data, in[0]->vec, do_curves_fac, CB_RGBA, CB_VAL);
+
+ out[0]->data= stackbuf;
+ }
+
+}
+
+static void node_composit_init_curve_rgb(bNodeTree *UNUSED(ntree), bNode* node, bNodeTemplate *UNUSED(ntemp))
+{
+ node->storage= curvemapping_add(4, 0.0f, 0.0f, 1.0f, 1.0f);
+}
+
+void register_node_type_cmp_curve_rgb(ListBase *lb)
+{
+ static bNodeType ntype;
+
+ node_type_base(&ntype, CMP_NODE_CURVE_RGB, "RGB Curves", NODE_CLASS_OP_COLOR, NODE_OPTIONS);
+ node_type_socket_templates(&ntype, cmp_node_curve_rgb_in, cmp_node_curve_rgb_out);
+ node_type_size(&ntype, 200, 140, 320);
+ node_type_init(&ntype, node_composit_init_curve_rgb);
+ node_type_storage(&ntype, "CurveMapping", node_free_curves, node_copy_curves);
+ node_type_exec(&ntype, node_composit_exec_curve_rgb);
+
+ nodeRegisterType(lb, &ntype);
+}
+
+
diff --git a/source/blender/nodes/composite/nodes/node_composite_defocus.c b/source/blender/nodes/composite/nodes/node_composite_defocus.c
new file mode 100644
index 00000000000..a218bfb009d
--- /dev/null
+++ b/source/blender/nodes/composite/nodes/node_composite_defocus.c
@@ -0,0 +1,892 @@
+/*
+ * $Id: CMP_defocus.c 36593 2011-05-10 11:19:26Z lukastoenne $
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2006 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/nodes/composite/nodes/node_composite_defocus.c
+ * \ingroup cmpnodes
+ */
+
+
+#include "node_composite_util.h"
+
+/* ************ qdn: Defocus node ****************** */
+static bNodeSocketTemplate cmp_node_defocus_in[]= {
+ { SOCK_RGBA, 1, "Image", 0.8f, 0.8f, 0.8f, 1.0f},
+ { SOCK_FLOAT, 1, "Z", 0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f, PROP_FACTOR},
+ { -1, 0, "" }
+};
+static bNodeSocketTemplate cmp_node_defocus_out[]= {
+ { SOCK_RGBA, 0, "Image"},
+ { -1, 0, "" }
+};
+
+
+// line coefs for point sampling & scancon. data.
+typedef struct BokehCoeffs {
+ float x0, y0, dx, dy;
+ float ls_x, ls_y;
+ float min_x, min_y, max_x, max_y;
+} BokehCoeffs;
+
+// returns array of BokehCoeffs
+// returns length of array in 'len_bkh',
+// radius squared of inscribed disk in 'inradsq', needed in getWeight() test,
+// BKH[8] is the data returned for the bokeh shape & bkh_b[4] is it's 2d bound
+static void makeBokeh(char bktype, char ro, int* len_bkh, float* inradsq, BokehCoeffs BKH[8], float bkh_b[4])
+{
+ float x0, x1, y0, y1, dx, dy, iDxy;
+ float w = MAX2(1e-5f, ro)*M_PI/180.f; // never reported stangely enough, but a zero offset causes missing center line...
+ float wi = (360.f/bktype)*M_PI/180.f;
+ int i, ov, nv;
+
+ // bktype must be at least 3 & <= 8
+ bktype = (bktype<3) ? 3 : ((bktype>8) ? 8 : bktype);
+ *len_bkh = bktype;
+ *inradsq = -1.f;
+
+ for (i=0; i<(*len_bkh); i++) {
+ x0 = cos(w);
+ y0 = sin(w);
+ w += wi;
+ x1 = cos(w);
+ y1 = sin(w);
+ if ((*inradsq)<0.f) {
+ // radius squared of inscribed disk
+ float idx=(x0+x1)*0.5f, idy=(y0+y1)*0.5f;
+ *inradsq = idx*idx + idy*idy;
+ }
+ BKH[i].x0 = x0;
+ BKH[i].y0 = y0;
+ dx = x1-x0, dy = y1-y0;
+ iDxy = 1.f / sqrt(dx*dx + dy*dy);
+ dx *= iDxy;
+ dy *= iDxy;
+ BKH[i].dx = dx;
+ BKH[i].dy = dy;
+ }
+
+ // precalc scanconversion data
+ // bokeh bound, not transformed, for scanconvert
+ bkh_b[0] = bkh_b[2] = 1e10f; // xmin/ymin
+ bkh_b[1] = bkh_b[3] = -1e10f; // xmax/ymax
+ ov = (*len_bkh) - 1;
+ for (nv=0; nv<(*len_bkh); nv++) {
+ bkh_b[0] = MIN2(bkh_b[0], BKH[nv].x0); // xmin
+ bkh_b[1] = MAX2(bkh_b[1], BKH[nv].x0); // xmax
+ bkh_b[2] = MIN2(bkh_b[2], BKH[nv].y0); // ymin
+ bkh_b[3] = MAX2(bkh_b[3], BKH[nv].y0); // ymax
+ BKH[nv].min_x = MIN2(BKH[ov].x0, BKH[nv].x0);
+ BKH[nv].max_x = MAX2(BKH[ov].x0, BKH[nv].x0);
+ BKH[nv].min_y = MIN2(BKH[ov].y0, BKH[nv].y0);
+ BKH[nv].max_y = MAX2(BKH[ov].y0, BKH[nv].y0);
+ dy = BKH[nv].y0 - BKH[ov].y0;
+ BKH[nv].ls_x = (BKH[nv].x0 - BKH[ov].x0) / ((dy==0.f) ? 1.f : dy);
+ BKH[nv].ls_y = (BKH[nv].ls_x==0.f) ? 1.f : (1.f/BKH[nv].ls_x);
+ ov = nv;
+ }
+}
+
+// test if u/v inside shape & returns weight value
+static float getWeight(BokehCoeffs* BKH, int len_bkh, float u, float v, float rad, float inradsq)
+{
+ BokehCoeffs* bc = BKH;
+ float cdist, irad = (rad==0.f) ? 1.f : (1.f/rad);
+ u *= irad;
+ v *= irad;
+
+ // early out test1: if point outside outer unit disk, it cannot be inside shape
+ cdist = u*u + v*v;
+ if (cdist>1.f) return 0.f;
+
+ // early out test2: if point inside or on inner disk, point must be inside shape
+ if (cdist<=inradsq) return 1.f;
+
+ while (len_bkh--) {
+ if ((bc->dy*(u - bc->x0) - bc->dx*(v - bc->y0)) > 0.f) return 0.f;
+ bc++;
+ }
+ return 1.f;
+}
+
+// QMC.seq. for sampling, A.Keller, EMS
+static float RI_vdC(unsigned int bits, unsigned int r)
+{
+ bits = ( bits << 16) | ( bits >> 16);
+ bits = ((bits & 0x00ff00ff) << 8) | ((bits & 0xff00ff00) >> 8);
+ bits = ((bits & 0x0f0f0f0f) << 4) | ((bits & 0xf0f0f0f0) >> 4);
+ bits = ((bits & 0x33333333) << 2) | ((bits & 0xcccccccc) >> 2);
+ bits = ((bits & 0x55555555) << 1) | ((bits & 0xaaaaaaaa) >> 1);
+ bits ^= r;
+ return (float)((double)bits / 4294967296.0);
+}
+
+// single channel IIR gaussian filtering
+// much faster than anything else, constant time independent of width
+// should extend to multichannel and make this a node, could be useful
+static void IIR_gauss_single(CompBuf* buf, float sigma)
+{
+ double q, q2, sc, cf[4], tsM[9], tsu[3], tsv[3];
+ float *X, *Y, *W;
+ int i, x, y, sz;
+
+ // single channel only for now
+ if (buf->type != CB_VAL) return;
+
+ // <0.5 not valid, though can have a possibly useful sort of sharpening effect
+ if (sigma < 0.5) return;
+
+ // see "Recursive Gabor Filtering" by Young/VanVliet
+ // all factors here in double.prec. Required, because for single.prec it seems to blow up if sigma > ~200
+ if (sigma >= 3.556)
+ q = 0.9804*(sigma - 3.556) + 2.5091;
+ else // sigma >= 0.5
+ q = (0.0561*sigma + 0.5784)*sigma - 0.2568;
+ q2 = q*q;
+ sc = (1.1668 + q)*(3.203729649 + (2.21566 + q)*q);
+ // no gabor filtering here, so no complex multiplies, just the regular coefs.
+ // all negated here, so as not to have to recalc Triggs/Sdika matrix
+ cf[1] = q*(5.788961737 + (6.76492 + 3.0*q)*q)/ sc;
+ cf[2] = -q2*(3.38246 + 3.0*q)/sc;
+ // 0 & 3 unchanged
+ cf[3] = q2*q/sc;
+ cf[0] = 1.0 - cf[1] - cf[2] - cf[3];
+
+ // Triggs/Sdika border corrections,
+ // it seems to work, not entirely sure if it is actually totally correct,
+ // Besides J.M.Geusebroek's anigauss.c (see http://www.science.uva.nl/~mark),
+ // found one other implementation by Cristoph Lampert,
+ // but neither seem to be quite the same, result seems to be ok sofar anyway.
+ // Extra scale factor here to not have to do it in filter,
+ // though maybe this had something to with the precision errors
+ sc = cf[0]/((1.0 + cf[1] - cf[2] + cf[3])*(1.0 - cf[1] - cf[2] - cf[3])*(1.0 + cf[2] + (cf[1] - cf[3])*cf[3]));
+ tsM[0] = sc*(-cf[3]*cf[1] + 1.0 - cf[3]*cf[3] - cf[2]);
+ tsM[1] = sc*((cf[3] + cf[1])*(cf[2] + cf[3]*cf[1]));
+ tsM[2] = sc*(cf[3]*(cf[1] + cf[3]*cf[2]));
+ tsM[3] = sc*(cf[1] + cf[3]*cf[2]);
+ tsM[4] = sc*(-(cf[2] - 1.0)*(cf[2] + cf[3]*cf[1]));
+ tsM[5] = sc*(-(cf[3]*cf[1] + cf[3]*cf[3] + cf[2] - 1.0)*cf[3]);
+ tsM[6] = sc*(cf[3]*cf[1] + cf[2] + cf[1]*cf[1] - cf[2]*cf[2]);
+ tsM[7] = sc*(cf[1]*cf[2] + cf[3]*cf[2]*cf[2] - cf[1]*cf[3]*cf[3] - cf[3]*cf[3]*cf[3] - cf[3]*cf[2] + cf[3]);
+ tsM[8] = sc*(cf[3]*(cf[1] + cf[3]*cf[2]));
+
+#define YVV(L)\
+{\
+ W[0] = cf[0]*X[0] + cf[1]*X[0] + cf[2]*X[0] + cf[3]*X[0];\
+ W[1] = cf[0]*X[1] + cf[1]*W[0] + cf[2]*X[0] + cf[3]*X[0];\
+ W[2] = cf[0]*X[2] + cf[1]*W[1] + cf[2]*W[0] + cf[3]*X[0];\
+ for (i=3; i<L; i++)\
+ W[i] = cf[0]*X[i] + cf[1]*W[i-1] + cf[2]*W[i-2] + cf[3]*W[i-3];\
+ tsu[0] = W[L-1] - X[L-1];\
+ tsu[1] = W[L-2] - X[L-1];\
+ tsu[2] = W[L-3] - X[L-1];\
+ tsv[0] = tsM[0]*tsu[0] + tsM[1]*tsu[1] + tsM[2]*tsu[2] + X[L-1];\
+ tsv[1] = tsM[3]*tsu[0] + tsM[4]*tsu[1] + tsM[5]*tsu[2] + X[L-1];\
+ tsv[2] = tsM[6]*tsu[0] + tsM[7]*tsu[1] + tsM[8]*tsu[2] + X[L-1];\
+ Y[L-1] = cf[0]*W[L-1] + cf[1]*tsv[0] + cf[2]*tsv[1] + cf[3]*tsv[2];\
+ Y[L-2] = cf[0]*W[L-2] + cf[1]*Y[L-1] + cf[2]*tsv[0] + cf[3]*tsv[1];\
+ Y[L-3] = cf[0]*W[L-3] + cf[1]*Y[L-2] + cf[2]*Y[L-1] + cf[3]*tsv[0];\
+ for (i=L-4; i>=0; i--)\
+ Y[i] = cf[0]*W[i] + cf[1]*Y[i+1] + cf[2]*Y[i+2] + cf[3]*Y[i+3];\
+}
+
+ // intermediate buffers
+ sz = MAX2(buf->x, buf->y);
+ Y = MEM_callocN(sz*sizeof(float), "IIR_gauss Y buf");
+ W = MEM_callocN(sz*sizeof(float), "IIR_gauss W buf");
+ // H
+ for (y=0; y<buf->y; y++) {
+ X = &buf->rect[y*buf->x];
+ YVV(buf->x);
+ memcpy(X, Y, sizeof(float)*buf->x);
+ }
+ // V
+ X = MEM_callocN(buf->y*sizeof(float), "IIR_gauss X buf");
+ for (x=0; x<buf->x; x++) {
+ for (y=0; y<buf->y; y++)
+ X[y] = buf->rect[x + y*buf->x];
+ YVV(buf->y);
+ for (y=0; y<buf->y; y++)
+ buf->rect[x + y*buf->x] = Y[y];
+ }
+ MEM_freeN(X);
+
+ MEM_freeN(W);
+ MEM_freeN(Y);
+#undef YVV
+}
+
+static void defocus_blur(bNode *node, CompBuf *new, CompBuf *img, CompBuf *zbuf, float inpval, int no_zbuf)
+{
+ NodeDefocus *nqd = node->storage;
+ CompBuf *wts; // weights buffer
+ CompBuf *crad; // CoC radius buffer
+ BokehCoeffs BKH[8]; // bokeh shape data, here never > 8 pts.
+ float bkh_b[4] = {0}; // shape 2D bound
+ float cam_fdist=1, cam_invfdist=1, cam_lens=35;
+ float dof_sp, maxfgc, bk_hn_theta=0, inradsq=0;
+ int y, len_bkh=0, ydone=0;
+ float aspect, aperture;
+ int minsz;
+ //float bcrad, nmaxc, scf;
+
+ // get some required params from the current scene camera
+ // (ton) this is wrong, needs fixed
+ Scene *scene= (Scene*)node->id;
+ Object* camob = (scene)? scene->camera: NULL;
+ if (camob && camob->type==OB_CAMERA) {
+ Camera* cam = (Camera*)camob->data;
+ cam_lens = cam->lens;
+ cam_fdist = dof_camera(camob);
+ if (cam_fdist==0.0) cam_fdist = 1e10f; /* if the dof is 0.0 then set it be be far away */
+ cam_invfdist = 1.f/cam_fdist;
+ }
+
+ // guess work here.. best match with raytraced result
+ minsz = MIN2(img->x, img->y);
+ dof_sp = (float)minsz / (16.f / cam_lens); // <- == aspect * MIN2(img->x, img->y) / tan(0.5f * fov);
+
+ // aperture
+ aspect = (img->x > img->y) ? (img->y / (float)img->x) : (img->x / (float)img->y);
+ aperture = 0.5f*(cam_lens / (aspect*32.f)) / nqd->fstop;
+
+ // if not disk, make bokeh coefficients and other needed data
+ if (nqd->bktype!=0) {
+ makeBokeh(nqd->bktype, nqd->rotation, &len_bkh, &inradsq, BKH, bkh_b);
+ bk_hn_theta = 0.5 * nqd->bktype * sin(2.0 * M_PI / nqd->bktype); // weight factor
+ }
+
+ // accumulated weights
+ wts = alloc_compbuf(img->x, img->y, CB_VAL, 1);
+ // CoC radius buffer
+ crad = alloc_compbuf(img->x, img->y, CB_VAL, 1);
+
+ // if 'no_zbuf' flag set (which is always set if input is not an image),
+ // values are instead interpreted directly as blur radius values
+ if (no_zbuf) {
+ // to prevent *reaaallly* big radius values and impossible calculation times,
+ // limit the maximum to half the image width or height, whichever is smaller
+ float maxr = 0.5f*(float)MIN2(img->x, img->y);
+ unsigned int p;
+
+ for (p=0; p<(unsigned int)(img->x*img->y); p++) {
+ crad->rect[p] = zbuf ? (zbuf->rect[p]*nqd->scale) : inpval;
+ // bug #5921, limit minimum
+ crad->rect[p] = MAX2(1e-5f, crad->rect[p]);
+ crad->rect[p] = MIN2(crad->rect[p], maxr);
+ // if maxblur!=0, limit maximum
+ if (nqd->maxblur != 0.f) crad->rect[p] = MIN2(crad->rect[p], nqd->maxblur);
+ }
+ }
+ else {
+ float wt;
+
+ // actual zbuffer.
+ // separate foreground from background CoC's
+ // then blur background and blend in again with foreground,
+ // improves the 'blurred foreground overlapping in-focus midground' sharp boundary problem.
+ // wts buffer here used for blendmask
+ maxfgc = 0.f; // maximum foreground CoC radius
+ for (y=0; y<img->y; y++) {
+ unsigned int p = y * img->x;
+ int x;
+ for (x=0; x<img->x; x++) {
+ unsigned int px = p + x;
+ float iZ = (zbuf->rect[px]==0.f) ? 0.f : (1.f/zbuf->rect[px]);
+ crad->rect[px] = 0.5f*(aperture*(dof_sp*(cam_invfdist - iZ) - 1.f));
+ if (crad->rect[px] <= 0.f) {
+ wts->rect[px] = 1.f;
+ crad->rect[px] = -crad->rect[px];
+ if (crad->rect[px] > maxfgc) maxfgc = crad->rect[px];
+ }
+ else crad->rect[px] = wts->rect[px] = 0;
+ }
+ }
+
+ // fast blur...
+ // bug #6656 part 1, probably when previous node_composite.c was split into separate files, it was not properly updated
+ // to include recent cvs commits (well, at least not defocus node), so this part was missing...
+ wt = aperture*128.f;
+ IIR_gauss_single(crad, wt);
+ IIR_gauss_single(wts, wt);
+
+ // bug #6656 part 2a, although foreground blur is not based anymore on closest object,
+ // the rescaling op below was still based on that anyway, and unlike the comment in below code,
+ // the difference is therefore not always that small at all...
+ // so for now commented out, not sure if this is going to cause other future problems, lets just wait and see...
+ /*
+ // find new maximum to scale it back to original
+ // (could skip this, not strictly necessary, in general, difference is quite small, but just in case...)
+ nmaxc = 0;
+ for (p=0; p<(img->x*img->y); p++)
+ if (crad->rect[p] > nmaxc) nmaxc = crad->rect[p];
+ // rescale factor
+ scf = (nmaxc==0.f) ? 1.f: (maxfgc / nmaxc);
+ */
+
+ // and blend...
+ for (y=0; y<img->y; y++) {
+ unsigned int p = y*img->x;
+ int x;
+
+ for (x=0; x<img->x; x++) {
+ unsigned px = p + x;
+ if (zbuf->rect[px]!=0.f) {
+ float iZ = (zbuf->rect[px]==0.f) ? 0.f : (1.f/zbuf->rect[px]);
+
+ // bug #6656 part 2b, do not rescale
+ /*
+ bcrad = 0.5f*fabs(aperture*(dof_sp*(cam_invfdist - iZ) - 1.f));
+ // scale crad back to original maximum and blend
+ crad->rect[px] = bcrad + wts->rect[px]*(scf*crad->rect[px] - bcrad);
+ */
+ crad->rect[px] = 0.5f*fabs(aperture*(dof_sp*(cam_invfdist - iZ) - 1.f));
+
+ // 'bug' #6615, limit minimum radius to 1 pixel, not really a solution, but somewhat mitigates the problem
+ crad->rect[px] = MAX2(crad->rect[px], 0.5f);
+ // if maxblur!=0, limit maximum
+ if (nqd->maxblur != 0.f) crad->rect[px] = MIN2(crad->rect[px], nqd->maxblur);
+ }
+ else crad->rect[px] = 0.f;
+ // clear weights for next part
+ wts->rect[px] = 0.f;
+ }
+ // esc set by main calling process
+ if(node->exec & NODE_BREAK)
+ break;
+ }
+ }
+
+ //------------------------------------------------------------------
+ // main loop
+#ifndef __APPLE__ /* can crash on Mac, see bug #22856, disabled for now */
+#ifdef __INTEL_COMPILER /* icc doesn't like the compound statement -- internal error: 0_1506 */
+ #pragma omp parallel for private(y) if(!nqd->preview) schedule(guided)
+#else
+ #pragma omp parallel for private(y) if(!nqd->preview && img->y*img->x > 16384) schedule(guided)
+#endif
+#endif
+ for (y=0; y<img->y; y++) {
+ unsigned int p, p4, zp, cp, cp4;
+ float *ctcol, u, v, ct_crad, cR2=0;
+ int x, sx, sy;
+
+ // some sort of visual feedback would be nice, or at least this text in the renderwin header
+ // but for now just print some info in the console every 8 scanlines.
+ #pragma omp critical
+ {
+ if (((ydone & 7)==0) || (ydone==(img->y-1))) {
+ if(G.background==0) {
+ printf("\rdefocus: Processing Line %d of %d ... ", ydone+1, img->y);
+ fflush(stdout);
+ }
+ }
+
+ ydone++;
+ }
+
+ // esc set by main calling process. don't break because openmp doesn't
+ // allow it, just continue and do nothing
+ if(node->exec & NODE_BREAK)
+ continue;
+
+ zp = y * img->x;
+ for (x=0; x<img->x; x++) {
+ cp = zp + x;
+ cp4 = cp * img->type;
+
+ // Circle of Confusion radius for current pixel
+ cR2 = ct_crad = crad->rect[cp];
+ // skip if zero (border render)
+ if (ct_crad==0.f) {
+ // related to bug #5921, forgot output image when skipping 0 radius values
+ new->rect[cp4] = img->rect[cp4];
+ if (new->type != CB_VAL) {
+ new->rect[cp4+1] = img->rect[cp4+1];
+ new->rect[cp4+2] = img->rect[cp4+2];
+ new->rect[cp4+3] = img->rect[cp4+3];
+ }
+ continue;
+ }
+ cR2 *= cR2;
+
+ // pixel color
+ ctcol = &img->rect[cp4];
+
+ if (!nqd->preview) {
+ int xs, xe, ys, ye;
+ float lwt, wtcol[4] = {0}, aacol[4] = {0};
+ float wt;
+
+ // shape weight
+ if (nqd->bktype==0) // disk
+ wt = 1.f/((float)M_PI*cR2);
+ else
+ wt = 1.f/(cR2*bk_hn_theta);
+
+ // weighted color
+ wtcol[0] = wt*ctcol[0];
+ if (new->type != CB_VAL) {
+ wtcol[1] = wt*ctcol[1];
+ wtcol[2] = wt*ctcol[2];
+ wtcol[3] = wt*ctcol[3];
+ }
+
+ // macro for background blur overlap test
+ // unfortunately, since this is done per pixel,
+ // it has a very significant negative impact on processing time...
+ // (eg. aa disk blur without test: 112 sec, vs with test: 176 sec...)
+ // iff center blur radius > threshold
+ // and if overlap pixel in focus, do nothing, else add color/weigbt
+ // (threshold constant is dependant on amount of blur)
+ #define TESTBG1(c, w) {\
+ if (ct_crad > nqd->bthresh) {\
+ if (crad->rect[p] > nqd->bthresh) {\
+ new->rect[p] += c[0];\
+ wts->rect[p] += w;\
+ }\
+ }\
+ else {\
+ new->rect[p] += c[0];\
+ wts->rect[p] += w;\
+ }\
+ }
+ #define TESTBG4(c, w) {\
+ if (ct_crad > nqd->bthresh) {\
+ if (crad->rect[p] > nqd->bthresh) {\
+ new->rect[p4] += c[0];\
+ new->rect[p4+1] += c[1];\
+ new->rect[p4+2] += c[2];\
+ new->rect[p4+3] += c[3];\
+ wts->rect[p] += w;\
+ }\
+ }\
+ else {\
+ new->rect[p4] += c[0];\
+ new->rect[p4+1] += c[1];\
+ new->rect[p4+2] += c[2];\
+ new->rect[p4+3] += c[3];\
+ wts->rect[p] += w;\
+ }\
+ }
+ if (nqd->bktype == 0) {
+ // Disk
+ int _x, i, j, di;
+ float Dj, T;
+ // AA pixel
+ #define AAPIX(a, b) {\
+ int _ny = b;\
+ if ((_ny >= 0) && (_ny < new->y)) {\
+ int _nx = a;\
+ if ((_nx >=0) && (_nx < new->x)) {\
+ p = _ny*new->x + _nx;\
+ if (new->type==CB_VAL) {\
+ TESTBG1(aacol, lwt);\
+ }\
+ else {\
+ p4 = p * new->type;\
+ TESTBG4(aacol, lwt);\
+ }\
+ }\
+ }\
+ }
+ // circle scanline
+ #define CSCAN(a, b) {\
+ int _ny = y + b;\
+ if ((_ny >= 0) && (_ny < new->y)) {\
+ xs = x - a + 1;\
+ if (xs < 0) xs = 0;\
+ xe = x + a;\
+ if (xe > new->x) xe = new->x;\
+ p = _ny*new->x + xs;\
+ if (new->type==CB_VAL) {\
+ for (_x=xs; _x<xe; _x++, p++) TESTBG1(wtcol, wt);\
+ }\
+ else {\
+ p4 = p * new->type;\
+ for (_x=xs; _x<xe; _x++, p++, p4+=new->type) TESTBG4(wtcol, wt);\
+ }\
+ }\
+ }
+ i = ceil(ct_crad);
+ j = 0;
+ T = 0;
+ while (i > j) {
+ Dj = sqrt(cR2 - j*j);
+ Dj -= floor(Dj);
+ di = 0;
+ if (Dj > T) { i--; di = 1; }
+ T = Dj;
+ aacol[0] = wtcol[0]*Dj;
+ if (new->type != CB_VAL) {
+ aacol[1] = wtcol[1]*Dj;
+ aacol[2] = wtcol[2]*Dj;
+ aacol[3] = wtcol[3]*Dj;
+ }
+ lwt = wt*Dj;
+ if (i!=j) {
+ // outer pixels
+ AAPIX(x+j, y+i);
+ AAPIX(x+j, y-i);
+ if (j) {
+ AAPIX(x-j, y+i); // BL
+ AAPIX(x-j, y-i); // TL
+ }
+ if (di) { // only when i changed, interior of outer section
+ CSCAN(j, i); // bottom
+ CSCAN(j, -i); // top
+ }
+ }
+ // lower mid section
+ AAPIX(x+i, y+j);
+ if (i) AAPIX(x-i, y+j);
+ CSCAN(i, j);
+ // upper mid section
+ if (j) {
+ AAPIX(x+i, y-j);
+ if (i) AAPIX(x-i, y-j);
+ CSCAN(i, -j);
+ }
+ j++;
+ }
+ #undef CSCAN
+ #undef AAPIX
+ }
+ else {
+ // n-agonal
+ int ov, nv;
+ float mind, maxd, lwt;
+ ys = MAX2((int)floor(bkh_b[2]*ct_crad + y), 0);
+ ye = MIN2((int)ceil(bkh_b[3]*ct_crad + y), new->y - 1);
+ for (sy=ys; sy<=ye; sy++) {
+ float fxs = 1e10f, fxe = -1e10f;
+ float yf = (sy - y)/ct_crad;
+ int found = 0;
+ ov = len_bkh - 1;
+ mind = maxd = 0;
+ for (nv=0; nv<len_bkh; nv++) {
+ if ((BKH[nv].max_y >= yf) && (BKH[nv].min_y <= yf)) {
+ float tx = BKH[ov].x0 + BKH[nv].ls_x*(yf - BKH[ov].y0);
+ if (tx < fxs) { fxs = tx; mind = BKH[nv].ls_x; }
+ if (tx > fxe) { fxe = tx; maxd = BKH[nv].ls_x; }
+ if (++found == 2) break;
+ }
+ ov = nv;
+ }
+ if (found) {
+ fxs = fxs*ct_crad + x;
+ fxe = fxe*ct_crad + x;
+ xs = (int)floor(fxs), xe = (int)ceil(fxe);
+ // AA hack for first and last x pixel, near vertical edges only
+ if (fabs(mind) <= 1.f) {
+ if ((xs >= 0) && (xs < new->x)) {
+ lwt = 1.f-(fxs - xs);
+ aacol[0] = wtcol[0]*lwt;
+ p = xs + sy*new->x;
+ if (new->type==CB_VAL) {
+ lwt *= wt;
+ TESTBG1(aacol, lwt);
+ }
+ else {
+ p4 = p * new->type;
+ aacol[1] = wtcol[1]*lwt;
+ aacol[2] = wtcol[2]*lwt;
+ aacol[3] = wtcol[3]*lwt;
+ lwt *= wt;
+ TESTBG4(aacol, lwt);
+ }
+ }
+ }
+ if (fabs(maxd) <= 1.f) {
+ if ((xe >= 0) && (xe < new->x)) {
+ lwt = 1.f-(xe - fxe);
+ aacol[0] = wtcol[0]*lwt;
+ p = xe + sy*new->x;
+ if (new->type==CB_VAL) {
+ lwt *= wt;
+ TESTBG1(aacol, lwt);
+ }
+ else {
+ p4 = p * new->type;
+ aacol[1] = wtcol[1]*lwt;
+ aacol[2] = wtcol[2]*lwt;
+ aacol[3] = wtcol[3]*lwt;
+ lwt *= wt;
+ TESTBG4(aacol, lwt);
+ }
+ }
+ }
+ xs = MAX2(xs+1, 0);
+ xe = MIN2(xe, new->x);
+ // remaining interior scanline
+ p = sy*new->x + xs;
+ if (new->type==CB_VAL) {
+ for (sx=xs; sx<xe; sx++, p++) TESTBG1(wtcol, wt);
+ }
+ else {
+ p4 = p * new->type;
+ for (sx=xs; sx<xe; sx++, p++, p4+=new->type) TESTBG4(wtcol, wt);
+ }
+ }
+ }
+
+ // now traverse in opposite direction, y scanlines,
+ // but this time only draw the near horizontal edges,
+ // applying same AA hack as above
+ xs = MAX2((int)floor(bkh_b[0]*ct_crad + x), 0);
+ xe = MIN2((int)ceil(bkh_b[1]*ct_crad + x), img->x - 1);
+ for (sx=xs; sx<=xe; sx++) {
+ float xf = (sx - x)/ct_crad;
+ float fys = 1e10f, fye = -1e10f;
+ int found = 0;
+ ov = len_bkh - 1;
+ mind = maxd = 0;
+ for (nv=0; nv<len_bkh; nv++) {
+ if ((BKH[nv].max_x >= xf) && (BKH[nv].min_x <= xf)) {
+ float ty = BKH[ov].y0 + BKH[nv].ls_y*(xf - BKH[ov].x0);
+ if (ty < fys) { fys = ty; mind = BKH[nv].ls_y; }
+ if (ty > fye) { fye = ty; maxd = BKH[nv].ls_y; }
+ if (++found == 2) break;
+ }
+ ov = nv;
+ }
+ if (found) {
+ fys = fys*ct_crad + y;
+ fye = fye*ct_crad + y;
+ // near horizontal edges only, line slope <= 1
+ if (fabs(mind) <= 1.f) {
+ int iys = (int)floor(fys);
+ if ((iys >= 0) && (iys < new->y)) {
+ lwt = 1.f - (fys - iys);
+ aacol[0] = wtcol[0]*lwt;
+ p = sx + iys*new->x;
+ if (new->type==CB_VAL) {
+ lwt *= wt;
+ TESTBG1(aacol, lwt);
+ }
+ else {
+ p4 = p * new->type;
+ aacol[1] = wtcol[1]*lwt;
+ aacol[2] = wtcol[2]*lwt;
+ aacol[3] = wtcol[3]*lwt;
+ lwt *= wt;
+ TESTBG4(aacol, lwt);
+ }
+ }
+ }
+ if (fabs(maxd) <= 1.f) {
+ int iye = ceil(fye);
+ if ((iye >= 0) && (iye < new->y)) {
+ lwt = 1.f - (iye - fye);
+ aacol[0] = wtcol[0]*lwt;
+ p = sx + iye*new->x;
+ if (new->type==CB_VAL) {
+ lwt *= wt;
+ TESTBG1(aacol, lwt);
+ }
+ else {
+ p4 = p * new->type;
+ aacol[1] = wtcol[1]*lwt;
+ aacol[2] = wtcol[2]*lwt;
+ aacol[3] = wtcol[3]*lwt;
+ lwt *= wt;
+ TESTBG4(aacol, lwt);
+ }
+ }
+ }
+ }
+ }
+
+ }
+ #undef TESTBG4
+ #undef TESTBG1
+
+ }
+ else {
+ // sampled, simple rejection sampling here, good enough
+ unsigned int maxsam, s, ui = BLI_rand()*BLI_rand();
+ float wcor, cpr = BLI_frand(), lwt;
+ if (no_zbuf)
+ maxsam = nqd->samples; // no zbuffer input, use sample value directly
+ else {
+ // depth adaptive sampling hack, the more out of focus, the more samples taken, 16 minimum.
+ maxsam = (int)(0.5f + nqd->samples*(1.f-(float)exp(-fabs(zbuf->rect[cp] - cam_fdist))));
+ if (maxsam < 16) maxsam = 16;
+ }
+ wcor = 1.f/(float)maxsam;
+ for (s=0; s<maxsam; ++s) {
+ u = ct_crad*(2.f*RI_vdC(s, ui) - 1.f);
+ v = ct_crad*(2.f*(s + cpr)/(float)maxsam - 1.f);
+ sx = (int)(x + u + 0.5f), sy = (int)(y + v + 0.5f);
+ if ((sx<0) || (sx >= new->x) || (sy<0) || (sy >= new->y)) continue;
+ p = sx + sy*new->x;
+ p4 = p * new->type;
+ if (nqd->bktype==0) // Disk
+ lwt = ((u*u + v*v)<=cR2) ? wcor : 0.f;
+ else // AA not needed here
+ lwt = wcor * getWeight(BKH, len_bkh, u, v, ct_crad, inradsq);
+ // prevent background bleeding onto in-focus pixels, user-option
+ if (ct_crad > nqd->bthresh) { // if center blur > threshold
+ if (crad->rect[p] > nqd->bthresh) { // if overlap pixel in focus, do nothing, else add color/weigbt
+ new->rect[p4] += ctcol[0] * lwt;
+ if (new->type != CB_VAL) {
+ new->rect[p4+1] += ctcol[1] * lwt;
+ new->rect[p4+2] += ctcol[2] * lwt;
+ new->rect[p4+3] += ctcol[3] * lwt;
+ }
+ wts->rect[p] += lwt;
+ }
+ }
+ else {
+ new->rect[p4] += ctcol[0] * lwt;
+ if (new->type != CB_VAL) {
+ new->rect[p4+1] += ctcol[1] * lwt;
+ new->rect[p4+2] += ctcol[2] * lwt;
+ new->rect[p4+3] += ctcol[3] * lwt;
+ }
+ wts->rect[p] += lwt;
+ }
+ }
+ }
+
+ }
+ }
+
+ // finally, normalize
+ for (y=0; y<new->y; y++) {
+ unsigned int p = y * new->x;
+ unsigned int p4 = p * new->type;
+ int x;
+
+ for (x=0; x<new->x; x++) {
+ float dv = (wts->rect[p]==0.f) ? 1.f : (1.f/wts->rect[p]);
+ new->rect[p4] *= dv;
+ if (new->type!=CB_VAL) {
+ new->rect[p4+1] *= dv;
+ new->rect[p4+2] *= dv;
+ new->rect[p4+3] *= dv;
+ }
+ p++;
+ p4 += new->type;
+ }
+ }
+
+ free_compbuf(crad);
+ free_compbuf(wts);
+
+ printf("Done\n");
+}
+
+
+static void node_composit_exec_defocus(void *UNUSED(data), bNode *node, bNodeStack **in, bNodeStack **out)
+{
+ CompBuf *new, *old, *zbuf_use = NULL, *img = in[0]->data, *zbuf = in[1]->data;
+ NodeDefocus *nqd = node->storage;
+ int no_zbuf = nqd->no_zbuf;
+
+ if ((img==NULL) || (out[0]->hasoutput==0)) return;
+
+ // if image not valid type or fstop==infinite (128), nothing to do, pass in to out
+ if (((img->type!=CB_RGBA) && (img->type!=CB_VAL)) || ((no_zbuf==0) && (nqd->fstop==128.f))) {
+ out[0]->data = pass_on_compbuf(img);
+ return;
+ }
+
+ if (zbuf!=NULL) {
+ // Zbuf input, check to make sure, single channel, same size
+ // doesn't have to be actual zbuffer, but must be value type
+ if ((zbuf->x != img->x) || (zbuf->y != img->y)) {
+ // could do a scale here instead...
+ printf("Z input must be same size as image !\n");
+ return;
+ }
+ zbuf_use = typecheck_compbuf(zbuf, CB_VAL);
+ }
+ else no_zbuf = 1; // no zbuffer input
+
+ // ok, process
+ old = img;
+ if (nqd->gamco) {
+ // gamma correct, blender func is simplified, fixed value & RGBA only,
+ // should make user param. also depremul and premul afterwards, gamma
+ // correction can't work with premul alpha
+ old = dupalloc_compbuf(img);
+ premul_compbuf(old, 1);
+ gamma_correct_compbuf(old, 0);
+ premul_compbuf(old, 0);
+ }
+
+ new = alloc_compbuf(old->x, old->y, old->type, 1);
+ defocus_blur(node, new, old, zbuf_use, in[1]->vec[0]*nqd->scale, no_zbuf);
+
+ if (nqd->gamco) {
+ premul_compbuf(new, 1);
+ gamma_correct_compbuf(new, 1);
+ premul_compbuf(new, 0);
+ free_compbuf(old);
+ }
+ if(node->exec & NODE_BREAK) {
+ free_compbuf(new);
+ new= NULL;
+ }
+ out[0]->data = new;
+ if (zbuf_use && (zbuf_use != zbuf)) free_compbuf(zbuf_use);
+}
+
+static void node_composit_init_defocus(bNodeTree *UNUSED(ntree), bNode* node, bNodeTemplate *UNUSED(ntemp))
+{
+ /* qdn: defocus node */
+ NodeDefocus *nbd = MEM_callocN(sizeof(NodeDefocus), "node defocus data");
+ nbd->bktype = 0;
+ nbd->rotation = 0.f;
+ nbd->preview = 1;
+ nbd->gamco = 0;
+ nbd->samples = 16;
+ nbd->fstop = 128.f;
+ nbd->maxblur = 0;
+ nbd->bthresh = 1.f;
+ nbd->scale = 1.f;
+ nbd->no_zbuf = 1;
+ node->storage = nbd;
+}
+
+void register_node_type_cmp_defocus(ListBase *lb)
+{
+ static bNodeType ntype;
+
+ node_type_base(&ntype, CMP_NODE_DEFOCUS, "Defocus", NODE_CLASS_OP_FILTER, NODE_OPTIONS);
+ node_type_socket_templates(&ntype, cmp_node_defocus_in, cmp_node_defocus_out);
+ node_type_size(&ntype, 150, 120, 200);
+ node_type_init(&ntype, node_composit_init_defocus);
+ node_type_storage(&ntype, "NodeDefocus", node_free_standard_storage, node_copy_standard_storage);
+ node_type_exec(&ntype, node_composit_exec_defocus);
+
+ nodeRegisterType(lb, &ntype);
+}
+
+
+
diff --git a/source/blender/nodes/composite/nodes/node_composite_diffMatte.c b/source/blender/nodes/composite/nodes/node_composite_diffMatte.c
new file mode 100644
index 00000000000..a0fff88f5dc
--- /dev/null
+++ b/source/blender/nodes/composite/nodes/node_composite_diffMatte.c
@@ -0,0 +1,151 @@
+/*
+ * $Id: CMP_diffMatte.c 36536 2011-05-07 13:27:27Z lukastoenne $
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2006 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): Bob Holcomb
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/nodes/composite/nodes/node_composite_diffMatte.c
+ * \ingroup cmpnodes
+ */
+
+
+#include "node_composite_util.h"
+
+/* ******************* channel Difference Matte ********************************* */
+static bNodeSocketTemplate cmp_node_diff_matte_in[]={
+ {SOCK_RGBA,1,"Image 1", 0.8f, 0.8f, 0.8f, 1.0f},
+ {SOCK_RGBA,1,"Image 2", 0.8f, 0.8f, 0.8f, 1.0f},
+ {-1,0,""}
+};
+
+static bNodeSocketTemplate cmp_node_diff_matte_out[]={
+ {SOCK_RGBA,0,"Image"},
+ {SOCK_FLOAT,0,"Matte"},
+ {-1,0,""}
+};
+
+static void do_diff_matte(bNode *node, float *outColor, float *inColor1, float *inColor2)
+{
+ NodeChroma *c= (NodeChroma *)node->storage;
+ float tolerence=c->t1;
+ float falloff=c->t2;
+ float difference;
+ float alpha;
+
+ difference= fabs(inColor2[0]-inColor1[0])+
+ fabs(inColor2[1]-inColor1[1])+
+ fabs(inColor2[2]-inColor1[2]);
+
+ /*average together the distances*/
+ difference=difference/3.0;
+
+ VECCOPY(outColor, inColor1);
+
+ /*make 100% transparent*/
+ if(difference < tolerence) {
+ outColor[3]=0.0;
+ }
+ /*in the falloff region, make partially transparent */
+ else if(difference < falloff+tolerence) {
+ difference=difference-tolerence;
+ alpha=difference/falloff;
+ /*only change if more transparent than before */
+ if(alpha < inColor1[3]) {
+ outColor[3]=alpha;
+ }
+ else { /* leave as before */
+ outColor[3]=inColor1[3];
+ }
+ }
+ else {
+ /*foreground object*/
+ outColor[3]= inColor1[3];
+ }
+}
+
+static void node_composit_exec_diff_matte(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
+{
+ CompBuf *outbuf=0;
+ CompBuf *imbuf1=0;
+ CompBuf *imbuf2=0;
+ NodeChroma *c;
+
+ /*is anything connected?*/
+ if(out[0]->hasoutput==0 && out[1]->hasoutput==0) return;
+
+ /*must have an image imput*/
+ if(in[0]->data==NULL) return;
+
+
+ imbuf1=typecheck_compbuf(in[0]->data, CB_RGBA);
+
+ /* if there's an image, use that, if not use the color */
+ if(in[1]->data) {
+ imbuf2=typecheck_compbuf(in[1]->data, CB_RGBA);
+ }
+
+ c=node->storage;
+ outbuf=dupalloc_compbuf(imbuf1);
+
+ /* note, processor gets a keyvals array passed on as buffer constant */
+ composit2_pixel_processor(node, outbuf, imbuf1, in[0]->vec, imbuf2, in[1]->vec, do_diff_matte, CB_RGBA, CB_RGBA);
+
+ out[0]->data=outbuf;
+ if(out[1]->hasoutput)
+ out[1]->data=valbuf_from_rgbabuf(outbuf, CHAN_A);
+ generate_preview(data, node, outbuf);
+
+ if(imbuf1!=in[0]->data)
+ free_compbuf(imbuf1);
+
+ if(imbuf2!=in[1]->data)
+ free_compbuf(imbuf2);
+}
+
+static void node_composit_init_diff_matte(bNodeTree *UNUSED(ntree), bNode* node, bNodeTemplate *UNUSED(ntemp))
+{
+ NodeChroma *c= MEM_callocN(sizeof(NodeChroma), "node chroma");
+ node->storage= c;
+ c->t1= 0.1f;
+ c->t2= 0.1f;
+}
+
+void register_node_type_cmp_diff_matte(ListBase *lb)
+{
+ static bNodeType ntype;
+
+ node_type_base(&ntype, CMP_NODE_DIFF_MATTE, "Difference Key", NODE_CLASS_MATTE, NODE_PREVIEW|NODE_OPTIONS);
+ node_type_socket_templates(&ntype, cmp_node_diff_matte_in, cmp_node_diff_matte_out);
+ node_type_size(&ntype, 200, 80, 250);
+ node_type_init(&ntype, node_composit_init_diff_matte);
+ node_type_storage(&ntype, "NodeChroma", node_free_standard_storage, node_copy_standard_storage);
+ node_type_exec(&ntype, node_composit_exec_diff_matte);
+
+ nodeRegisterType(lb, &ntype);
+}
+
+
+
diff --git a/source/blender/nodes/composite/nodes/node_composite_dilate.c b/source/blender/nodes/composite/nodes/node_composite_dilate.c
new file mode 100644
index 00000000000..ef47fdbfef0
--- /dev/null
+++ b/source/blender/nodes/composite/nodes/node_composite_dilate.c
@@ -0,0 +1,163 @@
+/*
+ * $Id: CMP_dilate.c 36593 2011-05-10 11:19:26Z lukastoenne $
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2006 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/nodes/composite/nodes/node_composite_dilate.c
+ * \ingroup cmpnodes
+ */
+
+
+#include "node_composite_util.h"
+
+
+/* **************** Dilate/Erode ******************** */
+
+static bNodeSocketTemplate cmp_node_dilateerode_in[]= {
+ { SOCK_FLOAT, 1, "Mask", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, PROP_FACTOR},
+ { -1, 0, "" }
+};
+static bNodeSocketTemplate cmp_node_dilateerode_out[]= {
+ { SOCK_FLOAT, 0, "Mask"},
+ { -1, 0, "" }
+};
+
+static void morpho_dilate(CompBuf *cbuf)
+{
+ int x, y;
+ float *p, *rectf = cbuf->rect;
+
+ for (y=0; y < cbuf->y; y++) {
+ for (x=0; x < cbuf->x-1; x++) {
+ p = rectf + cbuf->x*y + x;
+ *p = MAX2(*p, *(p + 1));
+ }
+ }
+
+ for (y=0; y < cbuf->y; y++) {
+ for (x=cbuf->x-1; x >= 1; x--) {
+ p = rectf + cbuf->x*y + x;
+ *p = MAX2(*p, *(p - 1));
+ }
+ }
+
+ for (x=0; x < cbuf->x; x++) {
+ for (y=0; y < cbuf->y-1; y++) {
+ p = rectf + cbuf->x*y + x;
+ *p = MAX2(*p, *(p + cbuf->x));
+ }
+ }
+
+ for (x=0; x < cbuf->x; x++) {
+ for (y=cbuf->y-1; y >= 1; y--) {
+ p = rectf + cbuf->x*y + x;
+ *p = MAX2(*p, *(p - cbuf->x));
+ }
+ }
+}
+
+static void morpho_erode(CompBuf *cbuf)
+{
+ int x, y;
+ float *p, *rectf = cbuf->rect;
+
+ for (y=0; y < cbuf->y; y++) {
+ for (x=0; x < cbuf->x-1; x++) {
+ p = rectf + cbuf->x*y + x;
+ *p = MIN2(*p, *(p + 1));
+ }
+ }
+
+ for (y=0; y < cbuf->y; y++) {
+ for (x=cbuf->x-1; x >= 1; x--) {
+ p = rectf + cbuf->x*y + x;
+ *p = MIN2(*p, *(p - 1));
+ }
+ }
+
+ for (x=0; x < cbuf->x; x++) {
+ for (y=0; y < cbuf->y-1; y++) {
+ p = rectf + cbuf->x*y + x;
+ *p = MIN2(*p, *(p + cbuf->x));
+ }
+ }
+
+ for (x=0; x < cbuf->x; x++) {
+ for (y=cbuf->y-1; y >= 1; y--) {
+ p = rectf + cbuf->x*y + x;
+ *p = MIN2(*p, *(p - cbuf->x));
+ }
+ }
+
+}
+
+static void node_composit_exec_dilateerode(void *UNUSED(data), bNode *node, bNodeStack **in, bNodeStack **out)
+{
+ /* stack order in: mask */
+ /* stack order out: mask */
+ if(out[0]->hasoutput==0)
+ return;
+
+ /* input no image? then only color operation */
+ if(in[0]->data==NULL) {
+ out[0]->vec[0] = out[0]->vec[1] = out[0]->vec[2] = 0.0f;
+ out[0]->vec[3] = 0.0f;
+ }
+ else {
+ /* make output size of input image */
+ CompBuf *cbuf= typecheck_compbuf(in[0]->data, CB_VAL);
+ CompBuf *stackbuf= dupalloc_compbuf(cbuf);
+ short i;
+
+ if (node->custom2 > 0) { // positive, dilate
+ for (i = 0; i < node->custom2; i++)
+ morpho_dilate(stackbuf);
+ } else if (node->custom2 < 0) { // negative, erode
+ for (i = 0; i > node->custom2; i--)
+ morpho_erode(stackbuf);
+ }
+
+ if(cbuf!=in[0]->data)
+ free_compbuf(cbuf);
+
+ out[0]->data= stackbuf;
+ }
+}
+
+void register_node_type_cmp_dilateerode(ListBase *lb)
+{
+ static bNodeType ntype;
+
+ node_type_base(&ntype, CMP_NODE_DILATEERODE, "Dilate/Erode", NODE_CLASS_OP_FILTER, NODE_OPTIONS);
+ node_type_socket_templates(&ntype, cmp_node_dilateerode_in, cmp_node_dilateerode_out);
+ node_type_size(&ntype, 130, 100, 320);
+ node_type_exec(&ntype, node_composit_exec_dilateerode);
+
+ nodeRegisterType(lb, &ntype);
+}
+
+
diff --git a/source/blender/nodes/composite/nodes/node_composite_directionalblur.c b/source/blender/nodes/composite/nodes/node_composite_directionalblur.c
new file mode 100644
index 00000000000..3d541120a61
--- /dev/null
+++ b/source/blender/nodes/composite/nodes/node_composite_directionalblur.c
@@ -0,0 +1,146 @@
+/*
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2006 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): Alfredo de Greef (eeshlo)
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/nodes/composite/nodes/node_composite_directionalblur.c
+ * \ingroup cmpnodes
+ */
+
+
+#include "node_composite_util.h"
+
+static bNodeSocketTemplate cmp_node_dblur_in[]= {
+ { SOCK_RGBA, 1, "Image", 0.8f, 0.8f, 0.8f, 1.f},
+ { -1, 0, "" }
+};
+
+static bNodeSocketTemplate cmp_node_dblur_out[]= {
+ { SOCK_RGBA, 0, "Image"},
+ { -1, 0, "" }
+};
+
+static CompBuf *dblur(bNode *node, CompBuf *img, int iterations, int wrap,
+ float center_x, float center_y, float dist, float angle, float spin, float zoom)
+{
+ if ((dist != 0.f) || (spin != 0.f) || (zoom != 0.f)) {
+ void (*getpix)(CompBuf*, float, float, float*) = wrap ? qd_getPixelLerpWrap : qd_getPixelLerp;
+ const float a= angle * (float)M_PI / 180.f;
+ const float itsc= 1.f / pow(2.f, (float)iterations);
+ float D;
+ float center_x_pix, center_y_pix;
+ float tx, ty;
+ float sc, rot;
+ CompBuf *tmp;
+ int i, j;
+
+ tmp= dupalloc_compbuf(img);
+
+ D= dist * sqrtf(img->x * img->x + img->y * img->y);
+ center_x_pix= center_x * img->x;
+ center_y_pix= center_y * img->y;
+
+ tx= itsc * D * cos(a);
+ ty= -itsc * D * sin(a);
+ sc= itsc * zoom;
+ rot= itsc * spin * (float)M_PI / 180.f;
+
+ /* blur the image */
+ for(i= 0; i < iterations; ++i) {
+ const float cs= cos(rot), ss= sin(rot);
+ const float isc= 1.f / (1.f + sc);
+ unsigned int x, y;
+ float col[4]= {0,0,0,0};
+
+ for(y= 0; y < img->y; ++y) {
+ const float v= isc * (y - center_y_pix) + ty;
+
+ for(x= 0; x < img->x; ++x) {
+ const float u= isc * (x - center_x_pix) + tx;
+ unsigned int p= (x + y * img->x) * img->type;
+
+ getpix(tmp, cs * u + ss * v + center_x_pix, cs * v - ss * u + center_y_pix, col);
+
+ /* mix img and transformed tmp */
+ for(j= 0; j < 4; ++j)
+ img->rect[p + j]= AVG2(img->rect[p + j], col[j]);
+ }
+ }
+
+ /* copy img to tmp */
+ if(i != (iterations - 1))
+ memcpy(tmp->rect, img->rect, sizeof(float) * img->x * img->y * img->type);
+
+ /* double transformations */
+ tx *= 2.f, ty *= 2.f;
+ sc *= 2.f, rot *= 2.f;
+
+ if(node->exec & NODE_BREAK) break;
+ }
+
+ free_compbuf(tmp);
+ }
+
+ return img;
+}
+
+static void node_composit_exec_dblur(void *UNUSED(data), bNode *node, bNodeStack **in, bNodeStack **out)
+{
+ NodeDBlurData *ndbd= node->storage;
+ CompBuf *new, *img= in[0]->data;
+
+ if((img == NULL) || (out[0]->hasoutput == 0)) return;
+
+ if (img->type != CB_RGBA)
+ new = typecheck_compbuf(img, CB_RGBA);
+ else
+ new = dupalloc_compbuf(img);
+
+ out[0]->data= dblur(node, new, ndbd->iter, ndbd->wrap, ndbd->center_x, ndbd->center_y, ndbd->distance, ndbd->angle, ndbd->spin, ndbd->zoom);
+}
+
+static void node_composit_init_dblur(bNodeTree *UNUSED(ntree), bNode* node, bNodeTemplate *UNUSED(ntemp))
+{
+ NodeDBlurData *ndbd= MEM_callocN(sizeof(NodeDBlurData), "node dblur data");
+ node->storage= ndbd;
+ ndbd->center_x= 0.5;
+ ndbd->center_y= 0.5;
+}
+
+void register_node_type_cmp_dblur(ListBase *lb)
+{
+ static bNodeType ntype;
+
+ node_type_base(&ntype, CMP_NODE_DBLUR, "Directional Blur", NODE_CLASS_OP_FILTER, NODE_OPTIONS);
+ node_type_socket_templates(&ntype, cmp_node_dblur_in, cmp_node_dblur_out);
+ node_type_size(&ntype, 150, 120, 200);
+ node_type_init(&ntype, node_composit_init_dblur);
+ node_type_storage(&ntype, "NodeDBlurData", node_free_standard_storage, node_copy_standard_storage);
+ node_type_exec(&ntype, node_composit_exec_dblur);
+
+ nodeRegisterType(lb, &ntype);
+}
+
diff --git a/source/blender/nodes/composite/nodes/node_composite_displace.c b/source/blender/nodes/composite/nodes/node_composite_displace.c
new file mode 100644
index 00000000000..4688553d27f
--- /dev/null
+++ b/source/blender/nodes/composite/nodes/node_composite_displace.c
@@ -0,0 +1,199 @@
+/*
+ * $Id: CMP_displace.c 36593 2011-05-10 11:19:26Z lukastoenne $
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2006 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/nodes/composite/nodes/node_composite_displace.c
+ * \ingroup cmpnodes
+ */
+
+
+#include "node_composite_util.h"
+
+
+/* **************** Displace ******************** */
+
+static bNodeSocketTemplate cmp_node_displace_in[]= {
+ { SOCK_RGBA, 1, "Image", 0.8f, 0.8f, 0.8f, 1.0f},
+ { SOCK_VECTOR, 1, "Vector", 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_TRANSLATION},
+ { SOCK_FLOAT, 1, "X Scale", 0.0f, 0.0f, 0.0f, 0.0f, -1000.0f, 1000.0f, PROP_FACTOR},
+ { SOCK_FLOAT, 1, "Y Scale", 0.0f, 0.0f, 0.0f, 0.0f, -1000.0f, 1000.0f, PROP_FACTOR},
+ { -1, 0, "" }
+};
+static bNodeSocketTemplate cmp_node_displace_out[]= {
+ { SOCK_RGBA, 0, "Image"},
+ { -1, 0, "" }
+};
+
+/* minimum distance (in pixels) a pixel has to be displaced
+ * in order to take effect */
+#define DISPLACE_EPSILON 0.01
+
+static void do_displace(bNode *node, CompBuf *stackbuf, CompBuf *cbuf, CompBuf *vecbuf, float *UNUSED(veccol), CompBuf *xbuf, CompBuf *ybuf, float *xscale, float *yscale)
+{
+ ImBuf *ibuf;
+ int x, y;
+ float p_dx, p_dy; /* main displacement in pixel space */
+ float d_dx, d_dy;
+ float dxt, dyt;
+ float u, v;
+ float xs, ys;
+ float vec[3], vecdx[3], vecdy[3];
+ float col[3];
+
+ ibuf= IMB_allocImBuf(cbuf->x, cbuf->y, 32, 0);
+ ibuf->rect_float= cbuf->rect;
+
+ for(y=0; y < stackbuf->y; y++) {
+ for(x=0; x < stackbuf->x; x++) {
+ /* calc pixel coordinates */
+ qd_getPixel(vecbuf, x-vecbuf->xof, y-vecbuf->yof, vec);
+
+ if (xbuf)
+ qd_getPixel(xbuf, x-xbuf->xof, y-xbuf->yof, &xs);
+ else
+ xs = xscale[0];
+
+ if (ybuf)
+ qd_getPixel(ybuf, x-ybuf->xof, y-ybuf->yof, &ys);
+ else
+ ys = yscale[0];
+
+ /* clamp x and y displacement to triple image resolution -
+ * to prevent hangs from huge values mistakenly plugged in eg. z buffers */
+ CLAMP(xs, -stackbuf->x*4, stackbuf->x*4);
+ CLAMP(ys, -stackbuf->y*4, stackbuf->y*4);
+
+ p_dx = vec[0] * xs;
+ p_dy = vec[1] * ys;
+
+ /* if no displacement, then just copy this pixel */
+ if (fabsf(p_dx) < DISPLACE_EPSILON && fabsf(p_dy) < DISPLACE_EPSILON) {
+ qd_getPixel(cbuf, x-cbuf->xof, y-cbuf->yof, col);
+ qd_setPixel(stackbuf, x, y, col);
+ continue;
+ }
+
+ /* displaced pixel in uv coords, for image sampling */
+ u = (x - cbuf->xof - p_dx + 0.5f) / (float)stackbuf->x;
+ v = (y - cbuf->yof - p_dy + 0.5f) / (float)stackbuf->y;
+
+
+ /* calc derivatives */
+ qd_getPixel(vecbuf, x-vecbuf->xof+1, y-vecbuf->yof, vecdx);
+ qd_getPixel(vecbuf, x-vecbuf->xof, y-vecbuf->yof+1, vecdy);
+ d_dx = vecdx[0] * xs;
+ d_dy = vecdy[0] * ys;
+
+ /* clamp derivatives to minimum displacement distance in UV space */
+ dxt = p_dx - d_dx;
+ dyt = p_dy - d_dy;
+
+ dxt = signf(dxt)*maxf(fabsf(dxt), DISPLACE_EPSILON)/(float)stackbuf->x;
+ dyt = signf(dyt)*maxf(fabsf(dyt), DISPLACE_EPSILON)/(float)stackbuf->y;
+
+ ibuf_sample(ibuf, u, v, dxt, dyt, col);
+ qd_setPixel(stackbuf, x, y, col);
+
+ if(node->exec & NODE_BREAK) break;
+ }
+
+ if(node->exec & NODE_BREAK) break;
+ }
+ IMB_freeImBuf(ibuf);
+
+
+/* simple method for reference, linear interpolation */
+/*
+ int x, y;
+ float dx, dy;
+ float u, v;
+ float vec[3];
+ float col[3];
+
+ for(y=0; y < stackbuf->y; y++) {
+ for(x=0; x < stackbuf->x; x++) {
+ qd_getPixel(vecbuf, x, y, vec);
+
+ dx = vec[0] * (xscale[0]);
+ dy = vec[1] * (yscale[0]);
+
+ u = (x - dx + 0.5f) / (float)stackbuf->x;
+ v = (y - dy + 0.5f) / (float)stackbuf->y;
+
+ qd_getPixelLerp(cbuf, u*cbuf->x - 0.5f, v*cbuf->y - 0.5f, col);
+ qd_setPixel(stackbuf, x, y, col);
+ }
+ }
+*/
+}
+
+
+static void node_composit_exec_displace(void *UNUSED(data), bNode *node, bNodeStack **in, bNodeStack **out)
+{
+ if(out[0]->hasoutput==0)
+ return;
+
+ if(in[0]->data && in[1]->data) {
+ CompBuf *cbuf= in[0]->data;
+ CompBuf *vecbuf= in[1]->data;
+ CompBuf *xbuf= in[2]->data;
+ CompBuf *ybuf= in[3]->data;
+ CompBuf *stackbuf;
+
+ cbuf= typecheck_compbuf(cbuf, CB_RGBA);
+ vecbuf= typecheck_compbuf(vecbuf, CB_VEC3);
+ xbuf= typecheck_compbuf(xbuf, CB_VAL);
+ ybuf= typecheck_compbuf(ybuf, CB_VAL);
+
+ stackbuf= alloc_compbuf(cbuf->x, cbuf->y, CB_RGBA, 1); /* allocs */
+
+ do_displace(node, stackbuf, cbuf, vecbuf, in[1]->vec, xbuf, ybuf, in[2]->vec, in[3]->vec);
+
+ out[0]->data= stackbuf;
+
+
+ if(cbuf!=in[0]->data)
+ free_compbuf(cbuf);
+ if(vecbuf!=in[1]->data)
+ free_compbuf(vecbuf);
+ }
+}
+
+void register_node_type_cmp_displace(ListBase *lb)
+{
+ static bNodeType ntype;
+
+ node_type_base(&ntype, CMP_NODE_DISPLACE, "Displace", NODE_CLASS_DISTORT, NODE_OPTIONS);
+ node_type_socket_templates(&ntype, cmp_node_displace_in, cmp_node_displace_out);
+ node_type_size(&ntype, 140, 100, 320);
+ node_type_exec(&ntype, node_composit_exec_displace);
+
+ nodeRegisterType(lb, &ntype);
+}
+
+
diff --git a/source/blender/nodes/composite/nodes/node_composite_distanceMatte.c b/source/blender/nodes/composite/nodes/node_composite_distanceMatte.c
new file mode 100644
index 00000000000..c895eab391c
--- /dev/null
+++ b/source/blender/nodes/composite/nodes/node_composite_distanceMatte.c
@@ -0,0 +1,148 @@
+/*
+ * $Id: CMP_distanceMatte.c 36536 2011-05-07 13:27:27Z lukastoenne $
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2006 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): Bob Holcomb
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/nodes/composite/nodes/node_composite_distanceMatte.c
+ * \ingroup cmpnodes
+ */
+
+
+#include "node_composite_util.h"
+
+/* ******************* channel Distance Matte ********************************* */
+static bNodeSocketTemplate cmp_node_distance_matte_in[]={
+ {SOCK_RGBA,1,"Image", 0.8f, 0.8f, 0.8f, 1.0f},
+ {SOCK_RGBA,1,"Key Color", 0.8f, 0.8f, 0.8f, 1.0f},
+ {-1,0,""}
+};
+
+static bNodeSocketTemplate cmp_node_distance_matte_out[]={
+ {SOCK_RGBA,0,"Image"},
+ {SOCK_FLOAT,0,"Matte"},
+ {-1,0,""}
+};
+
+/* note, keyvals is passed on from caller as stack array */
+/* might have been nicer as temp struct though... */
+static void do_distance_matte(bNode *node, float *out, float *in)
+{
+ NodeChroma *c= (NodeChroma *)node->storage;
+ float tolerence=c->t1;
+ float falloff=c->t2;
+ float distance;
+ float alpha;
+
+ distance=sqrt((c->key[0]-in[0])*(c->key[0]-in[0]) +
+ (c->key[1]-in[1])*(c->key[1]-in[1]) +
+ (c->key[2]-in[2])*(c->key[2]-in[2]));
+
+ VECCOPY(out, in);
+
+ /*make 100% transparent */
+ if(distance < tolerence) {
+ out[3]=0.0;
+ }
+ /*in the falloff region, make partially transparent */
+ else if(distance < falloff+tolerence){
+ distance=distance-tolerence;
+ alpha=distance/falloff;
+ /*only change if more transparent than before */
+ if(alpha < in[3]) {
+ out[3]=alpha;
+ }
+ else { /* leave as before */
+ out[3]=in[3];
+ }
+ }
+ else {
+ out[3]=in[3];
+ }
+}
+
+static void node_composit_exec_distance_matte(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
+{
+ /*
+ Loosely based on the Sequencer chroma key plug-in, but enhanced to work in other color spaces and
+ uses a different difference function (suggested in forums of vfxtalk.com).
+ */
+ CompBuf *workbuf;
+ CompBuf *inbuf;
+ NodeChroma *c;
+
+ /*is anything connected?*/
+ if(out[0]->hasoutput==0 && out[1]->hasoutput==0) return;
+ /*must have an image imput*/
+ if(in[0]->data==NULL) return;
+
+ inbuf=typecheck_compbuf(in[0]->data, CB_RGBA);
+
+ c=node->storage;
+ workbuf=dupalloc_compbuf(inbuf);
+
+ /*use the input color*/
+ c->key[0]= in[1]->vec[0];
+ c->key[1]= in[1]->vec[1];
+ c->key[2]= in[1]->vec[2];
+
+ /* note, processor gets a keyvals array passed on as buffer constant */
+ composit1_pixel_processor(node, workbuf, workbuf, in[0]->vec, do_distance_matte, CB_RGBA);
+
+
+ out[0]->data=workbuf;
+ if(out[1]->hasoutput)
+ out[1]->data=valbuf_from_rgbabuf(workbuf, CHAN_A);
+ generate_preview(data, node, workbuf);
+
+ if(inbuf!=in[0]->data)
+ free_compbuf(inbuf);
+}
+
+static void node_composit_init_distance_matte(bNodeTree *UNUSED(ntree), bNode* node, bNodeTemplate *UNUSED(ntemp))
+{
+ NodeChroma *c= MEM_callocN(sizeof(NodeChroma), "node chroma");
+ node->storage= c;
+ c->t1= 0.1f;
+ c->t2= 0.1f;
+}
+
+void register_node_type_cmp_distance_matte(ListBase *lb)
+{
+ static bNodeType ntype;
+
+ node_type_base(&ntype, CMP_NODE_DIST_MATTE, "Distance Key", NODE_CLASS_MATTE, NODE_PREVIEW|NODE_OPTIONS);
+ node_type_socket_templates(&ntype, cmp_node_distance_matte_in, cmp_node_distance_matte_out);
+ node_type_size(&ntype, 200, 80, 250);
+ node_type_init(&ntype, node_composit_init_distance_matte);
+ node_type_storage(&ntype, "NodeChroma", node_free_standard_storage, node_copy_standard_storage);
+ node_type_exec(&ntype, node_composit_exec_distance_matte);
+
+ nodeRegisterType(lb, &ntype);
+}
+
+
+
diff --git a/source/blender/nodes/composite/nodes/node_composite_filter.c b/source/blender/nodes/composite/nodes/node_composite_filter.c
new file mode 100644
index 00000000000..6beeec49c63
--- /dev/null
+++ b/source/blender/nodes/composite/nodes/node_composite_filter.c
@@ -0,0 +1,239 @@
+/*
+ * $Id: CMP_filter.c 36593 2011-05-10 11:19:26Z lukastoenne $
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2006 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/nodes/composite/nodes/node_composite_filter.c
+ * \ingroup cmpnodes
+ */
+
+
+#include "node_composite_util.h"
+
+/* **************** FILTER ******************** */
+static bNodeSocketTemplate cmp_node_filter_in[]= {
+ { SOCK_FLOAT, 1, "Fac", 1.0f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f, PROP_FACTOR},
+ { SOCK_RGBA, 1, "Image", 0.8f, 0.8f, 0.8f, 1.0f},
+ { -1, 0, "" }
+};
+static bNodeSocketTemplate cmp_node_filter_out[]= {
+ { SOCK_RGBA, 0, "Image"},
+ { -1, 0, "" }
+};
+
+static void do_filter_edge(CompBuf *out, CompBuf *in, float *filter, float fac)
+{
+ float *row1, *row2, *row3;
+ float *fp, f1, f2, mfac= 1.0f-fac;
+ int rowlen, x, y, c, pix= in->type;
+
+ rowlen= in->x;
+
+ for(y=0; y<in->y; y++) {
+ /* setup rows */
+ if(y==0) row1= in->rect;
+ else row1= in->rect + pix*(y-1)*rowlen;
+
+ row2= in->rect + y*pix*rowlen;
+
+ if(y==in->y-1) row3= row2;
+ else row3= row2 + pix*rowlen;
+
+ fp= out->rect + pix*y*rowlen;
+
+ if(pix==CB_RGBA) {
+ QUATCOPY(fp, row2);
+ fp+= pix;
+
+ for(x=2; x<rowlen; x++) {
+ for(c=0; c<3; c++) {
+ 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];
+ 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];
+ fp[0]= mfac*row2[4] + fac*sqrt(f1*f1 + f2*f2);
+ fp++; row1++; row2++; row3++;
+ }
+ fp[0]= row2[4];
+ /* no alpha... will clear it completely */
+ fp++; row1++; row2++; row3++;
+ }
+ QUATCOPY(fp, row2+4);
+ }
+ else if(pix==CB_VAL) {
+ fp+= pix;
+ for(x=2; x<rowlen; x++) {
+ f1= filter[0]*row1[0] + filter[1]*row1[1] + filter[2]*row1[2] + filter[3]*row2[0] + filter[4]*row2[1] + filter[5]*row2[2] + filter[6]*row3[0] + filter[7]*row3[1] + filter[8]*row3[2];
+ f2= filter[0]*row1[0] + filter[3]*row1[1] + filter[6]*row1[2] + filter[1]*row2[0] + filter[4]*row2[1] + filter[7]*row2[2] + filter[2]*row3[0] + filter[5]*row3[1] + filter[8]*row3[2];
+ fp[0]= mfac*row2[1] + fac*sqrt(f1*f1 + f2*f2);
+ fp++; row1++; row2++; row3++;
+ }
+ }
+ }
+}
+
+static void do_filter3(CompBuf *out, CompBuf *in, float *filter, float fac)
+{
+ float *row1, *row2, *row3;
+ float *fp, mfac= 1.0f-fac;
+ int rowlen, x, y, c;
+ int pixlen= in->type;
+
+ rowlen= in->x;
+
+ for(y=0; y<in->y; y++) {
+ /* setup rows */
+ if(y==0) row1= in->rect;
+ else row1= in->rect + pixlen*(y-1)*rowlen;
+
+ row2= in->rect + y*pixlen*rowlen;
+
+ if(y==in->y-1) row3= row2;
+ else row3= row2 + pixlen*rowlen;
+
+ fp= out->rect + pixlen*(y)*rowlen;
+
+ if(pixlen==1) {
+ fp[0]= row2[0];
+ fp+= 1;
+
+ for(x=2; x<rowlen; x++) {
+ fp[0]= mfac*row2[1] + fac*(filter[0]*row1[0] + filter[1]*row1[1] + filter[2]*row1[2] + filter[3]*row2[0] + filter[4]*row2[1] + filter[5]*row2[2] + filter[6]*row3[0] + filter[7]*row3[1] + filter[8]*row3[2]);
+ fp++; row1++; row2++; row3++;
+ }
+ fp[0]= row2[1];
+ }
+ else if(pixlen==2) {
+ fp[0]= row2[0];
+ fp[1]= row2[1];
+ fp+= 2;
+
+ for(x=2; x<rowlen; x++) {
+ for(c=0; c<2; c++) {
+ fp[0]= mfac*row2[2] + fac*(filter[0]*row1[0] + filter[1]*row1[2] + filter[2]*row1[4] + filter[3]*row2[0] + filter[4]*row2[2] + filter[5]*row2[4] + filter[6]*row3[0] + filter[7]*row3[2] + filter[8]*row3[4]);
+ fp++; row1++; row2++; row3++;
+ }
+ }
+ fp[0]= row2[2];
+ fp[1]= row2[3];
+ }
+ else if(pixlen==3) {
+ VECCOPY(fp, row2);
+ fp+= 3;
+
+ for(x=2; x<rowlen; x++) {
+ for(c=0; c<3; c++) {
+ fp[0]= mfac*row2[3] + fac*(filter[0]*row1[0] + filter[1]*row1[3] + filter[2]*row1[6] + filter[3]*row2[0] + filter[4]*row2[3] + filter[5]*row2[6] + filter[6]*row3[0] + filter[7]*row3[3] + filter[8]*row3[6]);
+ fp++; row1++; row2++; row3++;
+ }
+ }
+ VECCOPY(fp, row2+3);
+ }
+ else {
+ QUATCOPY(fp, row2);
+ fp+= 4;
+
+ for(x=2; x<rowlen; x++) {
+ for(c=0; c<4; c++) {
+ 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]);
+ fp++; row1++; row2++; row3++;
+ }
+ }
+ QUATCOPY(fp, row2+4);
+ }
+ }
+}
+
+
+static void node_composit_exec_filter(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
+{
+ 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};
+ float sharp[9]= {-1,-1,-1,-1,9,-1,-1,-1,-1};
+ 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};
+ float sobel[9]= {1,2,1,0,0,0,-1,-2,-1};
+ float prewitt[9]= {1,1,1,0,0,0,-1,-1,-1};
+ float kirsch[9]= {5,5,5,-3,-3,-3,-2,-2,-2};
+ float shadow[9]= {1,2,1,0,1,0,-1,-2,-1};
+
+ if(out[0]->hasoutput==0) return;
+
+ /* stack order in: Image */
+ /* stack order out: Image */
+
+ if(in[1]->data) {
+ /* make output size of first available input image */
+ CompBuf *cbuf= in[1]->data;
+ CompBuf *stackbuf= alloc_compbuf(cbuf->x, cbuf->y, cbuf->type, 1); /* allocs */
+
+ /* warning note: xof and yof are applied in pixelprocessor, but should be copied otherwise? */
+ stackbuf->xof= cbuf->xof;
+ stackbuf->yof= cbuf->yof;
+
+ switch(node->custom1) {
+ case CMP_FILT_SOFT:
+ do_filter3(stackbuf, cbuf, soft, in[0]->vec[0]);
+ break;
+ case CMP_FILT_SHARP:
+ do_filter3(stackbuf, cbuf, sharp, in[0]->vec[0]);
+ break;
+ case CMP_FILT_LAPLACE:
+ do_filter3(stackbuf, cbuf, laplace, in[0]->vec[0]);
+ break;
+ case CMP_FILT_SOBEL:
+ do_filter_edge(stackbuf, cbuf, sobel, in[0]->vec[0]);
+ break;
+ case CMP_FILT_PREWITT:
+ do_filter_edge(stackbuf, cbuf, prewitt, in[0]->vec[0]);
+ break;
+ case CMP_FILT_KIRSCH:
+ do_filter_edge(stackbuf, cbuf, kirsch, in[0]->vec[0]);
+ break;
+ case CMP_FILT_SHADOW:
+ do_filter3(stackbuf, cbuf, shadow, in[0]->vec[0]);
+ break;
+ }
+
+ out[0]->data= stackbuf;
+
+ generate_preview(data, node, out[0]->data);
+ }
+}
+
+
+void register_node_type_cmp_filter(ListBase *lb)
+{
+ static bNodeType ntype;
+
+ node_type_base(&ntype, CMP_NODE_FILTER, "Filter", NODE_CLASS_OP_FILTER, NODE_PREVIEW|NODE_OPTIONS);
+ node_type_socket_templates(&ntype, cmp_node_filter_in, cmp_node_filter_out);
+ node_type_size(&ntype, 80, 40, 120);
+ node_type_label(&ntype, node_filter_label);
+ node_type_exec(&ntype, node_composit_exec_filter);
+
+ nodeRegisterType(lb, &ntype);
+}
+
+
+
diff --git a/source/blender/nodes/composite/nodes/node_composite_flip.c b/source/blender/nodes/composite/nodes/node_composite_flip.c
new file mode 100644
index 00000000000..026130641a3
--- /dev/null
+++ b/source/blender/nodes/composite/nodes/node_composite_flip.c
@@ -0,0 +1,106 @@
+/*
+ * $Id: CMP_flip.c 36333 2011-04-26 09:27:43Z lukastoenne $
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2006 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/nodes/composite/nodes/node_composite_flip.c
+ * \ingroup cmpnodes
+ */
+
+
+#include "node_composite_util.h"
+
+/* **************** Flip ******************** */
+static bNodeSocketTemplate cmp_node_flip_in[]= {
+ { SOCK_RGBA, 1, "Image", 0.8f, 0.8f, 0.8f, 1.0f},
+ { -1, 0, "" }
+};
+
+static bNodeSocketTemplate cmp_node_flip_out[]= {
+ { SOCK_RGBA, 0, "Image"},
+ { -1, 0, "" }
+};
+
+static void node_composit_exec_flip(void *UNUSED(data), bNode *node, bNodeStack **in, bNodeStack **out)
+{
+ if(in[0]->data) {
+ CompBuf *cbuf= in[0]->data;
+ CompBuf *stackbuf= alloc_compbuf(cbuf->x, cbuf->y, cbuf->type, 1); /* note, this returns zero'd image */
+ int i, src_pix, src_width, src_height, srcydelt, outydelt, x, y;
+ float *srcfp, *outfp;
+
+ src_pix= cbuf->type;
+ src_width= cbuf->x;
+ src_height= cbuf->y;
+ srcfp= cbuf->rect;
+ outfp= stackbuf->rect;
+ srcydelt= src_width*src_pix;
+ outydelt= srcydelt;
+
+ if(node->custom1) { /*set up output pointer for y flip*/
+ outfp+= (src_height-1)*outydelt;
+ outydelt= -outydelt;
+ }
+
+ for(y=0; y<src_height; y++) {
+ if(node->custom1 == 1) { /* no x flip so just copy line*/
+ memcpy(outfp, srcfp, sizeof(float) * src_pix * src_width);
+ srcfp+=srcydelt;
+ }
+ else {
+ outfp += (src_width-1)*src_pix;
+ for(x=0; x<src_width; x++) {
+ for(i=0; i<src_pix; i++) {
+ outfp[i]= srcfp[i];
+ }
+ outfp -= src_pix;
+ srcfp += src_pix;
+ }
+ outfp += src_pix;
+ }
+ outfp += outydelt;
+ }
+
+ out[0]->data= stackbuf;
+
+ }
+}
+
+void register_node_type_cmp_flip(ListBase *lb)
+{
+ static bNodeType ntype;
+
+ node_type_base(&ntype, CMP_NODE_FLIP, "Flip", NODE_CLASS_DISTORT, NODE_OPTIONS);
+ node_type_socket_templates(&ntype, cmp_node_flip_in, cmp_node_flip_out);
+ node_type_size(&ntype, 140, 100, 320);
+ node_type_exec(&ntype, node_composit_exec_flip);
+
+ nodeRegisterType(lb, &ntype);
+}
+
+
+
diff --git a/source/blender/nodes/composite/nodes/node_composite_gamma.c b/source/blender/nodes/composite/nodes/node_composite_gamma.c
new file mode 100644
index 00000000000..d191f649f1f
--- /dev/null
+++ b/source/blender/nodes/composite/nodes/node_composite_gamma.c
@@ -0,0 +1,90 @@
+/*
+* $Id: CMP_gamma.c 36593 2011-05-10 11:19:26Z lukastoenne $
+*
+* ***** BEGIN GPL LICENSE BLOCK *****
+*
+* This program is free software; you can redistribute it and/or
+* modify it under the terms of the GNU General Public License
+* as published by the Free Software Foundation; either version 2
+* of the License, or (at your option) any later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program; if not, write to the Free Software Foundation,
+* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+* The Original Code is Copyright (C) 2006 Blender Foundation.
+* All rights reserved.
+*
+* The Original Code is: all of this file.
+*
+* Contributor(s): none yet.
+*
+* ***** END GPL LICENSE BLOCK *****
+
+*/
+
+/** \file blender/nodes/composite/nodes/node_composite_gamma.c
+ * \ingroup cmpnodes
+ */
+
+
+#include "node_composite_util.h"
+
+/* **************** Gamma Tools ******************** */
+
+static bNodeSocketTemplate cmp_node_gamma_in[]= {
+ { SOCK_RGBA, 1, "Image", 0.8f, 0.8f, 0.8f, 1.0f},
+ { SOCK_FLOAT, 1, "Gamma", 1.0f, 0.0f, 0.0f, 0.0f, 0.001f, 10.0f, PROP_UNSIGNED},
+ { -1, 0, "" }
+};
+static bNodeSocketTemplate cmp_node_gamma_out[]= {
+ { SOCK_RGBA, 0, "Image"},
+ { -1, 0, "" }
+};
+
+static void do_gamma(bNode *UNUSED(node), float *out, float *in, float *fac)
+{
+ int i=0;
+ for(i=0; i<3; i++) {
+ /* check for negative to avoid nan's */
+ out[i] = (in[i] > 0.0f)? pow(in[i],fac[0]): in[i];
+ }
+ out[3] = in[3];
+}
+static void node_composit_exec_gamma(void *UNUSED(data), bNode *node, bNodeStack **in, bNodeStack **out)
+{
+ /* stack order in: Fac, Image */
+ /* stack order out: Image */
+ if(out[0]->hasoutput==0) return;
+
+ /* input no image? then only color operation */
+ if(in[0]->data==NULL) {
+ do_gamma(node, out[0]->vec, in[0]->vec, in[1]->vec);
+ }
+ else {
+ /* make output size of input image */
+ CompBuf *cbuf= in[0]->data;
+ CompBuf *stackbuf= alloc_compbuf(cbuf->x, cbuf->y, CB_RGBA, 1); // allocs
+
+ composit2_pixel_processor(node, stackbuf, cbuf, in[0]->vec, in[1]->data, in[1]->vec, do_gamma, CB_RGBA, CB_VAL);
+
+ out[0]->data= stackbuf;
+ }
+}
+
+void register_node_type_cmp_gamma(ListBase *lb)
+{
+ static bNodeType ntype;
+
+ node_type_base(&ntype, CMP_NODE_GAMMA, "Gamma", NODE_CLASS_OP_COLOR, NODE_OPTIONS);
+ node_type_socket_templates(&ntype, cmp_node_gamma_in, cmp_node_gamma_out);
+ node_type_size(&ntype, 140, 100, 320);
+ node_type_exec(&ntype, node_composit_exec_gamma);
+
+ nodeRegisterType(lb, &ntype);
+}
diff --git a/source/blender/nodes/composite/nodes/node_composite_glare.c b/source/blender/nodes/composite/nodes/node_composite_glare.c
new file mode 100644
index 00000000000..0890b9ba24b
--- /dev/null
+++ b/source/blender/nodes/composite/nodes/node_composite_glare.c
@@ -0,0 +1,506 @@
+/*
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2006 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): Alfredo de Greef (eeshlo)
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/nodes/composite/nodes/node_composite_glare.c
+ * \ingroup cmpnodes
+ */
+
+
+#include "node_composite_util.h"
+
+static bNodeSocketTemplate cmp_node_glare_in[]= {
+ { SOCK_RGBA, 1, "Image", 0.8f, 0.8f, 0.8f, 1.0f},
+ { -1, 0, "" }
+};
+static bNodeSocketTemplate cmp_node_glare_out[]= {
+ { SOCK_RGBA, 0, "Image"},
+ { -1, 0, "" }
+};
+
+
+// mix two images, src buffer does not have to be same size,
+static void mixImages(CompBuf *dst, CompBuf *src, float mix)
+{
+ int x, y;
+ fRGB c1, c2, *dcolp, *scolp;
+ const float mf = 2.f - 2.f*fabsf(mix - 0.5f);
+ if ((dst->x == src->x) && (dst->y == src->y)) {
+ for (y=0; y<dst->y; y++) {
+ dcolp = (fRGB*)&dst->rect[y*dst->x*dst->type];
+ scolp = (fRGB*)&src->rect[y*dst->x*dst->type];
+ for (x=0; x<dst->x; x++) {
+ fRGB_copy(c1, dcolp[x]);
+ fRGB_copy(c2, scolp[x]);
+ c1[0] += mix*(c2[0] - c1[0]);
+ c1[1] += mix*(c2[1] - c1[1]);
+ c1[2] += mix*(c2[2] - c1[2]);
+ if (c1[0] < 0.f) c1[0] = 0.f;
+ if (c1[1] < 0.f) c1[1] = 0.f;
+ if (c1[2] < 0.f) c1[2] = 0.f;
+ fRGB_mult(c1, mf);
+ fRGB_copy(dcolp[x], c1);
+ }
+ }
+ }
+ else {
+ float xr = src->x / (float)dst->x;
+ float yr = src->y / (float)dst->y;
+ for (y=0; y<dst->y; y++) {
+ dcolp = (fRGB*)&dst->rect[y*dst->x*dst->type];
+ for (x=0; x<dst->x; x++) {
+ fRGB_copy(c1, dcolp[x]);
+ qd_getPixelLerp(src, (x + 0.5f)*xr - 0.5f, (y + 0.5f)*yr - 0.5f, c2);
+ c1[0] += mix*(c2[0] - c1[0]);
+ c1[1] += mix*(c2[1] - c1[1]);
+ c1[2] += mix*(c2[2] - c1[2]);
+ if (c1[0] < 0.f) c1[0] = 0.f;
+ if (c1[1] < 0.f) c1[1] = 0.f;
+ if (c1[2] < 0.f) c1[2] = 0.f;
+ fRGB_mult(c1, mf);
+ fRGB_copy(dcolp[x], c1);
+ }
+ }
+ }
+}
+
+
+// adds src to dst image, must be of same size
+static void addImage(CompBuf* dst, CompBuf* src, float scale)
+{
+ if ((dst->x == src->x) && (dst->y == src->y)) {
+ int p = dst->x*dst->y*dst->type;
+ float *dcol = dst->rect, *scol = src->rect;
+ while (p--) *dcol++ += *scol++ * scale;
+ }
+}
+
+
+// returns possibly downscaled copy of all pixels above threshold
+static CompBuf* BTP(CompBuf* src, float threshold, int scaledown)
+{
+ int x, y;
+ CompBuf* bsrc = qd_downScaledCopy(src, scaledown);
+ float* cr = bsrc->rect;
+ for (y=0; y<bsrc->y; ++y)
+ for (x=0; x<bsrc->x; ++x, cr+=4) {
+ if ((0.212671f*cr[0] + 0.71516f*cr[1] + 0.072169f*cr[2]) >= threshold) {
+ cr[0] -= threshold, cr[1] -= threshold, cr[2] -= threshold;
+ cr[0] = MAX2(cr[0], 0.f);
+ cr[1] = MAX2(cr[1], 0.f);
+ cr[2] = MAX2(cr[2], 0.f);
+ }
+ else cr[0] = cr[1] = cr[2] = 0.f;
+ }
+ return bsrc;
+}
+
+//--------------------------------------------------------------------------------------------
+// simple 4-point star filter
+
+static void star4(NodeGlare* ndg, CompBuf* dst, CompBuf* src)
+{
+ int x, y, i, xm, xp, ym, yp;
+ float c[4] = {0,0,0,0}, tc[4] = {0,0,0,0};
+ CompBuf *tbuf1, *tbuf2, *tsrc;
+ const float f1 = 1.f - ndg->fade, f2 = (1.f - f1)*0.5f;
+ //const float t3 = ndg->threshold*3.f;
+ const float sc = (float)(1 << ndg->quality);
+ const float isc = 1.f/sc;
+
+ tsrc = BTP(src, ndg->threshold, (int)sc);
+
+ tbuf1 = dupalloc_compbuf(tsrc);
+ tbuf2 = dupalloc_compbuf(tsrc);
+
+ for (i=0; i<ndg->iter; i++) {
+ // (x || x-1, y-1) to (x || x+1, y+1)
+ // F
+ for (y=0; y<tbuf1->y; y++) {
+ ym = y - i;
+ yp = y + i;
+ for (x=0; x<tbuf1->x; x++) {
+ xm = x - i;
+ xp = x + i;
+ qd_getPixel(tbuf1, x, y, c);
+ fRGB_mult(c, f1);
+ qd_getPixel(tbuf1, (ndg->angle ? xm : x), ym, tc);
+ fRGB_madd(c, tc, f2);
+ qd_getPixel(tbuf1, (ndg->angle ? xp : x), yp, tc);
+ fRGB_madd(c, tc, f2);
+ qd_setPixel(tbuf1, x, y, c);
+ }
+ }
+ // B
+ for (y=tbuf1->y-1; y>=0; y--) {
+ ym = y - i;
+ yp = y + i;
+ for (x=tbuf1->x-1; x>=0; x--) {
+ xm = x - i;
+ xp = x + i;
+ qd_getPixel(tbuf1, x, y, c);
+ fRGB_mult(c, f1);
+ qd_getPixel(tbuf1, (ndg->angle ? xm : x), ym, tc);
+ fRGB_madd(c, tc, f2);
+ qd_getPixel(tbuf1, (ndg->angle ? xp : x), yp, tc);
+ fRGB_madd(c, tc, f2);
+ qd_setPixel(tbuf1, x, y, c);
+ }
+ }
+ // (x-1, y || y+1) to (x+1, y || y-1)
+ // F
+ for (y=0; y<tbuf2->y; y++) {
+ ym = y - i;
+ yp = y + i;
+ for (x=0; x<tbuf2->x; x++) {
+ xm = x - i;
+ xp = x + i;
+ qd_getPixel(tbuf2, x, y, c);
+ fRGB_mult(c, f1);
+ qd_getPixel(tbuf2, xm, (ndg->angle ? yp : y), tc);
+ fRGB_madd(c, tc, f2);
+ qd_getPixel(tbuf2, xp, (ndg->angle ? ym : y), tc);
+ fRGB_madd(c, tc, f2);
+ qd_setPixel(tbuf2, x, y, c);
+ }
+ }
+ // B
+ for (y=tbuf2->y-1; y>=0; y--) {
+ ym = y - i;
+ yp = y + i;
+ for (x=tbuf2->x-1; x>=0; x--) {
+ xm = x - i;
+ xp = x + i;
+ qd_getPixel(tbuf2, x, y, c);
+ fRGB_mult(c, f1);
+ qd_getPixel(tbuf2, xm, (ndg->angle ? yp : y), tc);
+ fRGB_madd(c, tc, f2);
+ qd_getPixel(tbuf2, xp, (ndg->angle ? ym : y), tc);
+ fRGB_madd(c, tc, f2);
+ qd_setPixel(tbuf2, x, y, c);
+ }
+ }
+ }
+
+ for (y=0; y<tbuf1->y; ++y)
+ for (x=0; x<tbuf1->x; ++x) {
+ unsigned int p = (x + y*tbuf1->x)*tbuf1->type;
+ tbuf1->rect[p] += tbuf2->rect[p];
+ tbuf1->rect[p+1] += tbuf2->rect[p+1];
+ tbuf1->rect[p+2] += tbuf2->rect[p+2];
+ }
+
+ for (y=0; y<dst->y; ++y) {
+ const float m = 0.5f + 0.5f*ndg->mix;
+ for (x=0; x<dst->x; ++x) {
+ unsigned int p = (x + y*dst->x)*dst->type;
+ qd_getPixelLerp(tbuf1, x*isc, y*isc, tc);
+ dst->rect[p] = src->rect[p] + m*(tc[0] - src->rect[p]);
+ dst->rect[p+1] = src->rect[p+1] + m*(tc[1] - src->rect[p+1]);
+ dst->rect[p+2] = src->rect[p+2] + m*(tc[2] - src->rect[p+2]);
+ }
+ }
+
+ free_compbuf(tbuf1);
+ free_compbuf(tbuf2);
+ free_compbuf(tsrc);
+}
+
+//--------------------------------------------------------------------------------------------
+// streak filter
+
+static void streaks(NodeGlare* ndg, CompBuf* dst, CompBuf* src)
+{
+ CompBuf *bsrc, *tsrc, *tdst, *sbuf;
+ int x, y, n;
+ unsigned int nump=0;
+ fRGB c1, c2, c3, c4;
+ float a, ang = 360.f/(float)ndg->angle;
+
+ bsrc = BTP(src, ndg->threshold, 1 << ndg->quality);
+ tsrc = dupalloc_compbuf(bsrc); // sample from buffer
+ tdst = alloc_compbuf(tsrc->x, tsrc->y, tsrc->type, 1); // sample to buffer
+ sbuf = alloc_compbuf(tsrc->x, tsrc->y, tsrc->type, 1); // streak sum buffer
+
+
+ for (a=0.f; a<360.f; a+=ang) {
+ const float an = (a + (float)ndg->angle_ofs)*(float)M_PI/180.f;
+ const float vx = cos((double)an), vy = sin((double)an);
+ for (n=0; n<ndg->iter; ++n) {
+ const float p4 = pow(4.0, (double)n);
+ const float vxp = vx*p4, vyp = vy*p4;
+ const float wt = pow((double)ndg->fade, (double)p4);
+ const float cmo = 1.f - pow((double)ndg->colmod, (double)n+1); // colormodulation amount relative to current pass
+ float* tdstcol = tdst->rect;
+ for (y=0; y<tsrc->y; ++y) {
+ for (x=0; x<tsrc->x; ++x, tdstcol+=4) {
+ // first pass no offset, always same for every pass, exact copy,
+ // otherwise results in uneven brightness, only need once
+ if (n==0) qd_getPixel(tsrc, x, y, c1); else c1[0]=c1[1]=c1[2]=0;
+ qd_getPixelLerp(tsrc, x + vxp, y + vyp, c2);
+ qd_getPixelLerp(tsrc, x + vxp*2.f, y + vyp*2.f, c3);
+ qd_getPixelLerp(tsrc, x + vxp*3.f, y + vyp*3.f, c4);
+ // modulate color to look vaguely similar to a color spectrum
+ fRGB_rgbmult(c2, 1.f, cmo, cmo);
+ fRGB_rgbmult(c3, cmo, cmo, 1.f);
+ fRGB_rgbmult(c4, cmo, 1.f, cmo);
+ tdstcol[0] = 0.5f*(tdstcol[0] + c1[0] + wt*(c2[0] + wt*(c3[0] + wt*c4[0])));
+ tdstcol[1] = 0.5f*(tdstcol[1] + c1[1] + wt*(c2[1] + wt*(c3[1] + wt*c4[1])));
+ tdstcol[2] = 0.5f*(tdstcol[2] + c1[2] + wt*(c2[2] + wt*(c3[2] + wt*c4[2])));
+ }
+ }
+ memcpy(tsrc->rect, tdst->rect, sizeof(float)*tdst->x*tdst->y*tdst->type);
+ }
+
+ addImage(sbuf, tsrc, 1.f/(float)(6 - ndg->iter));
+ memset(tdst->rect, 0, tdst->x*tdst->y*tdst->type*sizeof(float));
+ memcpy(tsrc->rect, bsrc->rect, bsrc->x*bsrc->y*bsrc->type*sizeof(float));
+ nump++;
+ }
+
+ mixImages(dst, sbuf, 0.5f + 0.5f*ndg->mix);
+
+ free_compbuf(tsrc);
+ free_compbuf(tdst);
+ free_compbuf(sbuf);
+ free_compbuf(bsrc);
+}
+
+
+//--------------------------------------------------------------------------------------------
+// Ghosts (lensflare)
+
+static float smoothMask(float x, float y)
+{
+ float t;
+ x = 2.f*x - 1.f, y = 2.f*y - 1.f;
+ if ((t = 1.f - sqrtf(x*x + y*y)) <= 0.f) return 0.f;
+ return t;
+}
+
+static void ghosts(NodeGlare* ndg, CompBuf* dst, CompBuf* src)
+{
+ // colormodulation and scale factors (cm & scalef) for 16 passes max: 64
+ int x, y, n, p, np;
+ fRGB c, tc, cm[64];
+ float sc, isc, u, v, sm, s, t, ofs, scalef[64];
+ CompBuf *tbuf1, *tbuf2, *gbuf;
+ const float cmo = 1.f - ndg->colmod;
+ const int qt = 1 << ndg->quality;
+ const float s1 = 4.f/(float)qt, s2 = 2.f*s1;
+
+ gbuf = BTP(src, ndg->threshold, qt);
+ tbuf1 = dupalloc_compbuf(gbuf);
+ IIR_gauss(tbuf1, s1, 0, 3);
+ IIR_gauss(tbuf1, s1, 1, 3);
+ IIR_gauss(tbuf1, s1, 2, 3);
+ tbuf2 = dupalloc_compbuf(tbuf1);
+ IIR_gauss(tbuf2, s2, 0, 3);
+ IIR_gauss(tbuf2, s2, 1, 3);
+ IIR_gauss(tbuf2, s2, 2, 3);
+
+ if (ndg->iter & 1) ofs = 0.5f; else ofs = 0.f;
+ for (x=0; x<(ndg->iter*4); x++) {
+ y = x & 3;
+ cm[x][0] = cm[x][1] = cm[x][2] = 1;
+ if (y==1) fRGB_rgbmult(cm[x], 1.f, cmo, cmo);
+ if (y==2) fRGB_rgbmult(cm[x], cmo, cmo, 1.f);
+ if (y==3) fRGB_rgbmult(cm[x], cmo, 1.f, cmo);
+ scalef[x] = 2.1f*(1.f-(x+ofs)/(float)(ndg->iter*4));
+ if (x & 1) scalef[x] = -0.99f/scalef[x];
+ }
+
+ sc = 2.13;
+ isc = -0.97;
+ for (y=0; y<gbuf->y; y++) {
+ v = (float)(y+0.5f) / (float)gbuf->y;
+ for (x=0; x<gbuf->x; x++) {
+ u = (float)(x+0.5f) / (float)gbuf->x;
+ s = (u-0.5f)*sc + 0.5f, t = (v-0.5f)*sc + 0.5f;
+ qd_getPixelLerp(tbuf1, s*gbuf->x, t*gbuf->y, c);
+ sm = smoothMask(s, t);
+ fRGB_mult(c, sm);
+ s = (u-0.5f)*isc + 0.5f, t = (v-0.5f)*isc + 0.5f;
+ qd_getPixelLerp(tbuf2, s*gbuf->x - 0.5f, t*gbuf->y - 0.5f, tc);
+ sm = smoothMask(s, t);
+ fRGB_madd(c, tc, sm);
+ qd_setPixel(gbuf, x, y, c);
+ }
+ }
+
+ memset(tbuf1->rect, 0, tbuf1->x*tbuf1->y*tbuf1->type*sizeof(float));
+ for (n=1; n<ndg->iter; n++) {
+ for (y=0; y<gbuf->y; y++) {
+ v = (float)(y+0.5f) / (float)gbuf->y;
+ for (x=0; x<gbuf->x; x++) {
+ u = (float)(x+0.5f) / (float)gbuf->x;
+ tc[0] = tc[1] = tc[2] = 0.f;
+ for (p=0;p<4;p++) {
+ np = (n<<2) + p;
+ s = (u-0.5f)*scalef[np] + 0.5f;
+ t = (v-0.5f)*scalef[np] + 0.5f;
+ qd_getPixelLerp(gbuf, s*gbuf->x - 0.5f, t*gbuf->y - 0.5f, c);
+ fRGB_colormult(c, cm[np]);
+ sm = smoothMask(s, t)*0.25f;
+ fRGB_madd(tc, c, sm);
+ }
+ p = (x + y*tbuf1->x)*tbuf1->type;
+ tbuf1->rect[p] += tc[0];
+ tbuf1->rect[p+1] += tc[1];
+ tbuf1->rect[p+2] += tc[2];
+ }
+ }
+ memcpy(gbuf->rect, tbuf1->rect, tbuf1->x*tbuf1->y*tbuf1->type*sizeof(float));
+ }
+
+ free_compbuf(tbuf1);
+ free_compbuf(tbuf2);
+
+ mixImages(dst, gbuf, 0.5f + 0.5f*ndg->mix);
+ free_compbuf(gbuf);
+}
+
+//--------------------------------------------------------------------------------------------
+// Fog glow (convolution with kernel of exponential falloff)
+
+static void fglow(NodeGlare* ndg, CompBuf* dst, CompBuf* src)
+{
+ int x, y;
+ float scale, u, v, r, w, d;
+ fRGB fcol;
+ CompBuf *tsrc, *ckrn;
+ unsigned int sz = 1 << ndg->size;
+ const float cs_r = 1.f, cs_g = 1.f, cs_b = 1.f;
+
+ // temp. src image
+ tsrc = BTP(src, ndg->threshold, 1 << ndg->quality);
+ // make the convolution kernel
+ ckrn = alloc_compbuf(sz, sz, CB_RGBA, 1);
+
+ scale = 0.25f*sqrtf(sz*sz);
+
+ for (y=0; y<sz; ++y) {
+ v = 2.f*(y / (float)sz) - 1.f;
+ for (x=0; x<sz; ++x) {
+ u = 2.f*(x / (float)sz) - 1.f;
+ r = (u*u + v*v)*scale;
+ d = -sqrtf(sqrtf(sqrtf(r)))*9.f;
+ fcol[0] = expf(d*cs_r), fcol[1] = expf(d*cs_g), fcol[2] = expf(d*cs_b);
+ // linear window good enough here, visual result counts, not scientific analysis
+ //w = (1.f-fabs(u))*(1.f-fabs(v));
+ // actually, Hanning window is ok, cos^2 for some reason is slower
+ w = (0.5f + 0.5f*cos((double)u*M_PI))*(0.5f + 0.5f*cos((double)v*M_PI));
+ fRGB_mult(fcol, w);
+ qd_setPixel(ckrn, x, y, fcol);
+ }
+ }
+
+ convolve(tsrc, tsrc, ckrn);
+ free_compbuf(ckrn);
+ mixImages(dst, tsrc, 0.5f + 0.5f*ndg->mix);
+ free_compbuf(tsrc);
+}
+
+//--------------------------------------------------------------------------------------------
+
+static void node_composit_exec_glare(void *UNUSED(data), bNode *node, bNodeStack **in, bNodeStack **out)
+{
+ CompBuf *new, *src, *img = in[0]->data;
+ NodeGlare* ndg = node->storage;
+
+ if ((img == NULL) || (out[0]->hasoutput == 0)) return;
+
+ if (img->type != CB_RGBA) {
+ new = typecheck_compbuf(img, CB_RGBA);
+ src = typecheck_compbuf(img, CB_RGBA);
+ } else {
+ new = dupalloc_compbuf(img);
+ src = dupalloc_compbuf(img);
+ }
+
+ {
+ int x, y;
+ for (y=0; y<new->y; ++y) {
+ fRGB* col = (fRGB*)&new->rect[y*new->x*new->type];
+ for (x=0; x<new->x; ++x) {
+ col[x][0] = MAX2(col[x][0], 0.f);
+ col[x][1] = MAX2(col[x][1], 0.f);
+ col[x][2] = MAX2(col[x][2], 0.f);
+ }
+ }
+ }
+
+ switch (ndg->type) {
+ case 0:
+ star4(ndg, new, src);
+ break;
+ case 1:
+ fglow(ndg, new, src);
+ break;
+ case 3:
+ ghosts(ndg, new, src);
+ break;
+ case 2:
+ default:
+ streaks(ndg, new, src);
+ break;
+ }
+
+ free_compbuf(src);
+ out[0]->data = new;
+}
+
+static void node_composit_init_glare(bNodeTree *UNUSED(ntree), bNode* node, bNodeTemplate *UNUSED(ntemp))
+{
+ NodeGlare *ndg = MEM_callocN(sizeof(NodeGlare), "node glare data");
+ ndg->quality = 1;
+ ndg->type = 2;
+ ndg->iter = 3;
+ ndg->colmod = 0.25;
+ ndg->mix = 0;
+ ndg->threshold = 1;
+ ndg->angle = 4;
+ ndg->angle_ofs = 0;
+ ndg->fade = 0.9;
+ ndg->size = 8;
+ node->storage = ndg;
+}
+
+void register_node_type_cmp_glare(ListBase *lb)
+{
+ static bNodeType ntype;
+
+ node_type_base(&ntype, CMP_NODE_GLARE, "Glare", NODE_CLASS_OP_FILTER, NODE_OPTIONS);
+ node_type_socket_templates(&ntype, cmp_node_glare_in, cmp_node_glare_out);
+ node_type_size(&ntype, 150, 120, 200);
+ node_type_init(&ntype, node_composit_init_glare);
+ node_type_storage(&ntype, "NodeGlare", node_free_standard_storage, node_copy_standard_storage);
+ node_type_exec(&ntype, node_composit_exec_glare);
+
+ nodeRegisterType(lb, &ntype);
+}
+
diff --git a/source/blender/nodes/composite/nodes/node_composite_hueSatVal.c b/source/blender/nodes/composite/nodes/node_composite_hueSatVal.c
new file mode 100644
index 00000000000..525728ade31
--- /dev/null
+++ b/source/blender/nodes/composite/nodes/node_composite_hueSatVal.c
@@ -0,0 +1,122 @@
+/*
+ * $Id: CMP_hueSatVal.c 36593 2011-05-10 11:19:26Z lukastoenne $
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2006 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/nodes/composite/nodes/node_composite_hueSatVal.c
+ * \ingroup cmpnodes
+ */
+
+
+#include "node_composite_util.h"
+
+
+/* **************** Hue Saturation ******************** */
+static bNodeSocketTemplate cmp_node_hue_sat_in[]= {
+ { SOCK_FLOAT, 1, "Fac", 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR},
+ { SOCK_RGBA, 1, "Image", 0.8f, 0.8f, 0.8f, 1.0f},
+ { -1, 0, "" }
+};
+static bNodeSocketTemplate cmp_node_hue_sat_out[]= {
+ { SOCK_RGBA, 0, "Image"},
+ { -1, 0, "" }
+};
+
+static void do_hue_sat_fac(bNode *node, float *out, float *in, float *fac)
+{
+ NodeHueSat *nhs= node->storage;
+
+ if(*fac!=0.0f && (nhs->hue!=0.5f || nhs->sat!=1.0 || nhs->val!=1.0)) {
+ float col[3], hsv[3], mfac= 1.0f - *fac;
+
+ rgb_to_hsv(in[0], in[1], in[2], hsv, hsv+1, hsv+2);
+ hsv[0]+= (nhs->hue - 0.5f);
+ if(hsv[0]>1.0) hsv[0]-=1.0; else if(hsv[0]<0.0) hsv[0]+= 1.0;
+ hsv[1]*= nhs->sat;
+ hsv[2]*= nhs->val;
+ hsv_to_rgb(hsv[0], hsv[1], hsv[2], col, col+1, col+2);
+
+ out[0]= mfac*in[0] + *fac*col[0];
+ out[1]= mfac*in[1] + *fac*col[1];
+ out[2]= mfac*in[2] + *fac*col[2];
+ out[3]= in[3];
+ }
+ else {
+ QUATCOPY(out, in);
+ }
+}
+
+static void node_composit_exec_hue_sat(void *UNUSED(data), bNode *node, bNodeStack **in, bNodeStack **out)
+{
+ /* stack order in: Fac, Image */
+ /* stack order out: Image */
+ if(out[0]->hasoutput==0) return;
+
+ /* input no image? then only color operation */
+ if(in[1]->data==NULL) {
+ do_hue_sat_fac(node, out[0]->vec, in[1]->vec, in[0]->vec);
+ }
+ else {
+ /* make output size of input image */
+ CompBuf *cbuf= dupalloc_compbuf(in[1]->data);
+ CompBuf *stackbuf=typecheck_compbuf(cbuf,CB_RGBA);
+
+ composit2_pixel_processor(node, stackbuf, stackbuf, in[1]->vec, in[0]->data, in[0]->vec, do_hue_sat_fac, CB_RGBA, CB_VAL);
+
+ out[0]->data= stackbuf;
+
+ /* get rid of intermediary cbuf if it's extra */
+ if(stackbuf!=cbuf)
+ free_compbuf(cbuf);
+ }
+}
+
+static void node_composit_init_hue_sat(bNodeTree *UNUSED(ntree), bNode* node, bNodeTemplate *UNUSED(ntemp))
+{
+ NodeHueSat *nhs= MEM_callocN(sizeof(NodeHueSat), "node hue sat");
+ node->storage= nhs;
+ nhs->hue= 0.5f;
+ nhs->sat= 1.0f;
+ nhs->val= 1.0f;
+}
+
+void register_node_type_cmp_hue_sat(ListBase *lb)
+{
+ static bNodeType ntype;
+
+ node_type_base(&ntype, CMP_NODE_HUE_SAT, "Hue Saturation Value", NODE_CLASS_OP_COLOR, NODE_OPTIONS);
+ node_type_socket_templates(&ntype, cmp_node_hue_sat_in, cmp_node_hue_sat_out);
+ node_type_size(&ntype, 150, 80, 250);
+ node_type_init(&ntype, node_composit_init_hue_sat);
+ node_type_storage(&ntype, "NodeHueSat", node_free_standard_storage, node_copy_standard_storage);
+ node_type_exec(&ntype, node_composit_exec_hue_sat);
+
+ nodeRegisterType(lb, &ntype);
+}
+
+
+
diff --git a/source/blender/nodes/composite/nodes/node_composite_huecorrect.c b/source/blender/nodes/composite/nodes/node_composite_huecorrect.c
new file mode 100644
index 00000000000..edf26aed882
--- /dev/null
+++ b/source/blender/nodes/composite/nodes/node_composite_huecorrect.c
@@ -0,0 +1,170 @@
+/*
+ * $Id: CMP_huecorrect.c 36593 2011-05-10 11:19:26Z lukastoenne $
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2006 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): Matt Ebb
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/nodes/composite/nodes/node_composite_huecorrect.c
+ * \ingroup cmpnodes
+ */
+
+
+#include "node_composite_util.h"
+
+static bNodeSocketTemplate cmp_node_huecorrect_in[]= {
+ { SOCK_FLOAT, 1, "Fac", 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, PROP_FACTOR},
+ { SOCK_RGBA, 1, "Image", 0.0f, 0.0f, 0.0f, 1.0f},
+ { -1, 0, "" }
+};
+
+static bNodeSocketTemplate cmp_node_huecorrect_out[]= {
+ { SOCK_RGBA, 0, "Image"},
+ { -1, 0, "" }
+};
+
+static void do_huecorrect(bNode *node, float *out, float *in)
+{
+ float hsv[3], f;
+
+ rgb_to_hsv(in[0], in[1], in[2], hsv, hsv+1, hsv+2);
+
+ /* adjust hue, scaling returned default 0.5 up to 1 */
+ f = curvemapping_evaluateF(node->storage, 0, hsv[0]);
+ hsv[0] += f-0.5f;
+
+ /* adjust saturation, scaling returned default 0.5 up to 1 */
+ f = curvemapping_evaluateF(node->storage, 1, hsv[0]);
+ hsv[1] *= (f * 2.f);
+
+ /* adjust value, scaling returned default 0.5 up to 1 */
+ f = curvemapping_evaluateF(node->storage, 2, hsv[0]);
+ hsv[2] *= (f * 2.f);
+
+ hsv[0] = hsv[0] - floor(hsv[0]); /* mod 1.0 */
+ CLAMP(hsv[1], 0.f, 1.f);
+
+ /* convert back to rgb */
+ hsv_to_rgb(hsv[0], hsv[1], hsv[2], out, out+1, out+2);
+
+ out[3]= in[3];
+}
+
+static void do_huecorrect_fac(bNode *node, float *out, float *in, float *fac)
+{
+ float hsv[3], rgb[3], f;
+ const float mfac = 1.f-*fac;
+
+ rgb_to_hsv(in[0], in[1], in[2], hsv, hsv+1, hsv+2);
+
+ /* adjust hue, scaling returned default 0.5 up to 1 */
+ f = curvemapping_evaluateF(node->storage, 0, hsv[0]);
+ hsv[0] += f-0.5f;
+
+ /* adjust saturation, scaling returned default 0.5 up to 1 */
+ f = curvemapping_evaluateF(node->storage, 1, hsv[0]);
+ hsv[1] *= (f * 2.f);
+
+ /* adjust value, scaling returned default 0.5 up to 1 */
+ f = curvemapping_evaluateF(node->storage, 2, hsv[0]);
+ hsv[2] *= (f * 2.f);
+
+ hsv[0] = hsv[0] - floor(hsv[0]); /* mod 1.0 */
+ CLAMP(hsv[1], 0.f, 1.f);
+
+ /* convert back to rgb */
+ hsv_to_rgb(hsv[0], hsv[1], hsv[2], rgb, rgb+1, rgb+2);
+
+ out[0]= mfac*in[0] + *fac*rgb[0];
+ out[1]= mfac*in[1] + *fac*rgb[1];
+ out[2]= mfac*in[2] + *fac*rgb[2];
+ out[3]= in[3];
+}
+
+static void node_composit_exec_huecorrect(void *UNUSED(data), bNode *node, bNodeStack **in, bNodeStack **out)
+{
+ CompBuf *cbuf= in[1]->data;
+ CompBuf *stackbuf;
+
+ /* stack order input: fac, image, black level, white level */
+ /* stack order output: image */
+
+ if(out[0]->hasoutput==0)
+ return;
+
+ if(in[0]->vec[0] == 0.f && in[0]->data == NULL) {
+ out[0]->data = pass_on_compbuf(cbuf);
+ return;
+ }
+
+ /* input no image? then only color operation */
+ if(in[1]->data==NULL) {
+ do_huecorrect_fac(node, out[0]->vec, in[1]->vec, in[0]->vec);
+ }
+
+ if (cbuf) {
+ stackbuf= alloc_compbuf(cbuf->x, cbuf->y, CB_RGBA, 1); /* make output size of input image */
+
+ if ((in[0]->data==NULL) && (in[0]->vec[0] >= 1.f))
+ composit1_pixel_processor(node, stackbuf, in[1]->data, in[1]->vec, do_huecorrect, CB_RGBA);
+ else
+ composit2_pixel_processor(node, stackbuf, in[1]->data, in[1]->vec, in[0]->data, in[0]->vec, do_huecorrect_fac, CB_RGBA, CB_VAL);
+
+ out[0]->data= stackbuf;
+ }
+
+}
+
+static void node_composit_init_huecorrect(bNodeTree *UNUSED(ntree), bNode* node, bNodeTemplate *UNUSED(ntemp))
+{
+ CurveMapping *cumapping = node->storage= curvemapping_add(1, 0.0f, 0.0f, 1.0f, 1.0f);
+ int c;
+
+ cumapping->preset = CURVE_PRESET_MID9;
+
+ for (c=0; c<3; c++) {
+ CurveMap *cuma = &cumapping->cm[c];
+ curvemap_reset(cuma, &cumapping->clipr, cumapping->preset, CURVEMAP_SLOPE_POSITIVE);
+ }
+
+ /* default to showing Saturation */
+ cumapping->cur = 1;
+}
+
+void register_node_type_cmp_huecorrect(ListBase *lb)
+{
+ static bNodeType ntype;
+
+ node_type_base(&ntype, CMP_NODE_HUECORRECT, "Hue Correct", NODE_CLASS_OP_COLOR, NODE_OPTIONS);
+ node_type_socket_templates(&ntype, cmp_node_huecorrect_in, cmp_node_huecorrect_out);
+ node_type_size(&ntype, 320, 140, 400);
+ node_type_init(&ntype, node_composit_init_huecorrect);
+ node_type_storage(&ntype, "CurveMapping", node_free_curves, node_copy_curves);
+ node_type_exec(&ntype, node_composit_exec_huecorrect);
+
+ nodeRegisterType(lb, &ntype);
+}
+
+
diff --git a/source/blender/nodes/composite/nodes/node_composite_idMask.c b/source/blender/nodes/composite/nodes/node_composite_idMask.c
new file mode 100644
index 00000000000..97d84997697
--- /dev/null
+++ b/source/blender/nodes/composite/nodes/node_composite_idMask.c
@@ -0,0 +1,125 @@
+/*
+ * $Id: CMP_idMask.c 36593 2011-05-10 11:19:26Z lukastoenne $
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2006 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/nodes/composite/nodes/node_composite_idMask.c
+ * \ingroup cmpnodes
+ */
+
+
+#include "node_composite_util.h"
+
+
+/* **************** ID Mask ******************** */
+
+static bNodeSocketTemplate cmp_node_idmask_in[]= {
+ { SOCK_FLOAT, 1, "ID value", 0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f, PROP_NONE},
+ { -1, 0, "" }
+};
+static bNodeSocketTemplate cmp_node_idmask_out[]= {
+ { SOCK_FLOAT, 0, "Alpha"},
+ { -1, 0, "" }
+};
+
+/* stackbuf should be zeroed */
+static void do_idmask(CompBuf *stackbuf, CompBuf *cbuf, float idnr)
+{
+ float *rect;
+ int x;
+ char *abuf= MEM_mapallocN(cbuf->x*cbuf->y, "anti ali buf");
+
+ rect= cbuf->rect;
+ for(x= cbuf->x*cbuf->y - 1; x>=0; x--)
+ if(rect[x]==idnr)
+ abuf[x]= 255;
+
+ antialias_tagbuf(cbuf->x, cbuf->y, abuf);
+
+ rect= stackbuf->rect;
+ for(x= cbuf->x*cbuf->y - 1; x>=0; x--)
+ if(abuf[x]>1)
+ rect[x]= (1.0f/255.0f)*(float)abuf[x];
+
+ MEM_freeN(abuf);
+}
+
+/* full sample version */
+static void do_idmask_fsa(CompBuf *stackbuf, CompBuf *cbuf, float idnr)
+{
+ float *rect, *rs;
+ int x;
+
+ rect= cbuf->rect;
+ rs= stackbuf->rect;
+ for(x= cbuf->x*cbuf->y - 1; x>=0; x--)
+ if(rect[x]==idnr)
+ rs[x]= 1.0f;
+
+}
+
+
+static void node_composit_exec_idmask(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
+{
+ RenderData *rd= data;
+
+ if(out[0]->hasoutput==0)
+ return;
+
+ if(in[0]->data) {
+ CompBuf *cbuf= in[0]->data;
+ CompBuf *stackbuf;
+
+ if(cbuf->type!=CB_VAL)
+ return;
+
+ stackbuf= alloc_compbuf(cbuf->x, cbuf->y, CB_VAL, 1); /* allocs */;
+
+ if(rd->scemode & R_FULL_SAMPLE)
+ do_idmask_fsa(stackbuf, cbuf, (float)node->custom1);
+ else
+ do_idmask(stackbuf, cbuf, (float)node->custom1);
+
+ out[0]->data= stackbuf;
+ }
+}
+
+
+void register_node_type_cmp_idmask(ListBase *lb)
+{
+ static bNodeType ntype;
+
+ node_type_base(&ntype, CMP_NODE_ID_MASK, "ID Mask", NODE_CLASS_CONVERTOR, NODE_OPTIONS);
+ node_type_socket_templates(&ntype, cmp_node_idmask_in, cmp_node_idmask_out);
+ node_type_size(&ntype, 140, 100, 320);
+ node_type_exec(&ntype, node_composit_exec_idmask);
+
+ nodeRegisterType(lb, &ntype);
+}
+
+
+
diff --git a/source/blender/nodes/composite/nodes/node_composite_image.c b/source/blender/nodes/composite/nodes/node_composite_image.c
new file mode 100644
index 00000000000..1278202d5b5
--- /dev/null
+++ b/source/blender/nodes/composite/nodes/node_composite_image.c
@@ -0,0 +1,452 @@
+/*
+ * $Id: CMP_image.c 36536 2011-05-07 13:27:27Z lukastoenne $
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2006 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/nodes/composite/nodes/node_composite_image.c
+ * \ingroup cmpnodes
+ */
+
+
+#include "node_composite_util.h"
+
+
+/* **************** IMAGE (and RenderResult, multilayer image) ******************** */
+
+static bNodeSocketTemplate cmp_node_rlayers_out[]= {
+ { SOCK_RGBA, 0, "Image", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
+ { SOCK_FLOAT, 0, "Alpha", 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
+ { SOCK_FLOAT, 0, "Z", 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
+ { SOCK_VECTOR, 0, "Normal", 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
+ { SOCK_VECTOR, 0, "UV", 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
+ { SOCK_VECTOR, 0, "Speed", 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
+ { SOCK_RGBA, 0, "Color", 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
+ { SOCK_RGBA, 0, "Diffuse", 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
+ { SOCK_RGBA, 0, "Specular", 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
+ { SOCK_RGBA, 0, "Shadow", 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
+ { SOCK_RGBA, 0, "AO", 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
+ { SOCK_RGBA, 0, "Reflect", 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
+ { SOCK_RGBA, 0, "Refract", 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
+ { SOCK_RGBA, 0, "Indirect", 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
+ { SOCK_FLOAT, 0, "IndexOB", 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
+ { SOCK_FLOAT, 0, "IndexMA", 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
+ { SOCK_FLOAT, 0, "Mist", 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
+ { SOCK_RGBA, 0, "Emit", 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
+ { SOCK_RGBA, 0, "Environment",0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
+ { -1, 0, "" }
+};
+
+
+/* note: this function is used for multilayer too, to ensure uniform
+ handling with BKE_image_get_ibuf() */
+static CompBuf *node_composit_get_image(RenderData *rd, Image *ima, ImageUser *iuser)
+{
+ ImBuf *ibuf;
+ CompBuf *stackbuf;
+ int type;
+
+ float *rect;
+ int alloc= FALSE;
+
+ ibuf= BKE_image_get_ibuf(ima, iuser);
+ if(ibuf==NULL || (ibuf->rect==NULL && ibuf->rect_float==NULL)) {
+ return NULL;
+ }
+
+ if (ibuf->rect_float == NULL) {
+ IMB_float_from_rect(ibuf);
+ }
+
+ /* now we need a float buffer from the image with matching color management */
+ /* XXX weak code, multilayer is excluded from this */
+ if(ibuf->channels == 4 && ima->rr==NULL) {
+ if(rd->color_mgt_flag & R_COLOR_MANAGEMENT) {
+ if(ibuf->profile != IB_PROFILE_NONE) {
+ rect= ibuf->rect_float;
+ }
+ else {
+ rect= MEM_mapallocN(sizeof(float) * 4 * ibuf->x * ibuf->y, "node_composit_get_image");
+ srgb_to_linearrgb_rgba_rgba_buf(rect, ibuf->rect_float, ibuf->x * ibuf->y);
+ alloc= TRUE;
+ }
+ }
+ else {
+ if(ibuf->profile == IB_PROFILE_NONE) {
+ rect= ibuf->rect_float;
+ }
+ else {
+ rect= MEM_mapallocN(sizeof(float) * 4 * ibuf->x * ibuf->y, "node_composit_get_image");
+ linearrgb_to_srgb_rgba_rgba_buf(rect, ibuf->rect_float, ibuf->x * ibuf->y);
+ alloc= TRUE;
+ }
+ }
+ }
+ else {
+ /* non-rgba passes can't use color profiles */
+ rect= ibuf->rect_float;
+ }
+ /* done coercing into the correct color management */
+
+
+ type= ibuf->channels;
+
+ if(rd->scemode & R_COMP_CROP) {
+ stackbuf= get_cropped_compbuf(&rd->disprect, rect, ibuf->x, ibuf->y, type);
+ if(alloc)
+ MEM_freeN(rect);
+ }
+ else {
+ /* we put imbuf copy on stack, cbuf knows rect is from other ibuf when freed! */
+ stackbuf= alloc_compbuf(ibuf->x, ibuf->y, type, FALSE);
+ stackbuf->rect= rect;
+ stackbuf->malloc= alloc;
+ }
+
+ /*code to respect the premul flag of images; I'm
+ not sure if this is a good idea for multilayer images,
+ since it never worked before for them.
+ if (type==CB_RGBA && ima->flag & IMA_DO_PREMUL) {
+ //premul the image
+ int i;
+ float *pixel = stackbuf->rect;
+
+ for (i=0; i<stackbuf->x*stackbuf->y; i++, pixel += 4) {
+ pixel[0] *= pixel[3];
+ pixel[1] *= pixel[3];
+ pixel[2] *= pixel[3];
+ }
+ }
+ */
+ return stackbuf;
+}
+
+static CompBuf *node_composit_get_zimage(bNode *node, RenderData *rd)
+{
+ ImBuf *ibuf= BKE_image_get_ibuf((Image *)node->id, node->storage);
+ CompBuf *zbuf= NULL;
+
+ if(ibuf && ibuf->zbuf_float) {
+ if(rd->scemode & R_COMP_CROP) {
+ zbuf= get_cropped_compbuf(&rd->disprect, ibuf->zbuf_float, ibuf->x, ibuf->y, CB_VAL);
+ }
+ else {
+ zbuf= alloc_compbuf(ibuf->x, ibuf->y, CB_VAL, 0);
+ zbuf->rect= ibuf->zbuf_float;
+ }
+ }
+ return zbuf;
+}
+
+/* check if layer is available, returns pass buffer */
+static CompBuf *compbuf_multilayer_get(RenderData *rd, RenderLayer *rl, Image *ima, ImageUser *iuser, int passtype)
+{
+ RenderPass *rpass;
+ short index;
+
+ for(index=0, rpass= rl->passes.first; rpass; rpass= rpass->next, index++)
+ if(rpass->passtype==passtype)
+ break;
+
+ if(rpass) {
+ CompBuf *cbuf;
+
+ iuser->pass= index;
+ BKE_image_multilayer_index(ima->rr, iuser);
+ cbuf= node_composit_get_image(rd, ima, iuser);
+
+ return cbuf;
+ }
+ return NULL;
+}
+
+static void outputs_multilayer_get(RenderData *rd, RenderLayer *rl, bNodeStack **out, Image *ima, ImageUser *iuser)
+{
+ if(out[RRES_OUT_Z]->hasoutput)
+ out[RRES_OUT_Z]->data= compbuf_multilayer_get(rd, rl, ima, iuser, SCE_PASS_Z);
+ if(out[RRES_OUT_VEC]->hasoutput)
+ out[RRES_OUT_VEC]->data= compbuf_multilayer_get(rd, rl, ima, iuser, SCE_PASS_VECTOR);
+ if(out[RRES_OUT_NORMAL]->hasoutput)
+ out[RRES_OUT_NORMAL]->data= compbuf_multilayer_get(rd, rl, ima, iuser, SCE_PASS_NORMAL);
+ if(out[RRES_OUT_UV]->hasoutput)
+ out[RRES_OUT_UV]->data= compbuf_multilayer_get(rd, rl, ima, iuser, SCE_PASS_UV);
+
+ if(out[RRES_OUT_RGBA]->hasoutput)
+ out[RRES_OUT_RGBA]->data= compbuf_multilayer_get(rd, rl, ima, iuser, SCE_PASS_RGBA);
+ if(out[RRES_OUT_DIFF]->hasoutput)
+ out[RRES_OUT_DIFF]->data= compbuf_multilayer_get(rd, rl, ima, iuser, SCE_PASS_DIFFUSE);
+ if(out[RRES_OUT_SPEC]->hasoutput)
+ out[RRES_OUT_SPEC]->data= compbuf_multilayer_get(rd, rl, ima, iuser, SCE_PASS_SPEC);
+ if(out[RRES_OUT_SHADOW]->hasoutput)
+ out[RRES_OUT_SHADOW]->data= compbuf_multilayer_get(rd, rl, ima, iuser, SCE_PASS_SHADOW);
+ if(out[RRES_OUT_AO]->hasoutput)
+ out[RRES_OUT_AO]->data= compbuf_multilayer_get(rd, rl, ima, iuser, SCE_PASS_AO);
+ if(out[RRES_OUT_REFLECT]->hasoutput)
+ out[RRES_OUT_REFLECT]->data= compbuf_multilayer_get(rd, rl, ima, iuser, SCE_PASS_REFLECT);
+ if(out[RRES_OUT_REFRACT]->hasoutput)
+ out[RRES_OUT_REFRACT]->data= compbuf_multilayer_get(rd, rl, ima, iuser, SCE_PASS_REFRACT);
+ if(out[RRES_OUT_INDIRECT]->hasoutput)
+ out[RRES_OUT_INDIRECT]->data= compbuf_multilayer_get(rd, rl, ima, iuser, SCE_PASS_INDIRECT);
+ if(out[RRES_OUT_INDEXOB]->hasoutput)
+ out[RRES_OUT_INDEXOB]->data= compbuf_multilayer_get(rd, rl, ima, iuser, SCE_PASS_INDEXOB);
+ if(out[RRES_OUT_INDEXMA]->hasoutput)
+ out[RRES_OUT_INDEXMA]->data= compbuf_multilayer_get(rd, rl, ima, iuser, SCE_PASS_INDEXMA);
+ if(out[RRES_OUT_MIST]->hasoutput)
+ out[RRES_OUT_MIST]->data= compbuf_multilayer_get(rd, rl, ima, iuser, SCE_PASS_MIST);
+ if(out[RRES_OUT_EMIT]->hasoutput)
+ out[RRES_OUT_EMIT]->data= compbuf_multilayer_get(rd, rl, ima, iuser, SCE_PASS_EMIT);
+ if(out[RRES_OUT_ENV]->hasoutput)
+ out[RRES_OUT_ENV]->data= compbuf_multilayer_get(rd, rl, ima, iuser, SCE_PASS_ENVIRONMENT);
+}
+
+
+static void node_composit_exec_image(void *data, bNode *node, bNodeStack **UNUSED(in), bNodeStack **out)
+{
+
+ /* image assigned to output */
+ /* stack order input sockets: col, alpha */
+ if(node->id) {
+ RenderData *rd= data;
+ Image *ima= (Image *)node->id;
+ ImageUser *iuser= (ImageUser *)node->storage;
+ CompBuf *stackbuf= NULL;
+
+ /* first set the right frame number in iuser */
+ BKE_image_user_calc_frame(iuser, rd->cfra, 0);
+
+ /* force a load, we assume iuser index will be set OK anyway */
+ if(ima->type==IMA_TYPE_MULTILAYER)
+ BKE_image_get_ibuf(ima, iuser);
+
+ if(ima->type==IMA_TYPE_MULTILAYER && ima->rr) {
+ RenderLayer *rl= BLI_findlink(&ima->rr->layers, iuser->layer);
+
+ if(rl) {
+ out[0]->data= stackbuf= compbuf_multilayer_get(rd, rl, ima, iuser, SCE_PASS_COMBINED);
+
+ /* go over all layers */
+ outputs_multilayer_get(rd, rl, out, ima, iuser);
+ }
+ }
+ else {
+ stackbuf= node_composit_get_image(rd, ima, iuser);
+
+ if (stackbuf) {
+ /*respect image premul option*/
+ if (stackbuf->type==CB_RGBA && ima->flag & IMA_DO_PREMUL) {
+ int i;
+ float *pixel;
+
+ /*first duplicate stackbuf->rect, since it's just a pointer
+ to the source imbuf, and we don't want to change that.*/
+ stackbuf->rect = MEM_dupallocN(stackbuf->rect);
+
+ /* since stackbuf now has allocated memory, rather than just a pointer,
+ * mark it as allocated so it can be freed properly */
+ stackbuf->malloc=1;
+
+ /*premul the image*/
+ pixel = stackbuf->rect;
+ for (i=0; i<stackbuf->x*stackbuf->y; i++, pixel += 4) {
+ pixel[0] *= pixel[3];
+ pixel[1] *= pixel[3];
+ pixel[2] *= pixel[3];
+ }
+ }
+
+ /* put image on stack */
+ out[0]->data= stackbuf;
+
+ if(out[2]->hasoutput)
+ out[2]->data= node_composit_get_zimage(node, rd);
+ }
+ }
+
+ /* alpha and preview for both types */
+ if(stackbuf) {
+ if(out[1]->hasoutput)
+ out[1]->data= valbuf_from_rgbabuf(stackbuf, CHAN_A);
+
+ generate_preview(data, node, stackbuf);
+ }
+ }
+}
+
+static void node_composit_init_image(bNodeTree *UNUSED(ntree), bNode* node, bNodeTemplate *UNUSED(ntemp))
+{
+ ImageUser *iuser= MEM_callocN(sizeof(ImageUser), "node image user");
+ node->storage= iuser;
+ iuser->frames= 1;
+ iuser->sfra= 1;
+ iuser->fie_ima= 2;
+ iuser->ok= 1;
+}
+
+void register_node_type_cmp_image(ListBase *lb)
+{
+ static bNodeType ntype;
+
+ node_type_base(&ntype, CMP_NODE_IMAGE, "Image", NODE_CLASS_INPUT, NODE_PREVIEW|NODE_OPTIONS);
+ node_type_socket_templates(&ntype, NULL, cmp_node_rlayers_out);
+ node_type_size(&ntype, 120, 80, 300);
+ node_type_init(&ntype, node_composit_init_image);
+ node_type_storage(&ntype, "ImageUser", node_free_standard_storage, node_copy_standard_storage);
+ node_type_exec(&ntype, node_composit_exec_image);
+
+ nodeRegisterType(lb, &ntype);
+}
+
+
+/* **************** RENDER RESULT ******************** */
+
+static CompBuf *compbuf_from_pass(RenderData *rd, RenderLayer *rl, int rectx, int recty, int passcode)
+{
+ float *fp= RE_RenderLayerGetPass(rl, passcode);
+ if(fp) {
+ CompBuf *buf;
+ int buftype= CB_VEC3;
+
+ if(ELEM4(passcode, SCE_PASS_Z, SCE_PASS_INDEXOB, SCE_PASS_MIST, SCE_PASS_INDEXMA))
+ buftype= CB_VAL;
+ else if(passcode==SCE_PASS_VECTOR)
+ buftype= CB_VEC4;
+ else if(ELEM(passcode, SCE_PASS_COMBINED, SCE_PASS_RGBA))
+ buftype= CB_RGBA;
+
+ if(rd->scemode & R_COMP_CROP)
+ buf= get_cropped_compbuf(&rd->disprect, fp, rectx, recty, buftype);
+ else {
+ buf= alloc_compbuf(rectx, recty, buftype, 0);
+ buf->rect= fp;
+ }
+ return buf;
+ }
+ return NULL;
+}
+
+static void node_composit_rlayers_out(RenderData *rd, RenderLayer *rl, bNodeStack **out, int rectx, int recty)
+{
+ if(out[RRES_OUT_Z]->hasoutput)
+ out[RRES_OUT_Z]->data= compbuf_from_pass(rd, rl, rectx, recty, SCE_PASS_Z);
+ if(out[RRES_OUT_VEC]->hasoutput)
+ out[RRES_OUT_VEC]->data= compbuf_from_pass(rd, rl, rectx, recty, SCE_PASS_VECTOR);
+ if(out[RRES_OUT_NORMAL]->hasoutput)
+ out[RRES_OUT_NORMAL]->data= compbuf_from_pass(rd, rl, rectx, recty, SCE_PASS_NORMAL);
+ if(out[RRES_OUT_UV]->hasoutput)
+ out[RRES_OUT_UV]->data= compbuf_from_pass(rd, rl, rectx, recty, SCE_PASS_UV);
+
+ if(out[RRES_OUT_RGBA]->hasoutput)
+ out[RRES_OUT_RGBA]->data= compbuf_from_pass(rd, rl, rectx, recty, SCE_PASS_RGBA);
+ if(out[RRES_OUT_DIFF]->hasoutput)
+ out[RRES_OUT_DIFF]->data= compbuf_from_pass(rd, rl, rectx, recty, SCE_PASS_DIFFUSE);
+ if(out[RRES_OUT_SPEC]->hasoutput)
+ out[RRES_OUT_SPEC]->data= compbuf_from_pass(rd, rl, rectx, recty, SCE_PASS_SPEC);
+ if(out[RRES_OUT_SHADOW]->hasoutput)
+ out[RRES_OUT_SHADOW]->data= compbuf_from_pass(rd, rl, rectx, recty, SCE_PASS_SHADOW);
+ if(out[RRES_OUT_AO]->hasoutput)
+ out[RRES_OUT_AO]->data= compbuf_from_pass(rd, rl, rectx, recty, SCE_PASS_AO);
+ if(out[RRES_OUT_REFLECT]->hasoutput)
+ out[RRES_OUT_REFLECT]->data= compbuf_from_pass(rd, rl, rectx, recty, SCE_PASS_REFLECT);
+ if(out[RRES_OUT_REFRACT]->hasoutput)
+ out[RRES_OUT_REFRACT]->data= compbuf_from_pass(rd, rl, rectx, recty, SCE_PASS_REFRACT);
+ if(out[RRES_OUT_INDIRECT]->hasoutput)
+ out[RRES_OUT_INDIRECT]->data= compbuf_from_pass(rd, rl, rectx, recty, SCE_PASS_INDIRECT);
+ if(out[RRES_OUT_INDEXOB]->hasoutput)
+ out[RRES_OUT_INDEXOB]->data= compbuf_from_pass(rd, rl, rectx, recty, SCE_PASS_INDEXOB);
+ if(out[RRES_OUT_INDEXMA]->hasoutput)
+ out[RRES_OUT_INDEXMA]->data= compbuf_from_pass(rd, rl, rectx, recty, SCE_PASS_INDEXMA);
+ if(out[RRES_OUT_MIST]->hasoutput)
+ out[RRES_OUT_MIST]->data= compbuf_from_pass(rd, rl, rectx, recty, SCE_PASS_MIST);
+ if(out[RRES_OUT_EMIT]->hasoutput)
+ out[RRES_OUT_EMIT]->data= compbuf_from_pass(rd, rl, rectx, recty, SCE_PASS_EMIT);
+ if(out[RRES_OUT_ENV]->hasoutput)
+ out[RRES_OUT_ENV]->data= compbuf_from_pass(rd, rl, rectx, recty, SCE_PASS_ENVIRONMENT);
+}
+
+static void node_composit_exec_rlayers(void *data, bNode *node, bNodeStack **UNUSED(in), bNodeStack **out)
+{
+ Scene *sce= (Scene *)node->id;
+ Render *re= (sce)? RE_GetRender(sce->id.name): NULL;
+ RenderData *rd= data;
+ RenderResult *rr= NULL;
+
+ if(re)
+ rr= RE_AcquireResultRead(re);
+
+ if(rr) {
+ SceneRenderLayer *srl= BLI_findlink(&sce->r.layers, node->custom1);
+ if(srl) {
+ RenderLayer *rl= RE_GetRenderLayer(rr, srl->name);
+ if(rl && rl->rectf) {
+ CompBuf *stackbuf;
+
+ /* we put render rect on stack, cbuf knows rect is from other ibuf when freed! */
+ if(rd->scemode & R_COMP_CROP)
+ stackbuf= get_cropped_compbuf(&rd->disprect, rl->rectf, rr->rectx, rr->recty, CB_RGBA);
+ else {
+ stackbuf= alloc_compbuf(rr->rectx, rr->recty, CB_RGBA, 0);
+ stackbuf->rect= rl->rectf;
+ }
+ if(stackbuf==NULL) {
+ printf("Error; Preview Panel in UV Window returns zero sized image\n");
+ }
+ else {
+ stackbuf->xof= rr->xof;
+ stackbuf->yof= rr->yof;
+
+ /* put on stack */
+ out[RRES_OUT_IMAGE]->data= stackbuf;
+
+ if(out[RRES_OUT_ALPHA]->hasoutput)
+ out[RRES_OUT_ALPHA]->data= valbuf_from_rgbabuf(stackbuf, CHAN_A);
+
+ node_composit_rlayers_out(rd, rl, out, rr->rectx, rr->recty);
+
+ generate_preview(data, node, stackbuf);
+ }
+ }
+ }
+ }
+
+ if(re)
+ RE_ReleaseResult(re);
+}
+
+
+void register_node_type_cmp_rlayers(ListBase *lb)
+{
+ static bNodeType ntype;
+
+ node_type_base(&ntype, CMP_NODE_R_LAYERS, "Render Layers", NODE_CLASS_INPUT, NODE_PREVIEW|NODE_OPTIONS);
+ node_type_socket_templates(&ntype, NULL, cmp_node_rlayers_out);
+ node_type_size(&ntype, 150, 100, 300);
+ node_type_exec(&ntype, node_composit_exec_rlayers);
+
+ nodeRegisterType(lb, &ntype);
+}
+
+
+
diff --git a/source/blender/nodes/composite/nodes/node_composite_invert.c b/source/blender/nodes/composite/nodes/node_composite_invert.c
new file mode 100644
index 00000000000..1f7589cae8f
--- /dev/null
+++ b/source/blender/nodes/composite/nodes/node_composite_invert.c
@@ -0,0 +1,135 @@
+/*
+ * $Id: CMP_invert.c 36593 2011-05-10 11:19:26Z lukastoenne $
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2006 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/nodes/composite/nodes/node_composite_invert.c
+ * \ingroup cmpnodes
+ */
+
+#include "node_composite_util.h"
+
+/* **************** INVERT ******************** */
+static bNodeSocketTemplate cmp_node_invert_in[]= {
+ { SOCK_FLOAT, 1, "Fac", 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR},
+ { SOCK_RGBA, 1, "Color", 0.0f, 0.0f, 0.0f, 1.0f},
+ { -1, 0, "" }
+};
+
+static bNodeSocketTemplate cmp_node_invert_out[]= {
+ { SOCK_RGBA, 0, "Color"},
+ { -1, 0, "" }
+};
+
+static void do_invert(bNode *node, float *out, float *in)
+{
+ if(node->custom1 & CMP_CHAN_RGB) {
+ out[0] = 1.0f - in[0];
+ out[1] = 1.0f - in[1];
+ out[2] = 1.0f - in[2];
+ } else
+ VECCOPY(out, in);
+
+ if(node->custom1 & CMP_CHAN_A)
+ out[3] = 1.0f - in[3];
+ else
+ out[3] = in[3];
+}
+
+static void do_invert_fac(bNode *node, float *out, float *in, float *fac)
+{
+ float col[4], facm;
+
+ do_invert(node, col, in);
+
+ /* blend inverted result against original input with fac */
+ facm = 1.0 - fac[0];
+
+ if(node->custom1 & CMP_CHAN_RGB) {
+ col[0] = fac[0]*col[0] + (facm*in[0]);
+ col[1] = fac[0]*col[1] + (facm*in[1]);
+ col[2] = fac[0]*col[2] + (facm*in[2]);
+ }
+ if(node->custom1 & CMP_CHAN_A)
+ col[3] = fac[0]*col[3] + (facm*in[3]);
+
+ QUATCOPY(out, col);
+}
+
+static void node_composit_exec_invert(void *UNUSED(data), bNode *node, bNodeStack **in, bNodeStack **out)
+{
+ /* stack order in: fac, Image, Image */
+ /* stack order out: Image */
+ float *fac= in[0]->vec;
+
+ if(out[0]->hasoutput==0) return;
+
+ /* input no image? then only color operation */
+ if(in[1]->data==NULL && in[0]->data==NULL) {
+ do_invert_fac(node, out[0]->vec, in[1]->vec, fac);
+ }
+ else {
+ /* make output size of first available input image, or then size of fac */
+ CompBuf *cbuf= in[1]->data?in[1]->data:in[0]->data;
+
+ /* if neither RGB or A toggled on, pass through */
+ if (node->custom1 != 0) {
+ CompBuf *stackbuf= alloc_compbuf(cbuf->x, cbuf->y, CB_RGBA, 1); /* allocs */
+
+ if (fac[0] < 1.0f || in[0]->data!=NULL)
+ composit2_pixel_processor(node, stackbuf, in[1]->data, in[1]->vec, in[0]->data, fac, do_invert_fac, CB_RGBA, CB_VAL);
+ else
+ composit1_pixel_processor(node, stackbuf, in[1]->data, in[1]->vec, do_invert, CB_RGBA);
+ out[0]->data= stackbuf;
+ return;
+
+ } else {
+ out[0]->data = pass_on_compbuf(cbuf);
+ return;
+ }
+ }
+}
+
+static void node_composit_init_invert(bNodeTree *UNUSED(ntree), bNode* node, bNodeTemplate *UNUSED(ntemp))
+{
+ node->custom1 |= CMP_CHAN_RGB;
+}
+
+/* custom1 = mix type */
+void register_node_type_cmp_invert(ListBase *lb)
+{
+ static bNodeType ntype;
+
+ node_type_base(&ntype, CMP_NODE_INVERT, "Invert", NODE_CLASS_OP_COLOR, NODE_OPTIONS);
+ node_type_socket_templates(&ntype, cmp_node_invert_in, cmp_node_invert_out);
+ node_type_size(&ntype, 120, 120, 140);
+ node_type_init(&ntype, node_composit_init_invert);
+ node_type_exec(&ntype, node_composit_exec_invert);
+
+ nodeRegisterType(lb, &ntype);
+}
+
diff --git a/source/blender/nodes/composite/nodes/node_composite_lensdist.c b/source/blender/nodes/composite/nodes/node_composite_lensdist.c
new file mode 100644
index 00000000000..85578deecbb
--- /dev/null
+++ b/source/blender/nodes/composite/nodes/node_composite_lensdist.c
@@ -0,0 +1,207 @@
+/*
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2006 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): Alfredo de Greef (eeshlo)
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/nodes/composite/nodes/node_composite_lensdist.c
+ * \ingroup cmpnodes
+ */
+
+
+#include "node_composite_util.h"
+
+static bNodeSocketTemplate cmp_node_lensdist_in[]= {
+ { SOCK_RGBA, 1, "Image", 0.8f, 0.8f, 0.8f, 1.0f},
+ { SOCK_FLOAT, 1, "Distort", 0.f, 0.f, 0.f, 0.f, -0.999f, 1.f, PROP_NONE},
+ { SOCK_FLOAT, 1, "Dispersion", 0.f, 0.f, 0.f, 0.f, 0.f, 1.f, PROP_NONE},
+ { -1, 0, "" }
+};
+static bNodeSocketTemplate cmp_node_lensdist_out[]= {
+ { SOCK_RGBA, 0, "Image"},
+ { -1, 0, "" }
+};
+
+/* assumes *dst is type RGBA */
+static void lensDistort(CompBuf *dst, CompBuf *src, float kr, float kg, float kb, int jit, int proj, int fit)
+{
+ int x, y, z;
+ const float cx = 0.5f*(float)dst->x, cy = 0.5f*(float)dst->y;
+
+ if (proj) {
+ // shift
+ CompBuf *tsrc = dupalloc_compbuf(src);
+
+ for (z=0; z<tsrc->type; ++z)
+ IIR_gauss(tsrc, (kr+0.5f)*(kr+0.5f), z, 1);
+ kr *= 20.f;
+
+ for (y=0; y<dst->y; y++) {
+ fRGB *colp = (fRGB*)&dst->rect[y*dst->x*dst->type];
+ const float v = (y + 0.5f)/(float)dst->y;
+
+ for (x=0; x<dst->x; x++) {
+ const float u = (x + 0.5f)/(float)dst->x;
+
+ qd_getPixelLerpChan(tsrc, (u*dst->x + kr) - 0.5f, v*dst->y - 0.5f, 0, colp[x]);
+ if (tsrc->type == CB_VAL)
+ colp[x][1] = tsrc->rect[x + y*tsrc->x];
+ else
+ colp[x][1] = tsrc->rect[(x + y*tsrc->x)*tsrc->type + 1];
+ qd_getPixelLerpChan(tsrc, (u*dst->x - kr) - 0.5f, v*dst->y - 0.5f, 2, colp[x]+2);
+
+ /* set alpha */
+ colp[x][3]= 1.0f;
+ }
+ }
+ free_compbuf(tsrc);
+ }
+ else {
+ // Spherical
+ // Scale factor to make bottom/top & right/left sides fit in window after deform
+ // so in the case of pincushion (kn < 0), corners will be outside window.
+ // Now also optionally scales image such that black areas are not visible when distort factor is positive
+ // (makes distorted corners match window corners, but really only valid if mk<=0.5)
+ const float mk = MAX3(kr, kg, kb);
+ const float sc = (fit && (mk > 0.f)) ? (1.f/(1.f + 2.f*mk)) : (1.f/(1.f + mk));
+ const float drg = 4.f*(kg - kr), dgb = 4.f*(kb - kg);
+
+ kr *= 4.f, kg *= 4.f, kb *= 4.f;
+
+ for (y=0; y<dst->y; y++) {
+ fRGB *colp = (fRGB*)&dst->rect[y*dst->x*dst->type];
+ const float v = sc*((y + 0.5f) - cy)/cy;
+
+ for (x=0; x<dst->x; x++) {
+ int dr = 0, dg = 0, db = 0;
+ float d, t, ln[6] = {0, 0, 0, 0, 0, 0};
+ fRGB c1, tc = {0, 0, 0, 0};
+ const float u = sc*((x + 0.5f) - cx)/cx;
+ int sta = 0, mid = 0, end = 0;
+
+ if ((t = 1.f - kr*(u*u + v*v)) >= 0.f) {
+ d = 1.f/(1.f + sqrtf(t));
+ ln[0] = (u*d + 0.5f)*dst->x - 0.5f, ln[1] = (v*d + 0.5f)*dst->y - 0.5f;
+ sta = 1;
+ }
+ if ((t = 1.f - kg*(u*u + v*v)) >= 0.f) {
+ d = 1.f/(1.f + sqrtf(t));
+ ln[2] = (u*d + 0.5f)*dst->x - 0.5f, ln[3] = (v*d + 0.5f)*dst->y - 0.5f;
+ mid = 1;
+ }
+ if ((t = 1.f - kb*(u*u + v*v)) >= 0.f) {
+ d = 1.f/(1.f + sqrtf(t));
+ ln[4] = (u*d + 0.5f)*dst->x - 0.5f, ln[5] = (v*d + 0.5f)*dst->y - 0.5f;
+ end = 1;
+ }
+
+ if (sta && mid && end) {
+ // RG
+ const int dx = ln[2] - ln[0], dy = ln[3] - ln[1];
+ const float dsf = sqrtf(dx*dx + dy*dy) + 1.f;
+ const int ds = (int)(jit ? ((dsf < 4.f) ? 2.f : sqrtf(dsf)) : dsf);
+ const float sd = 1.f/(float)ds;
+
+ for (z=0; z<ds; ++z) {
+ const float tz = ((float)z + (jit ? BLI_frand() : 0.5f))*sd;
+ t = 1.f - (kr + tz*drg)*(u*u + v*v);
+ d = 1.f / (1.f + sqrtf(t));
+ qd_getPixelLerp(src, (u*d + 0.5f)*dst->x - 0.5f, (v*d + 0.5f)*dst->y - 0.5f, c1);
+ if (src->type == CB_VAL) c1[1] = c1[2] = c1[0];
+ tc[0] += (1.f-tz)*c1[0], tc[1] += tz*c1[1];
+ dr++, dg++;
+ }
+ // GB
+ {
+ const int dx = ln[4] - ln[2], dy = ln[5] - ln[3];
+ const float dsf = sqrtf(dx*dx + dy*dy) + 1.f;
+ const int ds = (int)(jit ? ((dsf < 4.f) ? 2.f : sqrtf(dsf)) : dsf);
+ const float sd = 1.f/(float)ds;
+
+ for (z=0; z<ds; ++z) {
+ const float tz = ((float)z + (jit ? BLI_frand() : 0.5f))*sd;
+ t = 1.f - (kg + tz*dgb)*(u*u + v*v);
+ d = 1.f / (1.f + sqrtf(t));
+ qd_getPixelLerp(src, (u*d + 0.5f)*dst->x - 0.5f, (v*d + 0.5f)*dst->y - 0.5f, c1);
+ if (src->type == CB_VAL) c1[1] = c1[2] = c1[0];
+ tc[1] += (1.f-tz)*c1[1], tc[2] += tz*c1[2];
+ dg++, db++;
+ }
+ }
+ }
+
+ if (dr) colp[x][0] = 2.f*tc[0] / (float)dr;
+ if (dg) colp[x][1] = 2.f*tc[1] / (float)dg;
+ if (db) colp[x][2] = 2.f*tc[2] / (float)db;
+
+ /* set alpha */
+ colp[x][3]= 1.0f;
+ }
+ }
+ }
+}
+
+
+static void node_composit_exec_lensdist(void *UNUSED(data), bNode *node, bNodeStack **in, bNodeStack **out)
+{
+ CompBuf *new, *img = in[0]->data;
+ NodeLensDist *nld = node->storage;
+ const float k = MAX2(MIN2(in[1]->vec[0], 1.f), -0.999f);
+ // smaller dispersion range for somewhat more control
+ const float d = 0.25f*MAX2(MIN2(in[2]->vec[0], 1.f), 0.f);
+ const float kr = MAX2(MIN2((k+d), 1.f), -0.999f), kb = MAX2(MIN2((k-d), 1.f), -0.999f);
+
+ if ((img==NULL) || (out[0]->hasoutput==0)) return;
+
+ new = alloc_compbuf(img->x, img->y, CB_RGBA, 1);
+
+ lensDistort(new, img, (nld->proj ? d : kr), k, kb, nld->jit, nld->proj, nld->fit);
+
+ out[0]->data = new;
+}
+
+
+static void node_composit_init_lensdist(bNodeTree *UNUSED(ntree), bNode* node, bNodeTemplate *UNUSED(ntemp))
+{
+ NodeLensDist *nld = MEM_callocN(sizeof(NodeLensDist), "node lensdist data");
+ nld->jit = nld->proj = nld->fit = 0;
+ node->storage = nld;
+}
+
+
+void register_node_type_cmp_lensdist(ListBase *lb)
+{
+ static bNodeType ntype;
+
+ node_type_base(&ntype, CMP_NODE_LENSDIST, "Lens Distortion", NODE_CLASS_DISTORT, NODE_OPTIONS);
+ node_type_socket_templates(&ntype, cmp_node_lensdist_in, cmp_node_lensdist_out);
+ node_type_size(&ntype, 150, 120, 200);
+ node_type_init(&ntype, node_composit_init_lensdist);
+ node_type_storage(&ntype, "NodeLensDist", node_free_standard_storage, node_copy_standard_storage);
+ node_type_exec(&ntype, node_composit_exec_lensdist);
+
+ nodeRegisterType(lb, &ntype);
+}
+
diff --git a/source/blender/nodes/composite/nodes/node_composite_levels.c b/source/blender/nodes/composite/nodes/node_composite_levels.c
new file mode 100644
index 00000000000..673ffe4cbef
--- /dev/null
+++ b/source/blender/nodes/composite/nodes/node_composite_levels.c
@@ -0,0 +1,339 @@
+/*
+ * $Id: CMP_levels.c 36536 2011-05-07 13:27:27Z lukastoenne $
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2006 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): Bob Holcomb.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/nodes/composite/nodes/node_composite_levels.c
+ * \ingroup cmpnodes
+ */
+
+
+#include "node_composite_util.h"
+
+
+/* **************** LEVELS ******************** */
+static bNodeSocketTemplate cmp_node_view_levels_in[]= {
+ { SOCK_RGBA, 1, "Image", 0.0f, 0.0f, 0.0f, 1.0f},
+ { -1, 0, "" }
+};
+
+static bNodeSocketTemplate cmp_node_view_levels_out[]={
+ {SOCK_FLOAT, 0,"Mean"},
+ {SOCK_FLOAT, 0,"Std Dev"},
+ {-1,0,""}
+};
+
+static void rgb_tobw(float r, float g, float b, float* out)
+{
+ *out= r*0.35f + g*0.45f + b*0.2f;
+}
+
+static void fill_bins(bNode* node, CompBuf* in, int* bins)
+{
+ float value[4];
+ int ivalue=0;
+ int x,y;
+
+ /*fill bins */
+ for(y=0; y<in->y; y++) {
+ for(x=0; x<in->x; x++) {
+
+ /* get the pixel */
+ qd_getPixel(in, x, y, value);
+
+ if(value[3] > 0.0) { /* don't count transparent pixels */
+ switch(node->custom1) {
+ case 1: { /* all colors */
+ rgb_tobw(value[0],value[1],value[2], &value[0]);
+ value[0]=value[0]*255; /* scale to 0-255 range */
+ ivalue=(int)value[0];
+ break;
+ }
+ case 2: { /* red channel */
+ value[0]=value[0]*255; /* scale to 0-255 range */
+ ivalue=(int)value[0];
+ break;
+ }
+ case 3: { /* green channel */
+ value[1]=value[1]*255; /* scale to 0-255 range */
+ ivalue=(int)value[1];
+ break;
+ }
+ case 4: /*blue channel */
+ {
+ value[2]=value[2]*255; /* scale to 0-255 range */
+ ivalue=(int)value[2];
+ break;
+ }
+ case 5: /* luminence */
+ {
+ rgb_to_yuv(value[0],value[1],value[2], &value[0], &value[1], &value[2]);
+ value[0]=value[0]*255; /* scale to 0-255 range */
+ ivalue=(int)value[0];
+ break;
+ }
+ } /*end switch */
+
+ /*clip*/
+ if(ivalue<0) ivalue=0;
+ if(ivalue>255) ivalue=255;
+
+ /*put in the correct bin*/
+ bins[ivalue]+=1;
+ } /*end if alpha */
+ }
+ }
+}
+
+static float brightness_mean(bNode* node, CompBuf* in)
+{
+ float sum=0.0;
+ int numPixels=0.0;
+ int x,y;
+ float value[4];
+
+ for(x=0; x< in->x; x++) {
+ for(y=0; y < in->y; y++) {
+
+ /* get the pixel */
+ qd_getPixel(in, x, y, value);
+
+ if(value[3] > 0.0) { /* don't count transparent pixels */
+ numPixels++;
+ switch(node->custom1)
+ {
+ case 1:
+ {
+ rgb_tobw(value[0],value[1],value[2], &value[0]);
+ sum+=value[0];
+ break;
+ }
+ case 2:
+ {
+ sum+=value[0];
+ break;
+ }
+ case 3:
+ {
+ sum+=value[1];
+ break;
+ }
+ case 4:
+ {
+ sum+=value[2];
+ break;
+ }
+ case 5:
+ {
+ rgb_to_yuv(value[0],value[1],value[2], &value[0], &value[1], &value[2]);
+ sum+=value[0];
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ return sum/numPixels;
+}
+
+static float brightness_standard_deviation(bNode* node, CompBuf* in, float mean)
+{
+ float sum=0.0;
+ int numPixels=0.0;
+ int x,y;
+ float value[4];
+
+ for(x=0; x< in->x; x++) {
+ for(y=0; y < in->y; y++) {
+
+ /* get the pixel */
+ qd_getPixel(in, x, y, value);
+
+ if(value[3] > 0.0) { /* don't count transparent pixels */
+ numPixels++;
+ switch(node->custom1)
+ {
+ case 1:
+ {
+ rgb_tobw(value[0],value[1],value[2], &value[0]);
+ sum+=(value[0]-mean)*(value[0]-mean);
+ break;
+ }
+ case 2:
+ {
+ sum+=value[0];
+ sum+=(value[0]-mean)*(value[0]-mean);
+ break;
+ }
+ case 3:
+ {
+ sum+=value[1];
+ sum+=(value[1]-mean)*(value[1]-mean);
+ break;
+ }
+ case 4:
+ {
+ sum+=value[2];
+ sum+=(value[2]-mean)*(value[2]-mean);
+ break;
+ }
+ case 5:
+ {
+ rgb_to_yuv(value[0],value[1],value[2], &value[0], &value[1], &value[2]);
+ sum+=(value[0]-mean)*(value[0]-mean);
+ break;
+ }
+ }
+ }
+ }
+ }
+
+
+ return sqrt(sum/(float)(numPixels-1));
+}
+
+static void draw_histogram(bNode *node, CompBuf *out, int* bins)
+{
+ int x,y;
+ float color[4];
+ float value;
+ int max;
+
+ /* find max value */
+ max=0;
+ for(x=0; x<256; x++) {
+ if(bins[x]>max) max=bins[x];
+ }
+
+ /*draw histogram in buffer */
+ for(x=0; x<out->x; x++) {
+ for(y=0;y<out->y; y++) {
+
+ /* get normalized value (0..255) */
+ value=((float)bins[x]/(float)max)*255.0;
+
+ if(y < (int)value) { /*if the y value is below the height of the bar for this line then draw with the color */
+ switch (node->custom1) {
+ case 1: { /* draw in black */
+ color[0]=0.0; color[1]=0.0; color[2]=0.0; color[3]=1.0;
+ break;
+ }
+ case 2: { /* draw in red */
+ color[0]=1.0; color[1]=0.0; color[2]=0.0; color[3]=1.0;
+ break;
+ }
+ case 3: { /* draw in green */
+ color[0]=0.0; color[1]=1.0; color[2]=0.0; color[3]=1.0;
+ break;
+ }
+ case 4: { /* draw in blue */
+ color[0]=0.0; color[1]=0.0; color[2]=1.0; color[3]=1.0;
+ break;
+ }
+ case 5: { /* draw in white */
+ color[0]=1.0; color[1]=1.0; color[2]=1.0; color[3]=1.0;
+ break;
+ }
+ }
+ }
+ else{
+ color[0]=0.8; color[1]=0.8; color[2]=0.8; color[3]=1.0;
+ }
+
+ /* set the color */
+ qd_setPixel(out, x, y, color);
+ }
+ }
+}
+
+static void node_composit_exec_view_levels(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
+{
+ CompBuf* cbuf;
+ CompBuf* histogram;
+ float mean, std_dev;
+ int bins[256];
+ int x;
+
+ if(in[0]->hasinput==0) return;
+ if(in[0]->data==NULL) return;
+
+ histogram=alloc_compbuf(256, 256, CB_RGBA, 1);
+ cbuf=typecheck_compbuf(in[0]->data, CB_RGBA);
+
+ /*initalize bins*/
+ for(x=0; x<256; x++) {
+ bins[x]=0;
+ }
+
+ /*fill bins */
+ fill_bins(node, in[0]->data, bins);
+
+ /* draw the histogram chart */
+ draw_histogram(node, histogram, bins);
+
+ /* calculate the average brightness and contrast */
+ mean=brightness_mean(node, in[0]->data);
+ std_dev=brightness_standard_deviation(node, in[0]->data, mean);
+
+ /* Printf debuging ;)
+ printf("Mean: %f\n", mean);
+ printf("Std Dev: %f\n", std_dev);
+ */
+
+ if(out[0]->hasoutput)
+ out[0]->vec[0]= mean;
+ if(out[1]->hasoutput)
+ out[1]->vec[0]= std_dev;
+
+ generate_preview(data, node, histogram);
+
+ if(cbuf!=in[0]->data)
+ free_compbuf(cbuf);
+ free_compbuf(histogram);
+}
+
+static void node_composit_init_view_levels(bNodeTree *UNUSED(ntree), bNode* node, bNodeTemplate *UNUSED(ntemp))
+{
+ node->custom1=1; /*All channels*/
+}
+
+void register_node_type_cmp_view_levels(ListBase *lb)
+{
+ static bNodeType ntype;
+
+ node_type_base(&ntype, CMP_NODE_VIEW_LEVELS, "Levels", NODE_CLASS_OUTPUT, NODE_OPTIONS|NODE_PREVIEW);
+ node_type_socket_templates(&ntype, cmp_node_view_levels_in, cmp_node_view_levels_out);
+ node_type_size(&ntype, 140, 100, 320);
+ node_type_init(&ntype, node_composit_init_view_levels);
+ node_type_storage(&ntype, "ImageUser", NULL, NULL);
+ node_type_exec(&ntype, node_composit_exec_view_levels);
+
+ nodeRegisterType(lb, &ntype);
+}
+
+
diff --git a/source/blender/nodes/composite/nodes/node_composite_lummaMatte.c b/source/blender/nodes/composite/nodes/node_composite_lummaMatte.c
new file mode 100644
index 00000000000..bc7676934fa
--- /dev/null
+++ b/source/blender/nodes/composite/nodes/node_composite_lummaMatte.c
@@ -0,0 +1,125 @@
+/*
+ * $Id: CMP_lummaMatte.c 36536 2011-05-07 13:27:27Z lukastoenne $
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2006 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): Bob Holcomb .
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/nodes/composite/nodes/node_composite_lummaMatte.c
+ * \ingroup cmpnodes
+ */
+
+
+#include "node_composite_util.h"
+
+
+/* ******************* Luma Matte Node ********************************* */
+static bNodeSocketTemplate cmp_node_luma_matte_in[]={
+ {SOCK_RGBA,1,"Image", 0.8f, 0.8f, 0.8f, 1.0f},
+ {-1,0,""}
+};
+
+static bNodeSocketTemplate cmp_node_luma_matte_out[]={
+ {SOCK_RGBA,0,"Image"},
+ {SOCK_FLOAT,0,"Matte"},
+ {-1,0,""}
+};
+
+static void do_luma_matte(bNode *node, float *out, float *in)
+{
+ NodeChroma *c=(NodeChroma *)node->storage;
+ float alpha;
+
+ alpha=0.0;
+
+ /* test range*/
+ if(in[0]>c->t1) {
+ alpha=1.0;
+ }
+ else if(in[0]<c->t2){
+ alpha=0.0;
+ }
+ else {/*blend */
+ alpha=(in[0]-c->t2)/(c->t1-c->t2);
+ }
+
+ /* don't make something that was more transparent less transparent */
+ if (alpha<in[3]) {
+ out[3]=alpha;
+ }
+ else {
+ out[3]=in[3];
+ }
+
+}
+
+static void node_composit_exec_luma_matte(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
+{
+ CompBuf *cbuf;
+ CompBuf *outbuf;
+
+ if(in[0]->hasinput==0) return;
+ if(in[0]->data==NULL) return;
+ if(out[0]->hasoutput==0 && out[1]->hasoutput==0) return;
+
+ cbuf=typecheck_compbuf(in[0]->data, CB_RGBA);
+
+ outbuf=dupalloc_compbuf(cbuf);
+
+ composit1_pixel_processor(node, outbuf, cbuf, in[1]->vec, do_rgba_to_yuva, CB_RGBA);
+ composit1_pixel_processor(node, outbuf, outbuf, in[1]->vec, do_luma_matte, CB_RGBA);
+ composit1_pixel_processor(node, outbuf, outbuf, in[1]->vec, do_yuva_to_rgba, CB_RGBA);
+
+ generate_preview(data, node, outbuf);
+ out[0]->data=outbuf;
+ if (out[1]->hasoutput)
+ out[1]->data=valbuf_from_rgbabuf(outbuf, CHAN_A);
+ if(cbuf!=in[0]->data)
+ free_compbuf(cbuf);
+}
+
+static void node_composit_init_luma_matte(bNodeTree *UNUSED(ntree), bNode* node, bNodeTemplate *UNUSED(ntemp))
+{
+ NodeChroma *c= MEM_callocN(sizeof(NodeChroma), "node chroma");
+ node->storage=c;
+ c->t1= 1.0f;
+ c->t2= 0.0f;
+}
+
+void register_node_type_cmp_luma_matte(ListBase *lb)
+{
+ static bNodeType ntype;
+
+ node_type_base(&ntype, CMP_NODE_LUMA_MATTE, "Luminance Key", NODE_CLASS_MATTE, NODE_PREVIEW|NODE_OPTIONS);
+ node_type_socket_templates(&ntype, cmp_node_luma_matte_in, cmp_node_luma_matte_out);
+ node_type_size(&ntype, 200, 80, 250);
+ node_type_init(&ntype, node_composit_init_luma_matte);
+ node_type_storage(&ntype, "NodeChroma", node_free_standard_storage, node_copy_standard_storage);
+ node_type_exec(&ntype, node_composit_exec_luma_matte);
+
+ nodeRegisterType(lb, &ntype);
+}
+
+
diff --git a/source/blender/nodes/composite/nodes/node_composite_mapUV.c b/source/blender/nodes/composite/nodes/node_composite_mapUV.c
new file mode 100644
index 00000000000..2d92c26b554
--- /dev/null
+++ b/source/blender/nodes/composite/nodes/node_composite_mapUV.c
@@ -0,0 +1,180 @@
+/*
+ * $Id: CMP_mapUV.c 36593 2011-05-10 11:19:26Z lukastoenne $
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2006 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/nodes/composite/nodes/node_composite_mapUV.c
+ * \ingroup cmpnodes
+ */
+
+
+#include "node_composite_util.h"
+
+/* **************** Map UV ******************** */
+
+static bNodeSocketTemplate cmp_node_mapuv_in[]= {
+ { SOCK_RGBA, 1, "Image", 0.8f, 0.8f, 0.8f, 1.0f},
+ { SOCK_VECTOR, 1, "UV", 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_NONE},
+ { -1, 0, "" }
+};
+static bNodeSocketTemplate cmp_node_mapuv_out[]= {
+ { SOCK_RGBA, 0, "Image"},
+ { -1, 0, "" }
+};
+
+/* foreach UV, use these values to read in cbuf and write to stackbuf */
+/* stackbuf should be zeroed */
+static void do_mapuv(CompBuf *stackbuf, CompBuf *cbuf, CompBuf *uvbuf, float threshold)
+{
+ ImBuf *ibuf;
+ float *out= stackbuf->rect, *uv, *uvnext, *uvprev;
+ float dx, dy, alpha;
+ int x, y, sx, sy, row= 3*stackbuf->x;
+
+ /* ibuf needed for sampling */
+ ibuf= IMB_allocImBuf(cbuf->x, cbuf->y, 32, 0);
+ ibuf->rect_float= cbuf->rect;
+
+ /* vars for efficient looping */
+ uv= uvbuf->rect;
+ uvnext= uv+row;
+ uvprev= uv-row;
+ sx= stackbuf->x;
+ sy= stackbuf->y;
+
+ for(y=0; y<sy; y++) {
+ for(x=0; x<sx; x++, out+=4, uv+=3, uvnext+=3, uvprev+=3) {
+ if(x>0 && x<sx-1 && y>0 && y<sy-1) {
+ if(uv[2]!=0.0f) {
+ float uv_l, uv_r;
+
+ /* adaptive sampling, red (U) channel */
+
+ /* prevent alpha zero UVs to be used */
+ uv_l= uv[-1]!=0.0f? fabs(uv[0]-uv[-3]) : 0.0f;
+ uv_r= uv[ 5]!=0.0f? fabs(uv[0]-uv[ 3]) : 0.0f;
+
+ //dx= 0.5f*(fabs(uv[0]-uv[-3]) + fabs(uv[0]-uv[3]));
+ dx= 0.5f*(uv_l + uv_r);
+
+ uv_l= uvprev[-1]!=0.0f? fabs(uv[0]-uvprev[-3]) : 0.0f;
+ uv_r= uvnext[-1]!=0.0f? fabs(uv[0]-uvnext[-3]) : 0.0f;
+
+ //dx+= 0.25f*(fabs(uv[0]-uvprev[-3]) + fabs(uv[0]-uvnext[-3]));
+ dx+= 0.25f*(uv_l + uv_r);
+
+ uv_l= uvprev[ 5]!=0.0f? fabs(uv[0]-uvprev[+3]) : 0.0f;
+ uv_r= uvnext[ 5]!=0.0f? fabs(uv[0]-uvnext[+3]) : 0.0f;
+
+ //dx+= 0.25f*(fabs(uv[0]-uvprev[+3]) + fabs(uv[0]-uvnext[+3]));
+ dx+= 0.25f*(uv_l + uv_r);
+
+ /* adaptive sampling, green (V) channel */
+
+ uv_l= uv[-row+2]!=0.0f? fabs(uv[1]-uv[-row+1]) : 0.0f;
+ uv_r= uv[ row+2]!=0.0f? fabs(uv[1]-uv[ row+1]) : 0.0f;
+
+ //dy= 0.5f*(fabs(uv[1]-uv[-row+1]) + fabs(uv[1]-uv[row+1]));
+ dy= 0.5f*(uv_l + uv_r);
+
+ uv_l= uvprev[-1]!=0.0f? fabs(uv[1]-uvprev[+1-3]) : 0.0f;
+ uv_r= uvnext[-1]!=0.0f? fabs(uv[1]-uvnext[+1-3]) : 0.0f;
+
+ //dy+= 0.25f*(fabs(uv[1]-uvprev[+1-3]) + fabs(uv[1]-uvnext[+1-3]));
+ dy+= 0.25f*(uv_l + uv_r);
+
+ uv_l= uvprev[ 5]!=0.0f? fabs(uv[1]-uvprev[+1+3]) : 0.0f;
+ uv_r= uvnext[ 5]!=0.0f? fabs(uv[1]-uvnext[+1+3]) : 0.0f;
+
+ //dy+= 0.25f*(fabs(uv[1]-uvprev[+1+3]) + fabs(uv[1]-uvnext[+1+3]));
+ dy+= 0.25f*(uv_l + uv_r);
+
+ /* UV to alpha threshold */
+ alpha= 1.0f - threshold*(dx+dy);
+ if(alpha<0.0f) alpha= 0.0f;
+ else alpha*= uv[2];
+
+ /* should use mipmap */
+ if(dx > 0.20f) dx= 0.20f;
+ if(dy > 0.20f) dy= 0.20f;
+
+ ibuf_sample(ibuf, uv[0], uv[1], dx, dy, out);
+ /* premul */
+ if(alpha<1.0f) {
+ out[0]*= alpha;
+ out[1]*= alpha;
+ out[2]*= alpha;
+ out[3]*= alpha;
+ }
+ }
+ }
+ }
+ }
+
+ IMB_freeImBuf(ibuf);
+}
+
+
+static void node_composit_exec_mapuv(void *UNUSED(data), bNode *node, bNodeStack **in, bNodeStack **out)
+{
+ if(out[0]->hasoutput==0)
+ return;
+
+ if(in[0]->data && in[1]->data) {
+ CompBuf *cbuf= in[0]->data;
+ CompBuf *uvbuf= in[1]->data;
+ CompBuf *stackbuf;
+
+ cbuf= typecheck_compbuf(cbuf, CB_RGBA);
+ uvbuf= typecheck_compbuf(uvbuf, CB_VEC3);
+ stackbuf= alloc_compbuf(uvbuf->x, uvbuf->y, CB_RGBA, 1); /* allocs */;
+
+ do_mapuv(stackbuf, cbuf, uvbuf, 0.05f*(float)node->custom1);
+
+ out[0]->data= stackbuf;
+
+ if(cbuf!=in[0]->data)
+ free_compbuf(cbuf);
+ if(uvbuf!=in[1]->data)
+ free_compbuf(uvbuf);
+ }
+}
+
+void register_node_type_cmp_mapuv(ListBase *lb)
+{
+ static bNodeType ntype;
+
+ node_type_base(&ntype, CMP_NODE_MAP_UV, "Map UV", NODE_CLASS_DISTORT, NODE_OPTIONS);
+ node_type_socket_templates(&ntype, cmp_node_mapuv_in, cmp_node_mapuv_out);
+ node_type_size(&ntype, 140, 100, 320);
+ node_type_exec(&ntype, node_composit_exec_mapuv);
+
+ nodeRegisterType(lb, &ntype);
+}
+
+
+
diff --git a/source/blender/nodes/composite/nodes/node_composite_mapValue.c b/source/blender/nodes/composite/nodes/node_composite_mapValue.c
new file mode 100644
index 00000000000..0d38aca4ce3
--- /dev/null
+++ b/source/blender/nodes/composite/nodes/node_composite_mapValue.c
@@ -0,0 +1,103 @@
+/*
+ * $Id: CMP_mapValue.c 36593 2011-05-10 11:19:26Z lukastoenne $
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2006 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/nodes/composite/nodes/node_composite_mapValue.c
+ * \ingroup cmpnodes
+ */
+
+
+#include "node_composite_util.h"
+
+/* **************** MAP VALUE ******************** */
+static bNodeSocketTemplate cmp_node_map_value_in[]= {
+ { SOCK_FLOAT, 1, "Value", 1.0f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f, PROP_NONE},
+ { -1, 0, "" }
+};
+static bNodeSocketTemplate cmp_node_map_value_out[]= {
+ { SOCK_FLOAT, 0, "Value"},
+ { -1, 0, "" }
+};
+
+static void do_map_value(bNode *node, float *out, float *src)
+{
+ TexMapping *texmap= node->storage;
+
+ out[0]= (src[0] + texmap->loc[0])*texmap->size[0];
+ if(texmap->flag & TEXMAP_CLIP_MIN)
+ if(out[0]<texmap->min[0])
+ out[0]= texmap->min[0];
+ if(texmap->flag & TEXMAP_CLIP_MAX)
+ if(out[0]>texmap->max[0])
+ out[0]= texmap->max[0];
+}
+
+static void node_composit_exec_map_value(void *UNUSED(data), bNode *node, bNodeStack **in, bNodeStack **out)
+{
+ /* stack order in: valbuf */
+ /* stack order out: valbuf */
+ if(out[0]->hasoutput==0) return;
+
+ /* input no image? then only value operation */
+ if(in[0]->data==NULL) {
+ do_map_value(node, out[0]->vec, in[0]->vec);
+ }
+ else {
+ /* make output size of input image */
+ CompBuf *cbuf= in[0]->data;
+ CompBuf *stackbuf= alloc_compbuf(cbuf->x, cbuf->y, CB_VAL, 1); /* allocs */
+
+ composit1_pixel_processor(node, stackbuf, in[0]->data, in[0]->vec, do_map_value, CB_VAL);
+
+ out[0]->data= stackbuf;
+ }
+}
+
+
+static void node_composit_init_map_value(bNodeTree *UNUSED(ntree), bNode* node, bNodeTemplate *UNUSED(ntemp))
+{
+ node->storage= add_mapping();
+}
+
+void register_node_type_cmp_map_value(ListBase *lb)
+{
+ static bNodeType ntype;
+
+ node_type_base(&ntype, CMP_NODE_MAP_VALUE, "Map Value", NODE_CLASS_OP_VECTOR, NODE_OPTIONS);
+ node_type_socket_templates(&ntype, cmp_node_map_value_in, cmp_node_map_value_out);
+ node_type_size(&ntype, 100, 60, 150);
+ node_type_init(&ntype, node_composit_init_map_value);
+ node_type_storage(&ntype, "TexMapping", node_free_standard_storage, node_copy_standard_storage);
+ node_type_exec(&ntype, node_composit_exec_map_value);
+
+ nodeRegisterType(lb, &ntype);
+}
+
+
+
+
diff --git a/source/blender/nodes/composite/nodes/node_composite_math.c b/source/blender/nodes/composite/nodes/node_composite_math.c
new file mode 100644
index 00000000000..2489491fdd8
--- /dev/null
+++ b/source/blender/nodes/composite/nodes/node_composite_math.c
@@ -0,0 +1,214 @@
+/*
+ * $Id: CMP_math.c 36593 2011-05-10 11:19:26Z lukastoenne $
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2006 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/nodes/composite/nodes/node_composite_math.c
+ * \ingroup cmpnodes
+ */
+
+
+#include "node_composite_util.h"
+
+/* **************** SCALAR MATH ******************** */
+static bNodeSocketTemplate cmp_node_math_in[]= {
+ { SOCK_FLOAT, 1, "Value", 0.5f, 0.5f, 0.5f, 1.0f, -10000.0f, 10000.0f, PROP_NONE},
+ { SOCK_FLOAT, 1, "Value", 0.5f, 0.5f, 0.5f, 1.0f, -10000.0f, 10000.0f, PROP_NONE},
+ { -1, 0, "" }
+};
+
+static bNodeSocketTemplate cmp_node_math_out[]= {
+ { SOCK_FLOAT, 0, "Value"},
+ { -1, 0, "" }
+};
+
+static void do_math(bNode *node, float *out, float *in, float *in2)
+{
+ switch(node->custom1)
+ {
+ case 0: /* Add */
+ out[0]= in[0] + in2[0];
+ break;
+ case 1: /* Subtract */
+ out[0]= in[0] - in2[0];
+ break;
+ case 2: /* Multiply */
+ out[0]= in[0] * in2[0];
+ break;
+ case 3: /* Divide */
+ {
+ if(in2[0]==0) /* We don't want to divide by zero. */
+ out[0]= 0.0;
+ else
+ out[0]= in[0] / in2[0];
+ }
+ break;
+ case 4: /* Sine */
+ out[0]= sin(in[0]);
+ break;
+ case 5: /* Cosine */
+ out[0]= cos(in[0]);
+ break;
+ case 6: /* Tangent */
+ out[0]= tan(in[0]);
+ break;
+ case 7: /* Arc-Sine */
+ {
+ /* Can't do the impossible... */
+ if(in[0] <= 1 && in[0] >= -1 )
+ out[0]= asin(in[0]);
+ else
+ out[0]= 0.0;
+ }
+ break;
+ case 8: /* Arc-Cosine */
+ {
+ /* Can't do the impossible... */
+ if( in[0] <= 1 && in[0] >= -1 )
+ out[0]= acos(in[0]);
+ else
+ out[0]= 0.0;
+ }
+ break;
+ case 9: /* Arc-Tangent */
+ out[0]= atan(in[0]);
+ break;
+ case 10: /* Power */
+ {
+ /* Only raise negative numbers by full integers */
+ if( in[0] >= 0 ) {
+ out[0]= pow(in[0], in2[0]);
+ } else {
+ float y_mod_1 = fmod(in2[0], 1);
+ /* if input value is not nearly an integer, fall back to zero, nicer than straight rounding */
+ if (y_mod_1 > 0.999 || y_mod_1 < 0.001) {
+ out[0]= pow(in[0], floor(in2[0] + 0.5));
+ } else {
+ out[0] = 0.0;
+ }
+ }
+ }
+ break;
+ case 11: /* Logarithm */
+ {
+ /* Don't want any imaginary numbers... */
+ if( in[0] > 0 && in2[0] > 0 )
+ out[0]= log(in[0]) / log(in2[0]);
+ else
+ out[0]= 0.0;
+ }
+ break;
+ case 12: /* Minimum */
+ {
+ if( in[0] < in2[0] )
+ out[0]= in[0];
+ else
+ out[0]= in2[0];
+ }
+ break;
+ case 13: /* Maximum */
+ {
+ if( in[0] > in2[0] )
+ out[0]= in[0];
+ else
+ out[0]= in2[0];
+ }
+ break;
+ case 14: /* Round */
+ {
+ /* round by the second value */
+ if( in2[0] != 0.0f )
+ out[0]= floorf(in[0] / in2[0] + 0.5f) * in2[0];
+ else
+ out[0]= floorf(in[0] + 0.5f);
+ }
+ break;
+ case 15: /* Less Than */
+ {
+ if( in[0] < in2[0] )
+ out[0]= 1.0f;
+ else
+ out[0]= 0.0f;
+ }
+ break;
+ case 16: /* Greater Than */
+ {
+ if( in[0] > in2[0] )
+ out[0]= 1.0f;
+ else
+ out[0]= 0.0f;
+ }
+ break;
+ }
+}
+
+static void node_composit_exec_math(void *UNUSED(data), bNode *node, bNodeStack **in, bNodeStack **out)
+{
+ CompBuf *cbuf=in[0]->data;
+ CompBuf *cbuf2=in[1]->data;
+ CompBuf *stackbuf;
+
+ /* check for inputs and outputs for early out*/
+ if(out[0]->hasoutput==0) return;
+
+ /* no image-color operation */
+ if(in[0]->data==NULL && in[1]->data==NULL) {
+ do_math(node, out[0]->vec, in[0]->vec, in[1]->vec);
+ return;
+ }
+
+ /*create output based on first input */
+ if(cbuf) {
+ stackbuf=alloc_compbuf(cbuf->x, cbuf->y, CB_VAL, 1);
+ }
+ /* and if it doesn't exist use the second input since we
+ know that one of them must exist at this point*/
+ else {
+ stackbuf=alloc_compbuf(cbuf2->x, cbuf2->y, CB_VAL, 1);
+ }
+
+ /* operate in case there's valid size */
+ composit2_pixel_processor(node, stackbuf, in[0]->data, in[0]->vec, in[1]->data, in[1]->vec, do_math, CB_VAL, CB_VAL);
+ out[0]->data= stackbuf;
+}
+
+void register_node_type_cmp_math(ListBase *lb)
+{
+ static bNodeType ntype;
+
+ node_type_base(&ntype, CMP_NODE_MATH, "Math", NODE_CLASS_CONVERTOR, NODE_OPTIONS);
+ node_type_socket_templates(&ntype, cmp_node_math_in, cmp_node_math_out);
+ node_type_size(&ntype, 120, 110, 160);
+ node_type_label(&ntype, node_math_label);
+ node_type_exec(&ntype, node_composit_exec_math);
+
+ nodeRegisterType(lb, &ntype);
+}
+
+
+
+
diff --git a/source/blender/nodes/composite/nodes/node_composite_mixrgb.c b/source/blender/nodes/composite/nodes/node_composite_mixrgb.c
new file mode 100644
index 00000000000..a5dcfcc44da
--- /dev/null
+++ b/source/blender/nodes/composite/nodes/node_composite_mixrgb.c
@@ -0,0 +1,99 @@
+/*
+ * $Id: CMP_mixrgb.c 36593 2011-05-10 11:19:26Z lukastoenne $
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2006 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/nodes/composite/nodes/node_composite_mixrgb.c
+ * \ingroup cmpnodes
+ */
+
+#include "node_composite_util.h"
+
+/* **************** MIX RGB ******************** */
+static bNodeSocketTemplate cmp_node_mix_rgb_in[]= {
+ { SOCK_FLOAT, 1, "Fac", 0.5f, 0.0f, 0.0f, 0.0f, 0.0f, 5.0f, PROP_FACTOR},
+ { SOCK_RGBA, 1, "Image", 0.8f, 0.8f, 0.8f, 1.0f},
+ { SOCK_RGBA, 1, "Image", 0.8f, 0.8f, 0.8f, 1.0f},
+ { -1, 0, "" }
+};
+static bNodeSocketTemplate cmp_node_mix_rgb_out[]= {
+ { SOCK_RGBA, 0, "Image"},
+ { -1, 0, "" }
+};
+
+static void do_mix_rgb(bNode *node, float *out, float *in1, float *in2, float *fac)
+{
+ float col[3];
+
+ VECCOPY(col, in1);
+ if(node->custom2)
+ ramp_blend(node->custom1, col, col+1, col+2, in2[3]*fac[0], in2);
+ else
+ ramp_blend(node->custom1, col, col+1, col+2, fac[0], in2);
+ VECCOPY(out, col);
+ out[3]= in1[3];
+}
+
+static void node_composit_exec_mix_rgb(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
+{
+ /* stack order in: fac, Image, Image */
+ /* stack order out: Image */
+ float *fac= in[0]->vec;
+
+ if(out[0]->hasoutput==0) return;
+
+ /* input no image? then only color operation */
+ if(in[1]->data==NULL && in[2]->data==NULL) {
+ do_mix_rgb(node, out[0]->vec, in[1]->vec, in[2]->vec, fac);
+ }
+ else {
+ /* make output size of first available input image */
+ CompBuf *cbuf= in[1]->data?in[1]->data:in[2]->data;
+ CompBuf *stackbuf= alloc_compbuf(cbuf->x, cbuf->y, CB_RGBA, 1); /* allocs */
+
+ composit3_pixel_processor(node, stackbuf, in[1]->data, in[1]->vec, in[2]->data, in[2]->vec, in[0]->data, fac, do_mix_rgb, CB_RGBA, CB_RGBA, CB_VAL);
+
+ out[0]->data= stackbuf;
+
+ generate_preview(data, node, out[0]->data);
+ }
+}
+
+/* custom1 = mix type */
+void register_node_type_cmp_mix_rgb(ListBase *lb)
+{
+ static bNodeType ntype;
+
+ node_type_base(&ntype, CMP_NODE_MIX_RGB, "Mix", NODE_CLASS_OP_COLOR, NODE_PREVIEW|NODE_OPTIONS);
+ node_type_socket_templates(&ntype, cmp_node_mix_rgb_in, cmp_node_mix_rgb_out);
+ node_type_size(&ntype, 110, 60, 120);
+ node_type_label(&ntype, node_blend_label);
+ node_type_exec(&ntype, node_composit_exec_mix_rgb);
+
+ nodeRegisterType(lb, &ntype);
+}
+
diff --git a/source/blender/nodes/composite/nodes/node_composite_normal.c b/source/blender/nodes/composite/nodes/node_composite_normal.c
new file mode 100644
index 00000000000..5f3c848903c
--- /dev/null
+++ b/source/blender/nodes/composite/nodes/node_composite_normal.c
@@ -0,0 +1,109 @@
+/*
+ * $Id: CMP_normal.c 36593 2011-05-10 11:19:26Z lukastoenne $
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2006 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/nodes/composite/nodes/node_composite_normal.c
+ * \ingroup cmpnodes
+ */
+
+
+#include "node_composite_util.h"
+
+
+/* **************** NORMAL ******************** */
+static bNodeSocketTemplate cmp_node_normal_in[]= {
+ { SOCK_VECTOR, 1, "Normal", 0.0f, 0.0f, 0.0f, 1.0f, -1.0f, 1.0f, PROP_DIRECTION},
+ { -1, 0, "" }
+};
+
+static bNodeSocketTemplate cmp_node_normal_out[]= {
+ { SOCK_VECTOR, 0, "Normal"},
+ { SOCK_FLOAT, 0, "Dot"},
+ { -1, 0, "" }
+};
+
+static void do_normal(bNode *node, float *out, float *in)
+{
+ bNodeSocket *sock= node->outputs.first;
+ float *nor= ((bNodeSocketValueVector*)sock->default_value)->value;
+
+ /* render normals point inside... the widget points outside */
+ out[0]= -INPR(nor, in);
+}
+
+/* generates normal, does dot product */
+static void node_composit_exec_normal(void *UNUSED(data), bNode *node, bNodeStack **in, bNodeStack **out)
+{
+ bNodeSocket *sock= node->outputs.first;
+ float *nor= ((bNodeSocketValueVector*)sock->default_value)->value;
+ /* stack order input: normal */
+ /* stack order output: normal, value */
+
+ /* input no image? then only vector op */
+ if(in[0]->data==NULL) {
+ VECCOPY(out[0]->vec, nor);
+ /* render normals point inside... the widget points outside */
+ out[1]->vec[0]= -INPR(out[0]->vec, in[0]->vec);
+ }
+ else if(out[1]->hasoutput) {
+ /* make output size of input image */
+ CompBuf *cbuf= in[0]->data;
+ CompBuf *stackbuf= alloc_compbuf(cbuf->x, cbuf->y, CB_VAL, 1); /* allocs */
+
+ composit1_pixel_processor(node, stackbuf, in[0]->data, in[0]->vec, do_normal, CB_VEC3);
+
+ out[1]->data= stackbuf;
+ }
+
+
+}
+
+static void init(bNodeTree *UNUSED(ntree), bNode *node, bNodeTemplate *UNUSED(ntemp))
+{
+ bNodeSocket *sock= node->outputs.first;
+ float *nor= ((bNodeSocketValueVector*)sock->default_value)->value;
+
+ nor[0] = 0.0f;
+ nor[1] = 0.0f;
+ nor[2] = 1.0f;
+}
+
+void register_node_type_cmp_normal(ListBase *lb)
+{
+ static bNodeType ntype;
+
+ node_type_base(&ntype, CMP_NODE_NORMAL, "Normal", NODE_CLASS_OP_VECTOR, NODE_OPTIONS);
+ node_type_socket_templates(&ntype, cmp_node_normal_in, cmp_node_normal_out);
+ node_type_init(&ntype, init);
+ node_type_size(&ntype, 100, 60, 200);
+ node_type_exec(&ntype, node_composit_exec_normal);
+
+ nodeRegisterType(lb, &ntype);
+}
+
+
diff --git a/source/blender/nodes/composite/nodes/node_composite_normalize.c b/source/blender/nodes/composite/nodes/node_composite_normalize.c
new file mode 100644
index 00000000000..1c5c3b57b80
--- /dev/null
+++ b/source/blender/nodes/composite/nodes/node_composite_normalize.c
@@ -0,0 +1,117 @@
+/*
+ * $Id: CMP_normalize.c 36593 2011-05-10 11:19:26Z lukastoenne $
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2006 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): gsr b3d, and a very minor edit from Robert Holcomb
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/nodes/composite/nodes/node_composite_normalize.c
+ * \ingroup cmpnodes
+ */
+
+
+#include "node_composite_util.h"
+
+
+/* **************** NORMALIZE single channel, useful for Z buffer ******************** */
+static bNodeSocketTemplate cmp_node_normalize_in[]= {
+ { SOCK_FLOAT, 1, "Value", 1.0f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f, PROP_NONE},
+ { -1, 0, "" }
+};
+static bNodeSocketTemplate cmp_node_normalize_out[]= {
+ { SOCK_FLOAT, 0, "Value"},
+ { -1, 0, "" }
+};
+
+static void do_normalize(bNode *UNUSED(node), float *out, float *src, float *min, float *mult)
+{
+ float res;
+ res = (src[0] - min[0]) * mult[0];
+ if (res > 1.0f) {
+ out[0] = 1.0f;
+ }
+ else if (res < 0.0f) {
+ out[0] = 0.0f;
+ }
+ else {
+ out[0] = res;
+ }
+}
+
+/* The code below assumes all data is inside range +- this, and that input buffer is single channel */
+#define BLENDER_ZMAX 10000.0f
+
+static void node_composit_exec_normalize(void *UNUSED(data), bNode *node, bNodeStack **in, bNodeStack **out)
+{
+ /* stack order in: valbuf */
+ /* stack order out: valbuf */
+ if(out[0]->hasoutput==0) return;
+
+ /* Input has no image buffer? Then pass the value */
+ if(in[0]->data==NULL) {
+ QUATCOPY(out[0]->vec, in[0]->vec);
+ }
+ else {
+ float min = 1.0f+BLENDER_ZMAX;
+ float max = -1.0f-BLENDER_ZMAX;
+ float mult = 1.0f;
+ float *val;
+ /* make output size of input image */
+ CompBuf *cbuf= in[0]->data;
+ int tot= cbuf->x*cbuf->y;
+ CompBuf *stackbuf= alloc_compbuf(cbuf->x, cbuf->y, CB_VAL, 1); /* allocs */
+
+ for (val = cbuf->rect; tot; tot--, val++) {
+ if ((*val > max) && (*val <= BLENDER_ZMAX)) {
+ max = *val;
+ }
+ if ((*val < min) && (*val >= -BLENDER_ZMAX)) {
+ min = *val;
+ }
+ }
+ /* In the rare case of flat buffer, which would cause a divide by 0, just pass the input to the output */
+ if ((max-min) != 0.0f) {
+ mult = 1.0f/(max-min);
+ composit3_pixel_processor(node, stackbuf, in[0]->data, in[0]->vec, NULL, &min, NULL, &mult, do_normalize, CB_VAL, CB_VAL, CB_VAL);
+ } else {
+ memcpy(stackbuf->rect, cbuf->rect, sizeof(float) * cbuf->x * cbuf->y);
+ }
+
+ out[0]->data= stackbuf;
+ }
+}
+
+void register_node_type_cmp_normalize(ListBase *lb)
+{
+ static bNodeType ntype;
+
+ node_type_base(&ntype, CMP_NODE_NORMALIZE, "Normalize", NODE_CLASS_OP_VECTOR, NODE_OPTIONS);
+ node_type_socket_templates(&ntype, cmp_node_normalize_in, cmp_node_normalize_out);
+ node_type_size(&ntype, 100, 60, 150);
+ node_type_exec(&ntype, node_composit_exec_normalize);
+ node_type_storage(&ntype, "TexMapping", NULL, NULL);
+
+ nodeRegisterType(lb, &ntype);
+}
diff --git a/source/blender/nodes/composite/nodes/node_composite_outputFile.c b/source/blender/nodes/composite/nodes/node_composite_outputFile.c
new file mode 100644
index 00000000000..13391a4a790
--- /dev/null
+++ b/source/blender/nodes/composite/nodes/node_composite_outputFile.c
@@ -0,0 +1,127 @@
+/*
+ * $Id: CMP_outputFile.c 36593 2011-05-10 11:19:26Z lukastoenne $
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2006 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/nodes/composite/nodes/node_composite_outputFile.c
+ * \ingroup cmpnodes
+ */
+
+
+#include "node_composite_util.h"
+
+/* **************** OUTPUT FILE ******************** */
+static bNodeSocketTemplate cmp_node_output_file_in[]= {
+ { SOCK_RGBA, 1, "Image", 0.0f, 0.0f, 0.0f, 1.0f},
+ { SOCK_FLOAT, 1, "Z", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, PROP_NONE},
+ { -1, 0, "" }
+};
+
+static void node_composit_exec_output_file(void *data, bNode *node, bNodeStack **in, bNodeStack **UNUSED(out))
+{
+ /* image assigned to output */
+ /* stack order input sockets: col, alpha */
+
+ if(in[0]->data) {
+ RenderData *rd= data;
+ NodeImageFile *nif= node->storage;
+ if(nif->sfra!=nif->efra && (rd->cfra<nif->sfra || rd->cfra>nif->efra)) {
+ return; /* BAIL OUT RETURN */
+ }
+ else if (!G.rendering) {
+ /* only output files when rendering a sequence -
+ * otherwise, it overwrites the output files just
+ * scrubbing through the timeline when the compositor updates */
+ return;
+ } else {
+ CompBuf *cbuf= typecheck_compbuf(in[0]->data, CB_RGBA);
+ ImBuf *ibuf= IMB_allocImBuf(cbuf->x, cbuf->y, 32, 0);
+ char string[256];
+
+ ibuf->rect_float= cbuf->rect;
+ ibuf->dither= rd->dither_intensity;
+
+ if (rd->color_mgt_flag & R_COLOR_MANAGEMENT)
+ ibuf->profile = IB_PROFILE_LINEAR_RGB;
+
+ if(in[1]->data) {
+ CompBuf *zbuf= in[1]->data;
+ if(zbuf->type==CB_VAL && zbuf->x==cbuf->x && zbuf->y==cbuf->y) {
+ nif->subimtype|= R_OPENEXR_ZBUF;
+ ibuf->zbuf_float= zbuf->rect;
+ }
+ }
+
+ BKE_makepicstring(string, nif->name, rd->cfra, nif->imtype, (rd->scemode & R_EXTENSION), TRUE);
+
+ if(0 == BKE_write_ibuf(ibuf, string, nif->imtype, nif->subimtype, nif->imtype==R_OPENEXR?nif->codec:nif->quality))
+ printf("Cannot save Node File Output to %s\n", string);
+ else
+ printf("Saved: %s\n", string);
+
+ IMB_freeImBuf(ibuf);
+
+ generate_preview(data, node, cbuf);
+
+ if(in[0]->data != cbuf)
+ free_compbuf(cbuf);
+ }
+ }
+}
+
+static void node_composit_init_output_file(bNodeTree *UNUSED(ntree), bNode* node, bNodeTemplate *UNUSED(ntemp))
+{
+ Scene *scene= (Scene *)node->id;
+ NodeImageFile *nif= MEM_callocN(sizeof(NodeImageFile), "node image file");
+ node->storage= nif;
+
+ if(scene) {
+ BLI_strncpy(nif->name, scene->r.pic, sizeof(nif->name));
+ nif->imtype= scene->r.imtype;
+ nif->subimtype= scene->r.subimtype;
+ nif->quality= scene->r.quality;
+ nif->sfra= scene->r.sfra;
+ nif->efra= scene->r.efra;
+ }
+}
+
+void register_node_type_cmp_output_file(ListBase *lb)
+{
+ static bNodeType ntype;
+
+ node_type_base(&ntype, CMP_NODE_OUTPUT_FILE, "File Output", NODE_CLASS_OUTPUT, NODE_PREVIEW|NODE_OPTIONS);
+ node_type_socket_templates(&ntype, cmp_node_output_file_in, NULL);
+ node_type_size(&ntype, 140, 80, 300);
+ node_type_init(&ntype, node_composit_init_output_file);
+ node_type_storage(&ntype, "NodeImageFile", node_free_standard_storage, node_copy_standard_storage);
+ node_type_exec(&ntype, node_composit_exec_output_file);
+
+ nodeRegisterType(lb, &ntype);
+}
+
+
+
diff --git a/source/blender/nodes/composite/nodes/node_composite_premulkey.c b/source/blender/nodes/composite/nodes/node_composite_premulkey.c
new file mode 100644
index 00000000000..066a8a81891
--- /dev/null
+++ b/source/blender/nodes/composite/nodes/node_composite_premulkey.c
@@ -0,0 +1,78 @@
+/*
+* $Id: CMP_premulkey.c 36333 2011-04-26 09:27:43Z lukastoenne $
+*
+* ***** BEGIN GPL LICENSE BLOCK *****
+*
+* This program is free software; you can redistribute it and/or
+* modify it under the terms of the GNU General Public License
+* as published by the Free Software Foundation; either version 2
+* of the License, or (at your option) any later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program; if not, write to the Free Software Foundation,
+* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+* The Original Code is Copyright (C) 2006 Blender Foundation.
+* All rights reserved.
+*
+* The Original Code is: all of this file.
+*
+* Contributor(s): none yet.
+*
+* ***** END GPL LICENSE BLOCK *****
+
+*/
+
+/** \file blender/nodes/composite/nodes/node_composite_premulkey.c
+ * \ingroup cmpnodes
+ */
+
+
+#include "node_composite_util.h"
+
+/* **************** Premul and Key Alpha Convert ******************** */
+
+static bNodeSocketTemplate cmp_node_premulkey_in[]= {
+ { SOCK_RGBA, 1, "Image", 0.8f, 0.8f, 0.8f, 1.0f},
+ { -1, 0, "" }
+};
+static bNodeSocketTemplate cmp_node_premulkey_out[]= {
+ { SOCK_RGBA, 0, "Image"},
+ { -1, 0, "" }
+};
+
+static void node_composit_exec_premulkey(void *UNUSED(data), bNode *node, bNodeStack **in, bNodeStack **out)
+{
+ if(out[0]->hasoutput==0)
+ return;
+
+ if(in[0]->data) {
+ CompBuf *stackbuf, *cbuf= typecheck_compbuf(in[0]->data, CB_RGBA);
+
+ stackbuf= dupalloc_compbuf(cbuf);
+ premul_compbuf(stackbuf, node->custom1 == 1);
+
+ out[0]->data = stackbuf;
+ if(cbuf != in[0]->data)
+ free_compbuf(cbuf);
+ }
+}
+
+void register_node_type_cmp_premulkey(ListBase *lb)
+{
+ static bNodeType ntype;
+
+ node_type_base(&ntype, CMP_NODE_PREMULKEY, "Alpha Convert", NODE_CLASS_CONVERTOR, NODE_OPTIONS);
+ node_type_socket_templates(&ntype, cmp_node_premulkey_in, cmp_node_premulkey_out);
+ node_type_size(&ntype, 140, 100, 320);
+ node_type_exec(&ntype, node_composit_exec_premulkey);
+
+ nodeRegisterType(lb, &ntype);
+}
+
+
diff --git a/source/blender/nodes/composite/nodes/node_composite_rgb.c b/source/blender/nodes/composite/nodes/node_composite_rgb.c
new file mode 100644
index 00000000000..41a13487edd
--- /dev/null
+++ b/source/blender/nodes/composite/nodes/node_composite_rgb.c
@@ -0,0 +1,77 @@
+/*
+ * $Id: CMP_rgb.c 36333 2011-04-26 09:27:43Z lukastoenne $
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2006 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/nodes/composite/nodes/node_composite_rgb.c
+ * \ingroup cmpnodes
+ */
+
+
+#include "node_composite_util.h"
+
+
+/* **************** RGB ******************** */
+static bNodeSocketTemplate cmp_node_rgb_out[]= {
+ { SOCK_RGBA, 0, "RGBA", 0.8f, 0.8f, 0.8f, 1.0f},
+ { -1, 0, "" }
+};
+
+static void node_composit_init_rgb(bNodeTree *UNUSED(ntree), bNode *node, bNodeTemplate *UNUSED(ntemp))
+{
+ bNodeSocket *sock= node->outputs.first;
+ float *col= ((bNodeSocketValueRGBA*)sock->default_value)->value;
+ /* uses the default value of the output socket, must be initialized here */
+ col[0] = 0.5f;
+ col[1] = 0.5f;
+ col[2] = 0.5f;
+ col[3] = 1.0f;
+}
+
+static void node_composit_exec_rgb(void *UNUSED(data), bNode *node, bNodeStack **UNUSED(in), bNodeStack **out)
+{
+ bNodeSocket *sock= node->outputs.first;
+ float *col= ((bNodeSocketValueRGBA*)sock->default_value)->value;
+
+ QUATCOPY(out[0]->vec, col);
+}
+
+void register_node_type_cmp_rgb(ListBase *lb)
+{
+ static bNodeType ntype;
+
+ node_type_base(&ntype, CMP_NODE_RGB, "RGB", NODE_CLASS_INPUT, NODE_OPTIONS);
+ node_type_socket_templates(&ntype, NULL, cmp_node_rgb_out);
+ node_type_init(&ntype, node_composit_init_rgb);
+ node_type_size(&ntype, 140, 80, 140);
+ node_type_exec(&ntype, node_composit_exec_rgb);
+
+ nodeRegisterType(lb, &ntype);
+}
+
+
+
diff --git a/source/blender/nodes/composite/nodes/node_composite_rotate.c b/source/blender/nodes/composite/nodes/node_composite_rotate.c
new file mode 100644
index 00000000000..4ece562c508
--- /dev/null
+++ b/source/blender/nodes/composite/nodes/node_composite_rotate.c
@@ -0,0 +1,142 @@
+/*
+ * $Id: CMP_rotate.c 36593 2011-05-10 11:19:26Z lukastoenne $
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2006 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/nodes/composite/nodes/node_composite_rotate.c
+ * \ingroup cmpnodes
+ */
+
+
+#include "node_composite_util.h"
+
+/* **************** Rotate ******************** */
+
+static bNodeSocketTemplate cmp_node_rotate_in[]= {
+ { SOCK_RGBA, 1, "Image", 0.8f, 0.8f, 0.8f, 1.0f},
+ { SOCK_FLOAT, 1, "Degr", 0.0f, 0.0f, 0.0f, 0.0f, -10000.0f, 10000.0f, PROP_ANGLE},
+ { -1, 0, "" }
+};
+static bNodeSocketTemplate cmp_node_rotate_out[]= {
+ { SOCK_RGBA, 0, "Image"},
+ { -1, 0, "" }
+};
+
+/* only supports RGBA nodes now */
+static void node_composit_exec_rotate(void *UNUSED(data), bNode *node, bNodeStack **in, bNodeStack **out)
+{
+
+ if(out[0]->hasoutput==0)
+ return;
+
+ if(in[0]->data) {
+ CompBuf *cbuf= typecheck_compbuf(in[0]->data, CB_RGBA);
+ CompBuf *stackbuf= alloc_compbuf(cbuf->x, cbuf->y, CB_RGBA, 1); /* note, this returns zero'd image */
+ float rad, u, v, s, c, centx, centy, miny, maxy, minx, maxx;
+ int x, y, yo, xo;
+ ImBuf *ibuf, *obuf;
+
+ rad= (M_PI*in[1]->vec[0])/180.0f;
+
+ s= sin(rad);
+ c= cos(rad);
+ centx= cbuf->x/2;
+ centy= cbuf->y/2;
+
+ minx= -centx;
+ maxx= -centx + (float)cbuf->x;
+ miny= -centy;
+ maxy= -centy + (float)cbuf->y;
+
+
+ ibuf=IMB_allocImBuf(cbuf->x, cbuf->y, 32, 0);
+ obuf=IMB_allocImBuf(stackbuf->x, stackbuf->y, 32, 0);
+
+ if(ibuf && obuf){
+ ibuf->rect_float=cbuf->rect;
+ obuf->rect_float=stackbuf->rect;
+
+ for(y=miny; y<maxy; y++) {
+ yo= y+(int)centy;
+
+ for(x=minx; x<maxx;x++) {
+ u=c*x + y*s + centx;
+ v=-s*x + c*y + centy;
+ xo= x+(int)centx;
+
+ switch(node->custom1) {
+ case 0:
+ neareast_interpolation(ibuf, obuf, u, v, xo, yo);
+ break ;
+ case 1:
+ bilinear_interpolation(ibuf, obuf, u, v, xo, yo);
+ break;
+ case 2:
+ bicubic_interpolation(ibuf, obuf, u, v, xo, yo);
+ break;
+ }
+
+ }
+ }
+
+ /* rotate offset vector too, but why negative rad, ehh?? Has to be replaced with [3][3] matrix once (ton) */
+ s= sin(-rad);
+ c= cos(-rad);
+ centx= (float)cbuf->xof; centy= (float)cbuf->yof;
+ stackbuf->xof= (int)( c*centx + s*centy);
+ stackbuf->yof= (int)(-s*centx + c*centy);
+
+ IMB_freeImBuf(ibuf);
+ IMB_freeImBuf(obuf);
+ }
+
+ /* pass on output and free */
+ out[0]->data= stackbuf;
+ if(cbuf!=in[0]->data) {
+ free_compbuf(cbuf);
+ }
+ }
+}
+
+static void node_composit_init_rotate(bNodeTree *UNUSED(ntree), bNode* node, bNodeTemplate *UNUSED(ntemp))
+{
+ node->custom1= 1; /* Bilinear Filter*/
+}
+
+void register_node_type_cmp_rotate(ListBase *lb)
+{
+ static bNodeType ntype;
+
+ node_type_base(&ntype, CMP_NODE_ROTATE, "Rotate", NODE_CLASS_DISTORT, NODE_OPTIONS);
+ node_type_socket_templates(&ntype, cmp_node_rotate_in, cmp_node_rotate_out);
+ node_type_size(&ntype, 140, 100, 320);
+ node_type_init(&ntype, node_composit_init_rotate);
+ node_type_exec(&ntype, node_composit_exec_rotate);
+
+ nodeRegisterType(lb, &ntype);
+}
+
diff --git a/source/blender/nodes/composite/nodes/node_composite_scale.c b/source/blender/nodes/composite/nodes/node_composite_scale.c
new file mode 100644
index 00000000000..4ba654e82d4
--- /dev/null
+++ b/source/blender/nodes/composite/nodes/node_composite_scale.c
@@ -0,0 +1,134 @@
+/*
+ * $Id: CMP_scale.c 36593 2011-05-10 11:19:26Z lukastoenne $
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2006 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/nodes/composite/nodes/node_composite_scale.c
+ * \ingroup cmpnodes
+ */
+
+
+#include "node_composite_util.h"
+
+/* **************** Scale ******************** */
+
+#define CMP_SCALE_MAX 12000
+
+static bNodeSocketTemplate cmp_node_scale_in[]= {
+ { SOCK_RGBA, 1, "Image", 0.8f, 0.8f, 0.8f, 1.0f},
+ { SOCK_FLOAT, 1, "X", 1.0f, 0.0f, 0.0f, 0.0f, 0.0001f, CMP_SCALE_MAX, PROP_FACTOR},
+ { SOCK_FLOAT, 1, "Y", 1.0f, 0.0f, 0.0f, 0.0f, 0.0001f, CMP_SCALE_MAX, PROP_FACTOR},
+ { -1, 0, "" }
+};
+static bNodeSocketTemplate cmp_node_scale_out[]= {
+ { SOCK_RGBA, 0, "Image"},
+ { -1, 0, "" }
+};
+
+/* only supports RGBA nodes now */
+/* node->custom1 stores if input values are absolute or relative scale */
+static void node_composit_exec_scale(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
+{
+ if(out[0]->hasoutput==0)
+ return;
+
+ if(in[0]->data) {
+ RenderData *rd= data;
+ CompBuf *stackbuf, *cbuf= typecheck_compbuf(in[0]->data, CB_RGBA);
+ ImBuf *ibuf;
+ int newx, newy;
+
+ if(node->custom1==CMP_SCALE_RELATIVE) {
+ newx= MAX2((int)(in[1]->vec[0]*cbuf->x), 1);
+ newy= MAX2((int)(in[2]->vec[0]*cbuf->y), 1);
+ }
+ else if(node->custom1==CMP_SCALE_SCENEPERCENT) {
+ newx = cbuf->x * (rd->size / 100.0f);
+ newy = cbuf->y * (rd->size / 100.0f);
+ }
+ else if (node->custom1==CMP_SCALE_RENDERPERCENT) {
+ newx= (rd->xsch * rd->size)/100;
+ newy= (rd->ysch * rd->size)/100;
+ } else { /* CMP_SCALE_ABSOLUTE */
+ newx= MAX2((int)in[1]->vec[0], 1);
+ newy= MAX2((int)in[2]->vec[0], 1);
+ }
+ newx= MIN2(newx, CMP_SCALE_MAX);
+ newy= MIN2(newy, CMP_SCALE_MAX);
+
+ ibuf= IMB_allocImBuf(cbuf->x, cbuf->y, 32, 0);
+ if(ibuf) {
+ ibuf->rect_float= cbuf->rect;
+ IMB_scaleImBuf(ibuf, newx, newy);
+
+ if(ibuf->rect_float == cbuf->rect) {
+ /* no scaling happened. */
+ stackbuf= pass_on_compbuf(in[0]->data);
+ }
+ else {
+ stackbuf= alloc_compbuf(newx, newy, CB_RGBA, 0);
+ stackbuf->rect= ibuf->rect_float;
+ stackbuf->malloc= 1;
+ }
+
+ ibuf->rect_float= NULL;
+ ibuf->mall &= ~IB_rectfloat;
+ IMB_freeImBuf(ibuf);
+
+ /* also do the translation vector */
+ stackbuf->xof = (int)(((float)newx/(float)cbuf->x) * (float)cbuf->xof);
+ stackbuf->yof = (int)(((float)newy/(float)cbuf->y) * (float)cbuf->yof);
+ }
+ else {
+ stackbuf= dupalloc_compbuf(cbuf);
+ printf("Scaling to %dx%d failed\n", newx, newy);
+ }
+
+ out[0]->data= stackbuf;
+ if(cbuf!=in[0]->data)
+ free_compbuf(cbuf);
+ }
+}
+
+void register_node_type_cmp_scale(ListBase *lb)
+{
+ static bNodeType ntype;
+
+ node_type_base(&ntype, CMP_NODE_SCALE, "Scale", NODE_CLASS_DISTORT, NODE_OPTIONS);
+ node_type_socket_templates(&ntype, cmp_node_scale_in, cmp_node_scale_out);
+ node_type_size(&ntype, 140, 100, 320);
+ node_type_exec(&ntype, node_composit_exec_scale);
+
+ nodeRegisterType(lb, &ntype);
+}
+
+
+
+
+
+
+
diff --git a/source/blender/nodes/composite/nodes/node_composite_sepcombHSVA.c b/source/blender/nodes/composite/nodes/node_composite_sepcombHSVA.c
new file mode 100644
index 00000000000..5460427fd73
--- /dev/null
+++ b/source/blender/nodes/composite/nodes/node_composite_sepcombHSVA.c
@@ -0,0 +1,187 @@
+/*
+ * $Id: CMP_sepcombHSVA.c 36593 2011-05-10 11:19:26Z lukastoenne $
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2006 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/nodes/composite/nodes/node_composite_sepcombHSVA.c
+ * \ingroup cmpnodes
+ */
+
+
+#include "node_composite_util.h"
+
+
+/* **************** SEPARATE HSVA ******************** */
+static bNodeSocketTemplate cmp_node_sephsva_in[]= {
+ { SOCK_RGBA, 1, "Image", 0.8f, 0.8f, 0.8f, 1.0f},
+ { -1, 0, "" }
+};
+static bNodeSocketTemplate cmp_node_sephsva_out[]= {
+ { SOCK_FLOAT, 0, "H"},
+ { SOCK_FLOAT, 0, "S"},
+ { SOCK_FLOAT, 0, "V"},
+ { SOCK_FLOAT, 0, "A"},
+ { -1, 0, "" }
+};
+
+static void do_sephsva(bNode *UNUSED(node), float *out, float *in)
+{
+ float h, s, v;
+
+ rgb_to_hsv(in[0], in[1], in[2], &h, &s, &v);
+
+ out[0]= h;
+ out[1]= s;
+ out[2]= v;
+ out[3]= in[3];
+}
+
+static void node_composit_exec_sephsva(void *UNUSED(data), bNode *node, bNodeStack **in, bNodeStack **out)
+{
+ /* stack order out: bw channels */
+ /* stack order in: col */
+
+ /* input no image? then only color operation */
+ if(in[0]->data==NULL) {
+ float h, s, v;
+
+ rgb_to_hsv(in[0]->vec[0], in[0]->vec[1], in[0]->vec[2], &h, &s, &v);
+
+ out[0]->vec[0] = h;
+ out[1]->vec[0] = s;
+ out[2]->vec[0] = v;
+ out[3]->vec[0] = in[0]->vec[3];
+ }
+ else if ((out[0]->hasoutput) || (out[1]->hasoutput) || (out[2]->hasoutput) || (out[3]->hasoutput)) {
+ /* create new buffer so input buffer doesn't get corrupted */
+ CompBuf *cbuf= dupalloc_compbuf(in[0]->data);
+ CompBuf *cbuf2= typecheck_compbuf(cbuf, CB_RGBA);
+
+ /* convert the RGB stackbuf to an HSV representation */
+ composit1_pixel_processor(node, cbuf2, cbuf2, in[0]->vec, do_sephsva, CB_RGBA);
+
+ /* separate each of those channels */
+ if(out[0]->hasoutput)
+ out[0]->data= valbuf_from_rgbabuf(cbuf2, CHAN_R);
+ if(out[1]->hasoutput)
+ out[1]->data= valbuf_from_rgbabuf(cbuf2, CHAN_G);
+ if(out[2]->hasoutput)
+ out[2]->data= valbuf_from_rgbabuf(cbuf2, CHAN_B);
+ if(out[3]->hasoutput)
+ out[3]->data= valbuf_from_rgbabuf(cbuf2, CHAN_A);
+
+ /*not used anymore */
+ if(cbuf2!=cbuf)
+ free_compbuf(cbuf2);
+ free_compbuf(cbuf);
+ }
+}
+
+void register_node_type_cmp_sephsva(ListBase *lb)
+{
+ static bNodeType ntype;
+
+ node_type_base(&ntype, CMP_NODE_SEPHSVA, "Separate HSVA", NODE_CLASS_CONVERTOR, 0);
+ node_type_socket_templates(&ntype, cmp_node_sephsva_in, cmp_node_sephsva_out);
+ node_type_size(&ntype, 80, 40, 140);
+ node_type_exec(&ntype, node_composit_exec_sephsva);
+
+ nodeRegisterType(lb, &ntype);
+}
+
+
+/* **************** COMBINE HSVA ******************** */
+static bNodeSocketTemplate cmp_node_combhsva_in[]= {
+ { SOCK_FLOAT, 1, "H", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, PROP_NONE},
+ { SOCK_FLOAT, 1, "S", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, PROP_NONE},
+ { SOCK_FLOAT, 1, "V", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, PROP_NONE},
+ { SOCK_FLOAT, 1, "A", 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, PROP_NONE},
+ { -1, 0, "" }
+};
+static bNodeSocketTemplate cmp_node_combhsva_out[]= {
+ { SOCK_RGBA, 0, "Image"},
+ { -1, 0, "" }
+};
+
+static void do_comb_hsva(bNode *UNUSED(node), float *out, float *in1, float *in2, float *in3, float *in4)
+{
+ float r,g,b;
+ hsv_to_rgb(in1[0], in2[0], in3[0], &r, &g, &b);
+
+ out[0] = r;
+ out[1] = g;
+ out[2] = b;
+ out[3] = in4[0];
+}
+
+static void node_composit_exec_combhsva(void *UNUSED(data), bNode *node, bNodeStack **in, bNodeStack **out)
+{
+ /* stack order out: 1 rgba channels */
+ /* stack order in: 4 value channels */
+
+ /* input no image? then only color operation */
+ if((in[0]->data==NULL) && (in[1]->data==NULL) && (in[2]->data==NULL) && (in[3]->data==NULL)) {
+ out[0]->vec[0] = in[0]->vec[0];
+ out[0]->vec[1] = in[1]->vec[0];
+ out[0]->vec[2] = in[2]->vec[0];
+ out[0]->vec[3] = in[3]->vec[0];
+ }
+ else {
+ /* make output size of first available input image */
+ CompBuf *cbuf;
+ CompBuf *stackbuf;
+
+ /* allocate a CompBuf the size of the first available input */
+ if (in[0]->data) cbuf = in[0]->data;
+ else if (in[1]->data) cbuf = in[1]->data;
+ else if (in[2]->data) cbuf = in[2]->data;
+ else cbuf = in[3]->data;
+
+ stackbuf = alloc_compbuf(cbuf->x, cbuf->y, CB_RGBA, 1); /* allocs */
+
+ composit4_pixel_processor(node, stackbuf, in[0]->data, in[0]->vec, in[1]->data, in[1]->vec,
+ in[2]->data, in[2]->vec, in[3]->data, in[3]->vec,
+ do_comb_hsva, CB_VAL, CB_VAL, CB_VAL, CB_VAL);
+
+ out[0]->data= stackbuf;
+ }
+}
+
+void register_node_type_cmp_combhsva(ListBase *lb)
+{
+ static bNodeType ntype;
+
+ node_type_base(&ntype, CMP_NODE_COMBHSVA, "Combine HSVA", NODE_CLASS_CONVERTOR, NODE_OPTIONS);
+ node_type_socket_templates(&ntype, cmp_node_combhsva_in, cmp_node_combhsva_out);
+ node_type_size(&ntype, 80, 40, 140);
+ node_type_exec(&ntype, node_composit_exec_combhsva);
+
+ nodeRegisterType(lb, &ntype);
+}
+
+
+
diff --git a/source/blender/nodes/composite/nodes/node_composite_sepcombRGBA.c b/source/blender/nodes/composite/nodes/node_composite_sepcombRGBA.c
new file mode 100644
index 00000000000..a074d895acb
--- /dev/null
+++ b/source/blender/nodes/composite/nodes/node_composite_sepcombRGBA.c
@@ -0,0 +1,162 @@
+/*
+ * $Id: CMP_sepcombRGBA.c 36593 2011-05-10 11:19:26Z lukastoenne $
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2006 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/nodes/composite/nodes/node_composite_sepcombRGBA.c
+ * \ingroup cmpnodes
+ */
+
+
+#include "node_composite_util.h"
+
+/* **************** SEPARATE RGBA ******************** */
+static bNodeSocketTemplate cmp_node_seprgba_in[]= {
+ { SOCK_RGBA, 1, "Image", 0.8f, 0.8f, 0.8f, 1.0f},
+ { -1, 0, "" }
+};
+static bNodeSocketTemplate cmp_node_seprgba_out[]= {
+ { SOCK_FLOAT, 0, "R"},
+ { SOCK_FLOAT, 0, "G"},
+ { SOCK_FLOAT, 0, "B"},
+ { SOCK_FLOAT, 0, "A"},
+ { -1, 0, "" }
+};
+
+static void node_composit_exec_seprgba(void *UNUSED(data), bNode *UNUSED(node), bNodeStack **in, bNodeStack **out)
+{
+ /* stack order out: bw channels */
+ /* stack order in: col */
+
+ /* input no image? then only color operation */
+ if(in[0]->data==NULL) {
+ out[0]->vec[0] = in[0]->vec[0];
+ out[1]->vec[0] = in[0]->vec[1];
+ out[2]->vec[0] = in[0]->vec[2];
+ out[3]->vec[0] = in[0]->vec[3];
+ }
+ else {
+ /* make sure we get right rgba buffer */
+ CompBuf *cbuf= typecheck_compbuf(in[0]->data, CB_RGBA);
+
+ /* don't do any pixel processing, just copy the stack directly (faster, I presume) */
+ if(out[0]->hasoutput)
+ out[0]->data= valbuf_from_rgbabuf(cbuf, CHAN_R);
+ if(out[1]->hasoutput)
+ out[1]->data= valbuf_from_rgbabuf(cbuf, CHAN_G);
+ if(out[2]->hasoutput)
+ out[2]->data= valbuf_from_rgbabuf(cbuf, CHAN_B);
+ if(out[3]->hasoutput)
+ out[3]->data= valbuf_from_rgbabuf(cbuf, CHAN_A);
+
+ if(cbuf!=in[0]->data)
+ free_compbuf(cbuf);
+
+ }
+}
+
+void register_node_type_cmp_seprgba(ListBase *lb)
+{
+ static bNodeType ntype;
+
+ node_type_base(&ntype, CMP_NODE_SEPRGBA, "Separate RGBA", NODE_CLASS_CONVERTOR, 0);
+ node_type_socket_templates(&ntype, cmp_node_seprgba_in, cmp_node_seprgba_out);
+ node_type_size(&ntype, 80, 40, 140);
+ node_type_exec(&ntype, node_composit_exec_seprgba);
+
+ nodeRegisterType(lb, &ntype);
+}
+
+
+
+/* **************** COMBINE RGBA ******************** */
+static bNodeSocketTemplate cmp_node_combrgba_in[]= {
+ { SOCK_FLOAT, 1, "R", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, PROP_NONE},
+ { SOCK_FLOAT, 1, "G", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, PROP_NONE},
+ { SOCK_FLOAT, 1, "B", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, PROP_NONE},
+ { SOCK_FLOAT, 1, "A", 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, PROP_NONE},
+ { -1, 0, "" }
+};
+static bNodeSocketTemplate cmp_node_combrgba_out[]= {
+ { SOCK_RGBA, 0, "Image"},
+ { -1, 0, "" }
+};
+
+static void do_combrgba(bNode *UNUSED(node), float *out, float *in1, float *in2, float *in3, float *in4)
+{
+ out[0] = in1[0];
+ out[1] = in2[0];
+ out[2] = in3[0];
+ out[3] = in4[0];
+}
+
+static void node_composit_exec_combrgba(void *UNUSED(data), bNode *node, bNodeStack **in, bNodeStack **out)
+{
+ /* stack order out: 1 rgba channels */
+ /* stack order in: 4 value channels */
+
+ /* input no image? then only color operation */
+ if((in[0]->data==NULL) && (in[1]->data==NULL) && (in[2]->data==NULL) && (in[3]->data==NULL)) {
+ out[0]->vec[0] = in[0]->vec[0];
+ out[0]->vec[1] = in[1]->vec[0];
+ out[0]->vec[2] = in[2]->vec[0];
+ out[0]->vec[3] = in[3]->vec[0];
+ }
+ else {
+ /* make output size of first available input image */
+ CompBuf *cbuf;
+ CompBuf *stackbuf;
+
+ /* allocate a CompBuf the size of the first available input */
+ if (in[0]->data) cbuf = in[0]->data;
+ else if (in[1]->data) cbuf = in[1]->data;
+ else if (in[2]->data) cbuf = in[2]->data;
+ else cbuf = in[3]->data;
+
+ stackbuf = alloc_compbuf(cbuf->x, cbuf->y, CB_RGBA, 1); /* allocs */
+
+ composit4_pixel_processor(node, stackbuf, in[0]->data, in[0]->vec, in[1]->data, in[1]->vec,
+ in[2]->data, in[2]->vec, in[3]->data, in[3]->vec,
+ do_combrgba, CB_VAL, CB_VAL, CB_VAL, CB_VAL);
+
+ out[0]->data= stackbuf;
+ }
+}
+
+void register_node_type_cmp_combrgba(ListBase *lb)
+{
+ static bNodeType ntype;
+
+ node_type_base(&ntype, CMP_NODE_COMBRGBA, "Combine RGBA", NODE_CLASS_CONVERTOR, NODE_OPTIONS);
+ node_type_socket_templates(&ntype, cmp_node_combrgba_in, cmp_node_combrgba_out);
+ node_type_size(&ntype, 80, 40, 140);
+ node_type_exec(&ntype, node_composit_exec_combrgba);
+
+ nodeRegisterType(lb, &ntype);
+}
+
+
diff --git a/source/blender/nodes/composite/nodes/node_composite_sepcombYCCA.c b/source/blender/nodes/composite/nodes/node_composite_sepcombYCCA.c
new file mode 100644
index 00000000000..61e88418e59
--- /dev/null
+++ b/source/blender/nodes/composite/nodes/node_composite_sepcombYCCA.c
@@ -0,0 +1,313 @@
+/*
+ * $Id: CMP_sepcombYCCA.c 36593 2011-05-10 11:19:26Z lukastoenne $
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2006 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/nodes/composite/nodes/node_composite_sepcombYCCA.c
+ * \ingroup cmpnodes
+ */
+
+
+#include "node_composite_util.h"
+
+
+/* **************** SEPARATE YCCA ******************** */
+static bNodeSocketTemplate cmp_node_sepycca_in[]= {
+ { SOCK_RGBA, 1, "Image", 0.8f, 0.8f, 0.8f, 1.0f},
+ { -1, 0, "" }
+};
+static bNodeSocketTemplate cmp_node_sepycca_out[]= {
+ { SOCK_FLOAT, 0, "Y"},
+ { SOCK_FLOAT, 0, "Cb"},
+ { SOCK_FLOAT, 0, "Cr"},
+ { SOCK_FLOAT, 0, "A"},
+ { -1, 0, "" }
+};
+
+static void do_sepycca_601(bNode *UNUSED(node), float *out, float *in)
+{
+ float y, cb, cr;
+
+ rgb_to_ycc(in[0], in[1], in[2], &y, &cb, &cr, BLI_YCC_ITU_BT601);
+
+ /*divided by 255 to normalize for viewing in */
+ out[0]= y/255.0;
+ out[1]= cb/255.0;
+ out[2]= cr/255.0;
+ out[3]= in[3];
+}
+
+static void do_sepycca_709(bNode *UNUSED(node), float *out, float *in)
+{
+ float y, cb, cr;
+
+ rgb_to_ycc(in[0], in[1], in[2], &y, &cb, &cr, BLI_YCC_ITU_BT709);
+
+ /*divided by 255 to normalize for viewing in */
+ out[0]= y/255.0;
+ out[1]= cb/255.0;
+ out[2]= cr/255.0;
+ out[3]= in[3];
+}
+
+static void do_sepycca_jfif(bNode *UNUSED(node), float *out, float *in)
+{
+ float y, cb, cr;
+
+ rgb_to_ycc(in[0], in[1], in[2], &y, &cb, &cr, BLI_YCC_JFIF_0_255);
+
+ /*divided by 255 to normalize for viewing in */
+ out[0]= y/255.0;
+ out[1]= cb/255.0;
+ out[2]= cr/255.0;
+ out[3]= in[3];
+}
+
+static void node_composit_exec_sepycca(void *UNUSED(data), bNode *node, bNodeStack **in, bNodeStack **out)
+{
+ /* input no image? then only color operation */
+ if(in[0]->data==NULL) {
+ float y, cb, cr;
+
+ switch(node->custom1)
+ {
+ case 1:
+ rgb_to_ycc(in[0]->vec[0], in[0]->vec[1], in[0]->vec[2], &y, &cb, &cr, BLI_YCC_ITU_BT709);
+ break;
+ case 2:
+ rgb_to_ycc(in[0]->vec[0], in[0]->vec[1], in[0]->vec[2], &y, &cb, &cr, BLI_YCC_JFIF_0_255);
+ break;
+ case 0:
+ default:
+ rgb_to_ycc(in[0]->vec[0], in[0]->vec[1], in[0]->vec[2], &y, &cb, &cr, BLI_YCC_ITU_BT601);
+ break;
+ }
+
+ /*divided by 255 to normalize for viewing in */
+ out[0]->vec[0] = y/255.0;
+ out[1]->vec[0] = cb/255.0;
+ out[2]->vec[0] = cr/255.0;
+ out[3]->vec[0] = in[0]->vec[3];
+ }
+ else if ((out[0]->hasoutput) || (out[1]->hasoutput) || (out[2]->hasoutput) || (out[3]->hasoutput)) {
+ /* make copy of buffer so input buffer doesn't get corrupted */
+ CompBuf *cbuf= dupalloc_compbuf(in[0]->data);
+ CompBuf *cbuf2=typecheck_compbuf(cbuf, CB_RGBA);
+
+ /* convert the RGB stackbuf to an HSV representation */
+ switch(node->custom1)
+ {
+ case 1:
+ composit1_pixel_processor(node, cbuf2, cbuf2, in[0]->vec, do_sepycca_709, CB_RGBA);
+ break;
+ case 2:
+ composit1_pixel_processor(node, cbuf2, cbuf2, in[0]->vec, do_sepycca_jfif, CB_RGBA);
+ break;
+ case 0:
+ default:
+ composit1_pixel_processor(node, cbuf2, cbuf2, in[0]->vec, do_sepycca_601, CB_RGBA);
+ break;
+ }
+
+ /* separate each of those channels */
+ if(out[0]->hasoutput)
+ out[0]->data= valbuf_from_rgbabuf(cbuf2, CHAN_R);
+ if(out[1]->hasoutput)
+ out[1]->data= valbuf_from_rgbabuf(cbuf2, CHAN_G);
+ if(out[2]->hasoutput)
+ out[2]->data= valbuf_from_rgbabuf(cbuf2, CHAN_B);
+ if(out[3]->hasoutput)
+ out[3]->data= valbuf_from_rgbabuf(cbuf2, CHAN_A);
+
+ /*not used anymore */
+ if(cbuf2!=cbuf)
+ free_compbuf(cbuf2);
+ free_compbuf(cbuf);
+ }
+}
+
+void register_node_type_cmp_sepycca(ListBase *lb)
+{
+ static bNodeType ntype;
+
+ node_type_base(&ntype, CMP_NODE_SEPYCCA, "Separate YCbCrA", NODE_CLASS_CONVERTOR, NODE_OPTIONS);
+ node_type_socket_templates(&ntype, cmp_node_sepycca_in, cmp_node_sepycca_out);
+ node_type_size(&ntype, 80, 40, 140);
+ node_type_exec(&ntype, node_composit_exec_sepycca);
+
+ nodeRegisterType(lb, &ntype);
+}
+
+
+
+/* **************** COMBINE YCCA ******************** */
+static bNodeSocketTemplate cmp_node_combycca_in[]= {
+ { SOCK_FLOAT, 1, "Y", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, PROP_NONE},
+ { SOCK_FLOAT, 1, "Cb", 0.5f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, PROP_NONE},
+ { SOCK_FLOAT, 1, "Cr", 0.5f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, PROP_NONE},
+ { SOCK_FLOAT, 1, "A", 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, PROP_NONE},
+ { -1, 0, "" }
+};
+static bNodeSocketTemplate cmp_node_combycca_out[]= {
+ { SOCK_RGBA, 0, "Image"},
+ { -1, 0, "" }
+};
+
+static void do_comb_ycca_601(bNode *UNUSED(node), float *out, float *in1, float *in2, float *in3, float *in4)
+{
+ float r,g,b;
+ float y, cb, cr;
+
+ /*need to un-normalize the data*/
+ y=in1[0]*255;
+ cb=in2[0]*255;
+ cr=in3[0]*255;
+
+ ycc_to_rgb(y,cb,cr, &r, &g, &b, BLI_YCC_ITU_BT601);
+
+ out[0] = r;
+ out[1] = g;
+ out[2] = b;
+ out[3] = in4[0];
+}
+
+static void do_comb_ycca_709(bNode *UNUSED(node), float *out, float *in1, float *in2, float *in3, float *in4)
+{
+ float r,g,b;
+ float y, cb, cr;
+
+ /*need to un-normalize the data*/
+ y=in1[0]*255;
+ cb=in2[0]*255;
+ cr=in3[0]*255;
+
+ ycc_to_rgb(y,cb,cr, &r, &g, &b, BLI_YCC_ITU_BT709);
+
+ out[0] = r;
+ out[1] = g;
+ out[2] = b;
+ out[3] = in4[0];
+}
+
+static void do_comb_ycca_jfif(bNode *UNUSED(node), float *out, float *in1, float *in2, float *in3, float *in4)
+{
+ float r,g,b;
+ float y, cb, cr;
+
+ /*need to un-normalize the data*/
+ y=in1[0]*255;
+ cb=in2[0]*255;
+ cr=in3[0]*255;
+
+ ycc_to_rgb(y,cb,cr, &r, &g, &b, BLI_YCC_JFIF_0_255);
+
+ out[0] = r;
+ out[1] = g;
+ out[2] = b;
+ out[3] = in4[0];
+}
+
+static void node_composit_exec_combycca(void *UNUSED(data), bNode *node, bNodeStack **in, bNodeStack **out)
+{
+ /* stack order out: 1 ycca channels */
+ /* stack order in: 4 value channels */
+
+ /* input no image? then only color operation */
+ if((in[0]->data==NULL) && (in[1]->data==NULL) && (in[2]->data==NULL) && (in[3]->data==NULL)) {
+ float y = in[0]->vec[0] * 255;
+ float cb = in[1]->vec[0] * 255;
+ float cr = in[2]->vec[0] * 255;
+
+ switch(node->custom1)
+ {
+ case 1:
+ ycc_to_rgb(y, cb, cr, &out[0]->vec[0], &out[0]->vec[1], &out[0]->vec[2], BLI_YCC_ITU_BT709);
+ break;
+ case 2:
+ ycc_to_rgb(y, cb, cr, &out[0]->vec[0], &out[0]->vec[1], &out[0]->vec[2], BLI_YCC_JFIF_0_255);
+ break;
+ case 0:
+ default:
+ ycc_to_rgb(y, cb, cr, &out[0]->vec[0], &out[0]->vec[1], &out[0]->vec[2], BLI_YCC_ITU_BT601);
+ break;
+ }
+
+ out[0]->vec[3] = in[3]->vec[0];
+ }
+ else {
+ /* make output size of first available input image */
+ CompBuf *cbuf;
+ CompBuf *stackbuf;
+
+ /* allocate a CompBuf the size of the first available input */
+ if (in[0]->data) cbuf = in[0]->data;
+ else if (in[1]->data) cbuf = in[1]->data;
+ else if (in[2]->data) cbuf = in[2]->data;
+ else cbuf = in[3]->data;
+
+ stackbuf = alloc_compbuf(cbuf->x, cbuf->y, CB_RGBA, 1); /* allocs */
+
+
+ switch(node->custom1)
+ {
+ case 1:
+ composit4_pixel_processor(node, stackbuf, in[0]->data, in[0]->vec, in[1]->data, in[1]->vec,
+ in[2]->data, in[2]->vec, in[3]->data, in[3]->vec,
+ do_comb_ycca_709, CB_VAL, CB_VAL, CB_VAL, CB_VAL);
+ break;
+
+ case 2:
+ composit4_pixel_processor(node, stackbuf, in[0]->data, in[0]->vec, in[1]->data, in[1]->vec,
+ in[2]->data, in[2]->vec, in[3]->data, in[3]->vec,
+ do_comb_ycca_jfif, CB_VAL, CB_VAL, CB_VAL, CB_VAL);
+ break;
+ case 0:
+ default:
+ composit4_pixel_processor(node, stackbuf, in[0]->data, in[0]->vec, in[1]->data, in[1]->vec,
+ in[2]->data, in[2]->vec, in[3]->data, in[3]->vec,
+ do_comb_ycca_601, CB_VAL, CB_VAL, CB_VAL, CB_VAL);
+ break;
+ }
+
+ out[0]->data= stackbuf;
+ }
+}
+
+void register_node_type_cmp_combycca(ListBase *lb)
+{
+ static bNodeType ntype;
+
+ node_type_base(&ntype, CMP_NODE_COMBYCCA, "Combine YCbCrA", NODE_CLASS_CONVERTOR, NODE_OPTIONS);
+ node_type_socket_templates(&ntype, cmp_node_combycca_in, cmp_node_combycca_out);
+ node_type_size(&ntype, 80, 40, 140);
+ node_type_exec(&ntype, node_composit_exec_combycca);
+
+ nodeRegisterType(lb, &ntype);
+}
+
+
+
diff --git a/source/blender/nodes/composite/nodes/node_composite_sepcombYUVA.c b/source/blender/nodes/composite/nodes/node_composite_sepcombYUVA.c
new file mode 100644
index 00000000000..14f086300c0
--- /dev/null
+++ b/source/blender/nodes/composite/nodes/node_composite_sepcombYUVA.c
@@ -0,0 +1,187 @@
+/*
+ * $Id: CMP_sepcombYUVA.c 36593 2011-05-10 11:19:26Z lukastoenne $
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2006 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/nodes/composite/nodes/node_composite_sepcombYUVA.c
+ * \ingroup cmpnodes
+ */
+
+
+#include "node_composite_util.h"
+
+
+/* **************** SEPARATE YUVA ******************** */
+static bNodeSocketTemplate cmp_node_sepyuva_in[]= {
+ { SOCK_RGBA, 1, "Image", 0.8f, 0.8f, 0.8f, 1.0f},
+ { -1, 0, "" }
+};
+static bNodeSocketTemplate cmp_node_sepyuva_out[]= {
+ { SOCK_FLOAT, 0, "Y"},
+ { SOCK_FLOAT, 0, "U"},
+ { SOCK_FLOAT, 0, "V"},
+ { SOCK_FLOAT, 0, "A"},
+ { -1, 0, "" }
+};
+
+static void do_sepyuva(bNode *UNUSED(node), float *out, float *in)
+{
+ float y, u, v;
+
+ rgb_to_yuv(in[0], in[1], in[2], &y, &u, &v);
+
+ out[0]= y;
+ out[1]= u;
+ out[2]= v;
+ out[3]= in[3];
+}
+
+static void node_composit_exec_sepyuva(void *UNUSED(data), bNode *node, bNodeStack **in, bNodeStack **out)
+{
+ /* stack order out: bw channels */
+ /* stack order in: col */
+
+ /* input no image? then only color operation */
+ if(in[0]->data==NULL) {
+ float y, u, v;
+
+ rgb_to_yuv(in[0]->vec[0], in[0]->vec[1], in[0]->vec[2], &y, &u, &v);
+
+ out[0]->vec[0] = y;
+ out[1]->vec[0] = u;
+ out[2]->vec[0] = v;
+ out[3]->vec[0] = in[0]->vec[3];
+ }
+ else if ((out[0]->hasoutput) || (out[1]->hasoutput) || (out[2]->hasoutput) || (out[3]->hasoutput)) {
+ /* make copy of buffer so input image doesn't get corrupted */
+ CompBuf *cbuf= dupalloc_compbuf(in[0]->data);
+ CompBuf *cbuf2=typecheck_compbuf(cbuf, CB_RGBA);
+
+ /* convert the RGB stackbuf to an YUV representation */
+ composit1_pixel_processor(node, cbuf2, cbuf2, in[0]->vec, do_sepyuva, CB_RGBA);
+
+ /* separate each of those channels */
+ if(out[0]->hasoutput)
+ out[0]->data= valbuf_from_rgbabuf(cbuf2, CHAN_R);
+ if(out[1]->hasoutput)
+ out[1]->data= valbuf_from_rgbabuf(cbuf2, CHAN_G);
+ if(out[2]->hasoutput)
+ out[2]->data= valbuf_from_rgbabuf(cbuf2, CHAN_B);
+ if(out[3]->hasoutput)
+ out[3]->data= valbuf_from_rgbabuf(cbuf2, CHAN_A);
+
+ /*not used anymore */
+ if(cbuf2!=cbuf)
+ free_compbuf(cbuf2);
+ free_compbuf(cbuf);
+ }
+}
+
+void register_node_type_cmp_sepyuva(ListBase *lb)
+{
+ static bNodeType ntype;
+
+ node_type_base(&ntype, CMP_NODE_SEPYUVA, "Separate YUVA", NODE_CLASS_CONVERTOR, 0);
+ node_type_socket_templates(&ntype, cmp_node_sepyuva_in, cmp_node_sepyuva_out);
+ node_type_size(&ntype, 80, 40, 140);
+ node_type_exec(&ntype, node_composit_exec_sepyuva);
+
+ nodeRegisterType(lb, &ntype);
+}
+
+
+
+/* **************** COMBINE YUVA ******************** */
+static bNodeSocketTemplate cmp_node_combyuva_in[]= {
+ { SOCK_FLOAT, 1, "Y", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, PROP_NONE},
+ { SOCK_FLOAT, 1, "U", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, PROP_NONE},
+ { SOCK_FLOAT, 1, "V", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, PROP_NONE},
+ { SOCK_FLOAT, 1, "A", 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, PROP_NONE},
+ { -1, 0, "" }
+};
+static bNodeSocketTemplate cmp_node_combyuva_out[]= {
+ { SOCK_RGBA, 0, "Image"},
+ { -1, 0, "" }
+};
+
+static void do_comb_yuva(bNode *UNUSED(node), float *out, float *in1, float *in2, float *in3, float *in4)
+{
+ float r,g,b;
+ yuv_to_rgb(in1[0], in2[0], in3[0], &r, &g, &b);
+
+ out[0] = r;
+ out[1] = g;
+ out[2] = b;
+ out[3] = in4[0];
+}
+
+static void node_composit_exec_combyuva(void *UNUSED(data), bNode *node, bNodeStack **in, bNodeStack **out)
+{
+ /* stack order out: 1 rgba channels */
+ /* stack order in: 4 value channels */
+
+ /* input no image? then only color operation */
+ if((in[0]->data==NULL) && (in[1]->data==NULL) && (in[2]->data==NULL) && (in[3]->data==NULL)) {
+ out[0]->vec[0] = in[0]->vec[0];
+ out[0]->vec[1] = in[1]->vec[0];
+ out[0]->vec[2] = in[2]->vec[0];
+ out[0]->vec[3] = in[3]->vec[0];
+ }
+ else {
+ /* make output size of first available input image */
+ CompBuf *cbuf;
+ CompBuf *stackbuf;
+
+ /* allocate a CompBuf the size of the first available input */
+ if (in[0]->data) cbuf = in[0]->data;
+ else if (in[1]->data) cbuf = in[1]->data;
+ else if (in[2]->data) cbuf = in[2]->data;
+ else cbuf = in[3]->data;
+
+ stackbuf = alloc_compbuf(cbuf->x, cbuf->y, CB_RGBA, 1); /* allocs */
+
+ composit4_pixel_processor(node, stackbuf, in[0]->data, in[0]->vec, in[1]->data, in[1]->vec,
+ in[2]->data, in[2]->vec, in[3]->data, in[3]->vec,
+ do_comb_yuva, CB_VAL, CB_VAL, CB_VAL, CB_VAL);
+
+ out[0]->data= stackbuf;
+ }
+}
+
+void register_node_type_cmp_combyuva(ListBase *lb)
+{
+ static bNodeType ntype;
+
+ node_type_base(&ntype, CMP_NODE_COMBYUVA, "Combine YUVA", NODE_CLASS_CONVERTOR, NODE_OPTIONS);
+ node_type_socket_templates(&ntype, cmp_node_combyuva_in, cmp_node_combyuva_out);
+ node_type_size(&ntype, 80, 40, 140);
+ node_type_exec(&ntype, node_composit_exec_combyuva);
+
+ nodeRegisterType(lb, &ntype);
+}
+
+
diff --git a/source/blender/nodes/composite/nodes/node_composite_setalpha.c b/source/blender/nodes/composite/nodes/node_composite_setalpha.c
new file mode 100644
index 00000000000..781d6f11614
--- /dev/null
+++ b/source/blender/nodes/composite/nodes/node_composite_setalpha.c
@@ -0,0 +1,89 @@
+/*
+ * $Id: CMP_setalpha.c 36593 2011-05-10 11:19:26Z lukastoenne $
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2006 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/nodes/composite/nodes/node_composite_setalpha.c
+ * \ingroup cmpnodes
+ */
+
+
+#include "node_composite_util.h"
+
+/* **************** SET ALPHA ******************** */
+static bNodeSocketTemplate cmp_node_setalpha_in[]= {
+ { SOCK_RGBA, 1, "Image", 0.0f, 0.0f, 0.0f, 1.0f},
+ { SOCK_FLOAT, 1, "Alpha", 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_NONE},
+ { -1, 0, "" }
+};
+static bNodeSocketTemplate cmp_node_setalpha_out[]= {
+ { SOCK_RGBA, 0, "Image"},
+ { -1, 0, "" }
+};
+
+static void node_composit_exec_setalpha(void *UNUSED(data), bNode *node, bNodeStack **in, bNodeStack **out)
+{
+ /* stack order out: RGBA image */
+ /* stack order in: col, alpha */
+
+ /* input no image? then only color operation */
+ if(in[0]->data==NULL && in[1]->data==NULL) {
+ out[0]->vec[0] = in[0]->vec[0];
+ out[0]->vec[1] = in[0]->vec[1];
+ out[0]->vec[2] = in[0]->vec[2];
+ out[0]->vec[3] = in[1]->vec[0];
+ }
+ else {
+ /* make output size of input image */
+ CompBuf *cbuf= in[0]->data?in[0]->data:in[1]->data;
+ CompBuf *stackbuf= alloc_compbuf(cbuf->x, cbuf->y, CB_RGBA, 1); /* allocs */
+
+ if(in[1]->data==NULL && in[1]->vec[0]==1.0f) {
+ /* pass on image */
+ composit1_pixel_processor(node, stackbuf, in[0]->data, in[0]->vec, do_copy_rgb, CB_RGBA);
+ }
+ else {
+ /* send an compbuf or a value to set as alpha - composit2_pixel_processor handles choosing the right one */
+ composit2_pixel_processor(node, stackbuf, in[0]->data, in[0]->vec, in[1]->data, in[1]->vec, do_copy_a_rgba, CB_RGBA, CB_VAL);
+ }
+
+ out[0]->data= stackbuf;
+ }
+}
+
+void register_node_type_cmp_setalpha(ListBase *lb)
+{
+ static bNodeType ntype;
+
+ node_type_base(&ntype, CMP_NODE_SETALPHA, "Set Alpha", NODE_CLASS_CONVERTOR, NODE_OPTIONS);
+ node_type_socket_templates(&ntype, cmp_node_setalpha_in, cmp_node_setalpha_out);
+ node_type_size(&ntype, 120, 40, 140);
+ node_type_exec(&ntype, node_composit_exec_setalpha);
+
+ nodeRegisterType(lb, &ntype);
+}
+
diff --git a/source/blender/nodes/composite/nodes/node_composite_splitViewer.c b/source/blender/nodes/composite/nodes/node_composite_splitViewer.c
new file mode 100644
index 00000000000..d78faf69e26
--- /dev/null
+++ b/source/blender/nodes/composite/nodes/node_composite_splitViewer.c
@@ -0,0 +1,171 @@
+/*
+ * $Id: CMP_splitViewer.c 36340 2011-04-26 13:24:20Z lukastoenne $
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2006 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/nodes/composite/nodes/node_composite_splitViewer.c
+ * \ingroup cmpnodes
+ */
+
+
+#include "node_composite_util.h"
+
+/* **************** SPLIT VIEWER ******************** */
+static bNodeSocketTemplate cmp_node_splitviewer_in[]= {
+ { SOCK_RGBA, 1, "Image", 0.0f, 0.0f, 0.0f, 1.0f},
+ { SOCK_RGBA, 1, "Image", 0.0f, 0.0f, 0.0f, 1.0f},
+ { -1, 0, "" }
+};
+
+static void do_copy_split_rgba(bNode *UNUSED(node), float *out, float *in1, float *in2, float *fac)
+{
+ if(*fac==0.0f) {
+ QUATCOPY(out, in1);
+ }
+ else {
+ QUATCOPY(out, in2);
+ }
+}
+
+static void node_composit_exec_splitviewer(void *data, bNode *node, bNodeStack **in, bNodeStack **UNUSED(out))
+{
+ /* image assigned to output */
+ /* stack order input sockets: image image */
+
+ if(in[0]->data==NULL || in[1]->data==NULL)
+ return;
+
+ if(node->id && (node->flag & NODE_DO_OUTPUT)) { /* only one works on out */
+ Image *ima= (Image *)node->id;
+ RenderData *rd= data;
+ ImBuf *ibuf;
+ CompBuf *cbuf, *buf1, *buf2, *mask;
+ int x, y;
+ float offset;
+ void *lock;
+
+ buf1= typecheck_compbuf(in[0]->data, CB_RGBA);
+ buf2= typecheck_compbuf(in[1]->data, CB_RGBA);
+
+ BKE_image_user_calc_frame(node->storage, rd->cfra, 0);
+
+ /* always returns for viewer image, but we check nevertheless */
+ ibuf= BKE_image_acquire_ibuf(ima, node->storage, &lock);
+ if(ibuf==NULL) {
+ printf("node_composit_exec_viewer error\n");
+ BKE_image_release_ibuf(ima, lock);
+ return;
+ }
+
+ /* free all in ibuf */
+ imb_freerectImBuf(ibuf);
+ imb_freerectfloatImBuf(ibuf);
+ IMB_freezbuffloatImBuf(ibuf);
+
+ /* make ibuf, and connect to ima */
+ ibuf->x= buf1->x;
+ ibuf->y= buf1->y;
+ imb_addrectfloatImBuf(ibuf);
+
+ ima->ok= IMA_OK_LOADED;
+
+ /* output buf */
+ cbuf= alloc_compbuf(buf1->x, buf1->y, CB_RGBA, 0); /* no alloc*/
+ cbuf->rect= ibuf->rect_float;
+
+ /* mask buf */
+ mask= alloc_compbuf(buf1->x, buf1->y, CB_VAL, 1);
+
+
+ /* Check which offset mode is selected and limit offset if needed */
+ if(node->custom2 == 0) {
+ offset = buf1->x / 100.0f * node->custom1;
+ CLAMP(offset, 0, buf1->x);
+ }
+ else {
+ offset = buf1->y / 100.0f * node->custom1;
+ CLAMP(offset, 0, buf1->y);
+ }
+
+ if(node->custom2 == 0) {
+ for(y=0; y<buf1->y; y++) {
+ float *fac= mask->rect + y*buf1->x;
+ for(x=offset; x>0; x--, fac++)
+ *fac= 1.0f;
+ }
+ }
+ else {
+ for(y=0; y<offset; y++) {
+ float *fac= mask->rect + y*buf1->x;
+ for(x=buf1->x; x>0; x--, fac++)
+ *fac= 1.0f;
+ }
+ }
+
+ composit3_pixel_processor(node, cbuf, buf1, in[0]->vec, buf2, in[1]->vec, mask, NULL, do_copy_split_rgba, CB_RGBA, CB_RGBA, CB_VAL);
+
+ BKE_image_release_ibuf(ima, lock);
+
+ generate_preview(data, node, cbuf);
+ free_compbuf(cbuf);
+ free_compbuf(mask);
+
+ if(in[0]->data != buf1)
+ free_compbuf(buf1);
+ if(in[1]->data != buf2)
+ free_compbuf(buf2);
+ }
+}
+
+static void node_composit_init_splitviewer(bNodeTree *UNUSED(ntree), bNode* node, bNodeTemplate *UNUSED(ntemp))
+{
+ ImageUser *iuser= MEM_callocN(sizeof(ImageUser), "node image user");
+ node->storage= iuser;
+ iuser->sfra= 1;
+ iuser->fie_ima= 2;
+ iuser->ok= 1;
+ node->custom1= 50; /* default 50% split */
+}
+
+void register_node_type_cmp_splitviewer(ListBase *lb)
+{
+ static bNodeType ntype;
+
+ node_type_base(&ntype, CMP_NODE_SPLITVIEWER, "SplitViewer", NODE_CLASS_OUTPUT, NODE_PREVIEW|NODE_OPTIONS);
+ node_type_socket_templates(&ntype, cmp_node_splitviewer_in, NULL);
+ node_type_size(&ntype, 140, 100, 320);
+ node_type_init(&ntype, node_composit_init_splitviewer);
+ node_type_storage(&ntype, "ImageUser", node_free_standard_storage, node_copy_standard_storage);
+ node_type_exec(&ntype, node_composit_exec_splitviewer);
+
+ nodeRegisterType(lb, &ntype);
+}
+
+
+
+
+
diff --git a/source/blender/nodes/composite/nodes/node_composite_texture.c b/source/blender/nodes/composite/nodes/node_composite_texture.c
new file mode 100644
index 00000000000..bdeef74c617
--- /dev/null
+++ b/source/blender/nodes/composite/nodes/node_composite_texture.c
@@ -0,0 +1,160 @@
+/*
+ * $Id: CMP_texture.c 36593 2011-05-10 11:19:26Z lukastoenne $
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2006 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/nodes/composite/nodes/node_composite_texture.c
+ * \ingroup cmpnodes
+ */
+
+
+#include "node_composite_util.h"
+
+/* **************** TEXTURE ******************** */
+static bNodeSocketTemplate cmp_node_texture_in[]= {
+ { SOCK_VECTOR, 1, "Offset", 0.0f, 0.0f, 0.0f, 0.0f, -2.0f, 2.0f, PROP_TRANSLATION},
+ { SOCK_VECTOR, 1, "Scale", 1.0f, 1.0f, 1.0f, 1.0f, -10.0f, 10.0f, PROP_XYZ},
+ { -1, 0, "" }
+};
+static bNodeSocketTemplate cmp_node_texture_out[]= {
+ { SOCK_FLOAT, 0, "Value"},
+ { SOCK_RGBA , 0, "Color"},
+ { -1, 0, "" }
+};
+
+/* called without rect allocated */
+static void texture_procedural(CompBuf *cbuf, float *out, float xco, float yco)
+{
+ bNode *node= cbuf->node;
+ TexResult texres= {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0, NULL};
+ float vec[3], *size, nor[3]={0.0f, 0.0f, 0.0f}, col[4];
+ int retval, type= cbuf->procedural_type;
+
+ size= cbuf->procedural_size;
+
+ vec[0]= size[0]*(xco + cbuf->procedural_offset[0]);
+ vec[1]= size[1]*(yco + cbuf->procedural_offset[1]);
+ vec[2]= size[2]*cbuf->procedural_offset[2];
+
+ retval= multitex_ext((Tex *)node->id, vec, NULL, NULL, 0, &texres);
+
+ if(type==CB_VAL) {
+ if(texres.talpha)
+ col[0]= texres.ta;
+ else
+ col[0]= texres.tin;
+ }
+ else if(type==CB_RGBA) {
+ if(texres.talpha)
+ col[3]= texres.ta;
+ else
+ col[3]= texres.tin;
+
+ if((retval & TEX_RGB)) {
+ col[0]= texres.tr;
+ col[1]= texres.tg;
+ col[2]= texres.tb;
+ }
+ else col[0]= col[1]= col[2]= col[3];
+ }
+ else {
+ VECCOPY(col, nor);
+ }
+
+ typecheck_compbuf_color(out, col, cbuf->type, cbuf->procedural_type);
+}
+
+/* texture node outputs get a small rect, to make sure all other nodes accept it */
+/* only the pixel-processor nodes do something with it though */
+static void node_composit_exec_texture(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
+{
+ /* outputs: value, color, normal */
+
+ if(node->id) {
+ RenderData *rd= data;
+ short sizex, sizey;
+
+ /* first make the preview image */
+ CompBuf *prevbuf= alloc_compbuf(140, 140, CB_RGBA, 1); /* alloc */
+
+ prevbuf->rect_procedural= texture_procedural;
+ prevbuf->node= node;
+ VECCOPY(prevbuf->procedural_offset, in[0]->vec);
+ VECCOPY(prevbuf->procedural_size, in[1]->vec);
+ prevbuf->procedural_type= CB_RGBA;
+ composit1_pixel_processor(node, prevbuf, prevbuf, out[0]->vec, do_copy_rgba, CB_RGBA);
+
+ generate_preview(data, node, prevbuf);
+ free_compbuf(prevbuf);
+
+ /* texture procedural buffer type doesnt work well, we now render a buffer in scene size */
+ sizex = (rd->size*rd->xsch)/100;
+ sizey = (rd->size*rd->ysch)/100;
+
+ if(out[0]->hasoutput) {
+ CompBuf *stackbuf= alloc_compbuf(sizex, sizey, CB_VAL, 1); /* alloc */
+
+ stackbuf->rect_procedural= texture_procedural;
+ stackbuf->node= node;
+ VECCOPY(stackbuf->procedural_offset, in[0]->vec);
+ VECCOPY(stackbuf->procedural_size, in[1]->vec);
+ stackbuf->procedural_type= CB_VAL;
+ composit1_pixel_processor(node, stackbuf, stackbuf, out[0]->vec, do_copy_value, CB_VAL);
+ stackbuf->rect_procedural= NULL;
+
+ out[0]->data= stackbuf;
+ }
+ if(out[1]->hasoutput) {
+ CompBuf *stackbuf= alloc_compbuf(sizex, sizey, CB_RGBA, 1); /* alloc */
+
+ stackbuf->rect_procedural= texture_procedural;
+ stackbuf->node= node;
+ VECCOPY(stackbuf->procedural_offset, in[0]->vec);
+ VECCOPY(stackbuf->procedural_size, in[1]->vec);
+ stackbuf->procedural_type= CB_RGBA;
+ composit1_pixel_processor(node, stackbuf, stackbuf, out[0]->vec, do_copy_rgba, CB_RGBA);
+ stackbuf->rect_procedural= NULL;
+
+ out[1]->data= stackbuf;
+ }
+ }
+}
+
+void register_node_type_cmp_texture(ListBase *lb)
+{
+ static bNodeType ntype;
+
+ node_type_base(&ntype, CMP_NODE_TEXTURE, "Texture", NODE_CLASS_INPUT, NODE_OPTIONS|NODE_PREVIEW);
+ node_type_socket_templates(&ntype, cmp_node_texture_in, cmp_node_texture_out);
+ node_type_size(&ntype, 120, 80, 240);
+ node_type_exec(&ntype, node_composit_exec_texture);
+
+ nodeRegisterType(lb, &ntype);
+}
+
+
+
diff --git a/source/blender/nodes/composite/nodes/node_composite_tonemap.c b/source/blender/nodes/composite/nodes/node_composite_tonemap.c
new file mode 100644
index 00000000000..31ffed08c95
--- /dev/null
+++ b/source/blender/nodes/composite/nodes/node_composite_tonemap.c
@@ -0,0 +1,179 @@
+/*
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2006 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): Alfredo de Greef (eeshlo)
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/nodes/composite/nodes/node_composite_tonemap.c
+ * \ingroup cmpnodes
+ */
+
+
+#include "node_composite_util.h"
+
+static bNodeSocketTemplate cmp_node_tonemap_in[]= {
+ { SOCK_RGBA, 1, "Image", 0.8f, 0.8f, 0.8f, 1.0f},
+ { -1, 0, "" }
+};
+static bNodeSocketTemplate cmp_node_tonemap_out[]= {
+ { SOCK_RGBA, 0, "Image"},
+ { -1, 0, "" }
+};
+
+
+static float avgLogLum(CompBuf *src, float* auto_key, float* Lav, float* Cav)
+{
+ float lsum = 0;
+ int p = src->x*src->y;
+ fRGB* bc = (fRGB*)src->rect;
+ float avl, maxl = -1e10f, minl = 1e10f;
+ const float sc = 1.f/(src->x*src->y);
+ *Lav = 0.f;
+ while (p--) {
+ float L = 0.212671f*bc[0][0] + 0.71516f*bc[0][1] + 0.072169f*bc[0][2];
+ *Lav += L;
+ fRGB_add(Cav, bc[0]);
+ lsum += (float)log((double)MAX2(L, 0.0) + 1e-5);
+ maxl = (L > maxl) ? L : maxl;
+ minl = (L < minl) ? L : minl;
+ bc++;
+ }
+ *Lav *= sc;
+ fRGB_mult(Cav, sc);
+ maxl = log((double)maxl + 1e-5); minl = log((double)minl + 1e-5f); avl = lsum*sc;
+ *auto_key = (maxl > minl) ? ((maxl - avl) / (maxl - minl)) : 1.f;
+ return exp((double)avl);
+}
+
+
+static void tonemap(NodeTonemap* ntm, CompBuf* dst, CompBuf* src)
+{
+ int x, y;
+ float dr, dg, db, al, igm = (ntm->gamma==0.f) ? 1 : (1.f / ntm->gamma);
+ float auto_key, Lav, Cav[3] = {0, 0, 0};
+
+ al = avgLogLum(src, &auto_key, &Lav, Cav);
+ al = (al == 0.f) ? 0.f : (ntm->key / al);
+
+ if (ntm->type == 1) {
+ // Reinhard/Devlin photoreceptor
+ const float f = exp((double)-ntm->f);
+ const float m = (ntm->m > 0.f) ? ntm->m : (0.3f + 0.7f*pow((double)auto_key, 1.4));
+ const float ic = 1.f - ntm->c, ia = 1.f - ntm->a;
+ if (ntm->m == 0.f) printf("tonemap node, M: %g\n", m);
+ for (y=0; y<src->y; ++y) {
+ fRGB* sp = (fRGB*)&src->rect[y*src->x*src->type];
+ fRGB* dp = (fRGB*)&dst->rect[y*src->x*src->type];
+ for (x=0; x<src->x; ++x) {
+ const float L = 0.212671f*sp[x][0] + 0.71516f*sp[x][1] + 0.072169f*sp[x][2];
+ float I_l = sp[x][0] + ic*(L - sp[x][0]);
+ float I_g = Cav[0] + ic*(Lav - Cav[0]);
+ float I_a = I_l + ia*(I_g - I_l);
+ dp[x][0] /= (dp[x][0] + pow((double)f*I_a, (double)m));
+ I_l = sp[x][1] + ic*(L - sp[x][1]);
+ I_g = Cav[1] + ic*(Lav - Cav[1]);
+ I_a = I_l + ia*(I_g - I_l);
+ dp[x][1] /= (dp[x][1] + pow((double)f*I_a,(double)m));
+ I_l = sp[x][2] + ic*(L - sp[x][2]);
+ I_g = Cav[2] + ic*(Lav - Cav[2]);
+ I_a = I_l + ia*(I_g - I_l);
+ dp[x][2] /= (dp[x][2] + pow((double)f*I_a, (double)m));
+ }
+ }
+ return;
+ }
+
+ // Reinhard simple photographic tm (simplest, not using whitepoint var)
+ for (y=0; y<src->y; y++) {
+ fRGB* sp = (fRGB*)&src->rect[y*src->x*src->type];
+ fRGB* dp = (fRGB*)&dst->rect[y*src->x*src->type];
+ for (x=0; x<src->x; x++) {
+ fRGB_copy(dp[x], sp[x]);
+ fRGB_mult(dp[x], al);
+ dr = dp[x][0] + ntm->offset;
+ dg = dp[x][1] + ntm->offset;
+ db = dp[x][2] + ntm->offset;
+ dp[x][0] /= ((dr == 0.f) ? 1.f : dr);
+ dp[x][1] /= ((dg == 0.f) ? 1.f : dg);
+ dp[x][2] /= ((db == 0.f) ? 1.f : db);
+ if (igm != 0.f) {
+ dp[x][0] = pow((double)MAX2(dp[x][0], 0.), igm);
+ dp[x][1] = pow((double)MAX2(dp[x][1], 0.), igm);
+ dp[x][2] = pow((double)MAX2(dp[x][2], 0.), igm);
+ }
+ }
+ }
+}
+
+
+static void node_composit_exec_tonemap(void *UNUSED(data), bNode *node, bNodeStack **in, bNodeStack **out)
+{
+ CompBuf *new, *img = in[0]->data;
+
+ if ((img==NULL) || (out[0]->hasoutput==0)) return;
+
+ if (img->type != CB_RGBA)
+ img = typecheck_compbuf(img, CB_RGBA);
+
+ new = dupalloc_compbuf(img);
+
+ tonemap(node->storage, new, img);
+
+ out[0]->data = new;
+
+ if(img!=in[0]->data)
+ free_compbuf(img);
+}
+
+static void node_composit_init_tonemap(bNodeTree *UNUSED(ntree), bNode* node, bNodeTemplate *UNUSED(ntemp))
+{
+ NodeTonemap *ntm = MEM_callocN(sizeof(NodeTonemap), "node tonemap data");
+ ntm->type = 1;
+ ntm->key = 0.18;
+ ntm->offset = 1;
+ ntm->gamma = 1;
+ ntm->f = 0;
+ ntm->m = 0; // actual value is set according to input
+ // default a of 1 works well with natural HDR images, but not always so for cgi.
+ // Maybe should use 0 or at least lower initial value instead
+ ntm->a = 1;
+ ntm->c = 0;
+ node->storage = ntm;
+}
+
+void register_node_type_cmp_tonemap(ListBase *lb)
+{
+ static bNodeType ntype;
+
+ node_type_base(&ntype, CMP_NODE_TONEMAP, "Tonemap", NODE_CLASS_OP_COLOR, NODE_OPTIONS);
+ node_type_socket_templates(&ntype, cmp_node_tonemap_in, cmp_node_tonemap_out);
+ node_type_size(&ntype, 150, 120, 200);
+ node_type_init(&ntype, node_composit_init_tonemap);
+ node_type_storage(&ntype, "NodeTonemap", node_free_standard_storage, node_copy_standard_storage);
+ node_type_exec(&ntype, node_composit_exec_tonemap);
+
+ nodeRegisterType(lb, &ntype);
+}
+
diff --git a/source/blender/nodes/composite/nodes/node_composite_translate.c b/source/blender/nodes/composite/nodes/node_composite_translate.c
new file mode 100644
index 00000000000..a07dfb936ae
--- /dev/null
+++ b/source/blender/nodes/composite/nodes/node_composite_translate.c
@@ -0,0 +1,76 @@
+/*
+ * $Id: CMP_translate.c 36593 2011-05-10 11:19:26Z lukastoenne $
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2006 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/nodes/composite/nodes/node_composite_translate.c
+ * \ingroup cmpnodes
+ */
+
+
+#include "node_composite_util.h"
+
+
+/* **************** Translate ******************** */
+
+static bNodeSocketTemplate cmp_node_translate_in[]= {
+ { SOCK_RGBA, 1, "Image", 0.8f, 0.8f, 0.8f, 1.0f},
+ { SOCK_FLOAT, 1, "X", 0.0f, 0.0f, 0.0f, 0.0f, -10000.0f, 10000.0f, PROP_NONE},
+ { SOCK_FLOAT, 1, "Y", 0.0f, 0.0f, 0.0f, 0.0f, -10000.0f, 10000.0f, PROP_NONE},
+ { -1, 0, "" }
+};
+static bNodeSocketTemplate cmp_node_translate_out[]= {
+ { SOCK_RGBA, 0, "Image"},
+ { -1, 0, "" }
+};
+
+static void node_composit_exec_translate(void *UNUSED(data), bNode *UNUSED(node), bNodeStack **in, bNodeStack **out)
+{
+ if(in[0]->data) {
+ CompBuf *cbuf= in[0]->data;
+ CompBuf *stackbuf= pass_on_compbuf(cbuf);
+
+ stackbuf->xof+= (int)floor(in[1]->vec[0]);
+ stackbuf->yof+= (int)floor(in[2]->vec[0]);
+
+ out[0]->data= stackbuf;
+ }
+}
+
+void register_node_type_cmp_translate(ListBase *lb)
+{
+ static bNodeType ntype;
+
+ node_type_base(&ntype, CMP_NODE_TRANSLATE, "Translate", NODE_CLASS_DISTORT, NODE_OPTIONS);
+ node_type_socket_templates(&ntype, cmp_node_translate_in, cmp_node_translate_out);
+ node_type_size(&ntype, 140, 100, 320);
+ node_type_exec(&ntype, node_composit_exec_translate);
+
+ nodeRegisterType(lb, &ntype);
+}
+
+
diff --git a/source/blender/nodes/composite/nodes/node_composite_valToRgb.c b/source/blender/nodes/composite/nodes/node_composite_valToRgb.c
new file mode 100644
index 00000000000..9481d769557
--- /dev/null
+++ b/source/blender/nodes/composite/nodes/node_composite_valToRgb.c
@@ -0,0 +1,152 @@
+/*
+ * $Id: CMP_valToRgb.c 36593 2011-05-10 11:19:26Z lukastoenne $
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2006 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/nodes/composite/nodes/node_composite_valToRgb.c
+ * \ingroup cmpnodes
+ */
+
+
+#include "node_composite_util.h"
+
+
+/* **************** VALTORGB ******************** */
+static bNodeSocketTemplate cmp_node_valtorgb_in[]= {
+ { SOCK_FLOAT, 1, "Fac", 0.5f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR},
+ { -1, 0, "" }
+};
+static bNodeSocketTemplate cmp_node_valtorgb_out[]= {
+ { SOCK_RGBA, 0, "Image"},
+ { SOCK_FLOAT, 0, "Alpha"},
+ { -1, 0, "" }
+};
+
+static void do_colorband_composit(bNode *node, float *out, float *in)
+{
+ do_colorband(node->storage, in[0], out);
+}
+
+static void node_composit_exec_valtorgb(void *UNUSED(data), bNode *node, bNodeStack **in, bNodeStack **out)
+{
+ /* stack order in: fac */
+ /* stack order out: col, alpha */
+
+ if(out[0]->hasoutput==0 && out[1]->hasoutput==0)
+ return;
+
+ if(node->storage) {
+ /* input no image? then only color operation */
+ if(in[0]->data==NULL) {
+ do_colorband(node->storage, in[0]->vec[0], out[0]->vec);
+ }
+ else {
+ /* make output size of input image */
+ CompBuf *cbuf= in[0]->data;
+ CompBuf *stackbuf= alloc_compbuf(cbuf->x, cbuf->y, CB_RGBA, 1); /* allocs */
+
+ composit1_pixel_processor(node, stackbuf, in[0]->data, in[0]->vec, do_colorband_composit, CB_VAL);
+
+ out[0]->data= stackbuf;
+
+ if(out[1]->hasoutput)
+ out[1]->data= valbuf_from_rgbabuf(stackbuf, CHAN_A);
+
+ }
+ }
+}
+
+static void node_composit_init_valtorgb(bNodeTree *UNUSED(ntree), bNode* node, bNodeTemplate *UNUSED(ntemp))
+{
+ node->storage= add_colorband(1);
+}
+
+void register_node_type_cmp_valtorgb(ListBase *lb)
+{
+ static bNodeType ntype;
+
+ node_type_base(&ntype, CMP_NODE_VALTORGB, "ColorRamp", NODE_CLASS_CONVERTOR, NODE_OPTIONS);
+ node_type_socket_templates(&ntype, cmp_node_valtorgb_in, cmp_node_valtorgb_out);
+ node_type_size(&ntype, 240, 200, 300);
+ node_type_init(&ntype, node_composit_init_valtorgb);
+ node_type_storage(&ntype, "ColorBand", node_free_standard_storage, node_copy_standard_storage);
+ node_type_exec(&ntype, node_composit_exec_valtorgb);
+
+ nodeRegisterType(lb, &ntype);
+}
+
+
+
+/* **************** RGBTOBW ******************** */
+static bNodeSocketTemplate cmp_node_rgbtobw_in[]= {
+ { SOCK_RGBA, 1, "Image", 0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f},
+ { -1, 0, "" }
+};
+static bNodeSocketTemplate cmp_node_rgbtobw_out[]= {
+ { SOCK_FLOAT, 0, "Val", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
+ { -1, 0, "" }
+};
+
+static void do_rgbtobw(bNode *UNUSED(node), float *out, float *in)
+{
+ out[0]= in[0]*0.35f + in[1]*0.45f + in[2]*0.2f;
+}
+
+static void node_composit_exec_rgbtobw(void *UNUSED(data), bNode *node, bNodeStack **in, bNodeStack **out)
+{
+ /* stack order out: bw */
+ /* stack order in: col */
+
+ if(out[0]->hasoutput==0)
+ return;
+
+ /* input no image? then only color operation */
+ if(in[0]->data==NULL) {
+ do_rgbtobw(node, out[0]->vec, in[0]->vec);
+ }
+ else {
+ /* make output size of input image */
+ CompBuf *cbuf= in[0]->data;
+ CompBuf *stackbuf= alloc_compbuf(cbuf->x, cbuf->y, CB_VAL, 1); /* allocs */
+
+ composit1_pixel_processor(node, stackbuf, in[0]->data, in[0]->vec, do_rgbtobw, CB_RGBA);
+
+ out[0]->data= stackbuf;
+ }
+}
+
+void register_node_type_cmp_rgbtobw(ListBase *lb)
+{
+ static bNodeType ntype;
+
+ node_type_base(&ntype, CMP_NODE_RGBTOBW, "RGB to BW", NODE_CLASS_CONVERTOR, 0);
+ node_type_socket_templates(&ntype, cmp_node_rgbtobw_in, cmp_node_rgbtobw_out);
+ node_type_size(&ntype, 80, 40, 120);
+ node_type_exec(&ntype, node_composit_exec_rgbtobw);
+
+ nodeRegisterType(lb, &ntype);
+}
diff --git a/source/blender/nodes/composite/nodes/node_composite_value.c b/source/blender/nodes/composite/nodes/node_composite_value.c
new file mode 100644
index 00000000000..e99b665f2ae
--- /dev/null
+++ b/source/blender/nodes/composite/nodes/node_composite_value.c
@@ -0,0 +1,72 @@
+/*
+ * $Id: CMP_value.c 36536 2011-05-07 13:27:27Z lukastoenne $
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2006 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/nodes/composite/nodes/node_composite_value.c
+ * \ingroup cmpnodes
+ */
+
+
+#include "node_composite_util.h"
+
+/* **************** VALUE ******************** */
+static bNodeSocketTemplate cmp_node_value_out[]= {
+ { SOCK_FLOAT, 0, "Value"},
+ { -1, 0, "" }
+};
+
+static void node_composit_init_value(bNodeTree *UNUSED(ntree), bNode *node, bNodeTemplate *UNUSED(ntemp))
+{
+ bNodeSocket *sock= node->outputs.first;
+ bNodeSocketValueFloat *dval= (bNodeSocketValueFloat*)sock->default_value;
+ /* uses the default value of the output socket, must be initialized here */
+ dval->value = 0.5f;
+}
+
+static void node_composit_exec_value(void *UNUSED(data), bNode *node, bNodeStack **UNUSED(in), bNodeStack **out)
+{
+ bNodeSocket *sock= node->outputs.first;
+ float val= ((bNodeSocketValueFloat*)sock->default_value)->value;
+
+ out[0]->vec[0]= val;
+}
+
+void register_node_type_cmp_value(ListBase *lb)
+{
+ static bNodeType ntype;
+
+ node_type_base(&ntype, CMP_NODE_VALUE, "Value", NODE_CLASS_INPUT, NODE_OPTIONS);
+ node_type_socket_templates(&ntype, NULL, cmp_node_value_out);
+ node_type_init(&ntype, node_composit_init_value);
+ node_type_size(&ntype, 80, 40, 120);
+ node_type_exec(&ntype, node_composit_exec_value);
+
+ nodeRegisterType(lb, &ntype);
+}
+
+
diff --git a/source/blender/nodes/composite/nodes/node_composite_vecBlur.c b/source/blender/nodes/composite/nodes/node_composite_vecBlur.c
new file mode 100644
index 00000000000..e730728d077
--- /dev/null
+++ b/source/blender/nodes/composite/nodes/node_composite_vecBlur.c
@@ -0,0 +1,113 @@
+/*
+ * $Id: CMP_vecBlur.c 36593 2011-05-10 11:19:26Z lukastoenne $
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2006 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/nodes/composite/nodes/node_composite_vecBlur.c
+ * \ingroup cmpnodes
+ */
+
+
+#include "node_composite_util.h"
+
+
+/* **************** VECTOR BLUR ******************** */
+static bNodeSocketTemplate cmp_node_vecblur_in[]= {
+ { SOCK_RGBA, 1, "Image", 0.8f, 0.8f, 0.8f, 1.0f},
+ { SOCK_FLOAT, 1, "Z", 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_NONE},
+ { SOCK_VECTOR, 1, "Speed", 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_VELOCITY},
+ { -1, 0, "" }
+};
+static bNodeSocketTemplate cmp_node_vecblur_out[]= {
+ { SOCK_RGBA, 0, "Image"},
+ { -1, 0, "" }
+};
+
+
+
+static void node_composit_exec_vecblur(void *UNUSED(data), bNode *node, bNodeStack **in, bNodeStack **out)
+{
+ NodeBlurData *nbd= node->storage;
+ CompBuf *new, *img= in[0]->data, *vecbuf= in[2]->data, *zbuf= in[1]->data;
+
+ if(img==NULL || vecbuf==NULL || zbuf==NULL || out[0]->hasoutput==0)
+ return;
+ if(vecbuf->x!=img->x || vecbuf->y!=img->y) {
+ printf("ERROR: cannot do different sized vecbuf yet\n");
+ return;
+ }
+ if(vecbuf->type!=CB_VEC4) {
+ printf("ERROR: input should be vecbuf\n");
+ return;
+ }
+ if(zbuf->type!=CB_VAL) {
+ printf("ERROR: input should be zbuf\n");
+ return;
+ }
+ if(zbuf->x!=img->x || zbuf->y!=img->y) {
+ printf("ERROR: cannot do different sized zbuf yet\n");
+ return;
+ }
+
+ /* allow the input image to be of another type */
+ img= typecheck_compbuf(in[0]->data, CB_RGBA);
+
+ new= dupalloc_compbuf(img);
+
+ /* call special zbuffer version */
+ RE_zbuf_accumulate_vecblur(nbd, img->x, img->y, new->rect, img->rect, vecbuf->rect, zbuf->rect);
+
+ out[0]->data= new;
+
+ if(img!=in[0]->data)
+ free_compbuf(img);
+}
+
+static void node_composit_init_vecblur(bNodeTree *UNUSED(ntree), bNode* node, bNodeTemplate *UNUSED(ntemp))
+{
+ NodeBlurData *nbd= MEM_callocN(sizeof(NodeBlurData), "node blur data");
+ node->storage= nbd;
+ nbd->samples= 32;
+ nbd->fac= 1.0f;
+}
+
+/* custom1: itterations, custom2: maxspeed (0 = nolimit) */
+void register_node_type_cmp_vecblur(ListBase *lb)
+{
+ static bNodeType ntype;
+
+ node_type_base(&ntype, CMP_NODE_VECBLUR, "Vector Blur", NODE_CLASS_OP_FILTER, NODE_OPTIONS);
+ node_type_socket_templates(&ntype, cmp_node_vecblur_in, cmp_node_vecblur_out);
+ node_type_size(&ntype, 120, 80, 200);
+ node_type_init(&ntype, node_composit_init_vecblur);
+ node_type_storage(&ntype, "NodeBlurData", node_free_standard_storage, node_copy_standard_storage);
+ node_type_exec(&ntype, node_composit_exec_vecblur);
+
+ nodeRegisterType(lb, &ntype);
+}
+
+
diff --git a/source/blender/nodes/composite/nodes/node_composite_viewer.c b/source/blender/nodes/composite/nodes/node_composite_viewer.c
new file mode 100644
index 00000000000..bcfb45411f1
--- /dev/null
+++ b/source/blender/nodes/composite/nodes/node_composite_viewer.c
@@ -0,0 +1,148 @@
+/*
+ * $Id: CMP_viewer.c 36593 2011-05-10 11:19:26Z lukastoenne $
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2006 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/nodes/composite/nodes/node_composite_viewer.c
+ * \ingroup cmpnodes
+ */
+
+
+#include "node_composite_util.h"
+
+
+/* **************** VIEWER ******************** */
+static bNodeSocketTemplate cmp_node_viewer_in[]= {
+ { SOCK_RGBA, 1, "Image", 0.0f, 0.0f, 0.0f, 1.0f},
+ { SOCK_FLOAT, 1, "Alpha", 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_NONE},
+ { SOCK_FLOAT, 1, "Z", 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_NONE},
+ { -1, 0, "" }
+};
+
+
+static void node_composit_exec_viewer(void *data, bNode *node, bNodeStack **in, bNodeStack **UNUSED(out))
+{
+ /* image assigned to output */
+ /* stack order input sockets: col, alpha, z */
+
+ if(node->id && (node->flag & NODE_DO_OUTPUT)) { /* only one works on out */
+ RenderData *rd= data;
+ Image *ima= (Image *)node->id;
+ ImBuf *ibuf;
+ CompBuf *cbuf, *tbuf;
+ int rectx, recty;
+ void *lock;
+
+ BKE_image_user_calc_frame(node->storage, rd->cfra, 0);
+
+ /* always returns for viewer image, but we check nevertheless */
+ ibuf= BKE_image_acquire_ibuf(ima, node->storage, &lock);
+ if(ibuf==NULL) {
+ printf("node_composit_exec_viewer error\n");
+ BKE_image_release_ibuf(ima, lock);
+ return;
+ }
+
+ /* free all in ibuf */
+ imb_freerectImBuf(ibuf);
+ imb_freerectfloatImBuf(ibuf);
+ IMB_freezbuffloatImBuf(ibuf);
+
+ /* get size */
+ tbuf= in[0]->data?in[0]->data:(in[1]->data?in[1]->data:in[2]->data);
+ if(tbuf==NULL) {
+ rectx= 320; recty= 256;
+ }
+ else {
+ rectx= tbuf->x;
+ recty= tbuf->y;
+ }
+
+ /* make ibuf, and connect to ima */
+ ibuf->x= rectx;
+ ibuf->y= recty;
+ imb_addrectfloatImBuf(ibuf);
+
+ ima->ok= IMA_OK_LOADED;
+
+ /* now we combine the input with ibuf */
+ cbuf= alloc_compbuf(rectx, recty, CB_RGBA, 0); /* no alloc*/
+ cbuf->rect= ibuf->rect_float;
+
+ /* when no alpha, we can simply copy */
+ if(in[1]->data==NULL) {
+ composit1_pixel_processor(node, cbuf, in[0]->data, in[0]->vec, do_copy_rgba, CB_RGBA);
+ }
+ else
+ composit2_pixel_processor(node, cbuf, in[0]->data, in[0]->vec, in[1]->data, in[1]->vec, do_copy_a_rgba, CB_RGBA, CB_VAL);
+
+ /* zbuf option */
+ if(in[2]->data) {
+ CompBuf *zbuf= alloc_compbuf(rectx, recty, CB_VAL, 1);
+ ibuf->zbuf_float= zbuf->rect;
+ ibuf->mall |= IB_zbuffloat;
+
+ composit1_pixel_processor(node, zbuf, in[2]->data, in[2]->vec, do_copy_value, CB_VAL);
+
+ /* free compbuf, but not the rect */
+ zbuf->malloc= 0;
+ free_compbuf(zbuf);
+ }
+
+ BKE_image_release_ibuf(ima, lock);
+
+ generate_preview(data, node, cbuf);
+ free_compbuf(cbuf);
+
+ }
+ else if(in[0]->data) {
+ generate_preview(data, node, in[0]->data);
+ }
+}
+
+static void node_composit_init_viewer(bNodeTree *UNUSED(ntree), bNode* node, bNodeTemplate *UNUSED(ntemp))
+{
+ ImageUser *iuser= MEM_callocN(sizeof(ImageUser), "node image user");
+ node->storage= iuser;
+ iuser->sfra= 1;
+ iuser->fie_ima= 2;
+ iuser->ok= 1;
+}
+
+void register_node_type_cmp_viewer(ListBase *lb)
+{
+ static bNodeType ntype;
+
+ node_type_base(&ntype, CMP_NODE_VIEWER, "Viewer", NODE_CLASS_OUTPUT, NODE_PREVIEW);
+ node_type_socket_templates(&ntype, cmp_node_viewer_in, NULL);
+ node_type_size(&ntype, 80, 60, 200);
+ node_type_init(&ntype, node_composit_init_viewer);
+ node_type_storage(&ntype, "ImageUser", node_free_standard_storage, node_copy_standard_storage);
+ node_type_exec(&ntype, node_composit_exec_viewer);
+
+ nodeRegisterType(lb, &ntype);
+}
diff --git a/source/blender/nodes/composite/nodes/node_composite_zcombine.c b/source/blender/nodes/composite/nodes/node_composite_zcombine.c
new file mode 100644
index 00000000000..dfed26be343
--- /dev/null
+++ b/source/blender/nodes/composite/nodes/node_composite_zcombine.c
@@ -0,0 +1,238 @@
+/*
+ * $Id: CMP_zcombine.c 36593 2011-05-10 11:19:26Z lukastoenne $
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2006 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/nodes/composite/nodes/node_composite_zcombine.c
+ * \ingroup cmpnodes
+ */
+
+
+#include "node_composite_util.h"
+
+
+/* **************** Z COMBINE ******************** */
+ /* lazy coder note: node->custom2 is abused to send signal */
+static bNodeSocketTemplate cmp_node_zcombine_in[]= {
+ { SOCK_RGBA, 1, "Image", 0.8f, 0.8f, 0.8f, 1.0f},
+ { SOCK_FLOAT, 1, "Z", 0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 10000.0f, PROP_NONE},
+ { SOCK_RGBA, 1, "Image", 0.8f, 0.8f, 0.8f, 1.0f},
+ { SOCK_FLOAT, 1, "Z", 0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 10000.0f, PROP_NONE},
+ { -1, 0, "" }
+};
+static bNodeSocketTemplate cmp_node_zcombine_out[]= {
+ { SOCK_RGBA, 0, "Image"},
+ { SOCK_FLOAT, 0, "Z"},
+ { -1, 0, "" }
+};
+
+static void do_zcombine(bNode *node, float *out, float *src1, float *z1, float *src2, float *z2)
+{
+ float alpha;
+ float malpha;
+
+ if(*z1 <= *z2) {
+ if (node->custom1) {
+ // use alpha in combine operation
+ alpha= src1[3];
+ malpha= 1.0f - alpha;
+ out[0]= malpha*src2[0] + alpha*src1[0];
+ out[1]= malpha*src2[1] + alpha*src1[1];
+ out[2]= malpha*src2[2] + alpha*src1[2];
+ out[3]= malpha*src2[3] + alpha*src1[3];
+ }
+ else {
+ // do combination based solely on z value
+ QUATCOPY(out, src1);
+ }
+ }
+ else {
+ if (node->custom1) {
+ // use alpha in combine operation
+ alpha= src2[3];
+ malpha= 1.0f - alpha;
+ out[0]= malpha*src1[0] + alpha*src2[0];
+ out[1]= malpha*src1[1] + alpha*src2[1];
+ out[2]= malpha*src1[2] + alpha*src2[2];
+ out[3]= malpha*src1[3] + alpha*src2[3];
+ }
+ else {
+ // do combination based solely on z value
+ QUATCOPY(out, src1);
+ }
+
+ if(node->custom2)
+ *z1= *z2;
+ }
+}
+
+static void do_zcombine_mask(bNode *node, float *out, float *z1, float *z2)
+{
+ if(*z1 > *z2) {
+ *out= 1.0f;
+ if(node->custom2)
+ *z1= *z2;
+ }
+}
+
+static void do_zcombine_add(bNode *node, float *out, float *col1, float *col2, float *acol)
+{
+ float alpha;
+ float malpha;
+
+ if (node->custom1) {
+ // use alpha in combine operation, antialiased mask in used here just as hint for the z value
+ if (*acol>0.0f) {
+ alpha= col2[3];
+ malpha= 1.0f - alpha;
+
+
+ out[0]= malpha*col1[0] + alpha*col2[0];
+ out[1]= malpha*col1[1] + alpha*col2[1];
+ out[2]= malpha*col1[2] + alpha*col2[2];
+ out[3]= malpha*col1[3] + alpha*col2[3];
+ }
+ else {
+ alpha= col1[3];
+ malpha= 1.0f - alpha;
+
+
+ out[0]= malpha*col2[0] + alpha*col1[0];
+ out[1]= malpha*col2[1] + alpha*col1[1];
+ out[2]= malpha*col2[2] + alpha*col1[2];
+ out[3]= malpha*col2[3] + alpha*col1[3];
+ }
+ }
+ else {
+ // do combination based solely on z value but with antialiased mask
+ alpha = *acol;
+ malpha= 1.0f - alpha;
+
+ out[0]= malpha*col1[0] + alpha*col2[0];
+ out[1]= malpha*col1[1] + alpha*col2[1];
+ out[2]= malpha*col1[2] + alpha*col2[2];
+ out[3]= malpha*col1[3] + alpha*col2[3];
+ }
+}
+
+static void node_composit_exec_zcombine(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
+{
+ RenderData *rd= data;
+ CompBuf *cbuf= in[0]->data;
+ CompBuf *zbuf;
+
+ /* stack order in: col z col z */
+ /* stack order out: col z */
+ if(out[0]->hasoutput==0 && out[1]->hasoutput==0)
+ return;
+
+ /* no input image; do nothing now */
+ if(in[0]->data==NULL) {
+ return;
+ }
+
+ if(out[1]->hasoutput) {
+ /* copy or make a buffer for for the first z value, here we write result in */
+ if(in[1]->data)
+ zbuf= dupalloc_compbuf(in[1]->data);
+ else {
+ float *zval;
+ int tot= cbuf->x*cbuf->y;
+
+ zbuf= alloc_compbuf(cbuf->x, cbuf->y, CB_VAL, 1);
+ for(zval= zbuf->rect; tot; tot--, zval++)
+ *zval= in[1]->vec[0];
+ }
+ /* lazy coder hack */
+ node->custom2= 1;
+ out[1]->data= zbuf;
+ }
+ else {
+ node->custom2= 0;
+ zbuf= in[1]->data;
+ }
+
+ if(rd->scemode & R_FULL_SAMPLE) {
+ /* make output size of first input image */
+ CompBuf *stackbuf= alloc_compbuf(cbuf->x, cbuf->y, CB_RGBA, 1); // allocs
+
+ composit4_pixel_processor(node, stackbuf, in[0]->data, in[0]->vec, zbuf, in[1]->vec, in[2]->data, in[2]->vec,
+ in[3]->data, in[3]->vec, do_zcombine, CB_RGBA, CB_VAL, CB_RGBA, CB_VAL);
+
+ out[0]->data= stackbuf;
+ }
+ else {
+ /* make output size of first input image */
+ CompBuf *stackbuf= alloc_compbuf(cbuf->x, cbuf->y, CB_RGBA, 1); /* allocs */
+ CompBuf *mbuf;
+ float *fp;
+ int x;
+ char *aabuf;
+
+
+ /* make a mask based on comparison, optionally write zvalue */
+ mbuf= alloc_compbuf(cbuf->x, cbuf->y, CB_VAL, 1);
+ composit2_pixel_processor(node, mbuf, zbuf, in[1]->vec, in[3]->data, in[3]->vec, do_zcombine_mask, CB_VAL, CB_VAL);
+
+ /* convert to char */
+ aabuf= MEM_mallocN(cbuf->x*cbuf->y, "aa buf");
+ fp= mbuf->rect;
+ for(x= cbuf->x*cbuf->y-1; x>=0; x--)
+ if(fp[x]==0.0f) aabuf[x]= 0;
+ else aabuf[x]= 255;
+
+ antialias_tagbuf(cbuf->x, cbuf->y, aabuf);
+
+ /* convert to float */
+ fp= mbuf->rect;
+ for(x= cbuf->x*cbuf->y-1; x>=0; x--)
+ if(aabuf[x]>1)
+ fp[x]= (1.0f/255.0f)*(float)aabuf[x];
+
+ composit3_pixel_processor(node, stackbuf, in[0]->data, in[0]->vec, in[2]->data, in[2]->vec, mbuf, NULL,
+ do_zcombine_add, CB_RGBA, CB_RGBA, CB_VAL);
+ /* free */
+ free_compbuf(mbuf);
+ MEM_freeN(aabuf);
+
+ out[0]->data= stackbuf;
+ }
+
+}
+
+void register_node_type_cmp_zcombine(ListBase *lb)
+{
+ static bNodeType ntype;
+
+ node_type_base(&ntype, CMP_NODE_ZCOMBINE, "Z Combine", NODE_CLASS_OP_COLOR, NODE_OPTIONS);
+ node_type_socket_templates(&ntype, cmp_node_zcombine_in, cmp_node_zcombine_out);
+ node_type_size(&ntype, 80, 40, 120);
+ node_type_exec(&ntype, node_composit_exec_zcombine);
+
+ nodeRegisterType(lb, &ntype);
+}
+