2011-10-23 17:52:20 +00:00
|
|
|
/*
|
2011-09-05 21:01:50 +00:00
|
|
|
* ***** 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"
|
|
|
|
|
2011-11-09 15:00:11 +00:00
|
|
|
#include "BLF_translation.h"
|
|
|
|
|
2011-09-05 21:01:50 +00:00
|
|
|
#include "BKE_animsys.h"
|
|
|
|
#include "BKE_colortools.h"
|
|
|
|
#include "BKE_fcurve.h"
|
|
|
|
#include "BKE_global.h"
|
|
|
|
#include "BKE_main.h"
|
|
|
|
#include "BKE_node.h"
|
2011-11-07 12:56:05 +00:00
|
|
|
#include "BKE_tracking.h"
|
2011-09-05 21:01:50 +00:00
|
|
|
#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;
|
2012-03-24 06:38:07 +00:00
|
|
|
for (sce= main->scene.first; sce; sce= sce->id.next) {
|
|
|
|
if (sce->nodetree) {
|
2011-09-05 21:01:50 +00:00
|
|
|
func(calldata, &sce->id, sce->nodetree);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-11-07 22:14:48 +00:00
|
|
|
static void foreach_nodeclass(Scene *UNUSED(scene), void *calldata, bNodeClassCallback func)
|
|
|
|
{
|
2012-05-16 15:01:46 +00:00
|
|
|
func(calldata, NODE_CLASS_INPUT, N_("Input"));
|
|
|
|
func(calldata, NODE_CLASS_OUTPUT, N_("Output"));
|
|
|
|
func(calldata, NODE_CLASS_OP_COLOR, N_("Color"));
|
|
|
|
func(calldata, NODE_CLASS_OP_VECTOR, N_("Vector"));
|
|
|
|
func(calldata, NODE_CLASS_OP_FILTER, N_("Filter"));
|
|
|
|
func(calldata, NODE_CLASS_CONVERTOR, N_("Convertor"));
|
|
|
|
func(calldata, NODE_CLASS_MATTE, N_("Matte"));
|
|
|
|
func(calldata, NODE_CLASS_DISTORT, N_("Distort"));
|
|
|
|
func(calldata, NODE_CLASS_GROUP, N_("Group"));
|
|
|
|
func(calldata, NODE_CLASS_LAYOUT, N_("Layout"));
|
2011-11-07 22:14:48 +00:00
|
|
|
}
|
|
|
|
|
2011-09-05 21:01:50 +00:00
|
|
|
static void free_node_cache(bNodeTree *UNUSED(ntree), bNode *node)
|
|
|
|
{
|
|
|
|
bNodeSocket *sock;
|
|
|
|
|
2012-03-24 06:38:07 +00:00
|
|
|
for (sock= node->outputs.first; sock; sock= sock->next) {
|
|
|
|
if (sock->cache) {
|
2011-09-05 21:01:50 +00:00
|
|
|
free_compbuf(sock->cache);
|
|
|
|
sock->cache= NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void free_cache(bNodeTree *ntree)
|
|
|
|
{
|
|
|
|
bNode *node;
|
2012-03-24 06:38:07 +00:00
|
|
|
for (node= ntree->nodes.first; node; node= node->next)
|
2011-09-05 21:01:50 +00:00
|
|
|
free_node_cache(ntree, node);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void update_node(bNodeTree *ntree, bNode *node)
|
|
|
|
{
|
|
|
|
bNodeSocket *sock;
|
|
|
|
|
2012-03-24 06:38:07 +00:00
|
|
|
for (sock= node->outputs.first; sock; sock= sock->next) {
|
|
|
|
if (sock->cache) {
|
2011-09-05 21:01:50 +00:00
|
|
|
//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 */
|
2012-02-27 17:38:16 +00:00
|
|
|
static void localize(bNodeTree *localtree, bNodeTree *ntree)
|
2011-09-05 21:01:50 +00:00
|
|
|
{
|
2012-02-27 17:38:16 +00:00
|
|
|
bNode *node, *node_next;
|
2011-09-05 21:01:50 +00:00
|
|
|
bNodeSocket *sock;
|
|
|
|
|
2012-03-24 06:38:07 +00:00
|
|
|
for (node= ntree->nodes.first; node; node= node->next) {
|
2011-09-05 21:01:50 +00:00
|
|
|
/* ensure new user input gets handled ok */
|
|
|
|
node->need_exec= 0;
|
|
|
|
|
|
|
|
/* move over the compbufs */
|
|
|
|
/* right after ntreeCopyTree() oldsock pointers are valid */
|
|
|
|
|
2012-03-24 06:38:07 +00:00
|
|
|
if (ELEM(node->type, CMP_NODE_VIEWER, CMP_NODE_SPLITVIEWER)) {
|
|
|
|
if (node->id) {
|
|
|
|
if (node->flag & NODE_DO_OUTPUT)
|
2012-05-05 14:03:12 +00:00
|
|
|
node->new_node->id= (ID *)BKE_image_copy((Image *)node->id);
|
2011-09-05 21:01:50 +00:00
|
|
|
else
|
|
|
|
node->new_node->id= NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-03-24 06:38:07 +00:00
|
|
|
for (sock= node->outputs.first; sock; sock= sock->next) {
|
2011-09-05 21:01:50 +00:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
2012-02-27 17:38:16 +00:00
|
|
|
|
|
|
|
/* replace muted nodes by internal links */
|
|
|
|
for (node= localtree->nodes.first; node; node= node_next) {
|
|
|
|
node_next = node->next;
|
|
|
|
|
|
|
|
if (node->flag & NODE_MUTED) {
|
|
|
|
/* make sure the update tag isn't lost when removing the muted node.
|
|
|
|
* propagate this to all downstream nodes.
|
|
|
|
*/
|
|
|
|
if (node->need_exec) {
|
|
|
|
bNodeLink *link;
|
|
|
|
for (link=localtree->links.first; link; link=link->next)
|
|
|
|
if (link->fromnode==node && link->tonode)
|
|
|
|
link->tonode->need_exec = 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
nodeInternalRelink(localtree, node);
|
|
|
|
nodeFreeNode(localtree, node);
|
|
|
|
}
|
|
|
|
}
|
2011-09-05 21:01:50 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void local_sync(bNodeTree *localtree, bNodeTree *ntree)
|
|
|
|
{
|
|
|
|
bNode *lnode;
|
|
|
|
|
|
|
|
/* move over the compbufs and previews */
|
2012-03-24 06:38:07 +00:00
|
|
|
for (lnode= localtree->nodes.first; lnode; lnode= lnode->next) {
|
|
|
|
if ( (lnode->exec & NODE_READY) && !(lnode->exec & NODE_SKIPPED) ) {
|
|
|
|
if (ntreeNodeExists(ntree, lnode->new_node)) {
|
2011-09-05 21:01:50 +00:00
|
|
|
|
2012-03-24 06:38:07 +00:00
|
|
|
if (lnode->preview && lnode->preview->rect) {
|
2011-09-05 21:01:50 +00:00
|
|
|
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 */
|
2012-03-24 06:38:07 +00:00
|
|
|
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)) {
|
2011-09-05 21:01:50 +00:00
|
|
|
/* image_merge does sanity check for pointers */
|
|
|
|
BKE_image_merge((Image *)lnode->new_node->id, (Image *)lnode->id);
|
|
|
|
}
|
|
|
|
}
|
2012-03-24 06:38:07 +00:00
|
|
|
else if (lnode->type==CMP_NODE_MOVIEDISTORTION) {
|
2011-11-07 12:56:05 +00:00
|
|
|
/* special case for distortion node: distortion context is allocating in exec function
|
|
|
|
and to achive much better performance on further calls this context should be
|
|
|
|
copied back to original node */
|
2012-03-24 06:38:07 +00:00
|
|
|
if (lnode->storage) {
|
|
|
|
if (lnode->new_node->storage)
|
2011-11-07 12:56:05 +00:00
|
|
|
BKE_tracking_distortion_destroy(lnode->new_node->storage);
|
|
|
|
|
|
|
|
lnode->new_node->storage= BKE_tracking_distortion_copy(lnode->storage);
|
|
|
|
}
|
|
|
|
}
|
2011-09-05 21:01:50 +00:00
|
|
|
|
2012-03-24 06:38:07 +00:00
|
|
|
for (lsock= lnode->outputs.first; lsock; lsock= lsock->next) {
|
|
|
|
if (ntreeOutputExists(lnode->new_node, lsock->new_sock)) {
|
2011-09-05 21:01:50 +00:00
|
|
|
lsock->new_sock->cache= lsock->cache;
|
|
|
|
compbuf_set_node(lsock->new_sock->cache, lnode->new_node);
|
|
|
|
lsock->cache= NULL;
|
|
|
|
lsock->new_sock= NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-10-19 17:08:35 +00:00
|
|
|
static void update(bNodeTree *ntree)
|
|
|
|
{
|
|
|
|
ntreeSetOutput(ntree);
|
|
|
|
}
|
|
|
|
|
2011-09-05 21:01:50 +00:00
|
|
|
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,
|
2011-11-07 22:14:48 +00:00
|
|
|
/* foreach_nodeclass */ foreach_nodeclass,
|
2011-09-05 21:01:50 +00:00
|
|
|
/* localize */ localize,
|
|
|
|
/* local_sync */ local_sync,
|
|
|
|
/* local_merge */ local_merge,
|
2011-10-19 17:08:35 +00:00
|
|
|
/* update */ update,
|
2011-11-20 16:38:23 +00:00
|
|
|
/* update_node */ update_node,
|
|
|
|
/* validate_link */ NULL,
|
2012-02-27 17:38:16 +00:00
|
|
|
/* internal_connect */ node_internal_connect_default
|
2011-09-05 21:01:50 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
|
2011-09-06 16:32:51 +00:00
|
|
|
/* XXX Group nodes must set use_tree_data to false, since their trees can be shared by multiple nodes.
|
|
|
|
* If use_tree_data is true, the ntree->execdata pointer is checked to avoid multiple execution of top-level trees.
|
|
|
|
*/
|
|
|
|
struct bNodeTreeExec *ntreeCompositBeginExecTree(bNodeTree *ntree, int use_tree_data)
|
2011-09-05 21:01:50 +00:00
|
|
|
{
|
|
|
|
bNodeTreeExec *exec;
|
|
|
|
bNode *node;
|
|
|
|
bNodeSocket *sock;
|
|
|
|
|
2011-09-06 16:32:51 +00:00
|
|
|
if (use_tree_data) {
|
|
|
|
/* XXX hack: prevent exec data from being generated twice.
|
|
|
|
* this should be handled by the renderer!
|
|
|
|
*/
|
|
|
|
if (ntree->execdata)
|
|
|
|
return ntree->execdata;
|
|
|
|
}
|
2011-09-05 21:01:50 +00:00
|
|
|
|
|
|
|
/* ensures only a single output node is enabled */
|
|
|
|
ntreeSetOutput(ntree);
|
|
|
|
|
|
|
|
exec = ntree_exec_begin(ntree);
|
|
|
|
|
2012-03-24 06:38:07 +00:00
|
|
|
for (node= exec->nodetree->nodes.first; node; node= node->next) {
|
2011-09-05 21:01:50 +00:00
|
|
|
/* initialize needed for groups */
|
|
|
|
node->exec= 0;
|
|
|
|
|
2012-03-24 06:38:07 +00:00
|
|
|
for (sock= node->outputs.first; sock; sock= sock->next) {
|
2011-09-05 21:01:50 +00:00
|
|
|
bNodeStack *ns= node_get_socket_stack(exec->stack, sock);
|
2012-03-24 06:38:07 +00:00
|
|
|
if (ns && sock->cache) {
|
2011-09-05 21:01:50 +00:00
|
|
|
ns->data= sock->cache;
|
|
|
|
sock->cache= NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/* cannot initialize them while using in threads */
|
2012-03-24 06:38:07 +00:00
|
|
|
if (ELEM4(node->type, CMP_NODE_TIME, CMP_NODE_CURVE_VEC, CMP_NODE_CURVE_RGB, CMP_NODE_HUECORRECT)) {
|
2011-09-05 21:01:50 +00:00
|
|
|
curvemapping_initialize(node->storage);
|
2012-03-24 06:38:07 +00:00
|
|
|
if (node->type==CMP_NODE_CURVE_RGB)
|
2011-09-05 21:01:50 +00:00
|
|
|
curvemapping_premultiply(node->storage, 0);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-09-06 16:32:51 +00:00
|
|
|
if (use_tree_data) {
|
|
|
|
/* XXX this should not be necessary, but is still used for cmp/sha/tex nodes,
|
2011-09-05 21:01:50 +00:00
|
|
|
* which only store the ntree pointer. Should be fixed at some point!
|
|
|
|
*/
|
2011-09-06 16:32:51 +00:00
|
|
|
ntree->execdata = exec;
|
|
|
|
}
|
2011-09-05 21:01:50 +00:00
|
|
|
|
|
|
|
return exec;
|
|
|
|
}
|
|
|
|
|
2011-09-06 16:32:51 +00:00
|
|
|
/* XXX Group nodes must set use_tree_data to false, since their trees can be shared by multiple nodes.
|
|
|
|
* If use_tree_data is true, the ntree->execdata pointer is checked to avoid multiple execution of top-level trees.
|
|
|
|
*/
|
|
|
|
void ntreeCompositEndExecTree(bNodeTreeExec *exec, int use_tree_data)
|
2011-09-05 21:01:50 +00:00
|
|
|
{
|
2012-03-24 06:38:07 +00:00
|
|
|
if (exec) {
|
2011-09-05 21:01:50 +00:00
|
|
|
bNodeTree *ntree= exec->nodetree;
|
|
|
|
bNode *node;
|
|
|
|
bNodeStack *ns;
|
|
|
|
|
2012-03-24 06:38:07 +00:00
|
|
|
for (node= exec->nodetree->nodes.first; node; node= node->next) {
|
2011-09-05 21:01:50 +00:00
|
|
|
bNodeSocket *sock;
|
|
|
|
|
2012-03-24 06:38:07 +00:00
|
|
|
for (sock= node->outputs.first; sock; sock= sock->next) {
|
2011-09-05 21:01:50 +00:00
|
|
|
ns = node_get_socket_stack(exec->stack, sock);
|
2012-03-24 06:38:07 +00:00
|
|
|
if (ns && ns->data) {
|
2011-09-05 21:01:50 +00:00
|
|
|
sock->cache= ns->data;
|
|
|
|
ns->data= NULL;
|
|
|
|
}
|
|
|
|
}
|
2012-03-24 06:38:07 +00:00
|
|
|
if (node->type==CMP_NODE_CURVE_RGB)
|
2011-09-05 21:01:50 +00:00
|
|
|
curvemapping_premultiply(node->storage, 1);
|
|
|
|
|
|
|
|
node->need_exec= 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
ntree_exec_end(exec);
|
|
|
|
|
2011-09-06 16:32:51 +00:00
|
|
|
if (use_tree_data) {
|
|
|
|
/* XXX clear nodetree backpointer to exec data, same problem as noted in ntreeBeginExecTree */
|
|
|
|
ntree->execdata = NULL;
|
|
|
|
}
|
2011-09-05 21:01:50 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* ***************************** 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;
|
|
|
|
|
2012-03-24 06:38:07 +00:00
|
|
|
if (ELEM3(node->type, CMP_NODE_TIME, CMP_NODE_VALUE, CMP_NODE_RGB))
|
2011-09-05 21:01:50 +00:00
|
|
|
return 1;
|
|
|
|
|
|
|
|
/* doing this for all node types goes wrong. memory free errors */
|
2012-03-24 06:38:07 +00:00
|
|
|
if (node->inputs.first && node->type==CMP_NODE_MAP_VALUE) {
|
2011-09-05 21:01:50 +00:00
|
|
|
int retval= 1;
|
2012-03-24 06:38:07 +00:00
|
|
|
for (sock= node->inputs.first; sock; sock= sock->next) {
|
|
|
|
if (sock->link)
|
2011-09-05 21:01:50 +00:00
|
|
|
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);
|
|
|
|
|
2012-03-24 06:38:07 +00:00
|
|
|
if (node->typeinfo->execfunc)
|
2011-09-05 21:01:50 +00:00
|
|
|
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;
|
2011-09-16 08:20:21 +00:00
|
|
|
return NULL;
|
2011-09-05 21:01:50 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* return total of executable nodes, for timecursor */
|
2011-09-07 10:26:22 +00:00
|
|
|
static int setExecutableNodes(bNodeTreeExec *exec, ThreadData *thd)
|
2011-09-05 21:01:50 +00:00
|
|
|
{
|
2011-09-07 10:26:22 +00:00
|
|
|
bNodeTree *ntree = exec->nodetree;
|
2011-09-05 21:01:50 +00:00
|
|
|
bNodeStack *nsin[MAX_SOCKET]; /* arbitrary... watch this */
|
|
|
|
bNodeStack *nsout[MAX_SOCKET]; /* arbitrary... watch this */
|
2011-09-07 10:26:22 +00:00
|
|
|
bNodeExec *nodeexec;
|
2011-09-05 21:01:50 +00:00
|
|
|
bNode *node;
|
|
|
|
bNodeSocket *sock;
|
2011-09-07 10:26:22 +00:00
|
|
|
int n, totnode= 0, group_edit= 0;
|
2011-09-05 21:01:50 +00:00
|
|
|
|
|
|
|
/* if we are in group edit, viewer nodes get skipped when group has viewer */
|
2012-03-24 06:38:07 +00:00
|
|
|
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))
|
2011-09-05 21:01:50 +00:00
|
|
|
group_edit= 1;
|
|
|
|
|
2011-09-07 10:26:22 +00:00
|
|
|
/* NB: using the exec data list here to have valid dependency sort */
|
2012-03-24 06:38:07 +00:00
|
|
|
for (n=0, nodeexec=exec->nodeexec; n < exec->totnodes; ++n, ++nodeexec) {
|
2011-09-05 21:01:50 +00:00
|
|
|
int a;
|
2011-09-07 10:26:22 +00:00
|
|
|
node = nodeexec->node;
|
2011-09-05 21:01:50 +00:00
|
|
|
|
2011-09-07 12:46:30 +00:00
|
|
|
node_get_stack(node, exec->stack, nsin, nsout);
|
2011-09-05 21:01:50 +00:00
|
|
|
|
|
|
|
/* test the outputs */
|
|
|
|
/* skip value-only nodes (should be in type!) */
|
2012-03-24 06:38:07 +00:00
|
|
|
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) {
|
2011-09-05 21:01:50 +00:00
|
|
|
node->need_exec= 1;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* test the inputs */
|
2012-03-24 06:38:07 +00:00
|
|
|
for (a=0, sock= node->inputs.first; sock; sock= sock->next, a++) {
|
2011-09-05 21:01:50 +00:00
|
|
|
/* skip viewer nodes in bg render or group edit */
|
2012-03-24 06:38:07 +00:00
|
|
|
if ( ELEM(node->type, CMP_NODE_VIEWER, CMP_NODE_SPLITVIEWER) && (G.background || group_edit))
|
2011-09-05 21:01:50 +00:00
|
|
|
node->need_exec= 0;
|
|
|
|
/* is sock in use? */
|
2012-03-24 06:38:07 +00:00
|
|
|
else if (sock->link) {
|
2011-09-05 21:01:50 +00:00
|
|
|
bNodeLink *link= sock->link;
|
|
|
|
|
|
|
|
/* this is the test for a cyclic case */
|
2012-03-24 06:38:07 +00:00
|
|
|
if (link->fromnode==NULL || link->tonode==NULL);
|
|
|
|
else if (link->fromnode->level >= link->tonode->level && link->tonode->level!=0xFFF) {
|
|
|
|
if (link->fromnode->need_exec) {
|
2011-09-05 21:01:50 +00:00
|
|
|
node->need_exec= 1;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
node->need_exec= 0;
|
|
|
|
printf("Node %s skipped, cyclic dependency\n", node->name);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-03-24 06:38:07 +00:00
|
|
|
if (node->need_exec) {
|
2011-09-05 21:01:50 +00:00
|
|
|
|
|
|
|
/* free output buffers */
|
2012-03-24 06:38:07 +00:00
|
|
|
for (a=0, sock= node->outputs.first; sock; sock= sock->next, a++) {
|
|
|
|
if (nsout[a]->data) {
|
2011-09-05 21:01:50 +00:00
|
|
|
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 */
|
2012-03-24 06:38:07 +00:00
|
|
|
if (totnode) {
|
|
|
|
for (n=0, nodeexec=exec->nodeexec; n < exec->totnodes; ++n, ++nodeexec) {
|
2011-09-07 10:26:22 +00:00
|
|
|
node = nodeexec->node;
|
2012-03-24 06:38:07 +00:00
|
|
|
if (node->need_exec==0 && node_only_value(node)) {
|
|
|
|
if (node->typeinfo->execfunc) {
|
2011-09-07 12:46:30 +00:00
|
|
|
node_get_stack(node, exec->stack, nsin, nsout);
|
2011-09-05 21:01:50 +00:00
|
|
|
node->typeinfo->execfunc(thd->rd, node, nsin, nsout);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return totnode;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* while executing tree, free buffers from nodes that are not needed anymore */
|
2011-09-07 10:26:22 +00:00
|
|
|
static void freeExecutableNode(bNodeTreeExec *exec)
|
2011-09-05 21:01:50 +00:00
|
|
|
{
|
|
|
|
/* node outputs can be freed when:
|
|
|
|
- not a render result or image node
|
|
|
|
- when node outputs go to nodes all being set NODE_FINISHED
|
|
|
|
*/
|
2011-09-07 10:26:22 +00:00
|
|
|
bNodeTree *ntree = exec->nodetree;
|
|
|
|
bNodeExec *nodeexec;
|
2011-09-05 21:01:50 +00:00
|
|
|
bNode *node;
|
|
|
|
bNodeSocket *sock;
|
2011-09-07 10:26:22 +00:00
|
|
|
int n;
|
2011-09-05 21:01:50 +00:00
|
|
|
|
|
|
|
/* set exec flag for finished nodes that might need freed */
|
2012-03-24 06:38:07 +00:00
|
|
|
for (node= ntree->nodes.first; node; node= node->next) {
|
|
|
|
if (node->type!=CMP_NODE_R_LAYERS)
|
|
|
|
if (node->exec & NODE_FINISHED)
|
2011-09-05 21:01:50 +00:00
|
|
|
node->exec |= NODE_FREEBUFS;
|
|
|
|
}
|
2011-09-07 10:26:22 +00:00
|
|
|
/* clear this flag for input links that are not done yet.
|
|
|
|
* Using the exec data for valid dependency sort.
|
|
|
|
*/
|
2012-03-24 06:38:07 +00:00
|
|
|
for (n=0, nodeexec=exec->nodeexec; n < exec->totnodes; ++n, ++nodeexec) {
|
2011-09-07 10:26:22 +00:00
|
|
|
node = nodeexec->node;
|
2012-03-24 06:38:07 +00:00
|
|
|
if ((node->exec & NODE_FINISHED)==0) {
|
|
|
|
for (sock= node->inputs.first; sock; sock= sock->next)
|
|
|
|
if (sock->link)
|
2011-09-05 21:01:50 +00:00
|
|
|
sock->link->fromnode->exec &= ~NODE_FREEBUFS;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/* now we can free buffers */
|
2012-03-24 06:38:07 +00:00
|
|
|
for (node= ntree->nodes.first; node; node= node->next) {
|
|
|
|
if (node->exec & NODE_FREEBUFS) {
|
|
|
|
for (sock= node->outputs.first; sock; sock= sock->next) {
|
2011-09-05 21:01:50 +00:00
|
|
|
bNodeStack *ns= node_get_socket_stack(exec->stack, sock);
|
2012-03-24 06:38:07 +00:00
|
|
|
if (ns && ns->data) {
|
2011-09-05 21:01:50 +00:00
|
|
|
free_compbuf(ns->data);
|
|
|
|
ns->data= NULL;
|
2012-03-31 00:59:17 +00:00
|
|
|
// printf("freed buf node %s\n", node->name);
|
2011-09-05 21:01:50 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static bNodeExec *getExecutableNode(bNodeTreeExec *exec)
|
|
|
|
{
|
|
|
|
bNodeExec *nodeexec;
|
|
|
|
bNodeSocket *sock;
|
|
|
|
int n;
|
|
|
|
|
2012-03-24 06:38:07 +00:00
|
|
|
for (n=0, nodeexec=exec->nodeexec; n < exec->totnodes; ++n, ++nodeexec) {
|
|
|
|
if (nodeexec->node->exec==0) {
|
2011-09-05 21:01:50 +00:00
|
|
|
/* input sockets should be ready */
|
2012-03-24 06:38:07 +00:00
|
|
|
for (sock= nodeexec->node->inputs.first; sock; sock= sock->next) {
|
|
|
|
if (sock->link && sock->link->fromnode)
|
|
|
|
if ((sock->link->fromnode->exec & NODE_READY)==0)
|
2011-09-05 21:01:50 +00:00
|
|
|
break;
|
|
|
|
}
|
2012-03-24 06:38:07 +00:00
|
|
|
if (sock==NULL)
|
2011-09-05 21:01:50 +00:00
|
|
|
return nodeexec;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* check if texture nodes need exec or end */
|
|
|
|
static void ntree_composite_texnode(bNodeTree *ntree, int init)
|
|
|
|
{
|
|
|
|
bNode *node;
|
|
|
|
|
2012-03-24 06:38:07 +00:00
|
|
|
for (node= ntree->nodes.first; node; node= node->next) {
|
|
|
|
if (node->type==CMP_NODE_TEXTURE && node->id) {
|
2011-09-05 21:01:50 +00:00
|
|
|
Tex *tex= (Tex *)node->id;
|
2012-03-24 06:38:07 +00:00
|
|
|
if (tex->nodetree && tex->use_nodes) {
|
2011-09-05 21:01:50 +00:00
|
|
|
/* has internal flag to detect it only does it once */
|
2012-03-24 06:38:07 +00:00
|
|
|
if (init) {
|
2011-09-05 21:01:50 +00:00
|
|
|
if (!tex->nodetree->execdata)
|
2011-09-06 16:32:51 +00:00
|
|
|
tex->nodetree->execdata = ntreeTexBeginExecTree(tex->nodetree, 1);
|
2011-09-05 21:01:50 +00:00
|
|
|
}
|
|
|
|
else
|
2011-09-06 16:32:51 +00:00
|
|
|
ntreeTexEndExecTree(tex->nodetree->execdata, 1);
|
2011-09-05 21:01:50 +00:00
|
|
|
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;
|
2012-02-25 09:06:17 +00:00
|
|
|
bNodeTreeExec *exec;
|
|
|
|
|
2012-03-24 06:38:07 +00:00
|
|
|
if (ntree==NULL) return;
|
2012-02-25 09:06:17 +00:00
|
|
|
|
|
|
|
exec = ntree->execdata;
|
|
|
|
|
2012-03-24 06:38:07 +00:00
|
|
|
if (do_preview)
|
2011-09-05 21:01:50 +00:00
|
|
|
ntreeInitPreview(ntree, 0, 0);
|
|
|
|
|
2011-09-06 16:32:51 +00:00
|
|
|
if (!ntree->execdata) {
|
|
|
|
/* XXX this is the top-level tree, so we use the ntree->execdata pointer. */
|
|
|
|
exec = ntreeCompositBeginExecTree(ntree, 1);
|
|
|
|
}
|
2011-09-05 21:01:50 +00:00
|
|
|
ntree_composite_texnode(ntree, 1);
|
|
|
|
|
|
|
|
/* prevent unlucky accidents */
|
2012-03-24 06:38:07 +00:00
|
|
|
if (G.background)
|
2011-09-05 21:01:50 +00:00
|
|
|
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 */
|
2011-09-07 10:26:22 +00:00
|
|
|
curnode = totnode= setExecutableNodes(exec, &thdata);
|
2011-09-05 21:01:50 +00:00
|
|
|
|
|
|
|
BLI_init_threads(&threads, exec_composite_node, rd->threads);
|
|
|
|
|
2012-03-24 06:38:07 +00:00
|
|
|
while (rendering) {
|
2011-09-05 21:01:50 +00:00
|
|
|
|
2012-03-24 06:38:07 +00:00
|
|
|
if (BLI_available_threads(&threads)) {
|
2011-09-05 21:01:50 +00:00
|
|
|
nodeexec= getExecutableNode(exec);
|
2012-03-24 06:38:07 +00:00
|
|
|
if (nodeexec) {
|
2011-09-05 21:01:50 +00:00
|
|
|
node = nodeexec->node;
|
2012-03-24 06:38:07 +00:00
|
|
|
if (ntree->progress && totnode)
|
2011-11-11 12:00:08 +00:00
|
|
|
ntree->progress(ntree->prh, (1.0f - curnode/(float)totnode));
|
2012-03-24 06:38:07 +00:00
|
|
|
if (ntree->stats_draw) {
|
2012-01-11 08:51:06 +00:00
|
|
|
char str[128];
|
2012-01-11 12:33:51 +00:00
|
|
|
BLI_snprintf(str, sizeof(str), "Compositing %d %s", curnode, node->name);
|
2011-09-05 21:01:50 +00:00
|
|
|
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 */
|
2012-03-24 06:38:07 +00:00
|
|
|
if (ntree->test_break && ntree->test_break(ntree->tbh)) {
|
|
|
|
for (node= ntree->nodes.first; node; node= node->next)
|
2011-09-05 21:01:50 +00:00
|
|
|
node->exec |= NODE_READY;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* check for ready ones, and if we need to continue */
|
2012-03-24 06:38:07 +00:00
|
|
|
for (n=0, nodeexec=exec->nodeexec; n < exec->totnodes; ++n, ++nodeexec) {
|
2011-09-05 21:01:50 +00:00
|
|
|
node = nodeexec->node;
|
2012-03-24 06:38:07 +00:00
|
|
|
if (node->exec & NODE_READY) {
|
|
|
|
if ((node->exec & NODE_FINISHED)==0) {
|
2011-09-05 21:01:50 +00:00
|
|
|
BLI_remove_thread(&threads, nodeexec); /* this waits for running thread to finish btw */
|
|
|
|
node->exec |= NODE_FINISHED;
|
|
|
|
|
|
|
|
/* freeing unused buffers */
|
2012-03-24 06:38:07 +00:00
|
|
|
if (rd->scemode & R_COMP_FREE)
|
2011-09-07 10:26:22 +00:00
|
|
|
freeExecutableNode(exec);
|
2011-09-05 21:01:50 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else rendering= 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
BLI_end_threads(&threads);
|
|
|
|
|
2011-09-06 16:32:51 +00:00
|
|
|
/* XXX top-level tree uses the ntree->execdata pointer */
|
|
|
|
ntreeCompositEndExecTree(exec, 1);
|
2011-09-05 21:01:50 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* *********************************************** */
|
|
|
|
|
|
|
|
/* clumsy checking... should do dynamic outputs once */
|
|
|
|
static void force_hidden_passes(bNode *node, int passflag)
|
|
|
|
{
|
|
|
|
bNodeSocket *sock;
|
|
|
|
|
2012-03-24 06:38:07 +00:00
|
|
|
for (sock= node->outputs.first; sock; sock= sock->next)
|
2011-09-05 21:01:50 +00:00
|
|
|
sock->flag &= ~SOCK_UNAVAIL;
|
|
|
|
|
2012-03-24 06:38:07 +00:00
|
|
|
if (!(passflag & SCE_PASS_COMBINED)) {
|
2012-01-30 08:48:11 +00:00
|
|
|
sock= BLI_findlink(&node->outputs, RRES_OUT_IMAGE);
|
|
|
|
sock->flag |= SOCK_UNAVAIL;
|
|
|
|
sock= BLI_findlink(&node->outputs, RRES_OUT_ALPHA);
|
|
|
|
sock->flag |= SOCK_UNAVAIL;
|
|
|
|
}
|
|
|
|
|
2011-09-05 21:01:50 +00:00
|
|
|
sock= BLI_findlink(&node->outputs, RRES_OUT_Z);
|
2012-03-24 06:38:07 +00:00
|
|
|
if (!(passflag & SCE_PASS_Z)) sock->flag |= SOCK_UNAVAIL;
|
2011-09-05 21:01:50 +00:00
|
|
|
sock= BLI_findlink(&node->outputs, RRES_OUT_NORMAL);
|
2012-03-24 06:38:07 +00:00
|
|
|
if (!(passflag & SCE_PASS_NORMAL)) sock->flag |= SOCK_UNAVAIL;
|
2011-09-05 21:01:50 +00:00
|
|
|
sock= BLI_findlink(&node->outputs, RRES_OUT_VEC);
|
2012-03-24 06:38:07 +00:00
|
|
|
if (!(passflag & SCE_PASS_VECTOR)) sock->flag |= SOCK_UNAVAIL;
|
2011-09-05 21:01:50 +00:00
|
|
|
sock= BLI_findlink(&node->outputs, RRES_OUT_UV);
|
2012-03-24 06:38:07 +00:00
|
|
|
if (!(passflag & SCE_PASS_UV)) sock->flag |= SOCK_UNAVAIL;
|
2011-09-05 21:01:50 +00:00
|
|
|
sock= BLI_findlink(&node->outputs, RRES_OUT_RGBA);
|
2012-03-24 06:38:07 +00:00
|
|
|
if (!(passflag & SCE_PASS_RGBA)) sock->flag |= SOCK_UNAVAIL;
|
2011-09-05 21:01:50 +00:00
|
|
|
sock= BLI_findlink(&node->outputs, RRES_OUT_DIFF);
|
2012-03-24 06:38:07 +00:00
|
|
|
if (!(passflag & SCE_PASS_DIFFUSE)) sock->flag |= SOCK_UNAVAIL;
|
2011-09-05 21:01:50 +00:00
|
|
|
sock= BLI_findlink(&node->outputs, RRES_OUT_SPEC);
|
2012-03-24 06:38:07 +00:00
|
|
|
if (!(passflag & SCE_PASS_SPEC)) sock->flag |= SOCK_UNAVAIL;
|
2011-09-05 21:01:50 +00:00
|
|
|
sock= BLI_findlink(&node->outputs, RRES_OUT_SHADOW);
|
2012-03-24 06:38:07 +00:00
|
|
|
if (!(passflag & SCE_PASS_SHADOW)) sock->flag |= SOCK_UNAVAIL;
|
2011-09-05 21:01:50 +00:00
|
|
|
sock= BLI_findlink(&node->outputs, RRES_OUT_AO);
|
2012-03-24 06:38:07 +00:00
|
|
|
if (!(passflag & SCE_PASS_AO)) sock->flag |= SOCK_UNAVAIL;
|
2011-09-05 21:01:50 +00:00
|
|
|
sock= BLI_findlink(&node->outputs, RRES_OUT_REFLECT);
|
2012-03-24 06:38:07 +00:00
|
|
|
if (!(passflag & SCE_PASS_REFLECT)) sock->flag |= SOCK_UNAVAIL;
|
2011-09-05 21:01:50 +00:00
|
|
|
sock= BLI_findlink(&node->outputs, RRES_OUT_REFRACT);
|
2012-03-24 06:38:07 +00:00
|
|
|
if (!(passflag & SCE_PASS_REFRACT)) sock->flag |= SOCK_UNAVAIL;
|
2011-09-05 21:01:50 +00:00
|
|
|
sock= BLI_findlink(&node->outputs, RRES_OUT_INDIRECT);
|
2012-03-24 06:38:07 +00:00
|
|
|
if (!(passflag & SCE_PASS_INDIRECT)) sock->flag |= SOCK_UNAVAIL;
|
2011-09-05 21:01:50 +00:00
|
|
|
sock= BLI_findlink(&node->outputs, RRES_OUT_INDEXOB);
|
2012-03-24 06:38:07 +00:00
|
|
|
if (!(passflag & SCE_PASS_INDEXOB)) sock->flag |= SOCK_UNAVAIL;
|
2011-09-05 21:01:50 +00:00
|
|
|
sock= BLI_findlink(&node->outputs, RRES_OUT_INDEXMA);
|
2012-03-24 06:38:07 +00:00
|
|
|
if (!(passflag & SCE_PASS_INDEXMA)) sock->flag |= SOCK_UNAVAIL;
|
2011-09-05 21:01:50 +00:00
|
|
|
sock= BLI_findlink(&node->outputs, RRES_OUT_MIST);
|
2012-03-24 06:38:07 +00:00
|
|
|
if (!(passflag & SCE_PASS_MIST)) sock->flag |= SOCK_UNAVAIL;
|
2011-09-05 21:01:50 +00:00
|
|
|
sock= BLI_findlink(&node->outputs, RRES_OUT_EMIT);
|
2012-03-24 06:38:07 +00:00
|
|
|
if (!(passflag & SCE_PASS_EMIT)) sock->flag |= SOCK_UNAVAIL;
|
2011-09-05 21:01:50 +00:00
|
|
|
sock= BLI_findlink(&node->outputs, RRES_OUT_ENV);
|
2012-03-24 06:38:07 +00:00
|
|
|
if (!(passflag & SCE_PASS_ENVIRONMENT)) sock->flag |= SOCK_UNAVAIL;
|
Cycles: Render Passes
Currently supported passes:
* Combined, Z, Normal, Object Index, Material Index, Emission, Environment,
Diffuse/Glossy/Transmission x Direct/Indirect/Color
Not supported yet:
* UV, Vector, Mist
Only enabled for CPU devices at the moment, will do GPU tweaks tommorrow,
also for environment importance sampling.
Documentation:
http://wiki.blender.org/index.php/Doc:2.6/Manual/Render/Cycles/Passes
2012-01-25 17:23:52 +00:00
|
|
|
|
|
|
|
sock= BLI_findlink(&node->outputs, RRES_OUT_DIFF_DIRECT);
|
2012-03-24 06:38:07 +00:00
|
|
|
if (!(passflag & SCE_PASS_DIFFUSE_DIRECT)) sock->flag |= SOCK_UNAVAIL;
|
Cycles: Render Passes
Currently supported passes:
* Combined, Z, Normal, Object Index, Material Index, Emission, Environment,
Diffuse/Glossy/Transmission x Direct/Indirect/Color
Not supported yet:
* UV, Vector, Mist
Only enabled for CPU devices at the moment, will do GPU tweaks tommorrow,
also for environment importance sampling.
Documentation:
http://wiki.blender.org/index.php/Doc:2.6/Manual/Render/Cycles/Passes
2012-01-25 17:23:52 +00:00
|
|
|
sock= BLI_findlink(&node->outputs, RRES_OUT_DIFF_INDIRECT);
|
2012-03-24 06:38:07 +00:00
|
|
|
if (!(passflag & SCE_PASS_DIFFUSE_INDIRECT)) sock->flag |= SOCK_UNAVAIL;
|
Cycles: Render Passes
Currently supported passes:
* Combined, Z, Normal, Object Index, Material Index, Emission, Environment,
Diffuse/Glossy/Transmission x Direct/Indirect/Color
Not supported yet:
* UV, Vector, Mist
Only enabled for CPU devices at the moment, will do GPU tweaks tommorrow,
also for environment importance sampling.
Documentation:
http://wiki.blender.org/index.php/Doc:2.6/Manual/Render/Cycles/Passes
2012-01-25 17:23:52 +00:00
|
|
|
sock= BLI_findlink(&node->outputs, RRES_OUT_DIFF_COLOR);
|
2012-03-24 06:38:07 +00:00
|
|
|
if (!(passflag & SCE_PASS_DIFFUSE_COLOR)) sock->flag |= SOCK_UNAVAIL;
|
Cycles: Render Passes
Currently supported passes:
* Combined, Z, Normal, Object Index, Material Index, Emission, Environment,
Diffuse/Glossy/Transmission x Direct/Indirect/Color
Not supported yet:
* UV, Vector, Mist
Only enabled for CPU devices at the moment, will do GPU tweaks tommorrow,
also for environment importance sampling.
Documentation:
http://wiki.blender.org/index.php/Doc:2.6/Manual/Render/Cycles/Passes
2012-01-25 17:23:52 +00:00
|
|
|
|
|
|
|
sock= BLI_findlink(&node->outputs, RRES_OUT_GLOSSY_DIRECT);
|
2012-03-24 06:38:07 +00:00
|
|
|
if (!(passflag & SCE_PASS_GLOSSY_DIRECT)) sock->flag |= SOCK_UNAVAIL;
|
Cycles: Render Passes
Currently supported passes:
* Combined, Z, Normal, Object Index, Material Index, Emission, Environment,
Diffuse/Glossy/Transmission x Direct/Indirect/Color
Not supported yet:
* UV, Vector, Mist
Only enabled for CPU devices at the moment, will do GPU tweaks tommorrow,
also for environment importance sampling.
Documentation:
http://wiki.blender.org/index.php/Doc:2.6/Manual/Render/Cycles/Passes
2012-01-25 17:23:52 +00:00
|
|
|
sock= BLI_findlink(&node->outputs, RRES_OUT_GLOSSY_INDIRECT);
|
2012-03-24 06:38:07 +00:00
|
|
|
if (!(passflag & SCE_PASS_GLOSSY_INDIRECT)) sock->flag |= SOCK_UNAVAIL;
|
Cycles: Render Passes
Currently supported passes:
* Combined, Z, Normal, Object Index, Material Index, Emission, Environment,
Diffuse/Glossy/Transmission x Direct/Indirect/Color
Not supported yet:
* UV, Vector, Mist
Only enabled for CPU devices at the moment, will do GPU tweaks tommorrow,
also for environment importance sampling.
Documentation:
http://wiki.blender.org/index.php/Doc:2.6/Manual/Render/Cycles/Passes
2012-01-25 17:23:52 +00:00
|
|
|
sock= BLI_findlink(&node->outputs, RRES_OUT_GLOSSY_COLOR);
|
2012-03-24 06:38:07 +00:00
|
|
|
if (!(passflag & SCE_PASS_GLOSSY_COLOR)) sock->flag |= SOCK_UNAVAIL;
|
Cycles: Render Passes
Currently supported passes:
* Combined, Z, Normal, Object Index, Material Index, Emission, Environment,
Diffuse/Glossy/Transmission x Direct/Indirect/Color
Not supported yet:
* UV, Vector, Mist
Only enabled for CPU devices at the moment, will do GPU tweaks tommorrow,
also for environment importance sampling.
Documentation:
http://wiki.blender.org/index.php/Doc:2.6/Manual/Render/Cycles/Passes
2012-01-25 17:23:52 +00:00
|
|
|
|
|
|
|
sock= BLI_findlink(&node->outputs, RRES_OUT_TRANSM_DIRECT);
|
2012-03-24 06:38:07 +00:00
|
|
|
if (!(passflag & SCE_PASS_TRANSM_DIRECT)) sock->flag |= SOCK_UNAVAIL;
|
Cycles: Render Passes
Currently supported passes:
* Combined, Z, Normal, Object Index, Material Index, Emission, Environment,
Diffuse/Glossy/Transmission x Direct/Indirect/Color
Not supported yet:
* UV, Vector, Mist
Only enabled for CPU devices at the moment, will do GPU tweaks tommorrow,
also for environment importance sampling.
Documentation:
http://wiki.blender.org/index.php/Doc:2.6/Manual/Render/Cycles/Passes
2012-01-25 17:23:52 +00:00
|
|
|
sock= BLI_findlink(&node->outputs, RRES_OUT_TRANSM_INDIRECT);
|
2012-03-24 06:38:07 +00:00
|
|
|
if (!(passflag & SCE_PASS_TRANSM_INDIRECT)) sock->flag |= SOCK_UNAVAIL;
|
Cycles: Render Passes
Currently supported passes:
* Combined, Z, Normal, Object Index, Material Index, Emission, Environment,
Diffuse/Glossy/Transmission x Direct/Indirect/Color
Not supported yet:
* UV, Vector, Mist
Only enabled for CPU devices at the moment, will do GPU tweaks tommorrow,
also for environment importance sampling.
Documentation:
http://wiki.blender.org/index.php/Doc:2.6/Manual/Render/Cycles/Passes
2012-01-25 17:23:52 +00:00
|
|
|
sock= BLI_findlink(&node->outputs, RRES_OUT_TRANSM_COLOR);
|
2012-03-24 06:38:07 +00:00
|
|
|
if (!(passflag & SCE_PASS_TRANSM_COLOR)) sock->flag |= SOCK_UNAVAIL;
|
Cycles: Render Passes
Currently supported passes:
* Combined, Z, Normal, Object Index, Material Index, Emission, Environment,
Diffuse/Glossy/Transmission x Direct/Indirect/Color
Not supported yet:
* UV, Vector, Mist
Only enabled for CPU devices at the moment, will do GPU tweaks tommorrow,
also for environment importance sampling.
Documentation:
http://wiki.blender.org/index.php/Doc:2.6/Manual/Render/Cycles/Passes
2012-01-25 17:23:52 +00:00
|
|
|
sock= BLI_findlink(&node->outputs, RRES_OUT_TRANSM_COLOR);
|
2011-09-05 21:01:50 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* based on rules, force sockets hidden always */
|
|
|
|
void ntreeCompositForceHidden(bNodeTree *ntree, Scene *curscene)
|
|
|
|
{
|
|
|
|
bNode *node;
|
|
|
|
|
2012-03-24 06:38:07 +00:00
|
|
|
if (ntree==NULL) return;
|
2011-09-05 21:01:50 +00:00
|
|
|
|
2012-03-24 06:38:07 +00:00
|
|
|
for (node= ntree->nodes.first; node; node= node->next) {
|
|
|
|
if ( node->type==CMP_NODE_R_LAYERS) {
|
2011-09-05 21:01:50 +00:00
|
|
|
Scene *sce= node->id?(Scene *)node->id:curscene;
|
|
|
|
SceneRenderLayer *srl= BLI_findlink(&sce->r.layers, node->custom1);
|
2012-03-24 06:38:07 +00:00
|
|
|
if (srl)
|
2011-09-05 21:01:50 +00:00
|
|
|
force_hidden_passes(node, srl->passflag);
|
|
|
|
}
|
2012-04-16 13:49:33 +00:00
|
|
|
/* XXX this stuff is called all the time, don't want that.
|
|
|
|
* Updates should only happen when actually necessary.
|
|
|
|
*/
|
|
|
|
#if 0
|
2012-03-24 06:38:07 +00:00
|
|
|
else if ( node->type==CMP_NODE_IMAGE) {
|
2012-04-16 13:49:33 +00:00
|
|
|
nodeUpdate(ntree, node);
|
2011-09-05 21:01:50 +00:00
|
|
|
}
|
2012-04-16 13:49:33 +00:00
|
|
|
#endif
|
2011-09-05 21:01:50 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
/* 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;
|
|
|
|
|
2012-03-24 06:38:07 +00:00
|
|
|
for (sce= G.main->scene.first; sce; sce= sce->id.next) {
|
|
|
|
if (sce->nodetree) {
|
2011-09-05 21:01:50 +00:00
|
|
|
bNode *node;
|
|
|
|
|
2012-03-24 06:38:07 +00:00
|
|
|
for (node= sce->nodetree->nodes.first; node; node= node->next) {
|
|
|
|
if (node->id==(ID *)curscene || node->type==CMP_NODE_COMPOSITE)
|
2011-10-19 17:08:35 +00:00
|
|
|
nodeUpdate(sce->nodetree, node);
|
2012-03-24 06:38:07 +00:00
|
|
|
else if (node->type==CMP_NODE_TEXTURE) /* uses scene sizex/sizey */
|
2011-10-19 17:08:35 +00:00
|
|
|
nodeUpdate(sce->nodetree, node);
|
2011-09-05 21:01:50 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
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)) {
|
2011-10-19 17:08:35 +00:00
|
|
|
nodeUpdate(ntree, node);
|
2011-09-05 21:01:50 +00:00
|
|
|
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)) {
|
2011-10-19 17:08:35 +00:00
|
|
|
nodeUpdate(ntree, node);
|
2011-09-05 21:01:50 +00:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* tags nodes that have animation capabilities */
|
|
|
|
int ntreeCompositTagAnimated(bNodeTree *ntree)
|
|
|
|
{
|
|
|
|
bNode *node;
|
|
|
|
int tagged= 0;
|
|
|
|
|
2012-03-24 06:38:07 +00:00
|
|
|
if (ntree==NULL) return 0;
|
2011-09-05 21:01:50 +00:00
|
|
|
|
2012-03-24 06:38:07 +00:00
|
|
|
for (node= ntree->nodes.first; node; node= node->next) {
|
2011-09-05 21:01:50 +00:00
|
|
|
|
|
|
|
tagged = node_animation_properties(ntree, node);
|
|
|
|
|
|
|
|
/* otherwise always tag these node types */
|
2012-03-24 06:38:07 +00:00
|
|
|
if (node->type==CMP_NODE_IMAGE) {
|
2011-09-05 21:01:50 +00:00
|
|
|
Image *ima= (Image *)node->id;
|
2012-03-24 06:38:07 +00:00
|
|
|
if (ima && ELEM(ima->source, IMA_SRC_MOVIE, IMA_SRC_SEQUENCE)) {
|
2011-10-19 17:08:35 +00:00
|
|
|
nodeUpdate(ntree, node);
|
2011-09-05 21:01:50 +00:00
|
|
|
tagged= 1;
|
|
|
|
}
|
|
|
|
}
|
2012-03-24 06:38:07 +00:00
|
|
|
else if (node->type==CMP_NODE_TIME) {
|
2011-10-19 17:08:35 +00:00
|
|
|
nodeUpdate(ntree, node);
|
2011-09-05 21:01:50 +00:00
|
|
|
tagged= 1;
|
|
|
|
}
|
|
|
|
/* here was tag render layer, but this is called after a render, so re-composites fail */
|
2012-03-24 06:38:07 +00:00
|
|
|
else if (node->type==NODE_GROUP) {
|
|
|
|
if ( ntreeCompositTagAnimated((bNodeTree *)node->id) ) {
|
2011-10-19 17:08:35 +00:00
|
|
|
nodeUpdate(ntree, node);
|
2011-09-05 21:01:50 +00:00
|
|
|
}
|
|
|
|
}
|
2012-03-24 06:38:07 +00:00
|
|
|
else if (ELEM(node->type, CMP_NODE_MOVIECLIP, CMP_NODE_TRANSFORM)) {
|
2011-11-07 12:56:05 +00:00
|
|
|
nodeUpdate(ntree, node);
|
|
|
|
tagged= 1;
|
|
|
|
}
|
2011-09-05 21:01:50 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return tagged;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* called from image window preview */
|
|
|
|
void ntreeCompositTagGenerators(bNodeTree *ntree)
|
|
|
|
{
|
|
|
|
bNode *node;
|
|
|
|
|
2012-03-24 06:38:07 +00:00
|
|
|
if (ntree==NULL) return;
|
2011-09-05 21:01:50 +00:00
|
|
|
|
2012-03-24 06:38:07 +00:00
|
|
|
for (node= ntree->nodes.first; node; node= node->next) {
|
|
|
|
if ( ELEM(node->type, CMP_NODE_R_LAYERS, CMP_NODE_IMAGE))
|
2011-10-19 17:08:35 +00:00
|
|
|
nodeUpdate(ntree, node);
|
2011-09-05 21:01:50 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* XXX after render animation system gets a refresh, this call allows composite to end clean */
|
2011-10-19 17:08:35 +00:00
|
|
|
void ntreeCompositClearTags(bNodeTree *ntree)
|
2011-09-05 21:01:50 +00:00
|
|
|
{
|
|
|
|
bNode *node;
|
|
|
|
|
2012-03-24 06:38:07 +00:00
|
|
|
if (ntree==NULL) return;
|
2011-09-05 21:01:50 +00:00
|
|
|
|
2012-03-24 06:38:07 +00:00
|
|
|
for (node= ntree->nodes.first; node; node= node->next) {
|
2011-09-05 21:01:50 +00:00
|
|
|
node->need_exec= 0;
|
2012-03-24 06:38:07 +00:00
|
|
|
if (node->type==NODE_GROUP)
|
2011-10-19 17:08:35 +00:00
|
|
|
ntreeCompositClearTags((bNodeTree *)node->id);
|
2011-09-05 21:01:50 +00:00
|
|
|
}
|
|
|
|
}
|