2023-08-15 16:20:26 +02:00
|
|
|
/* SPDX-FileCopyrightText: 2023 Blender Authors
|
2023-05-31 16:19:06 +02:00
|
|
|
*
|
|
|
|
* SPDX-License-Identifier: GPL-2.0-or-later */
|
2022-05-30 12:54:07 +02:00
|
|
|
|
|
|
|
#pragma once
|
|
|
|
|
|
|
|
#include <memory>
|
2022-08-31 12:15:57 +02:00
|
|
|
#include <mutex>
|
2022-05-30 12:54:07 +02:00
|
|
|
|
2022-12-20 13:05:02 +01:00
|
|
|
#include "BLI_cache_mutex.hh"
|
2023-02-28 17:35:32 +01:00
|
|
|
#include "BLI_math_vector_types.hh"
|
2022-08-31 12:15:57 +02:00
|
|
|
#include "BLI_multi_value_map.hh"
|
2023-01-05 14:05:30 +01:00
|
|
|
#include "BLI_resource_scope.hh"
|
2022-05-30 12:54:07 +02:00
|
|
|
#include "BLI_utility_mixins.hh"
|
2022-08-31 12:15:57 +02:00
|
|
|
#include "BLI_vector.hh"
|
2022-12-01 21:53:27 +01:00
|
|
|
#include "BLI_vector_set.hh"
|
2022-08-31 12:15:57 +02:00
|
|
|
|
|
|
|
#include "DNA_node_types.h"
|
|
|
|
|
2023-05-15 15:14:22 +02:00
|
|
|
#include "BKE_node.hh"
|
2023-08-30 12:37:21 +02:00
|
|
|
#include "BKE_node_tree_interface.hh"
|
2022-08-31 12:15:57 +02:00
|
|
|
|
|
|
|
struct bNode;
|
|
|
|
struct bNodeSocket;
|
|
|
|
struct bNodeTree;
|
|
|
|
struct bNodeType;
|
2022-05-30 12:54:07 +02:00
|
|
|
|
|
|
|
namespace blender::nodes {
|
|
|
|
struct FieldInferencingInterface;
|
2022-05-30 16:27:59 +02:00
|
|
|
class NodeDeclaration;
|
2022-09-13 08:44:26 +02:00
|
|
|
struct GeometryNodesLazyFunctionGraphInfo;
|
2023-01-05 14:05:30 +01:00
|
|
|
namespace anonymous_attribute_lifetime {
|
|
|
|
struct RelationsInNode;
|
|
|
|
}
|
|
|
|
namespace aal = anonymous_attribute_lifetime;
|
2022-05-30 15:31:13 +02:00
|
|
|
} // namespace blender::nodes
|
2023-06-20 10:25:41 +02:00
|
|
|
namespace blender::bke {
|
|
|
|
class bNodeTreeZones;
|
Geometry Nodes: add simulation support
This adds support for building simulations with geometry nodes. A new
`Simulation Input` and `Simulation Output` node allow maintaining a
simulation state across multiple frames. Together these two nodes form
a `simulation zone` which contains all the nodes that update the simulation
state from one frame to the next.
A new simulation zone can be added via the menu
(`Simulation > Simulation Zone`) or with the node add search.
The simulation state contains a geometry by default. However, it is possible
to add multiple geometry sockets as well as other socket types. Currently,
field inputs are evaluated and stored for the preceding geometry socket in
the order that the sockets are shown. Simulation state items can be added
by linking one of the empty sockets to something else. In the sidebar, there
is a new panel that allows adding, removing and reordering these sockets.
The simulation nodes behave as follows:
* On the first frame, the inputs of the `Simulation Input` node are evaluated
to initialize the simulation state. In later frames these sockets are not
evaluated anymore. The `Delta Time` at the first frame is zero, but the
simulation zone is still evaluated.
* On every next frame, the `Simulation Input` node outputs the simulation
state of the previous frame. Nodes in the simulation zone can edit that
data in arbitrary ways, also taking into account the `Delta Time`. The new
simulation state has to be passed to the `Simulation Output` node where it
is cached and forwarded.
* On a frame that is already cached or baked, the nodes in the simulation
zone are not evaluated, because the `Simulation Output` node can return
the previously cached data directly.
It is not allowed to connect sockets from inside the simulation zone to the
outside without going through the `Simulation Output` node. This is a necessary
restriction to make caching and sub-frame interpolation work. Links can go into
the simulation zone without problems though.
Anonymous attributes are not propagated by the simulation nodes unless they
are explicitly stored in the simulation state. This is unfortunate, but
currently there is no practical and reliable alternative. The core problem
is detecting which anonymous attributes will be required for the simulation
and afterwards. While we can detect this for the current evaluation, we can't
look into the future in time to see what data will be necessary. We intend to
make it easier to explicitly pass data through a simulation in the future,
even if the simulation is in a nested node group.
There is a new `Simulation Nodes` panel in the physics tab in the properties
editor. It allows baking all simulation zones on the selected objects. The
baking options are intentially kept at a minimum for this MVP. More features
for simulation baking as well as baking in general can be expected to be added
separately.
All baked data is stored on disk in a folder next to the .blend file. #106937
describes how baking is implemented in more detail. Volumes can not be baked
yet and materials are lost during baking for now. Packing the baked data into
the .blend file is not yet supported.
The timeline indicates which frames are currently cached, baked or cached but
invalidated by user-changes.
Simulation input and output nodes are internally linked together by their
`bNode.identifier` which stays the same even if the node name changes. They
are generally added and removed together. However, there are still cases where
"dangling" simulation nodes can be created currently. Those generally don't
cause harm, but would be nice to avoid this in more cases in the future.
Co-authored-by: Hans Goudey <h.goudey@me.com>
Co-authored-by: Lukas Tönne <lukas@blender.org>
Pull Request: https://projects.blender.org/blender/blender/pulls/104924
2023-05-03 13:18:51 +02:00
|
|
|
}
|
2023-06-14 13:56:57 +02:00
|
|
|
namespace blender::bke::anonymous_attribute_inferencing {
|
|
|
|
struct AnonymousAttributeInferencingResult;
|
|
|
|
};
|
2022-05-30 12:54:07 +02:00
|
|
|
|
2022-12-01 21:53:27 +01:00
|
|
|
namespace blender {
|
|
|
|
|
|
|
|
struct NodeIDHash {
|
|
|
|
uint64_t operator()(const bNode *node) const
|
|
|
|
{
|
|
|
|
return node->identifier;
|
|
|
|
}
|
|
|
|
uint64_t operator()(const int32_t id) const
|
|
|
|
{
|
|
|
|
return id;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
struct NodeIDEquality {
|
|
|
|
bool operator()(const bNode *a, const bNode *b) const
|
|
|
|
{
|
|
|
|
return a->identifier == b->identifier;
|
|
|
|
}
|
|
|
|
bool operator()(const bNode *a, const int32_t b) const
|
|
|
|
{
|
|
|
|
return a->identifier == b;
|
|
|
|
}
|
|
|
|
bool operator()(const int32_t a, const bNode *b) const
|
|
|
|
{
|
|
|
|
return this->operator()(b, a);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
} // namespace blender
|
|
|
|
|
2022-05-30 12:54:07 +02:00
|
|
|
namespace blender::bke {
|
|
|
|
|
Geometry Nodes: add simulation support
This adds support for building simulations with geometry nodes. A new
`Simulation Input` and `Simulation Output` node allow maintaining a
simulation state across multiple frames. Together these two nodes form
a `simulation zone` which contains all the nodes that update the simulation
state from one frame to the next.
A new simulation zone can be added via the menu
(`Simulation > Simulation Zone`) or with the node add search.
The simulation state contains a geometry by default. However, it is possible
to add multiple geometry sockets as well as other socket types. Currently,
field inputs are evaluated and stored for the preceding geometry socket in
the order that the sockets are shown. Simulation state items can be added
by linking one of the empty sockets to something else. In the sidebar, there
is a new panel that allows adding, removing and reordering these sockets.
The simulation nodes behave as follows:
* On the first frame, the inputs of the `Simulation Input` node are evaluated
to initialize the simulation state. In later frames these sockets are not
evaluated anymore. The `Delta Time` at the first frame is zero, but the
simulation zone is still evaluated.
* On every next frame, the `Simulation Input` node outputs the simulation
state of the previous frame. Nodes in the simulation zone can edit that
data in arbitrary ways, also taking into account the `Delta Time`. The new
simulation state has to be passed to the `Simulation Output` node where it
is cached and forwarded.
* On a frame that is already cached or baked, the nodes in the simulation
zone are not evaluated, because the `Simulation Output` node can return
the previously cached data directly.
It is not allowed to connect sockets from inside the simulation zone to the
outside without going through the `Simulation Output` node. This is a necessary
restriction to make caching and sub-frame interpolation work. Links can go into
the simulation zone without problems though.
Anonymous attributes are not propagated by the simulation nodes unless they
are explicitly stored in the simulation state. This is unfortunate, but
currently there is no practical and reliable alternative. The core problem
is detecting which anonymous attributes will be required for the simulation
and afterwards. While we can detect this for the current evaluation, we can't
look into the future in time to see what data will be necessary. We intend to
make it easier to explicitly pass data through a simulation in the future,
even if the simulation is in a nested node group.
There is a new `Simulation Nodes` panel in the physics tab in the properties
editor. It allows baking all simulation zones on the selected objects. The
baking options are intentially kept at a minimum for this MVP. More features
for simulation baking as well as baking in general can be expected to be added
separately.
All baked data is stored on disk in a folder next to the .blend file. #106937
describes how baking is implemented in more detail. Volumes can not be baked
yet and materials are lost during baking for now. Packing the baked data into
the .blend file is not yet supported.
The timeline indicates which frames are currently cached, baked or cached but
invalidated by user-changes.
Simulation input and output nodes are internally linked together by their
`bNode.identifier` which stays the same even if the node name changes. They
are generally added and removed together. However, there are still cases where
"dangling" simulation nodes can be created currently. Those generally don't
cause harm, but would be nice to avoid this in more cases in the future.
Co-authored-by: Hans Goudey <h.goudey@me.com>
Co-authored-by: Lukas Tönne <lukas@blender.org>
Pull Request: https://projects.blender.org/blender/blender/pulls/104924
2023-05-03 13:18:51 +02:00
|
|
|
using NodeIDVectorSet = VectorSet<bNode *, DefaultProbingStrategy, NodeIDHash, NodeIDEquality>;
|
|
|
|
|
2022-05-30 12:54:07 +02:00
|
|
|
class bNodeTreeRuntime : NonCopyable, NonMovable {
|
|
|
|
public:
|
|
|
|
/**
|
|
|
|
* Keeps track of what changed in the node tree until the next update.
|
2023-11-16 11:41:55 +01:00
|
|
|
* Should not be changed directly, instead use the functions in `BKE_node_tree_update.hh`.
|
2022-05-30 12:54:07 +02:00
|
|
|
* #eNodeTreeChangedFlag.
|
|
|
|
*/
|
|
|
|
uint32_t changed_flag = 0;
|
|
|
|
/**
|
|
|
|
* A hash of the topology of the node tree leading up to the outputs. This is used to determine
|
|
|
|
* of the node tree changed in a way that requires updating geometry nodes or shaders.
|
|
|
|
*/
|
|
|
|
uint32_t output_topology_hash = 0;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Used to cache run-time information of the node tree.
|
|
|
|
* #eNodeTreeRuntimeFlag.
|
|
|
|
*/
|
|
|
|
uint8_t runtime_flag = 0;
|
|
|
|
|
2023-08-08 17:36:06 +02:00
|
|
|
/**
|
2023-08-09 03:20:04 +02:00
|
|
|
* Contains a number increased for each node-tree update.
|
|
|
|
* Store a state variable in the #NestedTreePreviews structure to compare if they differ.
|
2023-08-08 17:36:06 +02:00
|
|
|
*/
|
|
|
|
uint32_t previews_refresh_state = 0;
|
|
|
|
|
2022-12-01 21:53:27 +01:00
|
|
|
/**
|
|
|
|
* Storage of nodes based on their identifier. Also used as a contiguous array of nodes to
|
|
|
|
* allow simpler and more cache friendly iteration. Supports lookup by integer or by node.
|
|
|
|
* Unlike other caches, this is maintained eagerly while changing the tree.
|
|
|
|
*/
|
Geometry Nodes: add simulation support
This adds support for building simulations with geometry nodes. A new
`Simulation Input` and `Simulation Output` node allow maintaining a
simulation state across multiple frames. Together these two nodes form
a `simulation zone` which contains all the nodes that update the simulation
state from one frame to the next.
A new simulation zone can be added via the menu
(`Simulation > Simulation Zone`) or with the node add search.
The simulation state contains a geometry by default. However, it is possible
to add multiple geometry sockets as well as other socket types. Currently,
field inputs are evaluated and stored for the preceding geometry socket in
the order that the sockets are shown. Simulation state items can be added
by linking one of the empty sockets to something else. In the sidebar, there
is a new panel that allows adding, removing and reordering these sockets.
The simulation nodes behave as follows:
* On the first frame, the inputs of the `Simulation Input` node are evaluated
to initialize the simulation state. In later frames these sockets are not
evaluated anymore. The `Delta Time` at the first frame is zero, but the
simulation zone is still evaluated.
* On every next frame, the `Simulation Input` node outputs the simulation
state of the previous frame. Nodes in the simulation zone can edit that
data in arbitrary ways, also taking into account the `Delta Time`. The new
simulation state has to be passed to the `Simulation Output` node where it
is cached and forwarded.
* On a frame that is already cached or baked, the nodes in the simulation
zone are not evaluated, because the `Simulation Output` node can return
the previously cached data directly.
It is not allowed to connect sockets from inside the simulation zone to the
outside without going through the `Simulation Output` node. This is a necessary
restriction to make caching and sub-frame interpolation work. Links can go into
the simulation zone without problems though.
Anonymous attributes are not propagated by the simulation nodes unless they
are explicitly stored in the simulation state. This is unfortunate, but
currently there is no practical and reliable alternative. The core problem
is detecting which anonymous attributes will be required for the simulation
and afterwards. While we can detect this for the current evaluation, we can't
look into the future in time to see what data will be necessary. We intend to
make it easier to explicitly pass data through a simulation in the future,
even if the simulation is in a nested node group.
There is a new `Simulation Nodes` panel in the physics tab in the properties
editor. It allows baking all simulation zones on the selected objects. The
baking options are intentially kept at a minimum for this MVP. More features
for simulation baking as well as baking in general can be expected to be added
separately.
All baked data is stored on disk in a folder next to the .blend file. #106937
describes how baking is implemented in more detail. Volumes can not be baked
yet and materials are lost during baking for now. Packing the baked data into
the .blend file is not yet supported.
The timeline indicates which frames are currently cached, baked or cached but
invalidated by user-changes.
Simulation input and output nodes are internally linked together by their
`bNode.identifier` which stays the same even if the node name changes. They
are generally added and removed together. However, there are still cases where
"dangling" simulation nodes can be created currently. Those generally don't
cause harm, but would be nice to avoid this in more cases in the future.
Co-authored-by: Hans Goudey <h.goudey@me.com>
Co-authored-by: Lukas Tönne <lukas@blender.org>
Pull Request: https://projects.blender.org/blender/blender/pulls/104924
2023-05-03 13:18:51 +02:00
|
|
|
NodeIDVectorSet nodes_by_id;
|
2022-12-01 21:53:27 +01:00
|
|
|
|
2023-05-27 07:10:58 +02:00
|
|
|
/**
|
|
|
|
* Execution data.
|
2022-11-23 14:05:30 +01:00
|
|
|
*
|
|
|
|
* XXX It would be preferable to completely move this data out of the underlying node tree,
|
|
|
|
* so node tree execution could finally run independent of the tree itself.
|
|
|
|
* This would allow node trees to be merely linked by other data (materials, textures, etc.),
|
|
|
|
* as ID data is supposed to.
|
|
|
|
* Execution data is generated from the tree once at execution start and can then be used
|
|
|
|
* as long as necessary, even while the tree is being modified.
|
|
|
|
*/
|
2023-08-05 04:47:22 +02:00
|
|
|
bNodeTreeExec *execdata = nullptr;
|
2022-11-23 14:05:30 +01:00
|
|
|
|
|
|
|
/* Callbacks. */
|
|
|
|
void (*progress)(void *, float progress) = nullptr;
|
|
|
|
/** \warning may be called by different threads */
|
|
|
|
void (*stats_draw)(void *, const char *str) = nullptr;
|
|
|
|
bool (*test_break)(void *) = nullptr;
|
|
|
|
void (*update_draw)(void *) = nullptr;
|
|
|
|
void *tbh = nullptr, *prh = nullptr, *sdh = nullptr, *udh = nullptr;
|
|
|
|
|
2022-05-30 12:54:07 +02:00
|
|
|
/** Information about how inputs and outputs of the node group interact with fields. */
|
|
|
|
std::unique_ptr<nodes::FieldInferencingInterface> field_inferencing_interface;
|
2023-01-05 14:05:30 +01:00
|
|
|
/** Information about usage of anonymous attributes within the group. */
|
2023-06-14 13:56:57 +02:00
|
|
|
std::unique_ptr<anonymous_attribute_inferencing::AnonymousAttributeInferencingResult>
|
|
|
|
anonymous_attribute_inferencing;
|
2022-08-31 12:15:57 +02:00
|
|
|
|
2022-09-13 08:44:26 +02:00
|
|
|
/**
|
|
|
|
* For geometry nodes, a lazy function graph with some additional info is cached. This is used to
|
|
|
|
* evaluate the node group. Caching it here allows us to reuse the preprocessed node tree in case
|
|
|
|
* its used multiple times.
|
|
|
|
*/
|
|
|
|
std::mutex geometry_nodes_lazy_function_graph_info_mutex;
|
|
|
|
std::unique_ptr<nodes::GeometryNodesLazyFunctionGraphInfo>
|
|
|
|
geometry_nodes_lazy_function_graph_info;
|
|
|
|
|
2022-08-31 12:15:57 +02:00
|
|
|
/**
|
|
|
|
* Protects access to all topology cache variables below. This is necessary so that the cache can
|
|
|
|
* be updated on a const #bNodeTree.
|
|
|
|
*/
|
2022-12-20 13:05:02 +01:00
|
|
|
CacheMutex topology_cache_mutex;
|
|
|
|
std::atomic<bool> topology_cache_exists = false;
|
2022-08-31 12:15:57 +02:00
|
|
|
/**
|
|
|
|
* Under some circumstances, it can be useful to use the cached data while editing the
|
|
|
|
* #bNodeTree. By default, this is protected against using an assert.
|
|
|
|
*/
|
|
|
|
mutable std::atomic<int> allow_use_dirty_topology_cache = 0;
|
|
|
|
|
Geometry Nodes: add simulation support
This adds support for building simulations with geometry nodes. A new
`Simulation Input` and `Simulation Output` node allow maintaining a
simulation state across multiple frames. Together these two nodes form
a `simulation zone` which contains all the nodes that update the simulation
state from one frame to the next.
A new simulation zone can be added via the menu
(`Simulation > Simulation Zone`) or with the node add search.
The simulation state contains a geometry by default. However, it is possible
to add multiple geometry sockets as well as other socket types. Currently,
field inputs are evaluated and stored for the preceding geometry socket in
the order that the sockets are shown. Simulation state items can be added
by linking one of the empty sockets to something else. In the sidebar, there
is a new panel that allows adding, removing and reordering these sockets.
The simulation nodes behave as follows:
* On the first frame, the inputs of the `Simulation Input` node are evaluated
to initialize the simulation state. In later frames these sockets are not
evaluated anymore. The `Delta Time` at the first frame is zero, but the
simulation zone is still evaluated.
* On every next frame, the `Simulation Input` node outputs the simulation
state of the previous frame. Nodes in the simulation zone can edit that
data in arbitrary ways, also taking into account the `Delta Time`. The new
simulation state has to be passed to the `Simulation Output` node where it
is cached and forwarded.
* On a frame that is already cached or baked, the nodes in the simulation
zone are not evaluated, because the `Simulation Output` node can return
the previously cached data directly.
It is not allowed to connect sockets from inside the simulation zone to the
outside without going through the `Simulation Output` node. This is a necessary
restriction to make caching and sub-frame interpolation work. Links can go into
the simulation zone without problems though.
Anonymous attributes are not propagated by the simulation nodes unless they
are explicitly stored in the simulation state. This is unfortunate, but
currently there is no practical and reliable alternative. The core problem
is detecting which anonymous attributes will be required for the simulation
and afterwards. While we can detect this for the current evaluation, we can't
look into the future in time to see what data will be necessary. We intend to
make it easier to explicitly pass data through a simulation in the future,
even if the simulation is in a nested node group.
There is a new `Simulation Nodes` panel in the physics tab in the properties
editor. It allows baking all simulation zones on the selected objects. The
baking options are intentially kept at a minimum for this MVP. More features
for simulation baking as well as baking in general can be expected to be added
separately.
All baked data is stored on disk in a folder next to the .blend file. #106937
describes how baking is implemented in more detail. Volumes can not be baked
yet and materials are lost during baking for now. Packing the baked data into
the .blend file is not yet supported.
The timeline indicates which frames are currently cached, baked or cached but
invalidated by user-changes.
Simulation input and output nodes are internally linked together by their
`bNode.identifier` which stays the same even if the node name changes. They
are generally added and removed together. However, there are still cases where
"dangling" simulation nodes can be created currently. Those generally don't
cause harm, but would be nice to avoid this in more cases in the future.
Co-authored-by: Hans Goudey <h.goudey@me.com>
Co-authored-by: Lukas Tönne <lukas@blender.org>
Pull Request: https://projects.blender.org/blender/blender/pulls/104924
2023-05-03 13:18:51 +02:00
|
|
|
CacheMutex tree_zones_cache_mutex;
|
2023-06-20 10:25:41 +02:00
|
|
|
std::unique_ptr<bNodeTreeZones> tree_zones;
|
Geometry Nodes: add simulation support
This adds support for building simulations with geometry nodes. A new
`Simulation Input` and `Simulation Output` node allow maintaining a
simulation state across multiple frames. Together these two nodes form
a `simulation zone` which contains all the nodes that update the simulation
state from one frame to the next.
A new simulation zone can be added via the menu
(`Simulation > Simulation Zone`) or with the node add search.
The simulation state contains a geometry by default. However, it is possible
to add multiple geometry sockets as well as other socket types. Currently,
field inputs are evaluated and stored for the preceding geometry socket in
the order that the sockets are shown. Simulation state items can be added
by linking one of the empty sockets to something else. In the sidebar, there
is a new panel that allows adding, removing and reordering these sockets.
The simulation nodes behave as follows:
* On the first frame, the inputs of the `Simulation Input` node are evaluated
to initialize the simulation state. In later frames these sockets are not
evaluated anymore. The `Delta Time` at the first frame is zero, but the
simulation zone is still evaluated.
* On every next frame, the `Simulation Input` node outputs the simulation
state of the previous frame. Nodes in the simulation zone can edit that
data in arbitrary ways, also taking into account the `Delta Time`. The new
simulation state has to be passed to the `Simulation Output` node where it
is cached and forwarded.
* On a frame that is already cached or baked, the nodes in the simulation
zone are not evaluated, because the `Simulation Output` node can return
the previously cached data directly.
It is not allowed to connect sockets from inside the simulation zone to the
outside without going through the `Simulation Output` node. This is a necessary
restriction to make caching and sub-frame interpolation work. Links can go into
the simulation zone without problems though.
Anonymous attributes are not propagated by the simulation nodes unless they
are explicitly stored in the simulation state. This is unfortunate, but
currently there is no practical and reliable alternative. The core problem
is detecting which anonymous attributes will be required for the simulation
and afterwards. While we can detect this for the current evaluation, we can't
look into the future in time to see what data will be necessary. We intend to
make it easier to explicitly pass data through a simulation in the future,
even if the simulation is in a nested node group.
There is a new `Simulation Nodes` panel in the physics tab in the properties
editor. It allows baking all simulation zones on the selected objects. The
baking options are intentially kept at a minimum for this MVP. More features
for simulation baking as well as baking in general can be expected to be added
separately.
All baked data is stored on disk in a folder next to the .blend file. #106937
describes how baking is implemented in more detail. Volumes can not be baked
yet and materials are lost during baking for now. Packing the baked data into
the .blend file is not yet supported.
The timeline indicates which frames are currently cached, baked or cached but
invalidated by user-changes.
Simulation input and output nodes are internally linked together by their
`bNode.identifier` which stays the same even if the node name changes. They
are generally added and removed together. However, there are still cases where
"dangling" simulation nodes can be created currently. Those generally don't
cause harm, but would be nice to avoid this in more cases in the future.
Co-authored-by: Hans Goudey <h.goudey@me.com>
Co-authored-by: Lukas Tönne <lukas@blender.org>
Pull Request: https://projects.blender.org/blender/blender/pulls/104924
2023-05-03 13:18:51 +02:00
|
|
|
|
2022-08-31 12:15:57 +02:00
|
|
|
/** Only valid when #topology_cache_is_dirty is false. */
|
|
|
|
Vector<bNodeLink *> links;
|
|
|
|
Vector<bNodeSocket *> sockets;
|
|
|
|
Vector<bNodeSocket *> input_sockets;
|
|
|
|
Vector<bNodeSocket *> output_sockets;
|
|
|
|
MultiValueMap<const bNodeType *, bNode *> nodes_by_type;
|
|
|
|
Vector<bNode *> toposort_left_to_right;
|
|
|
|
Vector<bNode *> toposort_right_to_left;
|
2022-09-13 08:44:26 +02:00
|
|
|
Vector<bNode *> group_nodes;
|
2022-09-20 13:21:03 +02:00
|
|
|
bool has_available_link_cycle = false;
|
2022-08-31 12:15:57 +02:00
|
|
|
bool has_undefined_nodes_or_sockets = false;
|
|
|
|
bNode *group_output_node = nullptr;
|
2022-11-18 11:20:13 +01:00
|
|
|
Vector<bNode *> root_frames;
|
2022-05-30 12:54:07 +02:00
|
|
|
};
|
|
|
|
|
2022-05-30 15:31:13 +02:00
|
|
|
/**
|
|
|
|
* Run-time data for every socket. This should only contain data that is somewhat persistent (i.e.
|
|
|
|
* data that lives longer than a single depsgraph evaluation + redraw). Data that's only used in
|
|
|
|
* smaller scopes should generally be stored in separate arrays and/or maps.
|
|
|
|
*/
|
|
|
|
class bNodeSocketRuntime : NonCopyable, NonMovable {
|
|
|
|
public:
|
|
|
|
/**
|
|
|
|
* References a socket declaration that is owned by `node->declaration`. This is only runtime
|
2022-08-31 12:15:57 +02:00
|
|
|
* data. It has to be updated when the node declaration changes. Access can be allowed by using
|
|
|
|
* #AllowUsingOutdatedInfo.
|
2022-05-30 15:31:13 +02:00
|
|
|
*/
|
|
|
|
const SocketDeclarationHandle *declaration = nullptr;
|
|
|
|
|
|
|
|
/** #eNodeTreeChangedFlag. */
|
|
|
|
uint32_t changed_flag = 0;
|
2022-08-31 12:15:57 +02:00
|
|
|
|
2023-01-02 23:55:32 +01:00
|
|
|
/**
|
|
|
|
* Runtime-only cache of the number of input links, for multi-input sockets,
|
|
|
|
* including dragged node links that aren't actually in the tree.
|
|
|
|
*/
|
2022-11-23 10:42:03 +01:00
|
|
|
short total_inputs = 0;
|
|
|
|
|
2023-03-19 07:03:01 +01:00
|
|
|
/**
|
|
|
|
* The location of the socket in the tree, calculated while drawing the nodes and invalid if the
|
|
|
|
* node tree hasn't been drawn yet. In the node tree's "world space" (the same as
|
|
|
|
* #bNode::runtime::totr).
|
|
|
|
*/
|
|
|
|
float2 location;
|
|
|
|
|
2022-08-31 12:15:57 +02:00
|
|
|
/** Only valid when #topology_cache_is_dirty is false. */
|
|
|
|
Vector<bNodeLink *> directly_linked_links;
|
|
|
|
Vector<bNodeSocket *> directly_linked_sockets;
|
|
|
|
Vector<bNodeSocket *> logically_linked_sockets;
|
|
|
|
Vector<bNodeSocket *> logically_linked_skipped_sockets;
|
|
|
|
bNode *owner_node = nullptr;
|
|
|
|
bNodeSocket *internal_link_input = nullptr;
|
|
|
|
int index_in_node = -1;
|
|
|
|
int index_in_all_sockets = -1;
|
|
|
|
int index_in_inout_sockets = -1;
|
2022-05-30 15:31:13 +02:00
|
|
|
};
|
|
|
|
|
2023-08-30 12:37:21 +02:00
|
|
|
class bNodePanelRuntime : NonCopyable, NonMovable {
|
|
|
|
public:
|
|
|
|
/* The vertical location of the panel in the tree, calculated while drawing the nodes and invalid
|
|
|
|
* if the node tree hasn't been drawn yet. In the node tree's "world space" (the same as
|
|
|
|
* #bNode::runtime::totr). */
|
|
|
|
float location_y;
|
|
|
|
/* Vertical start location of the panel content. */
|
|
|
|
float min_content_y;
|
|
|
|
/* Vertical end location of the panel content. */
|
|
|
|
float max_content_y;
|
|
|
|
};
|
|
|
|
|
2022-05-30 15:31:13 +02:00
|
|
|
/**
|
|
|
|
* Run-time data for every node. This should only contain data that is somewhat persistent (i.e.
|
|
|
|
* data that lives longer than a single depsgraph evaluation + redraw). Data that's only used in
|
|
|
|
* smaller scopes should generally be stored in separate arrays and/or maps.
|
|
|
|
*/
|
|
|
|
class bNodeRuntime : NonCopyable, NonMovable {
|
|
|
|
public:
|
|
|
|
/**
|
|
|
|
* Describes the desired interface of the node. This is run-time data only.
|
|
|
|
* The actual interface of the node may deviate from the declaration temporarily.
|
|
|
|
* It's possible to sync the actual state of the node to the desired state. Currently, this is
|
|
|
|
* only done when a node is created or loaded.
|
|
|
|
*
|
|
|
|
* In the future, we may want to keep more data only in the declaration, so that it does not have
|
|
|
|
* to be synced to other places that are stored in files. That especially applies to data that
|
|
|
|
* can't be edited by users directly (e.g. min/max values of sockets, tooltips, ...).
|
|
|
|
*
|
|
|
|
* The declaration of a node can be recreated at any time when it is used. Caching it here is
|
|
|
|
* just a bit more efficient when it is used a lot. To make sure that the cache is up-to-date,
|
|
|
|
* call #nodeDeclarationEnsure before using it.
|
|
|
|
*
|
|
|
|
* Currently, the declaration is the same for every node of the same type. Going forward, that is
|
|
|
|
* intended to change though. Especially when nodes become more dynamic with respect to how many
|
|
|
|
* sockets they have.
|
|
|
|
*/
|
|
|
|
NodeDeclarationHandle *declaration = nullptr;
|
|
|
|
|
|
|
|
/** #eNodeTreeChangedFlag. */
|
|
|
|
uint32_t changed_flag = 0;
|
2022-08-31 12:15:57 +02:00
|
|
|
|
2022-11-18 12:46:20 +01:00
|
|
|
/** Used as a boolean for execution. */
|
|
|
|
uint8_t need_exec = 0;
|
|
|
|
|
|
|
|
/** The original node in the tree (for localized tree). */
|
2023-08-05 04:47:22 +02:00
|
|
|
bNode *original = nullptr;
|
2022-11-18 12:46:20 +01:00
|
|
|
|
|
|
|
/**
|
2023-08-21 02:05:45 +02:00
|
|
|
* XXX:
|
|
|
|
* TODO: `prvr` does not exist!
|
|
|
|
* Node totr size depends on the `prvr` size, which in turn is determined from preview size.
|
2022-11-18 12:46:20 +01:00
|
|
|
* In earlier versions bNodePreview was stored directly in nodes, but since now there can be
|
|
|
|
* multiple instances using different preview images it is possible that required node size
|
|
|
|
* varies between instances. preview_xsize, preview_ysize defines a common reserved size for
|
|
|
|
* preview rect for now, could be replaced by more accurate node instance drawing,
|
|
|
|
* but that requires removing totr from DNA and replacing all uses with per-instance data.
|
|
|
|
*/
|
|
|
|
/** Reserved size of the preview rect. */
|
|
|
|
short preview_xsize, preview_ysize = 0;
|
|
|
|
/** Entire bound-box (world-space). */
|
|
|
|
rctf totr{};
|
|
|
|
|
|
|
|
/** Used at runtime when going through the tree. Initialize before use. */
|
|
|
|
short tmp_flag = 0;
|
|
|
|
|
|
|
|
/** Used at runtime when iterating over node branches. */
|
|
|
|
char iter_flag = 0;
|
|
|
|
|
|
|
|
/** Update flags. */
|
|
|
|
int update = 0;
|
|
|
|
|
2023-08-31 02:38:13 +02:00
|
|
|
/** Offset that will be added to #bNote::locx for insert offset animation. */
|
2022-11-18 12:46:20 +01:00
|
|
|
float anim_ofsx;
|
|
|
|
|
2022-11-18 13:46:21 +01:00
|
|
|
/** List of cached internal links (input to output), for muted nodes and operators. */
|
2023-01-10 05:29:58 +01:00
|
|
|
Vector<bNodeLink> internal_links;
|
2022-11-18 13:46:21 +01:00
|
|
|
|
2022-12-12 03:23:18 +01:00
|
|
|
/** Eagerly maintained cache of the node's index in the tree. */
|
|
|
|
int index_in_tree = -1;
|
|
|
|
|
2023-10-13 14:39:51 +02:00
|
|
|
/** Used to avoid running forward compatibility code more often than necessary. */
|
|
|
|
bool forward_compatible_versioning_done = false;
|
|
|
|
|
2022-08-31 12:15:57 +02:00
|
|
|
/** Only valid if #topology_cache_is_dirty is false. */
|
|
|
|
Vector<bNodeSocket *> inputs;
|
|
|
|
Vector<bNodeSocket *> outputs;
|
|
|
|
Map<StringRefNull, bNodeSocket *> inputs_by_identifier;
|
|
|
|
Map<StringRefNull, bNodeSocket *> outputs_by_identifier;
|
2022-09-20 13:21:03 +02:00
|
|
|
bool has_available_linked_inputs = false;
|
|
|
|
bool has_available_linked_outputs = false;
|
2022-11-18 11:20:13 +01:00
|
|
|
Vector<bNode *> direct_children_in_frame;
|
2022-08-31 12:15:57 +02:00
|
|
|
bNodeTree *owner_tree = nullptr;
|
2023-06-16 10:37:18 +02:00
|
|
|
/** Can be used to toposort a subset of nodes. */
|
|
|
|
int toposort_left_to_right_index = -1;
|
|
|
|
int toposort_right_to_left_index = -1;
|
2023-08-30 12:37:21 +02:00
|
|
|
|
|
|
|
/* Panel runtime state */
|
|
|
|
Array<bNodePanelRuntime> panels;
|
2022-05-30 15:31:13 +02:00
|
|
|
};
|
|
|
|
|
2022-08-31 12:15:57 +02:00
|
|
|
namespace node_tree_runtime {
|
|
|
|
|
2022-09-13 08:44:26 +02:00
|
|
|
/**
|
2022-09-16 16:02:08 +02:00
|
|
|
* Is executed when the node tree changed in the depsgraph.
|
2022-09-13 08:44:26 +02:00
|
|
|
*/
|
2022-09-16 16:02:08 +02:00
|
|
|
void preprocess_geometry_node_tree_for_evaluation(bNodeTree &tree_cow);
|
2022-09-13 08:44:26 +02:00
|
|
|
|
2022-08-31 12:15:57 +02:00
|
|
|
class AllowUsingOutdatedInfo : NonCopyable, NonMovable {
|
|
|
|
private:
|
|
|
|
const bNodeTree &tree_;
|
|
|
|
|
|
|
|
public:
|
|
|
|
AllowUsingOutdatedInfo(const bNodeTree &tree) : tree_(tree)
|
|
|
|
{
|
|
|
|
tree_.runtime->allow_use_dirty_topology_cache.fetch_add(1);
|
|
|
|
}
|
|
|
|
|
|
|
|
~AllowUsingOutdatedInfo()
|
|
|
|
{
|
|
|
|
tree_.runtime->allow_use_dirty_topology_cache.fetch_sub(1);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
inline bool topology_cache_is_available(const bNodeTree &tree)
|
|
|
|
{
|
|
|
|
if (!tree.runtime->topology_cache_exists) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
if (tree.runtime->allow_use_dirty_topology_cache.load() > 0) {
|
|
|
|
return true;
|
|
|
|
}
|
2022-12-20 13:05:02 +01:00
|
|
|
if (tree.runtime->topology_cache_mutex.is_dirty()) {
|
2022-08-31 13:55:21 +02:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return true;
|
2022-08-31 12:15:57 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
inline bool topology_cache_is_available(const bNode &node)
|
|
|
|
{
|
|
|
|
const bNodeTree *ntree = node.runtime->owner_tree;
|
|
|
|
if (ntree == nullptr) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return topology_cache_is_available(*ntree);
|
|
|
|
}
|
|
|
|
|
|
|
|
inline bool topology_cache_is_available(const bNodeSocket &socket)
|
|
|
|
{
|
|
|
|
const bNode *node = socket.runtime->owner_node;
|
|
|
|
if (node == nullptr) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return topology_cache_is_available(*node);
|
|
|
|
}
|
|
|
|
|
|
|
|
} // namespace node_tree_runtime
|
|
|
|
|
2022-12-10 11:32:04 +01:00
|
|
|
namespace node_field_inferencing {
|
|
|
|
bool update_field_inferencing(const bNodeTree &tree);
|
|
|
|
}
|
2022-05-30 12:54:07 +02:00
|
|
|
} // namespace blender::bke
|
2022-08-31 12:15:57 +02:00
|
|
|
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
|
|
/** \name #bNodeTree Inline Methods
|
|
|
|
* \{ */
|
|
|
|
|
2022-12-01 21:53:27 +01:00
|
|
|
inline blender::Span<const bNode *> bNodeTree::all_nodes() const
|
|
|
|
{
|
|
|
|
return this->runtime->nodes_by_id.as_span();
|
|
|
|
}
|
|
|
|
|
|
|
|
inline blender::Span<bNode *> bNodeTree::all_nodes()
|
|
|
|
{
|
|
|
|
return this->runtime->nodes_by_id;
|
|
|
|
}
|
|
|
|
|
|
|
|
inline bNode *bNodeTree::node_by_id(const int32_t identifier)
|
|
|
|
{
|
Geometry Nodes: add simulation support
This adds support for building simulations with geometry nodes. A new
`Simulation Input` and `Simulation Output` node allow maintaining a
simulation state across multiple frames. Together these two nodes form
a `simulation zone` which contains all the nodes that update the simulation
state from one frame to the next.
A new simulation zone can be added via the menu
(`Simulation > Simulation Zone`) or with the node add search.
The simulation state contains a geometry by default. However, it is possible
to add multiple geometry sockets as well as other socket types. Currently,
field inputs are evaluated and stored for the preceding geometry socket in
the order that the sockets are shown. Simulation state items can be added
by linking one of the empty sockets to something else. In the sidebar, there
is a new panel that allows adding, removing and reordering these sockets.
The simulation nodes behave as follows:
* On the first frame, the inputs of the `Simulation Input` node are evaluated
to initialize the simulation state. In later frames these sockets are not
evaluated anymore. The `Delta Time` at the first frame is zero, but the
simulation zone is still evaluated.
* On every next frame, the `Simulation Input` node outputs the simulation
state of the previous frame. Nodes in the simulation zone can edit that
data in arbitrary ways, also taking into account the `Delta Time`. The new
simulation state has to be passed to the `Simulation Output` node where it
is cached and forwarded.
* On a frame that is already cached or baked, the nodes in the simulation
zone are not evaluated, because the `Simulation Output` node can return
the previously cached data directly.
It is not allowed to connect sockets from inside the simulation zone to the
outside without going through the `Simulation Output` node. This is a necessary
restriction to make caching and sub-frame interpolation work. Links can go into
the simulation zone without problems though.
Anonymous attributes are not propagated by the simulation nodes unless they
are explicitly stored in the simulation state. This is unfortunate, but
currently there is no practical and reliable alternative. The core problem
is detecting which anonymous attributes will be required for the simulation
and afterwards. While we can detect this for the current evaluation, we can't
look into the future in time to see what data will be necessary. We intend to
make it easier to explicitly pass data through a simulation in the future,
even if the simulation is in a nested node group.
There is a new `Simulation Nodes` panel in the physics tab in the properties
editor. It allows baking all simulation zones on the selected objects. The
baking options are intentially kept at a minimum for this MVP. More features
for simulation baking as well as baking in general can be expected to be added
separately.
All baked data is stored on disk in a folder next to the .blend file. #106937
describes how baking is implemented in more detail. Volumes can not be baked
yet and materials are lost during baking for now. Packing the baked data into
the .blend file is not yet supported.
The timeline indicates which frames are currently cached, baked or cached but
invalidated by user-changes.
Simulation input and output nodes are internally linked together by their
`bNode.identifier` which stays the same even if the node name changes. They
are generally added and removed together. However, there are still cases where
"dangling" simulation nodes can be created currently. Those generally don't
cause harm, but would be nice to avoid this in more cases in the future.
Co-authored-by: Hans Goudey <h.goudey@me.com>
Co-authored-by: Lukas Tönne <lukas@blender.org>
Pull Request: https://projects.blender.org/blender/blender/pulls/104924
2023-05-03 13:18:51 +02:00
|
|
|
BLI_assert(identifier >= 0);
|
2022-12-01 21:53:27 +01:00
|
|
|
bNode *const *node = this->runtime->nodes_by_id.lookup_key_ptr_as(identifier);
|
|
|
|
return node ? *node : nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
inline const bNode *bNodeTree::node_by_id(const int32_t identifier) const
|
|
|
|
{
|
Geometry Nodes: add simulation support
This adds support for building simulations with geometry nodes. A new
`Simulation Input` and `Simulation Output` node allow maintaining a
simulation state across multiple frames. Together these two nodes form
a `simulation zone` which contains all the nodes that update the simulation
state from one frame to the next.
A new simulation zone can be added via the menu
(`Simulation > Simulation Zone`) or with the node add search.
The simulation state contains a geometry by default. However, it is possible
to add multiple geometry sockets as well as other socket types. Currently,
field inputs are evaluated and stored for the preceding geometry socket in
the order that the sockets are shown. Simulation state items can be added
by linking one of the empty sockets to something else. In the sidebar, there
is a new panel that allows adding, removing and reordering these sockets.
The simulation nodes behave as follows:
* On the first frame, the inputs of the `Simulation Input` node are evaluated
to initialize the simulation state. In later frames these sockets are not
evaluated anymore. The `Delta Time` at the first frame is zero, but the
simulation zone is still evaluated.
* On every next frame, the `Simulation Input` node outputs the simulation
state of the previous frame. Nodes in the simulation zone can edit that
data in arbitrary ways, also taking into account the `Delta Time`. The new
simulation state has to be passed to the `Simulation Output` node where it
is cached and forwarded.
* On a frame that is already cached or baked, the nodes in the simulation
zone are not evaluated, because the `Simulation Output` node can return
the previously cached data directly.
It is not allowed to connect sockets from inside the simulation zone to the
outside without going through the `Simulation Output` node. This is a necessary
restriction to make caching and sub-frame interpolation work. Links can go into
the simulation zone without problems though.
Anonymous attributes are not propagated by the simulation nodes unless they
are explicitly stored in the simulation state. This is unfortunate, but
currently there is no practical and reliable alternative. The core problem
is detecting which anonymous attributes will be required for the simulation
and afterwards. While we can detect this for the current evaluation, we can't
look into the future in time to see what data will be necessary. We intend to
make it easier to explicitly pass data through a simulation in the future,
even if the simulation is in a nested node group.
There is a new `Simulation Nodes` panel in the physics tab in the properties
editor. It allows baking all simulation zones on the selected objects. The
baking options are intentially kept at a minimum for this MVP. More features
for simulation baking as well as baking in general can be expected to be added
separately.
All baked data is stored on disk in a folder next to the .blend file. #106937
describes how baking is implemented in more detail. Volumes can not be baked
yet and materials are lost during baking for now. Packing the baked data into
the .blend file is not yet supported.
The timeline indicates which frames are currently cached, baked or cached but
invalidated by user-changes.
Simulation input and output nodes are internally linked together by their
`bNode.identifier` which stays the same even if the node name changes. They
are generally added and removed together. However, there are still cases where
"dangling" simulation nodes can be created currently. Those generally don't
cause harm, but would be nice to avoid this in more cases in the future.
Co-authored-by: Hans Goudey <h.goudey@me.com>
Co-authored-by: Lukas Tönne <lukas@blender.org>
Pull Request: https://projects.blender.org/blender/blender/pulls/104924
2023-05-03 13:18:51 +02:00
|
|
|
BLI_assert(identifier >= 0);
|
2022-12-01 21:53:27 +01:00
|
|
|
const bNode *const *node = this->runtime->nodes_by_id.lookup_key_ptr_as(identifier);
|
|
|
|
return node ? *node : nullptr;
|
|
|
|
}
|
|
|
|
|
2022-08-31 12:15:57 +02:00
|
|
|
inline blender::Span<bNode *> bNodeTree::nodes_by_type(const blender::StringRefNull type_idname)
|
|
|
|
{
|
|
|
|
BLI_assert(blender::bke::node_tree_runtime::topology_cache_is_available(*this));
|
|
|
|
return this->runtime->nodes_by_type.lookup(nodeTypeFind(type_idname.c_str()));
|
|
|
|
}
|
|
|
|
|
|
|
|
inline blender::Span<const bNode *> bNodeTree::nodes_by_type(
|
|
|
|
const blender::StringRefNull type_idname) const
|
|
|
|
{
|
|
|
|
BLI_assert(blender::bke::node_tree_runtime::topology_cache_is_available(*this));
|
|
|
|
return this->runtime->nodes_by_type.lookup(nodeTypeFind(type_idname.c_str()));
|
|
|
|
}
|
|
|
|
|
|
|
|
inline blender::Span<const bNode *> bNodeTree::toposort_left_to_right() const
|
|
|
|
{
|
|
|
|
BLI_assert(blender::bke::node_tree_runtime::topology_cache_is_available(*this));
|
|
|
|
return this->runtime->toposort_left_to_right;
|
|
|
|
}
|
|
|
|
|
|
|
|
inline blender::Span<const bNode *> bNodeTree::toposort_right_to_left() const
|
|
|
|
{
|
|
|
|
BLI_assert(blender::bke::node_tree_runtime::topology_cache_is_available(*this));
|
|
|
|
return this->runtime->toposort_right_to_left;
|
|
|
|
}
|
|
|
|
|
2022-11-21 18:30:49 +01:00
|
|
|
inline blender::Span<bNode *> bNodeTree::toposort_left_to_right()
|
|
|
|
{
|
|
|
|
BLI_assert(blender::bke::node_tree_runtime::topology_cache_is_available(*this));
|
|
|
|
return this->runtime->toposort_left_to_right;
|
|
|
|
}
|
|
|
|
|
|
|
|
inline blender::Span<bNode *> bNodeTree::toposort_right_to_left()
|
|
|
|
{
|
|
|
|
BLI_assert(blender::bke::node_tree_runtime::topology_cache_is_available(*this));
|
|
|
|
return this->runtime->toposort_right_to_left;
|
|
|
|
}
|
|
|
|
|
2022-09-13 08:44:26 +02:00
|
|
|
inline blender::Span<const bNode *> bNodeTree::group_nodes() const
|
|
|
|
{
|
|
|
|
BLI_assert(blender::bke::node_tree_runtime::topology_cache_is_available(*this));
|
|
|
|
return this->runtime->group_nodes;
|
|
|
|
}
|
|
|
|
|
|
|
|
inline blender::Span<bNode *> bNodeTree::group_nodes()
|
|
|
|
{
|
|
|
|
BLI_assert(blender::bke::node_tree_runtime::topology_cache_is_available(*this));
|
|
|
|
return this->runtime->group_nodes;
|
|
|
|
}
|
|
|
|
|
2022-09-20 13:21:03 +02:00
|
|
|
inline bool bNodeTree::has_available_link_cycle() const
|
2022-08-31 12:15:57 +02:00
|
|
|
{
|
|
|
|
BLI_assert(blender::bke::node_tree_runtime::topology_cache_is_available(*this));
|
2022-09-20 13:21:03 +02:00
|
|
|
return this->runtime->has_available_link_cycle;
|
2022-08-31 12:15:57 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
inline bool bNodeTree::has_undefined_nodes_or_sockets() const
|
|
|
|
{
|
|
|
|
BLI_assert(blender::bke::node_tree_runtime::topology_cache_is_available(*this));
|
|
|
|
return this->runtime->has_undefined_nodes_or_sockets;
|
|
|
|
}
|
|
|
|
|
2022-12-21 05:51:13 +01:00
|
|
|
inline bNode *bNodeTree::group_output_node()
|
|
|
|
{
|
|
|
|
BLI_assert(blender::bke::node_tree_runtime::topology_cache_is_available(*this));
|
|
|
|
return this->runtime->group_output_node;
|
|
|
|
}
|
|
|
|
|
2022-08-31 12:15:57 +02:00
|
|
|
inline const bNode *bNodeTree::group_output_node() const
|
|
|
|
{
|
|
|
|
BLI_assert(blender::bke::node_tree_runtime::topology_cache_is_available(*this));
|
|
|
|
return this->runtime->group_output_node;
|
|
|
|
}
|
|
|
|
|
2022-12-13 17:25:37 +01:00
|
|
|
inline blender::Span<const bNode *> bNodeTree::group_input_nodes() const
|
|
|
|
{
|
|
|
|
return this->nodes_by_type("NodeGroupInput");
|
|
|
|
}
|
|
|
|
|
2022-08-31 12:15:57 +02:00
|
|
|
inline blender::Span<const bNodeSocket *> bNodeTree::all_input_sockets() const
|
|
|
|
{
|
|
|
|
BLI_assert(blender::bke::node_tree_runtime::topology_cache_is_available(*this));
|
|
|
|
return this->runtime->input_sockets;
|
|
|
|
}
|
|
|
|
|
|
|
|
inline blender::Span<bNodeSocket *> bNodeTree::all_input_sockets()
|
|
|
|
{
|
|
|
|
BLI_assert(blender::bke::node_tree_runtime::topology_cache_is_available(*this));
|
|
|
|
return this->runtime->input_sockets;
|
|
|
|
}
|
|
|
|
|
|
|
|
inline blender::Span<const bNodeSocket *> bNodeTree::all_output_sockets() const
|
|
|
|
{
|
|
|
|
BLI_assert(blender::bke::node_tree_runtime::topology_cache_is_available(*this));
|
|
|
|
return this->runtime->output_sockets;
|
|
|
|
}
|
|
|
|
|
|
|
|
inline blender::Span<bNodeSocket *> bNodeTree::all_output_sockets()
|
|
|
|
{
|
|
|
|
BLI_assert(blender::bke::node_tree_runtime::topology_cache_is_available(*this));
|
|
|
|
return this->runtime->output_sockets;
|
|
|
|
}
|
|
|
|
|
|
|
|
inline blender::Span<const bNodeSocket *> bNodeTree::all_sockets() const
|
|
|
|
{
|
|
|
|
BLI_assert(blender::bke::node_tree_runtime::topology_cache_is_available(*this));
|
|
|
|
return this->runtime->sockets;
|
|
|
|
}
|
|
|
|
|
|
|
|
inline blender::Span<bNodeSocket *> bNodeTree::all_sockets()
|
|
|
|
{
|
|
|
|
BLI_assert(blender::bke::node_tree_runtime::topology_cache_is_available(*this));
|
|
|
|
return this->runtime->sockets;
|
|
|
|
}
|
|
|
|
|
2022-11-18 11:20:13 +01:00
|
|
|
inline blender::Span<bNode *> bNodeTree::root_frames() const
|
|
|
|
{
|
|
|
|
BLI_assert(blender::bke::node_tree_runtime::topology_cache_is_available(*this));
|
|
|
|
return this->runtime->root_frames;
|
|
|
|
}
|
|
|
|
|
2023-06-16 10:37:18 +02:00
|
|
|
inline blender::Span<bNodeLink *> bNodeTree::all_links()
|
|
|
|
{
|
|
|
|
BLI_assert(blender::bke::node_tree_runtime::topology_cache_is_available(*this));
|
|
|
|
return this->runtime->links;
|
|
|
|
}
|
|
|
|
|
|
|
|
inline blender::Span<const bNodeLink *> bNodeTree::all_links() const
|
|
|
|
{
|
|
|
|
BLI_assert(blender::bke::node_tree_runtime::topology_cache_is_available(*this));
|
|
|
|
return this->runtime->links;
|
|
|
|
}
|
|
|
|
|
Nodes: add nested node ids and use them for simulation state
The simulation state used by simulation nodes is owned by the modifier. Since a
geometry nodes setup can contain an arbitrary number of simulations, the modifier
has a mapping from `SimulationZoneID` to `SimulationZoneState`. This patch changes
what is used as `SimulationZoneID`.
Previously, the `SimulationZoneID` contained a list of `bNode::identifier` that described
the path from the root node tree to the simulation output node. This works ok in many
cases, but also has a significant problem: The `SimulationZoneID` changes when moving
the simulation zone into or out of a node group. This implies that any of these operations
loses the mapping from zone to simulation state, invalidating the cache or even baked data.
The goal of this patch is to introduce a single-integer ID that identifies a (nested) simulation
zone and is stable even when grouping and un-grouping. The ID should be stable even if the
node group containing the (nested) simulation zone is in a separate linked .blend file and
that linked file is changed.
In the future, the same kind of ID can be used to store e.g. checkpoint/baked/frozen data
in the modifier.
To achieve the described goal, node trees can now store an arbitrary number of nested node
references (an array of `bNestedNodeRef`). Each nested node reference has an ID that is
unique within the current node tree. The node tree does not store the entire path to the
nested node. Instead it only know which group node the nested node is in, and what the
nested node ID of the node is within that group. Grouping and un-grouping operations
have to update the nested node references to keep the IDs stable. Importantly though,
these operations only have to care about the two node groups that are affected. IDs in
higher level node groups remain unchanged by design.
A consequence of this design is that every `bNodeTree` now has a `bNestedNodeRef`
for every (nested) simulation zone. Two instances of the same simulation zone (because
a node group is reused) are referenced by two separate `bNestedNodeRef`. This is
important to keep in mind, because it also means that this solution doesn't scale well if
we wanted to use it to keep stable references to *all* nested nodes. I can't think of a
solution that fulfills the described requirements but scales better with more nodes. For
that reason, this solution should only be used when we want to store data for each
referenced nested node at the top level (like we do for simulations).
This is not a replacement for `ViewerPath` which can store a path to data in a node tree
without changing the node tree. Also `ViewerPath` can contain information like the loop
iteration that should be viewed (#109164). `bNestedNodeRef` can't differentiate between
different iterations of a loop. This also means that simulations can't be used inside of a
loop (loops inside of a simulation work fine though).
When baking, the new stable ID is now written to disk, which means that baked data is
not invalidated by grouping/un-grouping operations. Backward compatibility for baked
data is provided, but only works as long as the simulation zone has not been moved to
a different node group yet. Forward compatibility for the baked data is not provided
(so older versions can't load the data baked with a newer version of Blender).
Pull Request: https://projects.blender.org/blender/blender/pulls/109444
2023-07-01 11:54:32 +02:00
|
|
|
inline blender::MutableSpan<bNestedNodeRef> bNodeTree::nested_node_refs_span()
|
|
|
|
{
|
|
|
|
return {this->nested_node_refs, this->nested_node_refs_num};
|
|
|
|
}
|
|
|
|
|
|
|
|
inline blender::Span<bNestedNodeRef> bNodeTree::nested_node_refs_span() const
|
|
|
|
{
|
|
|
|
return {this->nested_node_refs, this->nested_node_refs_num};
|
|
|
|
}
|
|
|
|
|
2023-09-14 14:13:07 +02:00
|
|
|
inline void bNodeTree::ensure_interface_cache() const
|
|
|
|
{
|
|
|
|
this->tree_interface.ensure_items_cache();
|
|
|
|
}
|
|
|
|
|
2023-10-20 19:37:39 +02:00
|
|
|
inline blender::Span<bNodeTreeInterfaceSocket *> bNodeTree::interface_inputs()
|
2023-08-30 12:37:21 +02:00
|
|
|
{
|
2023-09-14 14:13:07 +02:00
|
|
|
BLI_assert(this->tree_interface.items_cache_is_available());
|
|
|
|
return this->tree_interface.runtime->inputs_;
|
2023-08-30 12:37:21 +02:00
|
|
|
}
|
|
|
|
|
2023-10-20 19:37:39 +02:00
|
|
|
inline blender::Span<const bNodeTreeInterfaceSocket *> bNodeTree::interface_inputs() const
|
|
|
|
{
|
|
|
|
BLI_assert(this->tree_interface.items_cache_is_available());
|
|
|
|
return this->tree_interface.runtime->inputs_;
|
|
|
|
}
|
|
|
|
|
|
|
|
inline blender::Span<bNodeTreeInterfaceSocket *> bNodeTree::interface_outputs()
|
2023-08-30 12:37:21 +02:00
|
|
|
{
|
2023-09-14 14:13:07 +02:00
|
|
|
BLI_assert(this->tree_interface.items_cache_is_available());
|
|
|
|
return this->tree_interface.runtime->outputs_;
|
2023-08-30 12:37:21 +02:00
|
|
|
}
|
|
|
|
|
2023-10-20 19:37:39 +02:00
|
|
|
inline blender::Span<const bNodeTreeInterfaceSocket *> bNodeTree::interface_outputs() const
|
|
|
|
{
|
|
|
|
BLI_assert(this->tree_interface.items_cache_is_available());
|
|
|
|
return this->tree_interface.runtime->outputs_;
|
|
|
|
}
|
|
|
|
|
|
|
|
inline blender::Span<bNodeTreeInterfaceItem *> bNodeTree::interface_items()
|
|
|
|
{
|
|
|
|
BLI_assert(this->tree_interface.items_cache_is_available());
|
|
|
|
return this->tree_interface.runtime->items_;
|
|
|
|
}
|
|
|
|
|
|
|
|
inline blender::Span<const bNodeTreeInterfaceItem *> bNodeTree::interface_items() const
|
2023-08-30 12:37:21 +02:00
|
|
|
{
|
2023-09-14 14:13:07 +02:00
|
|
|
BLI_assert(this->tree_interface.items_cache_is_available());
|
|
|
|
return this->tree_interface.runtime->items_;
|
2023-08-30 12:37:21 +02:00
|
|
|
}
|
|
|
|
|
2023-06-16 10:37:18 +02:00
|
|
|
/** \} */
|
|
|
|
|
2022-08-31 12:15:57 +02:00
|
|
|
/* -------------------------------------------------------------------- */
|
|
|
|
/** \name #bNode Inline Methods
|
|
|
|
* \{ */
|
|
|
|
|
2022-12-12 03:23:18 +01:00
|
|
|
inline int bNode::index() const
|
|
|
|
{
|
|
|
|
const int index = this->runtime->index_in_tree;
|
|
|
|
/* The order of nodes should always be consistent with the `nodes_by_id` vector. */
|
|
|
|
BLI_assert(index ==
|
|
|
|
this->runtime->owner_tree->runtime->nodes_by_id.index_of_as(this->identifier));
|
|
|
|
return index;
|
|
|
|
}
|
|
|
|
|
2022-08-31 12:15:57 +02:00
|
|
|
inline blender::Span<bNodeSocket *> bNode::input_sockets()
|
|
|
|
{
|
|
|
|
BLI_assert(blender::bke::node_tree_runtime::topology_cache_is_available(*this));
|
|
|
|
return this->runtime->inputs;
|
|
|
|
}
|
|
|
|
|
|
|
|
inline blender::Span<bNodeSocket *> bNode::output_sockets()
|
|
|
|
{
|
|
|
|
BLI_assert(blender::bke::node_tree_runtime::topology_cache_is_available(*this));
|
|
|
|
return this->runtime->outputs;
|
|
|
|
}
|
|
|
|
|
|
|
|
inline blender::Span<const bNodeSocket *> bNode::input_sockets() const
|
|
|
|
{
|
|
|
|
BLI_assert(blender::bke::node_tree_runtime::topology_cache_is_available(*this));
|
|
|
|
return this->runtime->inputs;
|
|
|
|
}
|
|
|
|
|
|
|
|
inline blender::Span<const bNodeSocket *> bNode::output_sockets() const
|
|
|
|
{
|
|
|
|
BLI_assert(blender::bke::node_tree_runtime::topology_cache_is_available(*this));
|
|
|
|
return this->runtime->outputs;
|
|
|
|
}
|
|
|
|
|
|
|
|
inline bNodeSocket &bNode::input_socket(int index)
|
|
|
|
{
|
|
|
|
BLI_assert(blender::bke::node_tree_runtime::topology_cache_is_available(*this));
|
|
|
|
return *this->runtime->inputs[index];
|
|
|
|
}
|
|
|
|
|
|
|
|
inline bNodeSocket &bNode::output_socket(int index)
|
|
|
|
{
|
|
|
|
BLI_assert(blender::bke::node_tree_runtime::topology_cache_is_available(*this));
|
|
|
|
return *this->runtime->outputs[index];
|
|
|
|
}
|
|
|
|
|
|
|
|
inline const bNodeSocket &bNode::input_socket(int index) const
|
|
|
|
{
|
|
|
|
BLI_assert(blender::bke::node_tree_runtime::topology_cache_is_available(*this));
|
|
|
|
return *this->runtime->inputs[index];
|
|
|
|
}
|
|
|
|
|
|
|
|
inline const bNodeSocket &bNode::output_socket(int index) const
|
|
|
|
{
|
|
|
|
BLI_assert(blender::bke::node_tree_runtime::topology_cache_is_available(*this));
|
|
|
|
return *this->runtime->outputs[index];
|
|
|
|
}
|
|
|
|
|
|
|
|
inline const bNodeSocket &bNode::input_by_identifier(blender::StringRef identifier) const
|
|
|
|
{
|
|
|
|
BLI_assert(blender::bke::node_tree_runtime::topology_cache_is_available(*this));
|
|
|
|
return *this->runtime->inputs_by_identifier.lookup_as(identifier);
|
|
|
|
}
|
|
|
|
|
|
|
|
inline const bNodeSocket &bNode::output_by_identifier(blender::StringRef identifier) const
|
|
|
|
{
|
|
|
|
BLI_assert(blender::bke::node_tree_runtime::topology_cache_is_available(*this));
|
|
|
|
return *this->runtime->outputs_by_identifier.lookup_as(identifier);
|
|
|
|
}
|
|
|
|
|
2022-11-25 12:10:56 +01:00
|
|
|
inline bNodeSocket &bNode::input_by_identifier(blender::StringRef identifier)
|
|
|
|
{
|
|
|
|
BLI_assert(blender::bke::node_tree_runtime::topology_cache_is_available(*this));
|
|
|
|
return *this->runtime->inputs_by_identifier.lookup_as(identifier);
|
|
|
|
}
|
|
|
|
|
|
|
|
inline bNodeSocket &bNode::output_by_identifier(blender::StringRef identifier)
|
|
|
|
{
|
|
|
|
BLI_assert(blender::bke::node_tree_runtime::topology_cache_is_available(*this));
|
|
|
|
return *this->runtime->outputs_by_identifier.lookup_as(identifier);
|
|
|
|
}
|
|
|
|
|
2022-09-07 10:24:34 +02:00
|
|
|
inline const bNodeTree &bNode::owner_tree() const
|
|
|
|
{
|
|
|
|
BLI_assert(blender::bke::node_tree_runtime::topology_cache_is_available(*this));
|
|
|
|
return *this->runtime->owner_tree;
|
|
|
|
}
|
|
|
|
|
2022-08-31 12:15:57 +02:00
|
|
|
inline blender::StringRefNull bNode::label_or_name() const
|
|
|
|
{
|
|
|
|
if (this->label[0] == '\0') {
|
|
|
|
return this->name;
|
|
|
|
}
|
|
|
|
return this->label;
|
|
|
|
}
|
|
|
|
|
|
|
|
inline bool bNode::is_muted() const
|
|
|
|
{
|
|
|
|
return this->flag & NODE_MUTED;
|
|
|
|
}
|
|
|
|
|
|
|
|
inline bool bNode::is_reroute() const
|
|
|
|
{
|
|
|
|
return this->type == NODE_REROUTE;
|
|
|
|
}
|
|
|
|
|
|
|
|
inline bool bNode::is_frame() const
|
|
|
|
{
|
|
|
|
return this->type == NODE_FRAME;
|
|
|
|
}
|
|
|
|
|
|
|
|
inline bool bNode::is_group() const
|
|
|
|
{
|
|
|
|
return ELEM(this->type, NODE_GROUP, NODE_CUSTOM_GROUP);
|
|
|
|
}
|
|
|
|
|
|
|
|
inline bool bNode::is_group_input() const
|
|
|
|
{
|
|
|
|
return this->type == NODE_GROUP_INPUT;
|
|
|
|
}
|
|
|
|
|
|
|
|
inline bool bNode::is_group_output() const
|
|
|
|
{
|
|
|
|
return this->type == NODE_GROUP_OUTPUT;
|
|
|
|
}
|
|
|
|
|
2023-01-10 05:29:58 +01:00
|
|
|
inline blender::Span<bNodeLink> bNode::internal_links() const
|
2022-08-31 12:15:57 +02:00
|
|
|
{
|
|
|
|
return this->runtime->internal_links;
|
|
|
|
}
|
|
|
|
|
2023-09-19 10:47:21 +02:00
|
|
|
inline bool bNode::is_socket_drawn(const bNodeSocket &socket) const
|
|
|
|
{
|
|
|
|
return socket.is_visible();
|
|
|
|
}
|
|
|
|
|
|
|
|
inline bool bNode::is_socket_icon_drawn(const bNodeSocket &socket) const
|
|
|
|
{
|
|
|
|
return socket.is_visible() && (this->flag & NODE_HIDDEN || !socket.is_panel_collapsed());
|
|
|
|
}
|
|
|
|
|
2022-11-18 11:20:13 +01:00
|
|
|
inline blender::Span<bNode *> bNode::direct_children_in_frame() const
|
|
|
|
{
|
|
|
|
BLI_assert(blender::bke::node_tree_runtime::topology_cache_is_available(*this));
|
|
|
|
BLI_assert(this->is_frame());
|
|
|
|
return this->runtime->direct_children_in_frame;
|
|
|
|
}
|
|
|
|
|
2022-08-31 12:15:57 +02:00
|
|
|
inline const blender::nodes::NodeDeclaration *bNode::declaration() const
|
|
|
|
{
|
|
|
|
return this->runtime->declaration;
|
|
|
|
}
|
|
|
|
|
2023-08-30 12:37:21 +02:00
|
|
|
inline blender::Span<bNodePanelState> bNode::panel_states() const
|
|
|
|
{
|
|
|
|
return {panel_states_array, num_panel_states};
|
|
|
|
}
|
|
|
|
|
|
|
|
inline blender::MutableSpan<bNodePanelState> bNode::panel_states()
|
|
|
|
{
|
|
|
|
return {panel_states_array, num_panel_states};
|
|
|
|
}
|
|
|
|
|
2022-08-31 12:15:57 +02:00
|
|
|
/** \} */
|
|
|
|
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
|
|
/** \name #bNodeLink Inline Methods
|
|
|
|
* \{ */
|
|
|
|
|
|
|
|
inline bool bNodeLink::is_muted() const
|
|
|
|
{
|
|
|
|
return this->flag & NODE_LINK_MUTED;
|
|
|
|
}
|
|
|
|
|
2022-09-20 13:21:03 +02:00
|
|
|
inline bool bNodeLink::is_available() const
|
|
|
|
{
|
|
|
|
return this->fromsock->is_available() && this->tosock->is_available();
|
|
|
|
}
|
|
|
|
|
2023-01-03 12:52:44 +01:00
|
|
|
inline bool bNodeLink::is_used() const
|
|
|
|
{
|
|
|
|
return !this->is_muted() && this->is_available();
|
|
|
|
}
|
|
|
|
|
2022-08-31 12:15:57 +02:00
|
|
|
/** \} */
|
|
|
|
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
|
|
/** \name #bNodeSocket Inline Methods
|
|
|
|
* \{ */
|
|
|
|
|
|
|
|
inline int bNodeSocket::index() const
|
|
|
|
{
|
|
|
|
BLI_assert(blender::bke::node_tree_runtime::topology_cache_is_available(*this));
|
|
|
|
return this->runtime->index_in_node;
|
|
|
|
}
|
|
|
|
|
|
|
|
inline int bNodeSocket::index_in_tree() const
|
|
|
|
{
|
|
|
|
BLI_assert(blender::bke::node_tree_runtime::topology_cache_is_available(*this));
|
|
|
|
return this->runtime->index_in_all_sockets;
|
|
|
|
}
|
|
|
|
|
2023-01-03 12:52:44 +01:00
|
|
|
inline int bNodeSocket::index_in_all_inputs() const
|
|
|
|
{
|
|
|
|
BLI_assert(blender::bke::node_tree_runtime::topology_cache_is_available(*this));
|
|
|
|
BLI_assert(this->is_input());
|
|
|
|
return this->runtime->index_in_inout_sockets;
|
|
|
|
}
|
|
|
|
|
|
|
|
inline int bNodeSocket::index_in_all_outputs() const
|
|
|
|
{
|
|
|
|
BLI_assert(blender::bke::node_tree_runtime::topology_cache_is_available(*this));
|
|
|
|
BLI_assert(this->is_output());
|
|
|
|
return this->runtime->index_in_inout_sockets;
|
|
|
|
}
|
|
|
|
|
2022-11-25 12:10:56 +01:00
|
|
|
inline bool bNodeSocket::is_hidden() const
|
|
|
|
{
|
|
|
|
return (this->flag & SOCK_HIDDEN) != 0;
|
|
|
|
}
|
|
|
|
|
2022-08-31 12:15:57 +02:00
|
|
|
inline bool bNodeSocket::is_available() const
|
|
|
|
{
|
|
|
|
return (this->flag & SOCK_UNAVAIL) == 0;
|
|
|
|
}
|
|
|
|
|
2023-08-30 12:37:21 +02:00
|
|
|
inline bool bNodeSocket::is_panel_collapsed() const
|
|
|
|
{
|
|
|
|
return (this->flag & SOCK_PANEL_COLLAPSED) != 0;
|
|
|
|
}
|
|
|
|
|
2022-12-29 16:27:27 +01:00
|
|
|
inline bool bNodeSocket::is_visible() const
|
|
|
|
{
|
2023-09-19 10:47:21 +02:00
|
|
|
return !this->is_hidden() && this->is_available();
|
2022-12-29 16:27:27 +01:00
|
|
|
}
|
|
|
|
|
2022-08-31 12:15:57 +02:00
|
|
|
inline bNode &bNodeSocket::owner_node()
|
|
|
|
{
|
|
|
|
BLI_assert(blender::bke::node_tree_runtime::topology_cache_is_available(*this));
|
|
|
|
return *this->runtime->owner_node;
|
|
|
|
}
|
|
|
|
|
|
|
|
inline const bNodeTree &bNodeSocket::owner_tree() const
|
|
|
|
{
|
|
|
|
BLI_assert(blender::bke::node_tree_runtime::topology_cache_is_available(*this));
|
|
|
|
return *this->runtime->owner_node->runtime->owner_tree;
|
|
|
|
}
|
|
|
|
|
|
|
|
inline blender::Span<const bNodeSocket *> bNodeSocket::logically_linked_sockets() const
|
|
|
|
{
|
|
|
|
BLI_assert(blender::bke::node_tree_runtime::topology_cache_is_available(*this));
|
|
|
|
return this->runtime->logically_linked_sockets;
|
|
|
|
}
|
|
|
|
|
|
|
|
inline blender::Span<const bNodeLink *> bNodeSocket::directly_linked_links() const
|
|
|
|
{
|
|
|
|
BLI_assert(blender::bke::node_tree_runtime::topology_cache_is_available(*this));
|
|
|
|
return this->runtime->directly_linked_links;
|
|
|
|
}
|
|
|
|
|
|
|
|
inline blender::Span<bNodeLink *> bNodeSocket::directly_linked_links()
|
|
|
|
{
|
|
|
|
BLI_assert(blender::bke::node_tree_runtime::topology_cache_is_available(*this));
|
|
|
|
return this->runtime->directly_linked_links;
|
|
|
|
}
|
|
|
|
|
|
|
|
inline blender::Span<const bNodeSocket *> bNodeSocket::directly_linked_sockets() const
|
|
|
|
{
|
|
|
|
BLI_assert(blender::bke::node_tree_runtime::topology_cache_is_available(*this));
|
|
|
|
return this->runtime->directly_linked_sockets;
|
|
|
|
}
|
|
|
|
|
2022-09-06 19:11:04 +02:00
|
|
|
inline blender::Span<bNodeSocket *> bNodeSocket::directly_linked_sockets()
|
|
|
|
{
|
|
|
|
BLI_assert(blender::bke::node_tree_runtime::topology_cache_is_available(*this));
|
|
|
|
return this->runtime->directly_linked_sockets;
|
|
|
|
}
|
|
|
|
|
2022-08-31 12:15:57 +02:00
|
|
|
inline bool bNodeSocket::is_directly_linked() const
|
|
|
|
{
|
|
|
|
return !this->directly_linked_links().is_empty();
|
|
|
|
}
|
|
|
|
|
|
|
|
inline bool bNodeSocket::is_logically_linked() const
|
|
|
|
{
|
|
|
|
return !this->logically_linked_sockets().is_empty();
|
|
|
|
}
|
|
|
|
|
|
|
|
inline const bNodeSocket *bNodeSocket::internal_link_input() const
|
|
|
|
{
|
|
|
|
BLI_assert(blender::bke::node_tree_runtime::topology_cache_is_available(*this));
|
|
|
|
BLI_assert(this->in_out == SOCK_OUT);
|
|
|
|
return this->runtime->internal_link_input;
|
|
|
|
}
|
|
|
|
|
2023-04-03 18:23:30 +02:00
|
|
|
template<typename T> T *bNodeSocket::default_value_typed()
|
|
|
|
{
|
|
|
|
return static_cast<T *>(this->default_value);
|
|
|
|
}
|
|
|
|
|
2022-08-31 12:15:57 +02:00
|
|
|
template<typename T> const T *bNodeSocket::default_value_typed() const
|
|
|
|
{
|
|
|
|
return static_cast<const T *>(this->default_value);
|
|
|
|
}
|
|
|
|
|
|
|
|
inline bool bNodeSocket::is_input() const
|
|
|
|
{
|
|
|
|
return this->in_out == SOCK_IN;
|
|
|
|
}
|
|
|
|
|
|
|
|
inline bool bNodeSocket::is_output() const
|
|
|
|
{
|
|
|
|
return this->in_out == SOCK_OUT;
|
|
|
|
}
|
|
|
|
|
|
|
|
inline bool bNodeSocket::is_multi_input() const
|
|
|
|
{
|
|
|
|
return this->flag & SOCK_MULTI_INPUT;
|
|
|
|
}
|
|
|
|
|
|
|
|
inline const bNode &bNodeSocket::owner_node() const
|
|
|
|
{
|
|
|
|
BLI_assert(blender::bke::node_tree_runtime::topology_cache_is_available(*this));
|
|
|
|
return *this->runtime->owner_node;
|
|
|
|
}
|
|
|
|
|
|
|
|
/** \} */
|
2023-08-30 12:37:21 +02:00
|
|
|
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
|
|
/** \name #bNode Inline Methods
|
|
|
|
* \{ */
|
|
|
|
|
|
|
|
inline bool bNodePanelState::is_collapsed() const
|
|
|
|
{
|
|
|
|
return flag & NODE_PANEL_COLLAPSED;
|
|
|
|
}
|
|
|
|
|
|
|
|
inline bool bNodePanelState::is_parent_collapsed() const
|
|
|
|
{
|
|
|
|
return flag & NODE_PANEL_PARENT_COLLAPSED;
|
|
|
|
}
|
|
|
|
|
2023-09-28 11:24:48 +02:00
|
|
|
inline bool bNodePanelState::has_visible_content() const
|
|
|
|
{
|
|
|
|
return flag & NODE_PANEL_CONTENT_VISIBLE;
|
|
|
|
}
|
|
|
|
|
2023-08-30 12:37:21 +02:00
|
|
|
/** \} */
|