Geometry Nodes: make evaluation and logging system aware of zones #109029
|
@ -87,8 +87,12 @@ class SPREADSHEET_HT_header(bpy.types.Header):
|
|||
layout.label(text="Invalid id")
|
||||
elif ctx.type == 'MODIFIER':
|
||||
layout.label(text=ctx.modifier_name, icon='MODIFIER')
|
||||
elif ctx.type == 'NODE':
|
||||
layout.label(text=ctx.node_name, icon='NODE')
|
||||
elif ctx.type == 'GROUP_NODE':
|
||||
layout.label(text=ctx.ui_name, icon='NODE')
|
||||
elif ctx.type == 'SIMULATION_ZONE':
|
||||
layout.label(text="Simulation Zone")
|
||||
elif ctx.type == 'VIEWER_NODE':
|
||||
layout.label(text=ctx.ui_name)
|
||||
|
||||
def draw_spreadsheet_viewer_path_icon(self, layout, space, icon='RIGHTARROW_THIN'):
|
||||
layout.prop(space, "display_viewer_path_collapsed", icon_only=True, emboss=False, icon=icon)
|
||||
|
|
|
@ -59,4 +59,23 @@ class NodeGroupComputeContext : public ComputeContext {
|
|||
void print_current_in_line(std::ostream &stream) const override;
|
||||
};
|
||||
|
||||
class SimulationZoneComputeContext : public ComputeContext {
|
||||
private:
|
||||
static constexpr const char *s_static_type = "SIMULATION_ZONE";
|
||||
|
||||
int32_t output_node_id_;
|
||||
|
||||
public:
|
||||
SimulationZoneComputeContext(const ComputeContext *parent, int output_node_id);
|
||||
SimulationZoneComputeContext(const ComputeContext *parent, const bNode &node);
|
||||
|
||||
int32_t output_node_id() const
|
||||
{
|
||||
return output_node_id_;
|
||||
}
|
||||
|
||||
private:
|
||||
void print_current_in_line(std::ostream &stream) const override;
|
||||
};
|
||||
|
||||
} // namespace blender::bke
|
||||
|
|
|
@ -14,6 +14,8 @@
|
|||
|
||||
namespace blender::bke::node_tree_zones {
|
||||
|
||||
class TreeZones;
|
||||
|
||||
struct TreeZone {
|
||||
TreeZones *owner = nullptr;
|
||||
/** Index of the zone in the array of all zones in a node tree. */
|
||||
|
@ -53,8 +55,25 @@ class TreeZones {
|
|||
* in a different zone than its output sockets.
|
||||
*/
|
||||
const TreeZone *get_zone_by_socket(const bNodeSocket &socket) const;
|
||||
|
||||
/**
|
||||
* Get the deepest zone that the node is in. Note that the e.g. Simulation Input and Output nodes
|
||||
* are considered to be inside of the zone they create.
|
||||
*/
|
||||
const TreeZone *get_zone_by_node(const int32_t node_id) const;
|
||||
|
||||
/**
|
||||
* Get a sorted list of zones that the node is in. First comes the root zone and last the most
|
||||
* nested zone. For nodes that are at the root level, the returned list is empty.
|
||||
*/
|
||||
Vector<const TreeZone *> get_zone_stack_for_node(const int32_t node_id) const;
|
||||
};
|
||||
|
||||
const TreeZones *get_tree_zones(const bNodeTree &tree);
|
||||
|
||||
} // namespace blender::bke::node_tree_zones
|
||||
|
||||
inline const blender::bke::node_tree_zones::TreeZones *bNodeTree::zones() const
|
||||
{
|
||||
return blender::bke::node_tree_zones::get_tree_zones(*this);
|
||||
}
|
||||
|
|
|
@ -50,7 +50,9 @@ void BKE_viewer_path_id_remap(ViewerPath *viewer_path, const struct IDRemapper *
|
|||
ViewerPathElem *BKE_viewer_path_elem_new(ViewerPathElemType type);
|
||||
IDViewerPathElem *BKE_viewer_path_elem_new_id(void);
|
||||
ModifierViewerPathElem *BKE_viewer_path_elem_new_modifier(void);
|
||||
NodeViewerPathElem *BKE_viewer_path_elem_new_node(void);
|
||||
GroupNodeViewerPathElem *BKE_viewer_path_elem_new_group_node(void);
|
||||
SimulationZoneViewerPathElem *BKE_viewer_path_elem_new_simulation_zone(void);
|
||||
ViewerNodeViewerPathElem *BKE_viewer_path_elem_new_viewer_node(void);
|
||||
ViewerPathElem *BKE_viewer_path_elem_copy(const ViewerPathElem *src);
|
||||
bool BKE_viewer_path_elem_equal(const ViewerPathElem *a, const ViewerPathElem *b);
|
||||
void BKE_viewer_path_elem_free(ViewerPathElem *elem);
|
||||
|
|
|
@ -62,4 +62,30 @@ void NodeGroupComputeContext::print_current_in_line(std::ostream &stream) const
|
|||
stream << "Node ID: " << node_id_;
|
||||
}
|
||||
|
||||
SimulationZoneComputeContext::SimulationZoneComputeContext(const ComputeContext *parent,
|
||||
const int32_t output_node_id)
|
||||
: ComputeContext(s_static_type, parent), output_node_id_(output_node_id)
|
||||
{
|
||||
/* Mix static type and node id into a single buffer so that only a single call to #mix_in is
|
||||
* necessary. */
|
||||
const int type_size = strlen(s_static_type);
|
||||
const int buffer_size = type_size + 1 + sizeof(int32_t);
|
||||
DynamicStackBuffer<64, 8> buffer_owner(buffer_size, 8);
|
||||
char *buffer = static_cast<char *>(buffer_owner.buffer());
|
||||
memcpy(buffer, s_static_type, type_size + 1);
|
||||
memcpy(buffer + type_size + 1, &output_node_id_, sizeof(int32_t));
|
||||
hash_.mix_in(buffer, buffer_size);
|
||||
}
|
||||
|
||||
SimulationZoneComputeContext::SimulationZoneComputeContext(const ComputeContext *parent,
|
||||
const bNode &node)
|
||||
: SimulationZoneComputeContext(parent, node.identifier)
|
||||
{
|
||||
}
|
||||
|
||||
void SimulationZoneComputeContext::print_current_in_line(std::ostream &stream) const
|
||||
{
|
||||
stream << "Simulation Zone ID: " << output_node_id_;
|
||||
}
|
||||
|
||||
} // namespace blender::bke
|
||||
|
|
|
@ -309,22 +309,44 @@ bool TreeZone::contains_zone_recursively(const TreeZone &other_zone) const
|
|||
const TreeZone *TreeZones::get_zone_by_socket(const bNodeSocket &socket) const
|
||||
{
|
||||
const bNode &node = socket.owner_node();
|
||||
const int zone_i = this->zone_by_node_id.lookup_default(node.identifier, -1);
|
||||
const TreeZone *zone = this->get_zone_by_node(node.identifier);
|
||||
if (zone == nullptr) {
|
||||
return zone;
|
||||
}
|
||||
if (zone->input_node == &node) {
|
||||
if (socket.is_input()) {
|
||||
return zone->parent_zone;
|
||||
}
|
||||
}
|
||||
if (zone->output_node == &node) {
|
||||
if (socket.is_output()) {
|
||||
return zone->parent_zone;
|
||||
}
|
||||
}
|
||||
return zone;
|
||||
}
|
||||
|
||||
const TreeZone *TreeZones::get_zone_by_node(const int32_t node_id) const
|
||||
{
|
||||
const int zone_i = this->zone_by_node_id.lookup_default(node_id, -1);
|
||||
if (zone_i == -1) {
|
||||
return nullptr;
|
||||
}
|
||||
const TreeZone &zone = *this->zones[zone_i];
|
||||
if (zone.input_node == &node) {
|
||||
if (socket.is_input()) {
|
||||
return zone.parent_zone;
|
||||
}
|
||||
return this->zones[zone_i].get();
|
||||
}
|
||||
|
||||
Vector<const TreeZone *> TreeZones::get_zone_stack_for_node(const int node_id) const
|
||||
{
|
||||
const TreeZone *zone = this->get_zone_by_node(node_id);
|
||||
if (zone == nullptr) {
|
||||
return {};
|
||||
}
|
||||
if (zone.output_node == &node) {
|
||||
if (socket.is_output()) {
|
||||
return zone.parent_zone;
|
||||
}
|
||||
Vector<const TreeZone *> zone_stack;
|
||||
for (; zone; zone = zone->parent_zone) {
|
||||
zone_stack.append(zone);
|
||||
}
|
||||
return &zone;
|
||||
std::reverse(zone_stack.begin(), zone_stack.end());
|
||||
return zone_stack;
|
||||
}
|
||||
|
||||
} // namespace blender::bke::node_tree_zones
|
||||
|
|
|
@ -73,13 +73,23 @@ void BKE_viewer_path_blend_write(BlendWriter *writer, const ViewerPath *viewer_p
|
|||
BLO_write_string(writer, typed_elem->modifier_name);
|
||||
break;
|
||||
}
|
||||
case VIEWER_PATH_ELEM_TYPE_NODE: {
|
||||
const auto *typed_elem = reinterpret_cast<NodeViewerPathElem *>(elem);
|
||||
BLO_write_struct(writer, NodeViewerPathElem, typed_elem);
|
||||
BLO_write_string(writer, typed_elem->node_name);
|
||||
case VIEWER_PATH_ELEM_TYPE_GROUP_NODE: {
|
||||
const auto *typed_elem = reinterpret_cast<GroupNodeViewerPathElem *>(elem);
|
||||
BLO_write_struct(writer, GroupNodeViewerPathElem, typed_elem);
|
||||
break;
|
||||
}
|
||||
case VIEWER_PATH_ELEM_TYPE_SIMULATION_ZONE: {
|
||||
const auto *typed_elem = reinterpret_cast<SimulationZoneViewerPathElem *>(elem);
|
||||
BLO_write_struct(writer, SimulationZoneViewerPathElem, typed_elem);
|
||||
break;
|
||||
}
|
||||
case VIEWER_PATH_ELEM_TYPE_VIEWER_NODE: {
|
||||
const auto *typed_elem = reinterpret_cast<ViewerNodeViewerPathElem *>(elem);
|
||||
BLO_write_struct(writer, ViewerNodeViewerPathElem, typed_elem);
|
||||
break;
|
||||
}
|
||||
}
|
||||
BLO_write_string(writer, elem->ui_name);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -87,7 +97,11 @@ void BKE_viewer_path_blend_read_data(BlendDataReader *reader, ViewerPath *viewer
|
|||
{
|
||||
BLO_read_list(reader, &viewer_path->path);
|
||||
LISTBASE_FOREACH (ViewerPathElem *, elem, &viewer_path->path) {
|
||||
BLO_read_data_address(reader, &elem->ui_name);
|
||||
switch (ViewerPathElemType(elem->type)) {
|
||||
case VIEWER_PATH_ELEM_TYPE_GROUP_NODE:
|
||||
case VIEWER_PATH_ELEM_TYPE_SIMULATION_ZONE:
|
||||
case VIEWER_PATH_ELEM_TYPE_VIEWER_NODE:
|
||||
case VIEWER_PATH_ELEM_TYPE_ID: {
|
||||
break;
|
||||
}
|
||||
|
@ -96,11 +110,6 @@ void BKE_viewer_path_blend_read_data(BlendDataReader *reader, ViewerPath *viewer
|
|||
BLO_read_data_address(reader, &typed_elem->modifier_name);
|
||||
break;
|
||||
}
|
||||
case VIEWER_PATH_ELEM_TYPE_NODE: {
|
||||
auto *typed_elem = reinterpret_cast<NodeViewerPathElem *>(elem);
|
||||
BLO_read_data_address(reader, &typed_elem->node_name);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -115,7 +124,9 @@ void BKE_viewer_path_blend_read_lib(BlendLibReader *reader, ID *self_id, ViewerP
|
|||
break;
|
||||
}
|
||||
case VIEWER_PATH_ELEM_TYPE_MODIFIER:
|
||||
case VIEWER_PATH_ELEM_TYPE_NODE: {
|
||||
case VIEWER_PATH_ELEM_TYPE_GROUP_NODE:
|
||||
case VIEWER_PATH_ELEM_TYPE_SIMULATION_ZONE:
|
||||
case VIEWER_PATH_ELEM_TYPE_VIEWER_NODE: {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -132,7 +143,9 @@ void BKE_viewer_path_foreach_id(LibraryForeachIDData *data, ViewerPath *viewer_p
|
|||
break;
|
||||
}
|
||||
case VIEWER_PATH_ELEM_TYPE_MODIFIER:
|
||||
case VIEWER_PATH_ELEM_TYPE_NODE: {
|
||||
case VIEWER_PATH_ELEM_TYPE_GROUP_NODE:
|
||||
case VIEWER_PATH_ELEM_TYPE_SIMULATION_ZONE:
|
||||
case VIEWER_PATH_ELEM_TYPE_VIEWER_NODE: {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -149,30 +162,39 @@ void BKE_viewer_path_id_remap(ViewerPath *viewer_path, const IDRemapper *mapping
|
|||
break;
|
||||
}
|
||||
case VIEWER_PATH_ELEM_TYPE_MODIFIER:
|
||||
case VIEWER_PATH_ELEM_TYPE_NODE: {
|
||||
case VIEWER_PATH_ELEM_TYPE_GROUP_NODE:
|
||||
case VIEWER_PATH_ELEM_TYPE_SIMULATION_ZONE:
|
||||
case VIEWER_PATH_ELEM_TYPE_VIEWER_NODE: {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T> static T *make_elem(const ViewerPathElemType type)
|
||||
{
|
||||
T *elem = MEM_cnew<T>(__func__);
|
||||
elem->base.type = type;
|
||||
return elem;
|
||||
}
|
||||
|
||||
ViewerPathElem *BKE_viewer_path_elem_new(const ViewerPathElemType type)
|
||||
{
|
||||
switch (type) {
|
||||
case VIEWER_PATH_ELEM_TYPE_ID: {
|
||||
IDViewerPathElem *elem = MEM_cnew<IDViewerPathElem>(__func__);
|
||||
elem->base.type = type;
|
||||
return &elem->base;
|
||||
return &make_elem<IDViewerPathElem>(type)->base;
|
||||
}
|
||||
case VIEWER_PATH_ELEM_TYPE_MODIFIER: {
|
||||
ModifierViewerPathElem *elem = MEM_cnew<ModifierViewerPathElem>(__func__);
|
||||
elem->base.type = type;
|
||||
return &elem->base;
|
||||
return &make_elem<ModifierViewerPathElem>(type)->base;
|
||||
}
|
||||
case VIEWER_PATH_ELEM_TYPE_NODE: {
|
||||
NodeViewerPathElem *elem = MEM_cnew<NodeViewerPathElem>(__func__);
|
||||
elem->base.type = type;
|
||||
return &elem->base;
|
||||
case VIEWER_PATH_ELEM_TYPE_GROUP_NODE: {
|
||||
return &make_elem<GroupNodeViewerPathElem>(type)->base;
|
||||
}
|
||||
case VIEWER_PATH_ELEM_TYPE_SIMULATION_ZONE: {
|
||||
return &make_elem<SimulationZoneViewerPathElem>(type)->base;
|
||||
}
|
||||
case VIEWER_PATH_ELEM_TYPE_VIEWER_NODE: {
|
||||
return &make_elem<ViewerNodeViewerPathElem>(type)->base;
|
||||
}
|
||||
}
|
||||
BLI_assert_unreachable();
|
||||
|
@ -190,15 +212,30 @@ ModifierViewerPathElem *BKE_viewer_path_elem_new_modifier()
|
|||
BKE_viewer_path_elem_new(VIEWER_PATH_ELEM_TYPE_MODIFIER));
|
||||
}
|
||||
|
||||
NodeViewerPathElem *BKE_viewer_path_elem_new_node()
|
||||
GroupNodeViewerPathElem *BKE_viewer_path_elem_new_group_node()
|
||||
{
|
||||
return reinterpret_cast<NodeViewerPathElem *>(
|
||||
BKE_viewer_path_elem_new(VIEWER_PATH_ELEM_TYPE_NODE));
|
||||
return reinterpret_cast<GroupNodeViewerPathElem *>(
|
||||
BKE_viewer_path_elem_new(VIEWER_PATH_ELEM_TYPE_GROUP_NODE));
|
||||
}
|
||||
|
||||
SimulationZoneViewerPathElem *BKE_viewer_path_elem_new_simulation_zone()
|
||||
{
|
||||
return reinterpret_cast<SimulationZoneViewerPathElem *>(
|
||||
BKE_viewer_path_elem_new(VIEWER_PATH_ELEM_TYPE_SIMULATION_ZONE));
|
||||
}
|
||||
|
||||
ViewerNodeViewerPathElem *BKE_viewer_path_elem_new_viewer_node()
|
||||
{
|
||||
return reinterpret_cast<ViewerNodeViewerPathElem *>(
|
||||
BKE_viewer_path_elem_new(VIEWER_PATH_ELEM_TYPE_VIEWER_NODE));
|
||||
}
|
||||
|
||||
ViewerPathElem *BKE_viewer_path_elem_copy(const ViewerPathElem *src)
|
||||
{
|
||||
ViewerPathElem *dst = BKE_viewer_path_elem_new(ViewerPathElemType(src->type));
|
||||
if (src->ui_name) {
|
||||
dst->ui_name = BLI_strdup(src->ui_name);
|
||||
}
|
||||
switch (ViewerPathElemType(src->type)) {
|
||||
case VIEWER_PATH_ELEM_TYPE_ID: {
|
||||
const auto *old_elem = reinterpret_cast<const IDViewerPathElem *>(src);
|
||||
|
@ -214,13 +251,22 @@ ViewerPathElem *BKE_viewer_path_elem_copy(const ViewerPathElem *src)
|
|||
}
|
||||
break;
|
||||
}
|
||||
case VIEWER_PATH_ELEM_TYPE_NODE: {
|
||||
const auto *old_elem = reinterpret_cast<const NodeViewerPathElem *>(src);
|
||||
auto *new_elem = reinterpret_cast<NodeViewerPathElem *>(dst);
|
||||
case VIEWER_PATH_ELEM_TYPE_GROUP_NODE: {
|
||||
const auto *old_elem = reinterpret_cast<const GroupNodeViewerPathElem *>(src);
|
||||
auto *new_elem = reinterpret_cast<GroupNodeViewerPathElem *>(dst);
|
||||
new_elem->node_id = old_elem->node_id;
|
||||
break;
|
||||
}
|
||||
case VIEWER_PATH_ELEM_TYPE_SIMULATION_ZONE: {
|
||||
const auto *old_elem = reinterpret_cast<const SimulationZoneViewerPathElem *>(src);
|
||||
auto *new_elem = reinterpret_cast<SimulationZoneViewerPathElem *>(dst);
|
||||
new_elem->sim_output_node_id = old_elem->sim_output_node_id;
|
||||
break;
|
||||
}
|
||||
case VIEWER_PATH_ELEM_TYPE_VIEWER_NODE: {
|
||||
const auto *old_elem = reinterpret_cast<const ViewerNodeViewerPathElem *>(src);
|
||||
auto *new_elem = reinterpret_cast<ViewerNodeViewerPathElem *>(dst);
|
||||
new_elem->node_id = old_elem->node_id;
|
||||
if (old_elem->node_name != nullptr) {
|
||||
new_elem->node_name = BLI_strdup(old_elem->node_name);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -243,9 +289,19 @@ bool BKE_viewer_path_elem_equal(const ViewerPathElem *a, const ViewerPathElem *b
|
|||
const auto *b_elem = reinterpret_cast<const ModifierViewerPathElem *>(b);
|
||||
return StringRef(a_elem->modifier_name) == StringRef(b_elem->modifier_name);
|
||||
}
|
||||
case VIEWER_PATH_ELEM_TYPE_NODE: {
|
||||
const auto *a_elem = reinterpret_cast<const NodeViewerPathElem *>(a);
|
||||
const auto *b_elem = reinterpret_cast<const NodeViewerPathElem *>(b);
|
||||
case VIEWER_PATH_ELEM_TYPE_GROUP_NODE: {
|
||||
const auto *a_elem = reinterpret_cast<const GroupNodeViewerPathElem *>(a);
|
||||
const auto *b_elem = reinterpret_cast<const GroupNodeViewerPathElem *>(b);
|
||||
return a_elem->node_id == b_elem->node_id;
|
||||
}
|
||||
case VIEWER_PATH_ELEM_TYPE_SIMULATION_ZONE: {
|
||||
const auto *a_elem = reinterpret_cast<const SimulationZoneViewerPathElem *>(a);
|
||||
const auto *b_elem = reinterpret_cast<const SimulationZoneViewerPathElem *>(b);
|
||||
return a_elem->sim_output_node_id == b_elem->sim_output_node_id;
|
||||
}
|
||||
case VIEWER_PATH_ELEM_TYPE_VIEWER_NODE: {
|
||||
const auto *a_elem = reinterpret_cast<const ViewerNodeViewerPathElem *>(a);
|
||||
const auto *b_elem = reinterpret_cast<const ViewerNodeViewerPathElem *>(b);
|
||||
return a_elem->node_id == b_elem->node_id;
|
||||
}
|
||||
}
|
||||
|
@ -255,7 +311,10 @@ bool BKE_viewer_path_elem_equal(const ViewerPathElem *a, const ViewerPathElem *b
|
|||
void BKE_viewer_path_elem_free(ViewerPathElem *elem)
|
||||
{
|
||||
switch (ViewerPathElemType(elem->type)) {
|
||||
case VIEWER_PATH_ELEM_TYPE_ID: {
|
||||
case VIEWER_PATH_ELEM_TYPE_ID:
|
||||
case VIEWER_PATH_ELEM_TYPE_GROUP_NODE:
|
||||
case VIEWER_PATH_ELEM_TYPE_SIMULATION_ZONE:
|
||||
case VIEWER_PATH_ELEM_TYPE_VIEWER_NODE: {
|
||||
break;
|
||||
}
|
||||
case VIEWER_PATH_ELEM_TYPE_MODIFIER: {
|
||||
|
@ -263,11 +322,9 @@ void BKE_viewer_path_elem_free(ViewerPathElem *elem)
|
|||
MEM_SAFE_FREE(typed_elem->modifier_name);
|
||||
break;
|
||||
}
|
||||
case VIEWER_PATH_ELEM_TYPE_NODE: {
|
||||
auto *typed_elem = reinterpret_cast<NodeViewerPathElem *>(elem);
|
||||
MEM_SAFE_FREE(typed_elem->node_name);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (elem->ui_name) {
|
||||
MEM_freeN(elem->ui_name);
|
||||
}
|
||||
MEM_freeN(elem);
|
||||
}
|
||||
|
|
|
@ -37,7 +37,7 @@ Object *parse_object_only(const ViewerPath &viewer_path);
|
|||
struct ViewerPathForGeometryNodesViewer {
|
||||
Object *object;
|
||||
blender::StringRefNull modifier_name;
|
||||
blender::Vector<int32_t> group_node_ids;
|
||||
blender::Vector<const ViewerPathElem *> node_path;
|
||||
int32_t viewer_node_id;
|
||||
};
|
||||
|
||||
|
@ -65,7 +65,6 @@ bool exists_geometry_nodes_viewer(const ViewerPathForGeometryNodesViewer &parsed
|
|||
* Checks if the node referenced by the viewer and its entire context is still active, i.e. some
|
||||
* editor is showing it.
|
||||
*/
|
||||
bool is_active_geometry_nodes_viewer(const bContext &C,
|
||||
const ViewerPathForGeometryNodesViewer &parsed_viewer_path);
|
||||
bool is_active_geometry_nodes_viewer(const bContext &C, const ViewerPath &viewer_path);
|
||||
|
||||
} // namespace blender::ed::viewer_path
|
||||
|
|
|
@ -20,11 +20,7 @@ static void validate_viewer_paths(bContext &C, WorkSpace &workspace)
|
|||
return;
|
||||
}
|
||||
|
||||
const std::optional<blender::ed::viewer_path::ViewerPathForGeometryNodesViewer> parsed_path =
|
||||
blender::ed::viewer_path::parse_geometry_nodes_viewer(workspace.viewer_path);
|
||||
if (parsed_path.has_value() &&
|
||||
blender::ed::viewer_path::is_active_geometry_nodes_viewer(C, *parsed_path))
|
||||
{
|
||||
if (blender::ed::viewer_path::is_active_geometry_nodes_viewer(C, workspace.viewer_path)) {
|
||||
/* The current viewer path is still valid and active. */
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -113,7 +113,7 @@ struct TreeDrawContext {
|
|||
* Geometry nodes logs various data during execution. The logged data that corresponds to the
|
||||
* currently drawn node tree can be retrieved from the log below.
|
||||
*/
|
||||
geo_log::GeoTreeLog *geo_tree_log = nullptr;
|
||||
blender::Map<const TreeZone *, geo_log::GeoTreeLog *> geo_log_by_zone;
|
||||
/**
|
||||
* True if there is an active realtime compositor using the node tree, false otherwise.
|
||||
*/
|
||||
|
@ -1068,8 +1068,8 @@ static void create_inspection_string_for_geometry_socket(std::stringstream &ss,
|
|||
}
|
||||
}
|
||||
|
||||
static std::optional<std::string> create_socket_inspection_string(TreeDrawContext &tree_draw_ctx,
|
||||
const bNodeSocket &socket)
|
||||
static std::optional<std::string> create_socket_inspection_string(
|
||||
geo_log::GeoTreeLog &geo_tree_log, const bNodeSocket &socket)
|
||||
{
|
||||
using namespace blender::nodes::geo_eval_log;
|
||||
|
||||
|
@ -1077,8 +1077,8 @@ static std::optional<std::string> create_socket_inspection_string(TreeDrawContex
|
|||
return std::nullopt;
|
||||
}
|
||||
|
||||
tree_draw_ctx.geo_tree_log->ensure_socket_values();
|
||||
ValueLog *value_log = tree_draw_ctx.geo_tree_log->find_socket_value_log(socket);
|
||||
geo_tree_log.ensure_socket_values();
|
||||
ValueLog *value_log = geo_tree_log.find_socket_value_log(socket);
|
||||
std::stringstream ss;
|
||||
if (const geo_log::GenericValueLog *generic_value_log =
|
||||
dynamic_cast<const geo_log::GenericValueLog *>(value_log))
|
||||
|
@ -1131,7 +1131,8 @@ static char *node_socket_get_tooltip(const SpaceNode *snode,
|
|||
TreeDrawContext tree_draw_ctx;
|
||||
if (snode != nullptr) {
|
||||
if (ntree.type == NTREE_GEOMETRY) {
|
||||
tree_draw_ctx.geo_tree_log = geo_log::GeoModifierLog::get_tree_log_for_node_editor(*snode);
|
||||
tree_draw_ctx.geo_log_by_zone =
|
||||
geo_log::GeoModifierLog::get_tree_log_by_zone_for_node_editor(*snode);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1144,13 +1145,22 @@ static char *node_socket_get_tooltip(const SpaceNode *snode,
|
|||
}
|
||||
}
|
||||
|
||||
if (ntree.type == NTREE_GEOMETRY && tree_draw_ctx.geo_tree_log != nullptr) {
|
||||
geo_log::GeoTreeLog *geo_tree_log = [&]() -> geo_log::GeoTreeLog * {
|
||||
const TreeZones *zones = ntree.zones();
|
||||
if (!zones) {
|
||||
return nullptr;
|
||||
}
|
||||
const TreeZone *zone = zones->get_zone_by_socket(socket);
|
||||
return tree_draw_ctx.geo_log_by_zone.lookup_default(zone, nullptr);
|
||||
}();
|
||||
|
||||
if (ntree.type == NTREE_GEOMETRY && geo_tree_log != nullptr) {
|
||||
if (!output.str().empty()) {
|
||||
output << ".\n\n";
|
||||
}
|
||||
|
||||
std::optional<std::string> socket_inspection_str = create_socket_inspection_string(
|
||||
tree_draw_ctx, socket);
|
||||
*geo_tree_log, socket);
|
||||
if (socket_inspection_str.has_value()) {
|
||||
output << *socket_inspection_str;
|
||||
}
|
||||
|
@ -1738,9 +1748,18 @@ static void node_add_error_message_button(const TreeDrawContext &tree_draw_ctx,
|
|||
return;
|
||||
}
|
||||
|
||||
geo_log::GeoTreeLog *geo_tree_log = [&]() -> geo_log::GeoTreeLog * {
|
||||
const TreeZones *zones = node.owner_tree().zones();
|
||||
if (!zones) {
|
||||
return nullptr;
|
||||
}
|
||||
const TreeZone *zone = zones->get_zone_by_node(node.identifier);
|
||||
return tree_draw_ctx.geo_log_by_zone.lookup_default(zone, nullptr);
|
||||
}();
|
||||
|
||||
Span<geo_log::NodeWarning> warnings;
|
||||
if (tree_draw_ctx.geo_tree_log) {
|
||||
geo_log::GeoNodeLog *node_log = tree_draw_ctx.geo_tree_log->nodes.lookup_ptr(node.identifier);
|
||||
if (geo_tree_log) {
|
||||
geo_log::GeoNodeLog *node_log = geo_tree_log->nodes.lookup_ptr(node.identifier);
|
||||
if (node_log != nullptr) {
|
||||
warnings = node_log->warnings;
|
||||
}
|
||||
|
@ -1778,7 +1797,15 @@ static void node_add_error_message_button(const TreeDrawContext &tree_draw_ctx,
|
|||
static std::optional<std::chrono::nanoseconds> node_get_execution_time(
|
||||
const TreeDrawContext &tree_draw_ctx, const bNodeTree &ntree, const bNode &node)
|
||||
{
|
||||
const geo_log::GeoTreeLog *tree_log = tree_draw_ctx.geo_tree_log;
|
||||
geo_log::GeoTreeLog *tree_log = [&]() -> geo_log::GeoTreeLog * {
|
||||
const TreeZones *zones = ntree.zones();
|
||||
if (!zones) {
|
||||
return nullptr;
|
||||
}
|
||||
const TreeZone *zone = zones->get_zone_by_node(node.identifier);
|
||||
return tree_draw_ctx.geo_log_by_zone.lookup_default(zone, nullptr);
|
||||
}();
|
||||
|
||||
if (tree_log == nullptr) {
|
||||
return std::nullopt;
|
||||
}
|
||||
|
@ -1936,7 +1963,15 @@ static NodeExtraInfoRow row_from_used_named_attribute(
|
|||
static std::optional<NodeExtraInfoRow> node_get_accessed_attributes_row(
|
||||
TreeDrawContext &tree_draw_ctx, const bNode &node)
|
||||
{
|
||||
if (tree_draw_ctx.geo_tree_log == nullptr) {
|
||||
geo_log::GeoTreeLog *geo_tree_log = [&]() -> geo_log::GeoTreeLog * {
|
||||
const TreeZones *zones = node.owner_tree().zones();
|
||||
if (!zones) {
|
||||
return nullptr;
|
||||
}
|
||||
const TreeZone *zone = zones->get_zone_by_node(node.identifier);
|
||||
return tree_draw_ctx.geo_log_by_zone.lookup_default(zone, nullptr);
|
||||
}();
|
||||
if (geo_tree_log == nullptr) {
|
||||
return std::nullopt;
|
||||
}
|
||||
if (ELEM(node.type,
|
||||
|
@ -1953,8 +1988,8 @@ static std::optional<NodeExtraInfoRow> node_get_accessed_attributes_row(
|
|||
}
|
||||
}
|
||||
}
|
||||
tree_draw_ctx.geo_tree_log->ensure_used_named_attributes();
|
||||
geo_log::GeoNodeLog *node_log = tree_draw_ctx.geo_tree_log->nodes.lookup_ptr(node.identifier);
|
||||
geo_tree_log->ensure_used_named_attributes();
|
||||
geo_log::GeoNodeLog *node_log = geo_tree_log->nodes.lookup_ptr(node.identifier);
|
||||
if (node_log == nullptr) {
|
||||
return std::nullopt;
|
||||
}
|
||||
|
@ -1998,7 +2033,16 @@ static Vector<NodeExtraInfoRow> node_get_extra_info(TreeDrawContext &tree_draw_c
|
|||
}
|
||||
|
||||
if (snode.edittree->type == NTREE_GEOMETRY) {
|
||||
if (geo_log::GeoTreeLog *tree_log = tree_draw_ctx.geo_tree_log) {
|
||||
geo_log::GeoTreeLog *tree_log = [&]() -> geo_log::GeoTreeLog * {
|
||||
const TreeZones *tree_zones = node.owner_tree().zones();
|
||||
if (!tree_zones) {
|
||||
return nullptr;
|
||||
}
|
||||
const TreeZone *zone = tree_zones->get_zone_by_node(node.identifier);
|
||||
return tree_draw_ctx.geo_log_by_zone.lookup_default(zone, nullptr);
|
||||
}();
|
||||
|
||||
if (tree_log) {
|
||||
tree_log->ensure_debug_messages();
|
||||
const geo_log::GeoNodeLog *node_log = tree_log->nodes.lookup_ptr(node.identifier);
|
||||
if (node_log != nullptr) {
|
||||
|
@ -3126,7 +3170,7 @@ static void node_draw_zones(TreeDrawContext & /*tree_draw_ctx*/,
|
|||
const SpaceNode &snode,
|
||||
const bNodeTree &ntree)
|
||||
{
|
||||
const TreeZones *zones = bke::node_tree_zones::get_tree_zones(ntree);
|
||||
const TreeZones *zones = ntree.zones();
|
||||
if (zones == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
@ -3368,10 +3412,11 @@ static void draw_nodetree(const bContext &C,
|
|||
|
||||
TreeDrawContext tree_draw_ctx;
|
||||
if (ntree.type == NTREE_GEOMETRY) {
|
||||
tree_draw_ctx.geo_tree_log = geo_log::GeoModifierLog::get_tree_log_for_node_editor(*snode);
|
||||
if (tree_draw_ctx.geo_tree_log != nullptr) {
|
||||
tree_draw_ctx.geo_tree_log->ensure_node_warnings();
|
||||
tree_draw_ctx.geo_tree_log->ensure_node_run_time();
|
||||
tree_draw_ctx.geo_log_by_zone = geo_log::GeoModifierLog::get_tree_log_by_zone_for_node_editor(
|
||||
*snode);
|
||||
for (geo_log::GeoTreeLog *log : tree_draw_ctx.geo_log_by_zone.values()) {
|
||||
log->ensure_node_warnings();
|
||||
log->ensure_node_run_time();
|
||||
}
|
||||
const WorkSpace *workspace = CTX_wm_workspace(&C);
|
||||
tree_draw_ctx.active_geometry_nodes_viewer = viewer_path::find_geometry_nodes_viewer(
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
#include "BKE_context.h"
|
||||
#include "BKE_node_runtime.hh"
|
||||
#include "BKE_node_tree_update.h"
|
||||
#include "BKE_node_tree_zones.hh"
|
||||
#include "BKE_object.h"
|
||||
|
||||
#include "RNA_access.h"
|
||||
|
@ -41,6 +42,8 @@ using blender::nodes::geo_eval_log::GeometryAttributeInfo;
|
|||
|
||||
namespace blender::ed::space_node {
|
||||
|
||||
using namespace bke::node_tree_zones;
|
||||
|
||||
struct AttributeSearchData {
|
||||
int32_t node_id;
|
||||
char socket_identifier[MAX_NAME];
|
||||
|
@ -69,23 +72,33 @@ static Vector<const GeometryAttributeInfo *> get_attribute_info_from_context(
|
|||
BLI_assert_unreachable();
|
||||
return {};
|
||||
}
|
||||
GeoTreeLog *tree_log = GeoModifierLog::get_tree_log_for_node_editor(*snode);
|
||||
if (tree_log == nullptr) {
|
||||
const TreeZones *tree_zones = node_tree->zones();
|
||||
if (!tree_zones) {
|
||||
return {};
|
||||
}
|
||||
tree_log->ensure_socket_values();
|
||||
const Map<const TreeZone *, GeoTreeLog *> log_by_zone =
|
||||
GeoModifierLog::get_tree_log_by_zone_for_node_editor(*snode);
|
||||
|
||||
/* For the attribute input node, collect attribute information from all nodes in the group. */
|
||||
if (node->type == GEO_NODE_INPUT_NAMED_ATTRIBUTE) {
|
||||
tree_log->ensure_existing_attributes();
|
||||
Vector<const GeometryAttributeInfo *> attributes;
|
||||
for (const GeometryAttributeInfo *attribute : tree_log->existing_attributes) {
|
||||
if (bke::allow_procedural_attribute_access(attribute->name)) {
|
||||
attributes.append(attribute);
|
||||
for (GeoTreeLog *tree_log : log_by_zone.values()) {
|
||||
tree_log->ensure_socket_values();
|
||||
tree_log->ensure_existing_attributes();
|
||||
for (const GeometryAttributeInfo *attribute : tree_log->existing_attributes) {
|
||||
if (bke::allow_procedural_attribute_access(attribute->name)) {
|
||||
attributes.append(attribute);
|
||||
}
|
||||
}
|
||||
}
|
||||
return attributes;
|
||||
}
|
||||
const TreeZone *zone = tree_zones->get_zone_by_node(node->identifier);
|
||||
GeoTreeLog *tree_log = log_by_zone.lookup_default(zone, nullptr);
|
||||
if (!tree_log) {
|
||||
return {};
|
||||
}
|
||||
tree_log->ensure_socket_values();
|
||||
GeoNodeLog *node_log = tree_log->nodes.lookup_ptr(node->identifier);
|
||||
if (node_log == nullptr) {
|
||||
return {};
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
#include "BKE_context.h"
|
||||
#include "BKE_main.h"
|
||||
#include "BKE_node_runtime.hh"
|
||||
#include "BKE_node_tree_zones.hh"
|
||||
#include "BKE_workspace.h"
|
||||
|
||||
#include "BLI_listbase.h"
|
||||
|
@ -22,6 +23,8 @@
|
|||
|
||||
namespace blender::ed::viewer_path {
|
||||
|
||||
using namespace bke::node_tree_zones;
|
||||
|
||||
static void viewer_path_for_geometry_node(const SpaceNode &snode,
|
||||
const bNode &node,
|
||||
ViewerPath &r_dst)
|
||||
|
@ -55,27 +58,56 @@ static void viewer_path_for_geometry_node(const SpaceNode &snode,
|
|||
modifier = nmd;
|
||||
}
|
||||
}
|
||||
if (modifier != nullptr) {
|
||||
ModifierViewerPathElem *modifier_elem = BKE_viewer_path_elem_new_modifier();
|
||||
modifier_elem->modifier_name = BLI_strdup(modifier->modifier.name);
|
||||
BLI_addtail(&r_dst.path, modifier_elem);
|
||||
if (modifier == nullptr) {
|
||||
return;
|
||||
}
|
||||
ModifierViewerPathElem *modifier_elem = BKE_viewer_path_elem_new_modifier();
|
||||
modifier_elem->modifier_name = BLI_strdup(modifier->modifier.name);
|
||||
BLI_addtail(&r_dst.path, modifier_elem);
|
||||
|
||||
Vector<const bNodeTreePath *, 16> tree_path = snode.treepath;
|
||||
for (const int i : tree_path.index_range().drop_back(1)) {
|
||||
bNodeTree *tree = tree_path[i]->nodetree;
|
||||
/* The tree path contains the name of the node but not its ID. */
|
||||
const bNode *node = nodeFindNodebyName(tree_path[i]->nodetree, tree_path[i + 1]->node_name);
|
||||
const char *node_name = tree_path[i + 1]->node_name;
|
||||
const bNode *node = nodeFindNodebyName(tree, node_name);
|
||||
/* The name in the tree path should match a group node in the tree. */
|
||||
BLI_assert(node != nullptr);
|
||||
NodeViewerPathElem *node_elem = BKE_viewer_path_elem_new_node();
|
||||
|
||||
tree->ensure_topology_cache();
|
||||
const TreeZones *tree_zones = tree->zones();
|
||||
if (!tree_zones) {
|
||||
return;
|
||||
}
|
||||
const Vector<const TreeZone *> zone_stack = tree_zones->get_zone_stack_for_node(
|
||||
node->identifier);
|
||||
for (const TreeZone *zone : zone_stack) {
|
||||
SimulationZoneViewerPathElem *node_elem = BKE_viewer_path_elem_new_simulation_zone();
|
||||
node_elem->sim_output_node_id = zone->output_node->identifier;
|
||||
BLI_addtail(&r_dst.path, node_elem);
|
||||
}
|
||||
|
||||
GroupNodeViewerPathElem *node_elem = BKE_viewer_path_elem_new_group_node();
|
||||
node_elem->node_id = node->identifier;
|
||||
node_elem->node_name = BLI_strdup(node->name);
|
||||
node_elem->base.ui_name = BLI_strdup(node->name);
|
||||
BLI_addtail(&r_dst.path, node_elem);
|
||||
}
|
||||
|
||||
NodeViewerPathElem *viewer_node_elem = BKE_viewer_path_elem_new_node();
|
||||
snode.edittree->ensure_topology_cache();
|
||||
const TreeZones *tree_zones = snode.edittree->zones();
|
||||
if (!tree_zones) {
|
||||
return;
|
||||
}
|
||||
const Vector<const TreeZone *> zone_stack = tree_zones->get_zone_stack_for_node(node.identifier);
|
||||
for (const TreeZone *zone : zone_stack) {
|
||||
SimulationZoneViewerPathElem *node_elem = BKE_viewer_path_elem_new_simulation_zone();
|
||||
node_elem->sim_output_node_id = zone->output_node->identifier;
|
||||
BLI_addtail(&r_dst.path, node_elem);
|
||||
}
|
||||
|
||||
ViewerNodeViewerPathElem *viewer_node_elem = BKE_viewer_path_elem_new_viewer_node();
|
||||
viewer_node_elem->node_id = node.identifier;
|
||||
viewer_node_elem->node_name = BLI_strdup(node.name);
|
||||
viewer_node_elem->base.ui_name = BLI_strdup(node.name);
|
||||
BLI_addtail(&r_dst.path, viewer_node_elem);
|
||||
}
|
||||
|
||||
|
@ -185,16 +217,21 @@ std::optional<ViewerPathForGeometryNodesViewer> parse_geometry_nodes_viewer(
|
|||
return std::nullopt;
|
||||
}
|
||||
remaining_elems = remaining_elems.drop_front(1);
|
||||
Vector<int32_t> node_ids;
|
||||
for (const ViewerPathElem *elem : remaining_elems) {
|
||||
if (elem->type != VIEWER_PATH_ELEM_TYPE_NODE) {
|
||||
Vector<const ViewerPathElem *> node_path;
|
||||
for (const ViewerPathElem *elem : remaining_elems.drop_back(1)) {
|
||||
if (!ELEM(elem->type, VIEWER_PATH_ELEM_TYPE_GROUP_NODE, VIEWER_PATH_ELEM_TYPE_SIMULATION_ZONE))
|
||||
{
|
||||
return std::nullopt;
|
||||
}
|
||||
const int32_t node_id = reinterpret_cast<const NodeViewerPathElem *>(elem)->node_id;
|
||||
node_ids.append(node_id);
|
||||
node_path.append(elem);
|
||||
}
|
||||
const int32_t viewer_node_id = node_ids.pop_last();
|
||||
return ViewerPathForGeometryNodesViewer{root_ob, modifier_name, node_ids, viewer_node_id};
|
||||
const ViewerPathElem *last_elem = remaining_elems.last();
|
||||
if (last_elem->type != VIEWER_PATH_ELEM_TYPE_VIEWER_NODE) {
|
||||
return std::nullopt;
|
||||
}
|
||||
const int32_t viewer_node_id =
|
||||
reinterpret_cast<const ViewerNodeViewerPathElem *>(last_elem)->node_id;
|
||||
return ViewerPathForGeometryNodesViewer{root_ob, modifier_name, node_path, viewer_node_id};
|
||||
}
|
||||
|
||||
bool exists_geometry_nodes_viewer(const ViewerPathForGeometryNodesViewer &parsed_viewer_path)
|
||||
|
@ -217,81 +254,72 @@ bool exists_geometry_nodes_viewer(const ViewerPathForGeometryNodesViewer &parsed
|
|||
return false;
|
||||
}
|
||||
const bNodeTree *ngroup = modifier->node_group;
|
||||
ngroup->ensure_topology_cache();
|
||||
for (const int32_t group_node_id : parsed_viewer_path.group_node_ids) {
|
||||
const bNode *group_node = nullptr;
|
||||
for (const bNode *node : ngroup->group_nodes()) {
|
||||
if (node->identifier != group_node_id) {
|
||||
continue;
|
||||
const TreeZone *zone = nullptr;
|
||||
for (const ViewerPathElem *path_elem : parsed_viewer_path.node_path) {
|
||||
ngroup->ensure_topology_cache();
|
||||
const TreeZones *tree_zones = ngroup->zones();
|
||||
switch (path_elem->type) {
|
||||
case VIEWER_PATH_ELEM_TYPE_SIMULATION_ZONE: {
|
||||
const auto &typed_elem = *reinterpret_cast<const SimulationZoneViewerPathElem *>(
|
||||
path_elem);
|
||||
const TreeZone *next_zone = tree_zones->get_zone_by_node(typed_elem.sim_output_node_id);
|
||||
if (next_zone == nullptr) {
|
||||
return false;
|
||||
}
|
||||
if (next_zone->parent_zone != zone) {
|
||||
return false;
|
||||
}
|
||||
zone = next_zone;
|
||||
break;
|
||||
}
|
||||
case VIEWER_PATH_ELEM_TYPE_GROUP_NODE: {
|
||||
const auto &typed_elem = *reinterpret_cast<const GroupNodeViewerPathElem *>(path_elem);
|
||||
const bNode *group_node = ngroup->node_by_id(typed_elem.node_id);
|
||||
if (group_node == nullptr) {
|
||||
return false;
|
||||
}
|
||||
const TreeZone *parent_zone = tree_zones->get_zone_by_node(typed_elem.node_id);
|
||||
if (parent_zone != zone) {
|
||||
return false;
|
||||
}
|
||||
if (group_node->id == nullptr) {
|
||||
return false;
|
||||
}
|
||||
ngroup = reinterpret_cast<const bNodeTree *>(group_node->id);
|
||||
zone = nullptr;
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
BLI_assert_unreachable();
|
||||
}
|
||||
group_node = node;
|
||||
break;
|
||||
}
|
||||
if (group_node == nullptr) {
|
||||
return false;
|
||||
}
|
||||
if (group_node->id == nullptr) {
|
||||
return false;
|
||||
}
|
||||
ngroup = reinterpret_cast<const bNodeTree *>(group_node->id);
|
||||
}
|
||||
const bNode *viewer_node = nullptr;
|
||||
for (const bNode *node : ngroup->nodes_by_type("GeometryNodeViewer")) {
|
||||
if (node->identifier != parsed_viewer_path.viewer_node_id) {
|
||||
continue;
|
||||
}
|
||||
viewer_node = node;
|
||||
break;
|
||||
}
|
||||
|
||||
const bNode *viewer_node = ngroup->node_by_id(parsed_viewer_path.viewer_node_id);
|
||||
if (viewer_node == nullptr) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool viewer_path_matches_node_editor_path(
|
||||
const SpaceNode &snode, const ViewerPathForGeometryNodesViewer &parsed_viewer_path)
|
||||
{
|
||||
Vector<const bNodeTreePath *, 16> tree_path = snode.treepath;
|
||||
if (tree_path.size() != parsed_viewer_path.group_node_ids.size() + 1) {
|
||||
const TreeZones *tree_zones = ngroup->zones();
|
||||
if (tree_zones == nullptr) {
|
||||
return false;
|
||||
}
|
||||
for (const int i : parsed_viewer_path.group_node_ids.index_range()) {
|
||||
const bNode *node = tree_path[i]->nodetree->node_by_id(parsed_viewer_path.group_node_ids[i]);
|
||||
if (!node) {
|
||||
return false;
|
||||
}
|
||||
if (!STREQ(node->name, tree_path[i + 1]->node_name)) {
|
||||
return false;
|
||||
}
|
||||
if (tree_zones->get_zone_by_node(viewer_node->identifier) != zone) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool is_active_geometry_nodes_viewer(const bContext &C,
|
||||
const ViewerPathForGeometryNodesViewer &parsed_viewer_path)
|
||||
bool is_active_geometry_nodes_viewer(const bContext &C, const ViewerPath &viewer_path)
|
||||
{
|
||||
const NodesModifierData *modifier = nullptr;
|
||||
LISTBASE_FOREACH (const ModifierData *, md, &parsed_viewer_path.object->modifiers) {
|
||||
if (md->name != parsed_viewer_path.modifier_name) {
|
||||
continue;
|
||||
}
|
||||
if (md->type != eModifierType_Nodes) {
|
||||
return false;
|
||||
}
|
||||
if ((md->mode & eModifierMode_Realtime) == 0) {
|
||||
return false;
|
||||
}
|
||||
modifier = reinterpret_cast<const NodesModifierData *>(md);
|
||||
break;
|
||||
}
|
||||
if (modifier == nullptr) {
|
||||
if (BLI_listbase_is_empty(&viewer_path.path)) {
|
||||
return false;
|
||||
}
|
||||
if (modifier->node_group == nullptr) {
|
||||
const ViewerPathElem *last_elem = static_cast<ViewerPathElem *>(viewer_path.path.last);
|
||||
if (last_elem->type != VIEWER_PATH_ELEM_TYPE_VIEWER_NODE) {
|
||||
return false;
|
||||
}
|
||||
const bool modifier_is_active = modifier->modifier.flag & eModifierFlag_Active;
|
||||
const int32_t viewer_node_id =
|
||||
reinterpret_cast<const ViewerNodeViewerPathElem *>(last_elem)->node_id;
|
||||
|
||||
const Main *bmain = CTX_data_main(&C);
|
||||
const wmWindowManager *wm = static_cast<wmWindowManager *>(bmain->wm.first);
|
||||
|
@ -315,30 +343,26 @@ bool is_active_geometry_nodes_viewer(const bContext &C,
|
|||
continue;
|
||||
}
|
||||
const SpaceNode &snode = *reinterpret_cast<const SpaceNode *>(sl);
|
||||
if (!modifier_is_active) {
|
||||
if (!(snode.flag & SNODE_PIN)) {
|
||||
/* Node tree has to be pinned when the modifier is not active. */
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (snode.id != &parsed_viewer_path.object->id) {
|
||||
if (snode.edittree == nullptr) {
|
||||
continue;
|
||||
}
|
||||
if (snode.nodetree != modifier->node_group) {
|
||||
if (snode.edittree->type != NTREE_GEOMETRY) {
|
||||
continue;
|
||||
}
|
||||
if (!viewer_path_matches_node_editor_path(snode, parsed_viewer_path)) {
|
||||
continue;
|
||||
}
|
||||
const bNodeTree *ngroup = snode.edittree;
|
||||
ngroup->ensure_topology_cache();
|
||||
const bNode *viewer_node = ngroup->node_by_id(parsed_viewer_path.viewer_node_id);
|
||||
snode.edittree->ensure_topology_cache();
|
||||
const bNode *viewer_node = snode.edittree->node_by_id(viewer_node_id);
|
||||
if (viewer_node == nullptr) {
|
||||
continue;
|
||||
}
|
||||
if (!(viewer_node->flag & NODE_DO_OUTPUT)) {
|
||||
continue;
|
||||
}
|
||||
ViewerPath tmp_viewer_path{};
|
||||
BLI_SCOPED_DEFER([&]() { BKE_viewer_path_clear(&tmp_viewer_path); });
|
||||
viewer_path_for_geometry_node(snode, *viewer_node, tmp_viewer_path);
|
||||
if (!BKE_viewer_path_equal(&viewer_path, &tmp_viewer_path)) {
|
||||
continue;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -30,7 +30,13 @@ namespace blender::bke {
|
|||
class bNodeTreeRuntime;
|
||||
class bNodeRuntime;
|
||||
class bNodeSocketRuntime;
|
||||
class bNodeZones;
|
||||
class bNodeZone;
|
||||
} // namespace blender::bke
|
||||
namespace blender::bke::node_tree_zones {
|
||||
class TreeZones;
|
||||
struct TreeZone;
|
||||
} // namespace blender::bke::node_tree_zones
|
||||
using NodeDeclarationHandle = blender::nodes::NodeDeclaration;
|
||||
using SocketDeclarationHandle = blender::nodes::SocketDeclaration;
|
||||
using bNodeTreeRuntimeHandle = blender::bke::bNodeTreeRuntime;
|
||||
|
@ -677,6 +683,8 @@ typedef struct bNodeTree {
|
|||
|
||||
blender::Span<const bNodePanel *> panels() const;
|
||||
blender::MutableSpan<bNodePanel *> panels_for_write();
|
||||
/** Zones in the node tree. Currently there are only simulation zones in geometry nodes. */
|
||||
const blender::bke::node_tree_zones::TreeZones *zones() const;
|
||||
#endif
|
||||
} bNodeTree;
|
||||
|
||||
|
|
|
@ -12,13 +12,16 @@ struct ID;
|
|||
typedef enum ViewerPathElemType {
|
||||
VIEWER_PATH_ELEM_TYPE_ID = 0,
|
||||
VIEWER_PATH_ELEM_TYPE_MODIFIER = 1,
|
||||
VIEWER_PATH_ELEM_TYPE_NODE = 2,
|
||||
VIEWER_PATH_ELEM_TYPE_GROUP_NODE = 2,
|
||||
VIEWER_PATH_ELEM_TYPE_SIMULATION_ZONE = 3,
|
||||
VIEWER_PATH_ELEM_TYPE_VIEWER_NODE = 4,
|
||||
} ViewerPathElemType;
|
||||
|
||||
typedef struct ViewerPathElem {
|
||||
struct ViewerPathElem *next, *prev;
|
||||
int type;
|
||||
char _pad[4];
|
||||
char *ui_name;
|
||||
} ViewerPathElem;
|
||||
|
||||
typedef struct IDViewerPathElem {
|
||||
|
@ -31,18 +34,26 @@ typedef struct ModifierViewerPathElem {
|
|||
char *modifier_name;
|
||||
} ModifierViewerPathElem;
|
||||
|
||||
typedef struct NodeViewerPathElem {
|
||||
typedef struct GroupNodeViewerPathElem {
|
||||
ViewerPathElem base;
|
||||
|
||||
int32_t node_id;
|
||||
char _pad1[4];
|
||||
} GroupNodeViewerPathElem;
|
||||
|
||||
/**
|
||||
* The name of the node with the identifier. Not used to lookup nodes, only for display
|
||||
* in the UI. Still stored here to avoid looking up the name for every redraw.
|
||||
*/
|
||||
char *node_name;
|
||||
} NodeViewerPathElem;
|
||||
typedef struct SimulationZoneViewerPathElem {
|
||||
ViewerPathElem base;
|
||||
|
||||
int32_t sim_output_node_id;
|
||||
char _pad1[4];
|
||||
} SimulationZoneViewerPathElem;
|
||||
|
||||
typedef struct ViewerNodeViewerPathElem {
|
||||
ViewerPathElem base;
|
||||
|
||||
int32_t node_id;
|
||||
char _pad1[4];
|
||||
} ViewerNodeViewerPathElem;
|
||||
|
||||
typedef struct ViewerPath {
|
||||
/** List of #ViewerPathElem. */
|
||||
|
|
|
@ -3331,8 +3331,12 @@ static StructRNA *rna_viewer_path_elem_refine(PointerRNA *ptr)
|
|||
return &RNA_IDViewerPathElem;
|
||||
case VIEWER_PATH_ELEM_TYPE_MODIFIER:
|
||||
return &RNA_ModifierViewerPathElem;
|
||||
case VIEWER_PATH_ELEM_TYPE_NODE:
|
||||
return &RNA_NodeViewerPathElem;
|
||||
case VIEWER_PATH_ELEM_TYPE_GROUP_NODE:
|
||||
return &RNA_GroupNodeViewerPathElem;
|
||||
case VIEWER_PATH_ELEM_TYPE_SIMULATION_ZONE:
|
||||
return &RNA_SimulationZoneViewerPathElem;
|
||||
case VIEWER_PATH_ELEM_TYPE_VIEWER_NODE:
|
||||
return &RNA_ViewerNodeViewerPathElem;
|
||||
}
|
||||
BLI_assert_unreachable();
|
||||
return nullptr;
|
||||
|
@ -8049,7 +8053,9 @@ static void rna_def_spreadsheet_row_filter(BlenderRNA *brna)
|
|||
static const EnumPropertyItem viewer_path_elem_type_items[] = {
|
||||
{VIEWER_PATH_ELEM_TYPE_ID, "ID", ICON_NONE, "ID", ""},
|
||||
{VIEWER_PATH_ELEM_TYPE_MODIFIER, "MODIFIER", ICON_NONE, "Modifier", ""},
|
||||
{VIEWER_PATH_ELEM_TYPE_NODE, "NODE", ICON_NONE, "Node", ""},
|
||||
{VIEWER_PATH_ELEM_TYPE_GROUP_NODE, "GROUP_NODE", ICON_NONE, "Group Node", ""},
|
||||
{VIEWER_PATH_ELEM_TYPE_SIMULATION_ZONE, "SIMULATION_ZONE", ICON_NONE, "Simulation Zone", ""},
|
||||
{VIEWER_PATH_ELEM_TYPE_VIEWER_NODE, "VIEWER_NODE", ICON_NONE, "Viewer Node", ""},
|
||||
{0, nullptr, 0, nullptr, nullptr},
|
||||
};
|
||||
|
||||
|
@ -8066,6 +8072,11 @@ static void rna_def_viewer_path_elem(BlenderRNA *brna)
|
|||
RNA_def_property_enum_items(prop, viewer_path_elem_type_items);
|
||||
RNA_def_property_ui_text(prop, "Type", "Type of the path element");
|
||||
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
|
||||
|
||||
prop = RNA_def_property(srna, "ui_name", PROP_STRING, PROP_NONE);
|
||||
RNA_def_property_ui_text(
|
||||
prop, "UI Name", "Name that can be displayed in the UI for this element");
|
||||
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
|
||||
}
|
||||
|
||||
static void rna_def_id_viewer_path_elem(BlenderRNA *brna)
|
||||
|
@ -8090,15 +8101,37 @@ static void rna_def_modifier_viewer_path_elem(BlenderRNA *brna)
|
|||
RNA_def_property_ui_text(prop, "Modifier Name", "");
|
||||
}
|
||||
|
||||
static void rna_def_node_viewer_path_elem(BlenderRNA *brna)
|
||||
static void rna_def_group_node_viewer_path_elem(BlenderRNA *brna)
|
||||
{
|
||||
StructRNA *srna;
|
||||
PropertyRNA *prop;
|
||||
|
||||
srna = RNA_def_struct(brna, "NodeViewerPathElem", "ViewerPathElem");
|
||||
srna = RNA_def_struct(brna, "GroupNodeViewerPathElem", "ViewerPathElem");
|
||||
|
||||
prop = RNA_def_property(srna, "node_name", PROP_STRING, PROP_NONE);
|
||||
RNA_def_property_ui_text(prop, "Node Name", "");
|
||||
prop = RNA_def_property(srna, "node_id", PROP_INT, PROP_NONE);
|
||||
RNA_def_property_ui_text(prop, "Node ID", "");
|
||||
}
|
||||
|
||||
static void rna_def_simulation_zone_viewer_path_elem(BlenderRNA *brna)
|
||||
{
|
||||
StructRNA *srna;
|
||||
PropertyRNA *prop;
|
||||
|
||||
srna = RNA_def_struct(brna, "SimulationZoneViewerPathElem", "ViewerPathElem");
|
||||
|
||||
prop = RNA_def_property(srna, "sim_output_node_id", PROP_INT, PROP_NONE);
|
||||
RNA_def_property_ui_text(prop, "Simulation Output Node ID", "");
|
||||
}
|
||||
|
||||
static void rna_def_viewer_node_viewer_path_elem(BlenderRNA *brna)
|
||||
{
|
||||
StructRNA *srna;
|
||||
PropertyRNA *prop;
|
||||
|
||||
srna = RNA_def_struct(brna, "ViewerNodeViewerPathElem", "ViewerPathElem");
|
||||
|
||||
prop = RNA_def_property(srna, "node_id", PROP_INT, PROP_NONE);
|
||||
RNA_def_property_ui_text(prop, "Node ID", "");
|
||||
}
|
||||
|
||||
static void rna_def_viewer_path(BlenderRNA *brna)
|
||||
|
@ -8109,7 +8142,9 @@ static void rna_def_viewer_path(BlenderRNA *brna)
|
|||
rna_def_viewer_path_elem(brna);
|
||||
rna_def_id_viewer_path_elem(brna);
|
||||
rna_def_modifier_viewer_path_elem(brna);
|
||||
rna_def_node_viewer_path_elem(brna);
|
||||
rna_def_group_node_viewer_path_elem(brna);
|
||||
rna_def_simulation_zone_viewer_path_elem(brna);
|
||||
rna_def_viewer_node_viewer_path_elem(brna);
|
||||
|
||||
srna = RNA_def_struct(brna, "ViewerPath", nullptr);
|
||||
RNA_def_struct_ui_text(srna, "Viewer Path", "Path to data that is viewed");
|
||||
|
|
|
@ -424,31 +424,14 @@ void MOD_nodes_update_interface(Object *object, NodesModifierData *nmd)
|
|||
|
||||
namespace blender {
|
||||
|
||||
static const lf::FunctionNode *find_viewer_lf_node(const bNode &viewer_bnode)
|
||||
{
|
||||
if (const nodes::GeometryNodesLazyFunctionGraphInfo *lf_graph_info =
|
||||
nodes::ensure_geometry_nodes_lazy_function_graph(viewer_bnode.owner_tree()))
|
||||
{
|
||||
return lf_graph_info->mapping.viewer_node_map.lookup_default(&viewer_bnode, nullptr);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
static const lf::FunctionNode *find_group_lf_node(const bNode &group_bnode)
|
||||
{
|
||||
if (const nodes::GeometryNodesLazyFunctionGraphInfo *lf_graph_info =
|
||||
nodes::ensure_geometry_nodes_lazy_function_graph(group_bnode.owner_tree()))
|
||||
{
|
||||
return lf_graph_info->mapping.group_node_map.lookup_default(&group_bnode, nullptr);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
static void find_side_effect_nodes_for_viewer_path(
|
||||
const ViewerPath &viewer_path,
|
||||
const NodesModifierData &nmd,
|
||||
const ModifierEvalContext &ctx,
|
||||
MultiValueMap<ComputeContextHash, const lf::FunctionNode *> &r_side_effect_nodes)
|
||||
{
|
||||
using namespace bke::node_tree_zones;
|
||||
|
||||
const std::optional<ed::viewer_path::ViewerPathForGeometryNodesViewer> parsed_path =
|
||||
ed::viewer_path::parse_geometry_nodes_viewer(viewer_path);
|
||||
if (!parsed_path.has_value()) {
|
||||
|
@ -464,45 +447,100 @@ static void find_side_effect_nodes_for_viewer_path(
|
|||
ComputeContextBuilder compute_context_builder;
|
||||
compute_context_builder.push<bke::ModifierComputeContext>(parsed_path->modifier_name);
|
||||
|
||||
/* Write side effect nodes to a new map and only if everything succeeds, move the nodes to the
|
||||
* caller. This is easier than changing r_side_effect_nodes directly and then undoing changes in
|
||||
* case of errors. */
|
||||
MultiValueMap<ComputeContextHash, const lf::FunctionNode *> local_side_effect_nodes;
|
||||
|
||||
const bNodeTree *group = nmd.node_group;
|
||||
Stack<const bNode *> group_node_stack;
|
||||
for (const int32_t group_node_id : parsed_path->group_node_ids) {
|
||||
const bNode *found_node = group->node_by_id(group_node_id);
|
||||
if (found_node == nullptr) {
|
||||
const TreeZone *zone = nullptr;
|
||||
for (const ViewerPathElem *elem : parsed_path->node_path) {
|
||||
const TreeZones *tree_zones = group->zones();
|
||||
if (tree_zones == nullptr) {
|
||||
return;
|
||||
}
|
||||
if (found_node->id == nullptr) {
|
||||
const auto *lf_graph_info = nodes::ensure_geometry_nodes_lazy_function_graph(*group);
|
||||
if (lf_graph_info == nullptr) {
|
||||
return;
|
||||
}
|
||||
if (found_node->is_muted()) {
|
||||
return;
|
||||
switch (elem->type) {
|
||||
case VIEWER_PATH_ELEM_TYPE_SIMULATION_ZONE: {
|
||||
const auto &typed_elem = *reinterpret_cast<const SimulationZoneViewerPathElem *>(elem);
|
||||
const TreeZone *next_zone = tree_zones->get_zone_by_node(typed_elem.sim_output_node_id);
|
||||
if (next_zone == nullptr) {
|
||||
return;
|
||||
}
|
||||
if (next_zone->parent_zone != zone) {
|
||||
return;
|
||||
}
|
||||
const lf::FunctionNode *lf_zone_node = lf_graph_info->mapping.zone_node_map.lookup_default(
|
||||
next_zone, nullptr);
|
||||
if (lf_zone_node == nullptr) {
|
||||
return;
|
||||
}
|
||||
local_side_effect_nodes.add(compute_context_builder.hash(), lf_zone_node);
|
||||
compute_context_builder.push<bke::SimulationZoneComputeContext>(*next_zone->output_node);
|
||||
zone = next_zone;
|
||||
break;
|
||||
}
|
||||
case VIEWER_PATH_ELEM_TYPE_GROUP_NODE: {
|
||||
const auto &typed_elem = *reinterpret_cast<const GroupNodeViewerPathElem *>(elem);
|
||||
const bNode *node = group->node_by_id(typed_elem.node_id);
|
||||
if (node == nullptr) {
|
||||
return;
|
||||
}
|
||||
if (node->id == nullptr) {
|
||||
return;
|
||||
}
|
||||
if (node->is_muted()) {
|
||||
return;
|
||||
}
|
||||
if (zone != tree_zones->get_zone_by_node(node->identifier)) {
|
||||
return;
|
||||
}
|
||||
const lf::FunctionNode *lf_group_node =
|
||||
lf_graph_info->mapping.group_node_map.lookup_default(node, nullptr);
|
||||
if (lf_group_node == nullptr) {
|
||||
return;
|
||||
}
|
||||
local_side_effect_nodes.add(compute_context_builder.hash(), lf_group_node);
|
||||
compute_context_builder.push<bke::NodeGroupComputeContext>(*node);
|
||||
group = reinterpret_cast<const bNodeTree *>(node->id);
|
||||
zone = nullptr;
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
BLI_assert_unreachable();
|
||||
return;
|
||||
}
|
||||
}
|
||||
group_node_stack.push(found_node);
|
||||
group = reinterpret_cast<bNodeTree *>(found_node->id);
|
||||
compute_context_builder.push<bke::NodeGroupComputeContext>(*found_node);
|
||||
}
|
||||
|
||||
const bNode *found_viewer_node = group->node_by_id(parsed_path->viewer_node_id);
|
||||
if (found_viewer_node == nullptr) {
|
||||
return;
|
||||
}
|
||||
const lf::FunctionNode *lf_viewer_node = find_viewer_lf_node(*found_viewer_node);
|
||||
const auto *lf_graph_info = nodes::ensure_geometry_nodes_lazy_function_graph(*group);
|
||||
if (lf_graph_info == nullptr) {
|
||||
return;
|
||||
}
|
||||
const TreeZones *tree_zones = group->zones();
|
||||
if (tree_zones == nullptr) {
|
||||
return;
|
||||
}
|
||||
if (tree_zones->get_zone_by_node(found_viewer_node->identifier) != zone) {
|
||||
return;
|
||||
}
|
||||
const lf::FunctionNode *lf_viewer_node = lf_graph_info->mapping.viewer_node_map.lookup_default(
|
||||
found_viewer_node, nullptr);
|
||||
if (lf_viewer_node == nullptr) {
|
||||
return;
|
||||
}
|
||||
local_side_effect_nodes.add(compute_context_builder.hash(), lf_viewer_node);
|
||||
|
||||
/* Not only mark the viewer node as having side effects, but also all group nodes it is contained
|
||||
* in. */
|
||||
r_side_effect_nodes.add_non_duplicates(compute_context_builder.hash(), lf_viewer_node);
|
||||
compute_context_builder.pop();
|
||||
while (!compute_context_builder.is_empty()) {
|
||||
const lf::FunctionNode *lf_group_node = find_group_lf_node(*group_node_stack.pop());
|
||||
if (lf_group_node == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
r_side_effect_nodes.add_non_duplicates(compute_context_builder.hash(), lf_group_node);
|
||||
compute_context_builder.pop();
|
||||
/* Successfully found all compute contexts for the viewer. */
|
||||
for (const auto item : local_side_effect_nodes.items()) {
|
||||
r_side_effect_nodes.add_multiple(item.key, item.value);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -550,11 +588,11 @@ static void find_socket_log_contexts(const NodesModifierData &nmd,
|
|||
const SpaceLink *sl = static_cast<SpaceLink *>(area->spacedata.first);
|
||||
if (sl->spacetype == SPACE_NODE) {
|
||||
const SpaceNode &snode = *reinterpret_cast<const SpaceNode *>(sl);
|
||||
if (const std::optional<ComputeContextHash> hash =
|
||||
geo_log::GeoModifierLog::get_compute_context_hash_for_node_editor(
|
||||
snode, nmd.modifier.name))
|
||||
{
|
||||
r_socket_log_contexts.add(*hash);
|
||||
const Map<const bke::node_tree_zones::TreeZone *, ComputeContextHash> hash_by_zone =
|
||||
geo_log::GeoModifierLog::get_context_hash_by_zone_for_node_editor(snode,
|
||||
nmd.modifier.name);
|
||||
for (const ComputeContextHash &hash : hash_by_zone.values()) {
|
||||
r_socket_log_contexts.add(hash);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -28,6 +28,7 @@
|
|||
|
||||
#include "BLI_compute_context.hh"
|
||||
|
||||
#include "BKE_node_tree_zones.hh"
|
||||
#include "BKE_simulation_state.hh"
|
||||
|
||||
struct Object;
|
||||
|
@ -175,7 +176,7 @@ struct GeometryNodeLazyFunctionGraphMapping {
|
|||
*/
|
||||
Map<const bNode *, const lf::FunctionNode *> group_node_map;
|
||||
Map<const bNode *, const lf::FunctionNode *> viewer_node_map;
|
||||
Map<const bNode *, const lf::FunctionNode *> sim_output_node_map;
|
||||
Map<const bke::node_tree_zones::TreeZone *, const lf::FunctionNode *> zone_node_map;
|
||||
|
||||
/* Indexed by #bNodeSocket::index_in_all_outputs. */
|
||||
Array<int> lf_input_index_for_output_bsocket_usage;
|
||||
|
@ -190,29 +191,9 @@ struct GeometryNodeLazyFunctionGraphMapping {
|
|||
*/
|
||||
struct GeometryNodesLazyFunctionGraphInfo {
|
||||
/**
|
||||
* Allocator used for many things contained in this struct.
|
||||
* Contains resources that need to be freed when the graph is not needed anymore.
|
||||
*/
|
||||
LinearAllocator<> allocator;
|
||||
/**
|
||||
* Many nodes are implemented as multi-functions. So this contains a mapping from nodes to their
|
||||
* corresponding multi-functions.
|
||||
*/
|
||||
std::unique_ptr<NodeMultiFunctions> node_multi_functions;
|
||||
/**
|
||||
* Many lazy-functions are build for the lazy-function graph. Since the graph does not own them,
|
||||
* we have to keep track of them separately.
|
||||
*/
|
||||
Vector<std::unique_ptr<LazyFunction>> functions;
|
||||
/**
|
||||
* Debug info that has to be destructed when the graph is not used anymore.
|
||||
*/
|
||||
Vector<std::unique_ptr<lf::DummyDebugInfo>> dummy_debug_infos_;
|
||||
/**
|
||||
* Many sockets have default values. Since those are not owned by the lazy-function graph, we
|
||||
* have to keep track of them separately. This only owns the values, the memory is owned by the
|
||||
* allocator above.
|
||||
*/
|
||||
Vector<GMutablePointer> values_to_destruct;
|
||||
ResourceScope scope;
|
||||
/**
|
||||
* The actual lazy-function graph.
|
||||
*/
|
||||
|
@ -226,9 +207,6 @@ struct GeometryNodesLazyFunctionGraphInfo {
|
|||
* This can be used as a simple heuristic for the complexity of the node group.
|
||||
*/
|
||||
int num_inline_nodes_approximate = 0;
|
||||
|
||||
GeometryNodesLazyFunctionGraphInfo();
|
||||
~GeometryNodesLazyFunctionGraphInfo();
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
@ -37,6 +37,7 @@
|
|||
|
||||
#include "BKE_attribute.h"
|
||||
#include "BKE_geometry_set.hh"
|
||||
#include "BKE_node_tree_zones.hh"
|
||||
#include "BKE_viewer_path.h"
|
||||
|
||||
#include "FN_field.hh"
|
||||
|
@ -333,9 +334,11 @@ class GeoModifierLog {
|
|||
/**
|
||||
* Utility accessor to logged data.
|
||||
*/
|
||||
static std::optional<ComputeContextHash> get_compute_context_hash_for_node_editor(
|
||||
const SpaceNode &snode, StringRefNull modifier_name);
|
||||
static GeoTreeLog *get_tree_log_for_node_editor(const SpaceNode &snode);
|
||||
static Map<const bke::node_tree_zones::TreeZone *, ComputeContextHash>
|
||||
get_context_hash_by_zone_for_node_editor(const SpaceNode &snode, StringRefNull modifier_name);
|
||||
|
||||
static Map<const bke::node_tree_zones::TreeZone *, GeoTreeLog *>
|
||||
get_tree_log_by_zone_for_node_editor(const SpaceNode &snode);
|
||||
static const ViewerNodeLog *find_viewer_node_log_for_path(const ViewerPath &viewer_path);
|
||||
};
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -21,6 +21,7 @@ namespace blender::nodes::geo_eval_log {
|
|||
|
||||
using fn::FieldInput;
|
||||
using fn::FieldInputs;
|
||||
using namespace bke::node_tree_zones;
|
||||
|
||||
GenericValueLog::~GenericValueLog()
|
||||
{
|
||||
|
@ -518,46 +519,82 @@ static std::optional<ObjectAndModifier> get_modifier_for_node_editor(const Space
|
|||
return ObjectAndModifier{object, used_modifier};
|
||||
}
|
||||
|
||||
std::optional<ComputeContextHash> GeoModifierLog::get_compute_context_hash_for_node_editor(
|
||||
const SpaceNode &snode, const StringRefNull modifier_name)
|
||||
static void find_tree_zone_hash_recursive(
|
||||
const TreeZone &zone,
|
||||
ComputeContextBuilder &compute_context_builder,
|
||||
Map<const TreeZone *, ComputeContextHash> &r_hash_by_zone)
|
||||
{
|
||||
Vector<const bNodeTreePath *> tree_path = snode.treepath;
|
||||
if (tree_path.is_empty()) {
|
||||
return std::nullopt;
|
||||
compute_context_builder.push<bke::SimulationZoneComputeContext>(*zone.output_node);
|
||||
r_hash_by_zone.add_new(&zone, compute_context_builder.hash());
|
||||
for (const TreeZone *child_zone : zone.child_zones) {
|
||||
find_tree_zone_hash_recursive(*child_zone, compute_context_builder, r_hash_by_zone);
|
||||
}
|
||||
ComputeContextBuilder compute_context_builder;
|
||||
compute_context_builder.push<bke::ModifierComputeContext>(modifier_name);
|
||||
for (const int i : tree_path.index_range().drop_back(1)) {
|
||||
/* The tree path contains the name of the node but not its ID. */
|
||||
const bNode *node = nodeFindNodebyName(tree_path[i]->nodetree, tree_path[i + 1]->node_name);
|
||||
if (node == nullptr) {
|
||||
/* The current tree path is invalid, probably because some parent group node has been
|
||||
* deleted. */
|
||||
return std::nullopt;
|
||||
}
|
||||
compute_context_builder.push<bke::NodeGroupComputeContext>(*node);
|
||||
}
|
||||
return compute_context_builder.hash();
|
||||
compute_context_builder.pop();
|
||||
}
|
||||
|
||||
GeoTreeLog *GeoModifierLog::get_tree_log_for_node_editor(const SpaceNode &snode)
|
||||
Map<const TreeZone *, ComputeContextHash> GeoModifierLog::get_context_hash_by_zone_for_node_editor(
|
||||
const SpaceNode &snode, StringRefNull modifier_name)
|
||||
{
|
||||
const Vector<const bNodeTreePath *> tree_path = snode.treepath;
|
||||
if (tree_path.is_empty()) {
|
||||
return {};
|
||||
}
|
||||
|
||||
ComputeContextBuilder compute_context_builder;
|
||||
compute_context_builder.push<bke::ModifierComputeContext>(modifier_name);
|
||||
|
||||
for (const int i : tree_path.index_range().drop_back(1)) {
|
||||
bNodeTree *tree = tree_path[i]->nodetree;
|
||||
const char *group_node_name = tree_path[i + 1]->node_name;
|
||||
const bNode *group_node = nodeFindNodebyName(tree, group_node_name);
|
||||
if (group_node == nullptr) {
|
||||
return {};
|
||||
}
|
||||
const TreeZones *tree_zones = tree->zones();
|
||||
if (tree_zones == nullptr) {
|
||||
return {};
|
||||
}
|
||||
const Vector<const TreeZone *> zone_stack = tree_zones->get_zone_stack_for_node(
|
||||
group_node->identifier);
|
||||
for (const TreeZone *zone : zone_stack) {
|
||||
compute_context_builder.push<bke::SimulationZoneComputeContext>(*zone->output_node);
|
||||
}
|
||||
compute_context_builder.push<bke::NodeGroupComputeContext>(*group_node);
|
||||
}
|
||||
|
||||
const TreeZones *tree_zones = snode.edittree->zones();
|
||||
if (tree_zones == nullptr) {
|
||||
return {};
|
||||
}
|
||||
Map<const TreeZone *, ComputeContextHash> hash_by_zone;
|
||||
hash_by_zone.add_new(nullptr, compute_context_builder.hash());
|
||||
for (const TreeZone *zone : tree_zones->root_zones) {
|
||||
find_tree_zone_hash_recursive(*zone, compute_context_builder, hash_by_zone);
|
||||
}
|
||||
return hash_by_zone;
|
||||
}
|
||||
|
||||
Map<const TreeZone *, GeoTreeLog *> GeoModifierLog::get_tree_log_by_zone_for_node_editor(
|
||||
const SpaceNode &snode)
|
||||
{
|
||||
std::optional<ObjectAndModifier> object_and_modifier = get_modifier_for_node_editor(snode);
|
||||
if (!object_and_modifier) {
|
||||
return nullptr;
|
||||
return {};
|
||||
}
|
||||
GeoModifierLog *modifier_log = static_cast<GeoModifierLog *>(
|
||||
object_and_modifier->nmd->runtime_eval_log);
|
||||
if (modifier_log == nullptr) {
|
||||
return nullptr;
|
||||
return {};
|
||||
}
|
||||
if (const std::optional<ComputeContextHash> hash =
|
||||
GeoModifierLog::get_compute_context_hash_for_node_editor(
|
||||
snode, object_and_modifier->nmd->modifier.name))
|
||||
{
|
||||
return &modifier_log->get_tree_log(*hash);
|
||||
const Map<const TreeZone *, ComputeContextHash> hash_by_zone =
|
||||
GeoModifierLog::get_context_hash_by_zone_for_node_editor(
|
||||
snode, object_and_modifier->nmd->modifier.name);
|
||||
Map<const TreeZone *, GeoTreeLog *> log_by_zone;
|
||||
for (const auto item : hash_by_zone.items()) {
|
||||
GeoTreeLog &tree_log = modifier_log->get_tree_log(item.value);
|
||||
log_by_zone.add(item.key, &tree_log);
|
||||
}
|
||||
return nullptr;
|
||||
return log_by_zone;
|
||||
}
|
||||
|
||||
const ViewerNodeLog *GeoModifierLog::find_viewer_node_log_for_path(const ViewerPath &viewer_path)
|
||||
|
@ -587,8 +624,24 @@ const ViewerNodeLog *GeoModifierLog::find_viewer_node_log_for_path(const ViewerP
|
|||
|
||||
ComputeContextBuilder compute_context_builder;
|
||||
compute_context_builder.push<bke::ModifierComputeContext>(parsed_path->modifier_name);
|
||||
for (const int32_t group_node_id : parsed_path->group_node_ids) {
|
||||
compute_context_builder.push<bke::NodeGroupComputeContext>(group_node_id);
|
||||
for (const ViewerPathElem *elem : parsed_path->node_path) {
|
||||
switch (elem->type) {
|
||||
case VIEWER_PATH_ELEM_TYPE_GROUP_NODE: {
|
||||
const auto &typed_elem = *reinterpret_cast<const GroupNodeViewerPathElem *>(elem);
|
||||
compute_context_builder.push<bke::NodeGroupComputeContext>(typed_elem.node_id);
|
||||
break;
|
||||
}
|
||||
case VIEWER_PATH_ELEM_TYPE_SIMULATION_ZONE: {
|
||||
const auto &typed_elem = *reinterpret_cast<const SimulationZoneViewerPathElem *>(elem);
|
||||
compute_context_builder.push<bke::SimulationZoneComputeContext>(
|
||||
typed_elem.sim_output_node_id);
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
BLI_assert_unreachable();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
const ComputeContextHash context_hash = compute_context_builder.hash();
|
||||
nodes::geo_eval_log::GeoTreeLog &tree_log = modifier_log->get_tree_log(context_hash);
|
||||
|
|
Loading…
Reference in New Issue