2023-08-16 00:20:26 +10:00
|
|
|
/* SPDX-FileCopyrightText: 2007 Blender Authors
|
2023-05-31 16:19:06 +02:00
|
|
|
*
|
|
|
|
|
* SPDX-License-Identifier: GPL-2.0-or-later */
|
2011-09-05 21:01:50 +00:00
|
|
|
|
2019-02-18 08:08:12 +11:00
|
|
|
/** \file
|
|
|
|
|
* \ingroup nodes
|
2011-09-05 21:01:50 +00:00
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#include "DNA_node_types.h"
|
2020-03-19 09:33:03 +01:00
|
|
|
#include "DNA_scene_types.h"
|
2011-09-05 21:01:50 +00:00
|
|
|
|
2025-02-11 16:59:42 +01:00
|
|
|
#include "BLI_listbase.h"
|
|
|
|
|
|
2023-11-16 11:41:55 +01:00
|
|
|
#include "BKE_context.hh"
|
2024-02-10 18:25:14 +01:00
|
|
|
#include "BKE_global.hh"
|
2024-11-12 15:21:59 +01:00
|
|
|
#include "BKE_image.hh"
|
2023-12-01 19:43:16 +01:00
|
|
|
#include "BKE_main.hh"
|
2023-05-15 15:14:22 +02:00
|
|
|
#include "BKE_node.hh"
|
2022-11-18 14:03:00 +01:00
|
|
|
#include "BKE_node_runtime.hh"
|
2023-11-16 11:41:55 +01:00
|
|
|
#include "BKE_node_tree_update.hh"
|
2011-11-07 12:56:05 +00:00
|
|
|
#include "BKE_tracking.h"
|
2011-09-05 21:01:50 +00:00
|
|
|
|
2023-08-05 02:57:52 +02:00
|
|
|
#include "UI_resources.hh"
|
2021-12-24 22:47:58 -05:00
|
|
|
|
2012-08-06 18:49:28 +00:00
|
|
|
#include "node_common.h"
|
2011-09-05 21:01:50 +00:00
|
|
|
|
2024-07-10 18:30:02 +02:00
|
|
|
#include "RNA_prototypes.hh"
|
2011-09-05 21:01:50 +00:00
|
|
|
|
2023-10-16 10:45:54 +02:00
|
|
|
#include "NOD_composite.hh"
|
2021-09-28 15:29:16 -04:00
|
|
|
#include "node_composite_util.hh"
|
2012-06-30 14:14:22 +00:00
|
|
|
|
2024-05-13 16:07:12 +02:00
|
|
|
static void composite_get_from_context(const bContext *C,
|
|
|
|
|
blender::bke::bNodeTreeType * /*treetype*/,
|
|
|
|
|
bNodeTree **r_ntree,
|
|
|
|
|
ID **r_id,
|
|
|
|
|
ID **r_from)
|
2011-09-05 21:01:50 +00:00
|
|
|
{
|
2013-03-18 16:34:57 +00:00
|
|
|
Scene *scene = CTX_data_scene(C);
|
2018-06-08 08:07:48 +02:00
|
|
|
|
2021-09-28 15:29:16 -04:00
|
|
|
*r_from = nullptr;
|
2013-03-18 16:34:57 +00:00
|
|
|
*r_id = &scene->id;
|
2025-06-10 17:46:55 +02:00
|
|
|
*r_ntree = scene->compositing_node_group;
|
2011-09-05 21:01:50 +00:00
|
|
|
}
|
|
|
|
|
|
2024-05-13 16:07:12 +02:00
|
|
|
static void foreach_nodeclass(void *calldata, blender::bke::bNodeClassCallback func)
|
2011-11-07 22:14:48 +00:00
|
|
|
{
|
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"));
|
2021-08-23 16:23:58 +02:00
|
|
|
func(calldata, NODE_CLASS_CONVERTER, N_("Converter"));
|
2012-05-16 15:01:46 +00:00
|
|
|
func(calldata, NODE_CLASS_MATTE, N_("Matte"));
|
|
|
|
|
func(calldata, NODE_CLASS_DISTORT, N_("Distort"));
|
|
|
|
|
func(calldata, NODE_CLASS_GROUP, N_("Group"));
|
2013-03-18 16:34:57 +00:00
|
|
|
func(calldata, NODE_CLASS_INTERFACE, N_("Interface"));
|
2012-05-16 15:01:46 +00:00
|
|
|
func(calldata, NODE_CLASS_LAYOUT, N_("Layout"));
|
2011-11-07 22:14:48 +00:00
|
|
|
}
|
|
|
|
|
|
2011-09-05 21:01:50 +00:00
|
|
|
/* local tree then owns all compbufs */
|
2019-06-03 17:08:25 +02:00
|
|
|
static void localize(bNodeTree *localtree, bNodeTree *ntree)
|
2011-09-05 21:01:50 +00:00
|
|
|
{
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2021-09-28 15:29:16 -04:00
|
|
|
bNode *node = (bNode *)ntree->nodes.first;
|
|
|
|
|
bNode *local_node = (bNode *)localtree->nodes.first;
|
|
|
|
|
while (node != nullptr) {
|
2019-06-03 17:08:25 +02:00
|
|
|
|
2020-03-15 21:46:18 +11:00
|
|
|
/* Ensure new user input gets handled ok. */
|
2022-11-18 12:46:20 +01:00
|
|
|
node->runtime->need_exec = 0;
|
|
|
|
|
local_node->runtime->original = node;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2011-09-05 21:01:50 +00:00
|
|
|
/* move over the compbufs */
|
2024-08-19 20:27:37 +02:00
|
|
|
/* right after #blender::bke::node_tree_copy_tree() `oldsock` pointers are valid */
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2025-01-09 15:28:57 +01:00
|
|
|
if (node->type_legacy == CMP_NODE_VIEWER) {
|
2012-03-24 06:38:07 +00:00
|
|
|
if (node->id) {
|
2019-04-22 13:31:31 +10:00
|
|
|
if (node->flag & NODE_DO_OUTPUT) {
|
2019-06-03 17:08:25 +02:00
|
|
|
local_node->id = (ID *)node->id;
|
2019-04-22 13:31:31 +10:00
|
|
|
}
|
|
|
|
|
else {
|
2021-09-28 15:29:16 -04:00
|
|
|
local_node->id = nullptr;
|
2019-04-22 13:31:31 +10:00
|
|
|
}
|
2011-09-05 21:01:50 +00:00
|
|
|
}
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2019-06-03 17:08:25 +02:00
|
|
|
node = node->next;
|
|
|
|
|
local_node = local_node->next;
|
2011-09-05 21:01:50 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2018-06-11 15:40:37 +02:00
|
|
|
static void local_merge(Main *bmain, bNodeTree *localtree, bNodeTree *ntree)
|
2011-09-05 21:01:50 +00:00
|
|
|
{
|
|
|
|
|
/* move over the compbufs and previews */
|
2023-05-15 15:14:22 +02:00
|
|
|
blender::bke::node_preview_merge_tree(ntree, localtree, true);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2023-08-04 08:51:13 +10:00
|
|
|
LISTBASE_FOREACH (bNode *, lnode, &localtree->nodes) {
|
2025-02-19 13:44:11 +01:00
|
|
|
if (bNode *orig_node = blender::bke::node_find_node_by_name(*ntree, lnode->name)) {
|
2025-01-09 15:28:57 +01:00
|
|
|
if (lnode->type_legacy == CMP_NODE_VIEWER) {
|
2012-03-24 06:38:07 +00:00
|
|
|
if (lnode->id && (lnode->flag & NODE_DO_OUTPUT)) {
|
2011-09-05 21:01:50 +00:00
|
|
|
/* image_merge does sanity check for pointers */
|
2021-12-22 08:47:46 -06:00
|
|
|
BKE_image_merge(bmain, (Image *)orig_node->id, (Image *)lnode->id);
|
2011-09-05 21:01:50 +00:00
|
|
|
}
|
|
|
|
|
}
|
2025-01-09 15:28:57 +01:00
|
|
|
else if (lnode->type_legacy == CMP_NODE_MOVIEDISTORTION) {
|
2011-11-07 12:56:05 +00:00
|
|
|
/* special case for distortion node: distortion context is allocating in exec function
|
2012-09-26 20:05:38 +00:00
|
|
|
* and to achieve much better performance on further calls this context should be
|
2012-06-30 22:49:33 +00:00
|
|
|
* copied back to original node */
|
2012-03-24 06:38:07 +00:00
|
|
|
if (lnode->storage) {
|
2021-12-22 08:47:46 -06:00
|
|
|
if (orig_node->storage) {
|
|
|
|
|
BKE_tracking_distortion_free((MovieDistortion *)orig_node->storage);
|
2019-04-22 13:31:31 +10:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2021-12-22 08:47:46 -06:00
|
|
|
orig_node->storage = BKE_tracking_distortion_copy((MovieDistortion *)lnode->storage);
|
2011-11-07 12:56:05 +00:00
|
|
|
}
|
|
|
|
|
}
|
2011-09-05 21:01:50 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2011-10-19 17:08:35 +00:00
|
|
|
static void update(bNodeTree *ntree)
|
|
|
|
|
{
|
2025-02-19 13:44:11 +01:00
|
|
|
blender::bke::node_tree_set_output(*ntree);
|
2018-06-08 08:07:48 +02:00
|
|
|
|
2012-08-06 18:49:28 +00:00
|
|
|
ntree_update_reroute_nodes(ntree);
|
2011-10-19 17:08:35 +00:00
|
|
|
}
|
|
|
|
|
|
2022-10-03 17:37:25 -05:00
|
|
|
static void composite_node_add_init(bNodeTree * /*bnodetree*/, bNode *bnode)
|
2013-12-10 13:44:46 +11:00
|
|
|
{
|
2018-06-08 08:07:48 +02:00
|
|
|
/* Composite node will only show previews for input classes
|
|
|
|
|
* by default, other will be hidden
|
2013-12-08 21:53:35 +01:00
|
|
|
* but can be made visible with the show_preview option */
|
|
|
|
|
if (bnode->typeinfo->nclass != NODE_CLASS_INPUT) {
|
|
|
|
|
bnode->flag &= ~NODE_PREVIEW;
|
2018-06-08 08:07:48 +02:00
|
|
|
}
|
2013-12-08 21:53:35 +01:00
|
|
|
}
|
|
|
|
|
|
2024-05-13 16:07:12 +02:00
|
|
|
static bool composite_node_tree_socket_type_valid(blender::bke::bNodeTreeType * /*ntreetype*/,
|
|
|
|
|
blender::bke::bNodeSocketType *socket_type)
|
2021-04-29 23:36:46 -05:00
|
|
|
{
|
2025-02-19 13:44:11 +01:00
|
|
|
return blender::bke::node_is_static_socket_type(*socket_type) &&
|
2025-03-21 12:03:09 +01:00
|
|
|
ELEM(socket_type->type, SOCK_FLOAT, SOCK_INT, SOCK_BOOLEAN, SOCK_VECTOR, SOCK_RGBA);
|
2021-04-29 23:36:46 -05:00
|
|
|
}
|
|
|
|
|
|
2025-02-28 16:34:38 +02:00
|
|
|
static bool composite_validate_link(eNodeSocketDatatype /*from*/, eNodeSocketDatatype /*to*/)
|
|
|
|
|
{
|
|
|
|
|
/* All supported types can be implicitly converted to other types. */
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2024-05-13 16:07:12 +02:00
|
|
|
blender::bke::bNodeTreeType *ntreeType_Composite;
|
2013-03-18 16:34:57 +00:00
|
|
|
|
2021-12-07 12:36:33 -05:00
|
|
|
void register_node_tree_type_cmp()
|
2013-03-18 16:34:57 +00:00
|
|
|
{
|
2025-01-08 16:34:41 +01:00
|
|
|
blender::bke::bNodeTreeType *tt = ntreeType_Composite = MEM_new<blender::bke::bNodeTreeType>(
|
2024-05-13 16:07:12 +02:00
|
|
|
__func__);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2013-03-18 16:34:57 +00:00
|
|
|
tt->type = NTREE_COMPOSIT;
|
2025-01-08 16:34:41 +01:00
|
|
|
tt->idname = "CompositorNodeTree";
|
|
|
|
|
tt->group_idname = "CompositorNodeGroup";
|
|
|
|
|
tt->ui_name = N_("Compositor");
|
2021-12-24 22:47:58 -05:00
|
|
|
tt->ui_icon = ICON_NODE_COMPOSITING;
|
2025-01-08 16:34:41 +01:00
|
|
|
tt->ui_description = N_("Compositing nodes");
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2013-03-18 16:34:57 +00:00
|
|
|
tt->foreach_nodeclass = foreach_nodeclass;
|
|
|
|
|
tt->localize = localize;
|
|
|
|
|
tt->local_merge = local_merge;
|
|
|
|
|
tt->update = update;
|
|
|
|
|
tt->get_from_context = composite_get_from_context;
|
2013-12-08 21:53:35 +01:00
|
|
|
tt->node_add_init = composite_node_add_init;
|
2025-02-28 16:34:38 +02:00
|
|
|
tt->validate_link = composite_validate_link;
|
2021-04-29 23:36:46 -05:00
|
|
|
tt->valid_socket_type = composite_node_tree_socket_type_valid;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2020-04-03 18:24:08 +02:00
|
|
|
tt->rna_ext.srna = &RNA_CompositorNodeTree;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2025-02-19 13:44:11 +01:00
|
|
|
blender::bke::node_tree_type_add(*tt);
|
2013-03-18 16:34:57 +00:00
|
|
|
}
|
2011-09-05 21:01:50 +00:00
|
|
|
|
|
|
|
|
/* *********************************************** */
|
|
|
|
|
|
Render API/Cycles: Identify Render Passes by their name instead of a type flag
Previously, every RenderPass would have a bitfield that specified its type. That limits the number of passes to 32, which was reached a while ago.
However, most of the code already supported arbitrary RenderPasses since they were also used to store Multilayer EXR images.
Therefore, this commit completely removes the passflag from RenderPass and changes all code to use the unique pass name for identification.
Since Blender Internal relies on hardcoded passes and to preserve compatibility, 32 pass names are reserved for the old hardcoded passes.
To support these arbitrary passes, the Render Result compositor node now adds dynamic sockets. For compatibility, the old hardcoded sockets are always stored and just hidden when the corresponding pass isn't available.
To use these changes, the Render Engine API now includes a function that allows render engines to add arbitrary passes to the render result. To be able to add options for these passes, addons can now add their own properties to SceneRenderLayers.
To keep the compositor input node updated, render engine plugins have to implement a callback that registers all the passes that will be generated.
From a user perspective, nothing should change with this commit.
Differential Revision: https://developer.blender.org/D2443
Differential Revision: https://developer.blender.org/D2444
2017-05-03 00:21:18 +02:00
|
|
|
void ntreeCompositUpdateRLayers(bNodeTree *ntree)
|
2011-09-05 21:01:50 +00:00
|
|
|
{
|
2021-09-28 15:29:16 -04:00
|
|
|
if (ntree == nullptr) {
|
Render API/Cycles: Identify Render Passes by their name instead of a type flag
Previously, every RenderPass would have a bitfield that specified its type. That limits the number of passes to 32, which was reached a while ago.
However, most of the code already supported arbitrary RenderPasses since they were also used to store Multilayer EXR images.
Therefore, this commit completely removes the passflag from RenderPass and changes all code to use the unique pass name for identification.
Since Blender Internal relies on hardcoded passes and to preserve compatibility, 32 pass names are reserved for the old hardcoded passes.
To support these arbitrary passes, the Render Result compositor node now adds dynamic sockets. For compatibility, the old hardcoded sockets are always stored and just hidden when the corresponding pass isn't available.
To use these changes, the Render Engine API now includes a function that allows render engines to add arbitrary passes to the render result. To be able to add options for these passes, addons can now add their own properties to SceneRenderLayers.
To keep the compositor input node updated, render engine plugins have to implement a callback that registers all the passes that will be generated.
From a user perspective, nothing should change with this commit.
Differential Revision: https://developer.blender.org/D2443
Differential Revision: https://developer.blender.org/D2444
2017-05-03 00:21:18 +02:00
|
|
|
return;
|
2019-04-22 13:31:31 +10:00
|
|
|
}
|
Render API/Cycles: Identify Render Passes by their name instead of a type flag
Previously, every RenderPass would have a bitfield that specified its type. That limits the number of passes to 32, which was reached a while ago.
However, most of the code already supported arbitrary RenderPasses since they were also used to store Multilayer EXR images.
Therefore, this commit completely removes the passflag from RenderPass and changes all code to use the unique pass name for identification.
Since Blender Internal relies on hardcoded passes and to preserve compatibility, 32 pass names are reserved for the old hardcoded passes.
To support these arbitrary passes, the Render Result compositor node now adds dynamic sockets. For compatibility, the old hardcoded sockets are always stored and just hidden when the corresponding pass isn't available.
To use these changes, the Render Engine API now includes a function that allows render engines to add arbitrary passes to the render result. To be able to add options for these passes, addons can now add their own properties to SceneRenderLayers.
To keep the compositor input node updated, render engine plugins have to implement a callback that registers all the passes that will be generated.
From a user perspective, nothing should change with this commit.
Differential Revision: https://developer.blender.org/D2443
Differential Revision: https://developer.blender.org/D2444
2017-05-03 00:21:18 +02:00
|
|
|
|
2022-12-02 11:12:51 -06:00
|
|
|
for (bNode *node : ntree->all_nodes()) {
|
2025-01-09 15:28:57 +01:00
|
|
|
if (node->type_legacy == CMP_NODE_R_LAYERS) {
|
Render API/Cycles: Identify Render Passes by their name instead of a type flag
Previously, every RenderPass would have a bitfield that specified its type. That limits the number of passes to 32, which was reached a while ago.
However, most of the code already supported arbitrary RenderPasses since they were also used to store Multilayer EXR images.
Therefore, this commit completely removes the passflag from RenderPass and changes all code to use the unique pass name for identification.
Since Blender Internal relies on hardcoded passes and to preserve compatibility, 32 pass names are reserved for the old hardcoded passes.
To support these arbitrary passes, the Render Result compositor node now adds dynamic sockets. For compatibility, the old hardcoded sockets are always stored and just hidden when the corresponding pass isn't available.
To use these changes, the Render Engine API now includes a function that allows render engines to add arbitrary passes to the render result. To be able to add options for these passes, addons can now add their own properties to SceneRenderLayers.
To keep the compositor input node updated, render engine plugins have to implement a callback that registers all the passes that will be generated.
From a user perspective, nothing should change with this commit.
Differential Revision: https://developer.blender.org/D2443
Differential Revision: https://developer.blender.org/D2444
2017-05-03 00:21:18 +02:00
|
|
|
node_cmp_rlayers_outputs(ntree, node);
|
2019-04-22 13:31:31 +10:00
|
|
|
}
|
2025-01-09 15:28:57 +01:00
|
|
|
else if (node->type_legacy == CMP_NODE_CRYPTOMATTE &&
|
2024-07-17 09:40:28 +02:00
|
|
|
node->custom1 == CMP_NODE_CRYPTOMATTE_SOURCE_RENDER)
|
|
|
|
|
{
|
|
|
|
|
node->typeinfo->updatefunc(ntree, node);
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
Render API/Cycles: Identify Render Passes by their name instead of a type flag
Previously, every RenderPass would have a bitfield that specified its type. That limits the number of passes to 32, which was reached a while ago.
However, most of the code already supported arbitrary RenderPasses since they were also used to store Multilayer EXR images.
Therefore, this commit completely removes the passflag from RenderPass and changes all code to use the unique pass name for identification.
Since Blender Internal relies on hardcoded passes and to preserve compatibility, 32 pass names are reserved for the old hardcoded passes.
To support these arbitrary passes, the Render Result compositor node now adds dynamic sockets. For compatibility, the old hardcoded sockets are always stored and just hidden when the corresponding pass isn't available.
To use these changes, the Render Engine API now includes a function that allows render engines to add arbitrary passes to the render result. To be able to add options for these passes, addons can now add their own properties to SceneRenderLayers.
To keep the compositor input node updated, render engine plugins have to implement a callback that registers all the passes that will be generated.
From a user perspective, nothing should change with this commit.
Differential Revision: https://developer.blender.org/D2443
Differential Revision: https://developer.blender.org/D2444
2017-05-03 00:21:18 +02:00
|
|
|
}
|
|
|
|
|
|
2020-09-04 20:59:13 +02:00
|
|
|
void ntreeCompositTagRender(Scene *scene)
|
2011-09-05 21:01:50 +00:00
|
|
|
{
|
2018-06-25 12:02:20 +02:00
|
|
|
/* XXX Think using G_MAIN here is valid, since you want to update current file's scene nodes,
|
|
|
|
|
* not the ones in temp main generated for rendering?
|
2019-04-29 20:12:09 +10:00
|
|
|
* This is still rather weak though,
|
2024-03-07 16:20:36 -05:00
|
|
|
* ideally render struct would store its own main AND original G_MAIN. */
|
2019-04-29 20:12:09 +10:00
|
|
|
|
2021-09-28 15:29:16 -04:00
|
|
|
for (Scene *sce_iter = (Scene *)G_MAIN->scenes.first; sce_iter;
|
|
|
|
|
sce_iter = (Scene *)sce_iter->id.next)
|
|
|
|
|
{
|
2025-06-10 17:46:55 +02:00
|
|
|
if (sce_iter->compositing_node_group) {
|
|
|
|
|
for (bNode *node : sce_iter->compositing_node_group->all_nodes()) {
|
2025-01-09 15:28:57 +01:00
|
|
|
if (node->id == (ID *)scene || node->type_legacy == CMP_NODE_COMPOSITE) {
|
2025-06-10 17:46:55 +02:00
|
|
|
BKE_ntree_update_tag_node_property(sce_iter->compositing_node_group, node);
|
2019-04-22 13:31:31 +10:00
|
|
|
}
|
2011-09-05 21:01:50 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2025-01-09 17:00:05 +01:00
|
|
|
BKE_ntree_update(*G_MAIN);
|
2011-09-05 21:01:50 +00:00
|
|
|
}
|
|
|
|
|
|
2011-10-19 17:08:35 +00:00
|
|
|
void ntreeCompositClearTags(bNodeTree *ntree)
|
2011-09-05 21:01:50 +00:00
|
|
|
{
|
2023-03-29 14:16:31 +11:00
|
|
|
/* XXX: after render animation system gets a refresh, this call allows composite to end clean. */
|
|
|
|
|
|
2021-09-28 15:29:16 -04:00
|
|
|
if (ntree == nullptr) {
|
2012-08-23 07:10:48 +00:00
|
|
|
return;
|
2019-04-22 13:31:31 +10:00
|
|
|
}
|
2012-08-23 07:10:48 +00:00
|
|
|
|
2022-12-02 11:12:51 -06:00
|
|
|
for (bNode *node : ntree->all_nodes()) {
|
2022-11-18 12:46:20 +01:00
|
|
|
node->runtime->need_exec = 0;
|
2025-01-17 12:17:49 +01:00
|
|
|
if (node->is_group()) {
|
2011-10-19 17:08:35 +00:00
|
|
|
ntreeCompositClearTags((bNodeTree *)node->id);
|
2019-04-22 13:31:31 +10:00
|
|
|
}
|
2011-09-05 21:01:50 +00:00
|
|
|
}
|
|
|
|
|
}
|
2022-11-18 12:46:20 +01:00
|
|
|
|
|
|
|
|
void ntreeCompositTagNeedExec(bNode *node)
|
|
|
|
|
{
|
|
|
|
|
node->runtime->need_exec = true;
|
|
|
|
|
}
|