diff options
author | Lukas Toenne <lukas.toenne@googlemail.com> | 2011-09-06 01:01:50 +0400 |
---|---|---|
committer | Lukas Toenne <lukas.toenne@googlemail.com> | 2011-09-06 01:01:50 +0400 |
commit | 8e0fe8bff72e2dc2926618577eaffdd3417a8304 (patch) | |
tree | 43b933c88cac451518dc68846c1119acacffca4f /source/blender/nodes/composite | |
parent | 6e9ff495eb082aeb49e6a1da23a7827d3fcd0fde (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')
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); +} + |