WIP: Geometry Nodes: Viewer Node Group #112152
@ -25,33 +25,48 @@ def add_node_type(layout, node_type, *, label=None, poll=None):
|
||||
return props
|
||||
|
||||
|
||||
def draw_node_group_add_menu(context, layout):
|
||||
"""Add items to the layout used for interacting with node groups."""
|
||||
def node_groups(context):
|
||||
"""All node groups allowed in current context."""
|
||||
space_node = context.space_data
|
||||
node_tree = space_node.edit_tree
|
||||
all_node_groups = context.blend_data.node_groups
|
||||
if node_tree is None:
|
||||
return None
|
||||
|
||||
def group_allowed_in_context(group):
|
||||
if group.bl_idname is node_tree.bl_idname:
|
||||
return False
|
||||
if group.name.startswith('.'):
|
||||
return False
|
||||
if group.contains_tree(node_tree):
|
||||
return False
|
||||
return True
|
||||
|
||||
return [group for group in all_node_groups if group_allowed_in_context(group)]
|
||||
|
||||
|
||||
def draw_node_group_add_menu(context, layout, groups = None):
|
||||
"""Add items to the layout used for interacting with node groups."""
|
||||
space_node = context.space_data
|
||||
node_tree = space_node.edit_tree
|
||||
if groups is None:
|
||||
groups = node_groups(context)
|
||||
|
||||
all_node_groups = context.blend_data.node_groups
|
||||
if node_tree in all_node_groups.values():
|
||||
layout.separator()
|
||||
add_node_type(layout, "NodeGroupInput")
|
||||
add_node_type(layout, "NodeGroupOutput")
|
||||
|
||||
if node_tree:
|
||||
if node_tree and groups:
|
||||
from nodeitems_builtins import node_tree_group_type
|
||||
|
||||
groups = [
|
||||
group for group in context.blend_data.node_groups
|
||||
if (group.bl_idname == node_tree.bl_idname and
|
||||
not group.contains_tree(node_tree) and
|
||||
not group.name.startswith('.'))
|
||||
]
|
||||
if groups:
|
||||
layout.separator()
|
||||
for group in groups:
|
||||
props = add_node_type(layout, node_tree_group_type[group.bl_idname], label=group.name)
|
||||
ops = props.settings.add()
|
||||
ops.name = "node_tree"
|
||||
ops.value = "bpy.data.node_groups[%r]" % group.name
|
||||
layout.separator()
|
||||
for group in groups:
|
||||
props = add_node_type(layout, node_tree_group_type[group.bl_idname], label=group.name)
|
||||
ops = props.settings.add()
|
||||
ops.name = "node_tree"
|
||||
ops.value = "bpy.data.node_groups[%r]" % group.name
|
||||
|
||||
|
||||
def draw_assets_for_catalog(layout, catalog_path):
|
||||
|
@ -456,10 +456,13 @@ class NODE_MT_category_GEO_OUTPUT(Menu):
|
||||
bl_idname = "NODE_MT_category_GEO_OUTPUT"
|
||||
bl_label = "Output"
|
||||
|
||||
def draw(self, _context):
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
node_add_menu.add_node_type(layout, "NodeGroupOutput")
|
||||
node_add_menu.add_node_type(layout, "GeometryNodeViewer")
|
||||
groups = node_add_menu.node_groups(context)
|
||||
groups = [group for group in groups if group.is_viewer]
|
||||
node_add_menu.draw_node_group_add_menu(context, layout, groups)
|
||||
node_add_menu.draw_assets_for_catalog(layout, self.bl_label)
|
||||
|
||||
|
||||
|
@ -64,6 +64,31 @@ class NodeGroupComputeContext : public ComputeContext {
|
||||
void print_current_in_line(std::ostream &stream) const override;
|
||||
};
|
||||
|
||||
class NodeViewerGroupComputeContext : public ComputeContext {
|
||||
private:
|
||||
static constexpr const char *s_static_type = "NODE_GROUP";
|
||||
|
||||
int32_t node_id_;
|
||||
|
||||
#ifdef DEBUG
|
||||
std::string debug_node_name_;
|
||||
#endif
|
||||
|
||||
public:
|
||||
NodeViewerGroupComputeContext(const ComputeContext *parent,
|
||||
int32_t node_id,
|
||||
const std::optional<ComputeContextHash> &cached_hash = {});
|
||||
NodeViewerGroupComputeContext(const ComputeContext *parent, const bNode &node);
|
||||
|
||||
int32_t node_id() const
|
||||
{
|
||||
return node_id_;
|
||||
}
|
||||
|
||||
private:
|
||||
void print_current_in_line(std::ostream &stream) const override;
|
||||
};
|
||||
|
||||
class SimulationZoneComputeContext : public ComputeContext {
|
||||
private:
|
||||
static constexpr const char *s_static_type = "SIMULATION_ZONE";
|
||||
|
@ -125,6 +125,10 @@ bool nodeLinkIsSelected(const bNodeLink *link);
|
||||
|
||||
void nodeInternalRelink(bNodeTree *ntree, bNode *node);
|
||||
|
||||
bool node_is_viewer_group(const bNode &node);
|
||||
|
||||
int get_internal_link_type_priority(const bNodeSocketType &from, const bNodeSocketType &to);
|
||||
|
||||
float2 nodeToView(const bNode *node, float2 loc);
|
||||
|
||||
float2 nodeFromView(const bNode *node, float2 view_loc);
|
||||
|
@ -589,6 +589,11 @@ inline blender::Span<const bNodeTreeInterfaceItem *> bNodeTree::interface_items(
|
||||
return this->tree_interface.runtime->items_;
|
||||
}
|
||||
|
||||
inline bool bNodeTree::is_viewer() const
|
||||
{
|
||||
return this->flag & NTREE_IS_VIEWER;
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
|
@ -56,6 +56,7 @@ ModifierViewerPathElem *BKE_viewer_path_elem_new_modifier(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);
|
||||
ViewerNodeGroupViewerPathElem *BKE_viewer_path_elem_new_viewer_node_group(void);
|
||||
RepeatZoneViewerPathElem *BKE_viewer_path_elem_new_repeat_zone(void);
|
||||
ViewerPathElem *BKE_viewer_path_elem_copy(const ViewerPathElem *src);
|
||||
bool BKE_viewer_path_elem_equal(const ViewerPathElem *a,
|
||||
|
@ -64,6 +64,48 @@ void NodeGroupComputeContext::print_current_in_line(std::ostream &stream) const
|
||||
stream << "Node ID: " << node_id_;
|
||||
}
|
||||
|
||||
NodeViewerGroupComputeContext::NodeViewerGroupComputeContext(
|
||||
const ComputeContext *parent,
|
||||
const int32_t node_id,
|
||||
const std::optional<ComputeContextHash> &cached_hash)
|
||||
: ComputeContext(s_static_type, parent), node_id_(node_id)
|
||||
{
|
||||
if (cached_hash.has_value()) {
|
||||
hash_ = *cached_hash;
|
||||
}
|
||||
else {
|
||||
/* 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, &node_id_, sizeof(int32_t));
|
||||
hash_.mix_in(buffer, buffer_size);
|
||||
}
|
||||
}
|
||||
|
||||
NodeViewerGroupComputeContext::NodeViewerGroupComputeContext(const ComputeContext *parent,
|
||||
const bNode &node)
|
||||
: NodeViewerGroupComputeContext(parent, node.identifier)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
debug_node_name_ = node.name;
|
||||
#endif
|
||||
}
|
||||
|
||||
void NodeViewerGroupComputeContext::print_current_in_line(std::ostream &stream) const
|
||||
{
|
||||
#ifdef DEBUG
|
||||
if (!debug_node_name_.empty()) {
|
||||
stream << "Viewer Node: " << debug_node_name_;
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
stream << "Viewer 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)
|
||||
|
@ -3702,6 +3702,12 @@ void nodeSetActive(bNodeTree *ntree, bNode *node)
|
||||
|
||||
namespace blender::bke {
|
||||
|
||||
bool node_is_viewer_group(const bNode &node)
|
||||
{
|
||||
const bNodeTree *tree = reinterpret_cast<bNodeTree *>(node.id);
|
||||
return node.is_group() && (tree != nullptr) && tree->is_viewer();
|
||||
}
|
||||
|
||||
void nodeSetSocketAvailability(bNodeTree *ntree, bNodeSocket *sock, const bool is_available)
|
||||
{
|
||||
if (is_available == sock->is_available()) {
|
||||
|
@ -82,11 +82,11 @@ namespace blender::bke {
|
||||
* `< 0`: never connect these types.
|
||||
* `>= 0`: priority of connection (higher values chosen first).
|
||||
*/
|
||||
static int get_internal_link_type_priority(const bNodeSocketType *from, const bNodeSocketType *to)
|
||||
int get_internal_link_type_priority(const bNodeSocketType &from, const bNodeSocketType &to)
|
||||
{
|
||||
switch (to->type) {
|
||||
switch (to.type) {
|
||||
case SOCK_RGBA:
|
||||
switch (from->type) {
|
||||
switch (from.type) {
|
||||
case SOCK_RGBA:
|
||||
return 4;
|
||||
case SOCK_FLOAT:
|
||||
@ -98,7 +98,7 @@ static int get_internal_link_type_priority(const bNodeSocketType *from, const bN
|
||||
}
|
||||
return -1;
|
||||
case SOCK_VECTOR:
|
||||
switch (from->type) {
|
||||
switch (from.type) {
|
||||
case SOCK_VECTOR:
|
||||
return 4;
|
||||
case SOCK_FLOAT:
|
||||
@ -110,7 +110,7 @@ static int get_internal_link_type_priority(const bNodeSocketType *from, const bN
|
||||
}
|
||||
return -1;
|
||||
case SOCK_FLOAT:
|
||||
switch (from->type) {
|
||||
switch (from.type) {
|
||||
case SOCK_FLOAT:
|
||||
return 5;
|
||||
case SOCK_INT:
|
||||
@ -124,7 +124,7 @@ static int get_internal_link_type_priority(const bNodeSocketType *from, const bN
|
||||
}
|
||||
return -1;
|
||||
case SOCK_INT:
|
||||
switch (from->type) {
|
||||
switch (from.type) {
|
||||
case SOCK_INT:
|
||||
return 5;
|
||||
case SOCK_FLOAT:
|
||||
@ -138,7 +138,7 @@ static int get_internal_link_type_priority(const bNodeSocketType *from, const bN
|
||||
}
|
||||
return -1;
|
||||
case SOCK_BOOLEAN:
|
||||
switch (from->type) {
|
||||
switch (from.type) {
|
||||
case SOCK_BOOLEAN:
|
||||
return 5;
|
||||
case SOCK_INT:
|
||||
@ -155,7 +155,7 @@ static int get_internal_link_type_priority(const bNodeSocketType *from, const bN
|
||||
|
||||
/* The rest of the socket types only allow an internal link if both the input and output socket
|
||||
* have the same type. If the sockets are custom, we check the idname instead. */
|
||||
if (to->type == from->type && (to->type != SOCK_CUSTOM || STREQ(to->idname, from->idname))) {
|
||||
if (to.type == from.type && (to.type != SOCK_CUSTOM || STREQ(to.idname, from.idname))) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
@ -485,6 +485,8 @@ class NodeTreeMainUpdater {
|
||||
this->remove_unused_previews_when_necessary(ntree);
|
||||
this->make_node_previews_dirty(ntree);
|
||||
|
||||
this->propagate_viewers(ntree);
|
||||
|
||||
this->propagate_runtime_flags(ntree);
|
||||
if (ntree.type == NTREE_GEOMETRY) {
|
||||
if (node_field_inferencing::update_field_inferencing(ntree)) {
|
||||
@ -664,8 +666,8 @@ class NodeTreeMainUpdater {
|
||||
if (input_socket->flag & SOCK_NO_INTERNAL_LINK) {
|
||||
continue;
|
||||
}
|
||||
const int priority = get_internal_link_type_priority(input_socket->typeinfo,
|
||||
output_socket->typeinfo);
|
||||
const int priority = get_internal_link_type_priority(*input_socket->typeinfo,
|
||||
*output_socket->typeinfo);
|
||||
if (priority < 0) {
|
||||
continue;
|
||||
}
|
||||
@ -733,6 +735,37 @@ class NodeTreeMainUpdater {
|
||||
}
|
||||
}
|
||||
|
||||
void propagate_viewers(bNodeTree &ntree)
|
||||
{
|
||||
ntree.ensure_topology_cache();
|
||||
ntree.ensure_interface_cache();
|
||||
ntree.flag &= ~NTREE_IS_VIEWER;
|
||||
if (!ntree.interface_outputs().is_empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
const Span<bNode *> viewers = ntree.nodes_by_type("GeometryNodeViewer");
|
||||
const Span<bNode *> groups = ntree.group_nodes();
|
||||
|
||||
const bNode *viewer_node = viewers.size() != 1 ? nullptr : viewers.first();
|
||||
const bNode *viewer_group = [&]() -> bNode * {
|
||||
bNode *viewer_group = nullptr;
|
||||
for (bNode *group_node : groups) {
|
||||
if (bke::node_is_viewer_group(*group_node)) {
|
||||
if (viewer_group != nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
viewer_group = group_node;
|
||||
}
|
||||
}
|
||||
return viewer_group;
|
||||
}();
|
||||
|
||||
if ((viewer_node == nullptr) != (viewer_group == nullptr)) {
|
||||
ntree.flag |= NTREE_IS_VIEWER;
|
||||
}
|
||||
}
|
||||
|
||||
void propagate_runtime_flags(const bNodeTree &ntree)
|
||||
{
|
||||
ntree.ensure_topology_cache();
|
||||
@ -892,6 +925,9 @@ class NodeTreeMainUpdater {
|
||||
if (node.typeinfo->nclass == NODE_CLASS_OUTPUT) {
|
||||
return true;
|
||||
}
|
||||
if (bke::node_is_viewer_group(node)) {
|
||||
return true;
|
||||
}
|
||||
if (node.type == NODE_GROUP_OUTPUT) {
|
||||
return true;
|
||||
}
|
||||
|
@ -80,6 +80,11 @@ void BKE_viewer_path_blend_write(BlendWriter *writer, const ViewerPath *viewer_p
|
||||
BLO_write_struct(writer, GroupNodeViewerPathElem, typed_elem);
|
||||
break;
|
||||
}
|
||||
case VIEWER_PATH_ELEM_TYPE_VIEWER_NODE_GROUP: {
|
||||
const auto *typed_elem = reinterpret_cast<ViewerNodeGroupViewerPathElem *>(elem);
|
||||
BLO_write_struct(writer, ViewerNodeGroupViewerPathElem, 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);
|
||||
@ -109,6 +114,7 @@ void BKE_viewer_path_blend_read_data(BlendDataReader *reader, ViewerPath *viewer
|
||||
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_VIEWER_NODE_GROUP:
|
||||
case VIEWER_PATH_ELEM_TYPE_REPEAT_ZONE:
|
||||
case VIEWER_PATH_ELEM_TYPE_ID: {
|
||||
break;
|
||||
@ -133,6 +139,7 @@ void BKE_viewer_path_foreach_id(LibraryForeachIDData *data, ViewerPath *viewer_p
|
||||
}
|
||||
case VIEWER_PATH_ELEM_TYPE_MODIFIER:
|
||||
case VIEWER_PATH_ELEM_TYPE_GROUP_NODE:
|
||||
case VIEWER_PATH_ELEM_TYPE_VIEWER_NODE_GROUP:
|
||||
case VIEWER_PATH_ELEM_TYPE_SIMULATION_ZONE:
|
||||
case VIEWER_PATH_ELEM_TYPE_VIEWER_NODE:
|
||||
case VIEWER_PATH_ELEM_TYPE_REPEAT_ZONE: {
|
||||
@ -153,6 +160,7 @@ void BKE_viewer_path_id_remap(ViewerPath *viewer_path, const IDRemapper *mapping
|
||||
}
|
||||
case VIEWER_PATH_ELEM_TYPE_MODIFIER:
|
||||
case VIEWER_PATH_ELEM_TYPE_GROUP_NODE:
|
||||
case VIEWER_PATH_ELEM_TYPE_VIEWER_NODE_GROUP:
|
||||
case VIEWER_PATH_ELEM_TYPE_SIMULATION_ZONE:
|
||||
case VIEWER_PATH_ELEM_TYPE_VIEWER_NODE:
|
||||
case VIEWER_PATH_ELEM_TYPE_REPEAT_ZONE: {
|
||||
@ -181,6 +189,9 @@ ViewerPathElem *BKE_viewer_path_elem_new(const ViewerPathElemType type)
|
||||
case VIEWER_PATH_ELEM_TYPE_GROUP_NODE: {
|
||||
return &make_elem<GroupNodeViewerPathElem>(type)->base;
|
||||
}
|
||||
case VIEWER_PATH_ELEM_TYPE_VIEWER_NODE_GROUP: {
|
||||
return &make_elem<ViewerNodeGroupViewerPathElem>(type)->base;
|
||||
}
|
||||
case VIEWER_PATH_ELEM_TYPE_SIMULATION_ZONE: {
|
||||
return &make_elem<SimulationZoneViewerPathElem>(type)->base;
|
||||
}
|
||||
@ -224,6 +235,12 @@ ViewerNodeViewerPathElem *BKE_viewer_path_elem_new_viewer_node()
|
||||
BKE_viewer_path_elem_new(VIEWER_PATH_ELEM_TYPE_VIEWER_NODE));
|
||||
}
|
||||
|
||||
ViewerNodeGroupViewerPathElem *BKE_viewer_path_elem_new_viewer_node_group()
|
||||
{
|
||||
return reinterpret_cast<ViewerNodeGroupViewerPathElem *>(
|
||||
BKE_viewer_path_elem_new(VIEWER_PATH_ELEM_TYPE_VIEWER_NODE_GROUP));
|
||||
}
|
||||
|
||||
RepeatZoneViewerPathElem *BKE_viewer_path_elem_new_repeat_zone()
|
||||
{
|
||||
return reinterpret_cast<RepeatZoneViewerPathElem *>(
|
||||
@ -257,6 +274,12 @@ ViewerPathElem *BKE_viewer_path_elem_copy(const ViewerPathElem *src)
|
||||
new_elem->node_id = old_elem->node_id;
|
||||
break;
|
||||
}
|
||||
case VIEWER_PATH_ELEM_TYPE_VIEWER_NODE_GROUP: {
|
||||
const auto *old_elem = reinterpret_cast<const ViewerNodeGroupViewerPathElem *>(src);
|
||||
auto *new_elem = reinterpret_cast<ViewerNodeGroupViewerPathElem *>(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);
|
||||
@ -303,6 +326,11 @@ bool BKE_viewer_path_elem_equal(const ViewerPathElem *a,
|
||||
const auto *b_elem = reinterpret_cast<const GroupNodeViewerPathElem *>(b);
|
||||
return a_elem->node_id == b_elem->node_id;
|
||||
}
|
||||
case VIEWER_PATH_ELEM_TYPE_VIEWER_NODE_GROUP: {
|
||||
const auto *a_elem = reinterpret_cast<const ViewerNodeGroupViewerPathElem *>(a);
|
||||
const auto *b_elem = reinterpret_cast<const ViewerNodeGroupViewerPathElem *>(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);
|
||||
@ -329,6 +357,7 @@ void BKE_viewer_path_elem_free(ViewerPathElem *elem)
|
||||
switch (ViewerPathElemType(elem->type)) {
|
||||
case VIEWER_PATH_ELEM_TYPE_ID:
|
||||
case VIEWER_PATH_ELEM_TYPE_GROUP_NODE:
|
||||
case VIEWER_PATH_ELEM_TYPE_VIEWER_NODE_GROUP:
|
||||
case VIEWER_PATH_ELEM_TYPE_SIMULATION_ZONE:
|
||||
case VIEWER_PATH_ELEM_TYPE_VIEWER_NODE:
|
||||
case VIEWER_PATH_ELEM_TYPE_REPEAT_ZONE: {
|
||||
|
@ -40,7 +40,14 @@ struct ViewerPathForGeometryNodesViewer {
|
||||
blender::StringRefNull modifier_name;
|
||||
/* Contains only group node and simulation zone elements. */
|
||||
blender::Vector<const ViewerPathElem *> node_path;
|
||||
int32_t viewer_node_id;
|
||||
Vector<int32_t> node_ids;
|
||||
};
|
||||
|
||||
struct ViewerPathMemory {
|
||||
ViewerPath viewer_group_path;
|
||||
|
||||
ViewerPathMemory();
|
||||
~ViewerPathMemory();
|
||||
};
|
||||
|
||||
/**
|
||||
@ -48,14 +55,14 @@ struct ViewerPathForGeometryNodesViewer {
|
||||
* work.
|
||||
*/
|
||||
std::optional<ViewerPathForGeometryNodesViewer> parse_geometry_nodes_viewer(
|
||||
const ViewerPath &viewer_path);
|
||||
const ViewerPath &viewer_path, ViewerPathMemory &memory);
|
||||
|
||||
/**
|
||||
* Finds the node referenced by the #ViewerPath within the provided editor. If no node is
|
||||
* referenced, null is returned. When two different editors show the same node group but in a
|
||||
* different context, it's possible that the same node is active in one editor but not the other.
|
||||
*/
|
||||
bNode *find_geometry_nodes_viewer(const ViewerPath &viewer_path, SpaceNode &snode);
|
||||
bNode *find_geometry_nodes_viewer_in_space(const ViewerPath &viewer_path, SpaceNode &snode);
|
||||
|
||||
/**
|
||||
* Checks if the node referenced by the viewer path and its entire context still exists. The node
|
||||
|
@ -2,6 +2,8 @@
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
#include <iostream>
|
||||
|
||||
#include "BKE_context.h"
|
||||
|
||||
#include "ED_screen.hh"
|
||||
@ -34,6 +36,8 @@ static void validate_viewer_paths(bContext &C, WorkSpace &workspace)
|
||||
break;
|
||||
}
|
||||
|
||||
std::cout << __func__ << std::endl;
|
||||
|
||||
WM_event_add_notifier(&C, NC_VIEWER_PATH, nullptr);
|
||||
}
|
||||
|
||||
|
@ -1063,8 +1063,12 @@ static int node_get_colorid(TreeDrawContext &tree_draw_ctx, const bNode &node)
|
||||
return TH_NODE_VECTOR;
|
||||
case NODE_CLASS_OP_FILTER:
|
||||
return TH_NODE_FILTER;
|
||||
case NODE_CLASS_GROUP:
|
||||
case NODE_CLASS_GROUP: {
|
||||
if (bke::node_is_viewer_group(node)) {
|
||||
return &node == tree_draw_ctx.active_geometry_nodes_viewer ? TH_NODE_OUTPUT : TH_NODE;
|
||||
}
|
||||
return TH_NODE_GROUP;
|
||||
}
|
||||
case NODE_CLASS_INTERFACE:
|
||||
return TH_NODE_INTERFACE;
|
||||
case NODE_CLASS_MATTE:
|
||||
@ -2984,7 +2988,7 @@ static void node_draw_basis(const bContext &C,
|
||||
"");
|
||||
UI_block_emboss_set(&block, UI_EMBOSS);
|
||||
}
|
||||
if (node.type == GEO_NODE_VIEWER) {
|
||||
if (node.type == GEO_NODE_VIEWER || bke::node_is_viewer_group(node)) {
|
||||
const bool is_active = &node == tree_draw_ctx.active_geometry_nodes_viewer;
|
||||
iconofs -= iconbutw;
|
||||
UI_block_emboss_set(&block, UI_EMBOSS_NONE);
|
||||
@ -4114,7 +4118,7 @@ static void draw_nodetree(const bContext &C,
|
||||
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(
|
||||
tree_draw_ctx.active_geometry_nodes_viewer = viewer_path::find_geometry_nodes_viewer_in_space(
|
||||
workspace->viewer_path, *snode);
|
||||
}
|
||||
else if (ntree.type == NTREE_COMPOSIT) {
|
||||
|
@ -691,7 +691,7 @@ void ED_node_set_active(
|
||||
}
|
||||
|
||||
nodeSetActive(ntree, node);
|
||||
if (node->type == NODE_GROUP) {
|
||||
if (node->is_group() && !blender::bke::node_is_viewer_group(*node)) {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -813,10 +813,10 @@ void ED_node_set_active(
|
||||
}
|
||||
}
|
||||
else if (ntree->type == NTREE_GEOMETRY) {
|
||||
if (node->type == GEO_NODE_VIEWER) {
|
||||
if (node->type == GEO_NODE_VIEWER || blender::bke::node_is_viewer_group(*node)) {
|
||||
if ((node->flag & NODE_DO_OUTPUT) == 0) {
|
||||
for (bNode *node_iter : ntree->all_nodes()) {
|
||||
if (node_iter->type == GEO_NODE_VIEWER) {
|
||||
if (node_iter->type == GEO_NODE_VIEWER || blender::bke::node_is_viewer_group(*node)) {
|
||||
node_iter->flag &= ~NODE_DO_OUTPUT;
|
||||
}
|
||||
}
|
||||
@ -1684,21 +1684,14 @@ static int node_deactivate_viewer_exec(bContext *C, wmOperator * /*op*/)
|
||||
SpaceNode &snode = *CTX_wm_space_node(C);
|
||||
WorkSpace &workspace = *CTX_wm_workspace(C);
|
||||
|
||||
bNode *active_viewer = viewer_path::find_geometry_nodes_viewer(workspace.viewer_path, snode);
|
||||
bNode *active_viewer = viewer_path::find_geometry_nodes_viewer_in_space(workspace.viewer_path,
|
||||
snode);
|
||||
|
||||
for (bNode *node : snode.edittree->all_nodes()) {
|
||||
if (node->type != GEO_NODE_VIEWER) {
|
||||
continue;
|
||||
}
|
||||
if (!(node->flag & SELECT)) {
|
||||
continue;
|
||||
}
|
||||
if (node == active_viewer) {
|
||||
node->flag &= ~NODE_DO_OUTPUT;
|
||||
BKE_ntree_update_tag_node_property(snode.edittree, node);
|
||||
}
|
||||
if (active_viewer == nullptr) {
|
||||
return OPERATOR_FINISHED;
|
||||
}
|
||||
|
||||
active_viewer->flag &= ~NODE_DO_OUTPUT;
|
||||
BKE_ntree_update_tag_node_property(snode.edittree, active_viewer);
|
||||
ED_node_tree_propagate_change(C, CTX_data_main(C), snode.edittree);
|
||||
|
||||
return OPERATOR_FINISHED;
|
||||
|
@ -50,6 +50,7 @@
|
||||
#include "BLT_translation.h"
|
||||
|
||||
#include "NOD_node_declaration.hh"
|
||||
#include "NOD_socket.hh"
|
||||
#include "NOD_socket_declarations.hh"
|
||||
#include "NOD_socket_declarations_geometry.hh"
|
||||
|
||||
@ -413,6 +414,28 @@ namespace viewer_linking {
|
||||
/** \name Link Viewer Operator
|
||||
* \{ */
|
||||
|
||||
/* Find index of socket int viewer that the best to connect to a to_viewer. */
|
||||
static std::optional<int> best_socket_of_viewer(const bNode &viewer, const bNodeSocket &to_viewer)
|
||||
{
|
||||
const Span<const bNodeSocket *> inputs = viewer.input_sockets();
|
||||
if (inputs.is_empty()) {
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
int max_value = 0;
|
||||
std::optional<int> index_of_max;
|
||||
for (const int index : inputs.index_range()) {
|
||||
const bNodeSocket &socket = *inputs[index];
|
||||
const int priority = bke::get_internal_link_type_priority(*to_viewer.typeinfo,
|
||||
*socket.typeinfo);
|
||||
if (priority > max_value) {
|
||||
max_value = priority;
|
||||
index_of_max.emplace(index);
|
||||
}
|
||||
}
|
||||
return index_of_max;
|
||||
}
|
||||
|
||||
/* Depending on the node tree type, different socket types are supported by viewer nodes. */
|
||||
static bool socket_can_be_viewed(const bNode &node, const bNodeSocket &socket)
|
||||
{
|
||||
@ -425,19 +448,13 @@ static bool socket_can_be_viewed(const bNode &node, const bNodeSocket &socket)
|
||||
if (socket.owner_tree().type != NTREE_GEOMETRY) {
|
||||
return true;
|
||||
}
|
||||
return ELEM(socket.typeinfo->type,
|
||||
SOCK_GEOMETRY,
|
||||
SOCK_FLOAT,
|
||||
SOCK_VECTOR,
|
||||
SOCK_INT,
|
||||
SOCK_BOOLEAN,
|
||||
SOCK_ROTATION,
|
||||
SOCK_RGBA);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the socket to link to in a viewer node.
|
||||
*/
|
||||
|
||||
static bNodeSocket *node_link_viewer_get_socket(bNodeTree &ntree,
|
||||
bNode &viewer_node,
|
||||
bNodeSocket &src_socket)
|
||||
@ -466,7 +483,8 @@ static bNodeSocket *node_link_viewer_get_socket(bNodeTree &ntree,
|
||||
|
||||
static bool is_viewer_node(const bNode &node)
|
||||
{
|
||||
return ELEM(node.type, CMP_NODE_VIEWER, CMP_NODE_SPLITVIEWER, GEO_NODE_VIEWER);
|
||||
return ELEM(node.type, CMP_NODE_VIEWER, CMP_NODE_SPLITVIEWER, GEO_NODE_VIEWER) ||
|
||||
bke::node_is_viewer_group(node);
|
||||
}
|
||||
|
||||
static bool is_viewer_socket_in_viewer(const bNodeSocket &socket)
|
||||
@ -593,16 +611,60 @@ static void finalize_viewer_link(const bContext &C,
|
||||
ED_node_tree_propagate_change(&C, bmain, snode.edittree);
|
||||
}
|
||||
|
||||
static int view_socket(const bContext &C,
|
||||
SpaceNode &snode,
|
||||
bNodeTree &btree,
|
||||
bNode &bnode_to_view,
|
||||
bNodeSocket &bsocket_to_view)
|
||||
static Array<const bNode *> all_view_nodes(const bNodeTree &tree)
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
static Array<const bNode *> all_connected_viewer(const bNodeTree &tree, const bNode &bnode_to_view)
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
static const bNode *active_viewer_in_tree(const bNodeTree &tree)
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
static int link_view_sockets(const bContext &C,
|
||||
SpaceNode &snode,
|
||||
bNodeTree &btree,
|
||||
bNodeSocket &bsocket_to_view,
|
||||
bNodeSocket &bsocket_of_viewer)
|
||||
{
|
||||
bNode &node = bsocket_to_view.owner_node();
|
||||
bNode &viewer = bsocket_of_viewer.owner_node();
|
||||
|
||||
bNodeLink *viewer_link = nullptr;
|
||||
for (bNodeLink *link : btree.all_links()) {
|
||||
if (link->tosock == &bsocket_of_viewer) {
|
||||
viewer_link = link;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (viewer_link == nullptr) {
|
||||
viewer_link = nodeAddLink(&btree, &node, &bsocket_to_view, &viewer, &bsocket_of_viewer);
|
||||
}
|
||||
else {
|
||||
viewer_link->fromnode = &node;
|
||||
viewer_link->fromsock = &bsocket_to_view;
|
||||
BKE_ntree_update_tag_link_changed(&btree);
|
||||
}
|
||||
finalize_viewer_link(C, snode, viewer, *viewer_link);
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
|
||||
static bNodeSocket *best_view_socket_find_or_new(const bNodeTree &btree,
|
||||
const bNodeSocket &bsocket_to_view,
|
||||
const Span<const bNode *> viewers,
|
||||
const Span<const bNode *> connected_viewers,
|
||||
const bNode *active_viewer)
|
||||
{
|
||||
return {};
|
||||
/*
|
||||
bNode *viewer_node = nullptr;
|
||||
/* Try to find a viewer that is already active. */
|
||||
for (bNode *node : btree.all_nodes()) {
|
||||
if (is_viewer_node(*node)) {
|
||||
if (is_viewer_node(*node) || bke::node_is_viewer_group(*node)) {
|
||||
if (node->flag & NODE_DO_OUTPUT) {
|
||||
viewer_node = node;
|
||||
break;
|
||||
@ -610,7 +672,6 @@ static int view_socket(const bContext &C,
|
||||
}
|
||||
}
|
||||
|
||||
/* Try to reactivate existing viewer connection. */
|
||||
for (bNodeLink *link : bsocket_to_view.directly_linked_links()) {
|
||||
bNodeSocket &target_socket = *link->tosock;
|
||||
bNode &target_node = *link->tonode;
|
||||
@ -635,46 +696,357 @@ static int view_socket(const bContext &C,
|
||||
socket_location.y / UI_SCALE_FAC};
|
||||
viewer_node = add_static_node(C, viewer_type, location);
|
||||
}
|
||||
|
||||
bNodeSocket *viewer_bsocket = node_link_viewer_get_socket(btree, *viewer_node, bsocket_to_view);
|
||||
if (viewer_bsocket == nullptr) {
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
bNodeLink *viewer_link = nullptr;
|
||||
LISTBASE_FOREACH_MUTABLE (bNodeLink *, link, &btree.links) {
|
||||
if (link->tosock == viewer_bsocket) {
|
||||
viewer_link = link;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (viewer_link == nullptr) {
|
||||
viewer_link = nodeAddLink(
|
||||
&btree, &bnode_to_view, &bsocket_to_view, viewer_node, viewer_bsocket);
|
||||
}
|
||||
else {
|
||||
viewer_link->fromnode = &bnode_to_view;
|
||||
viewer_link->fromsock = &bsocket_to_view;
|
||||
BKE_ntree_update_tag_link_changed(&btree);
|
||||
}
|
||||
finalize_viewer_link(C, snode, *viewer_node, *viewer_link);
|
||||
return OPERATOR_CANCELLED;
|
||||
*/
|
||||
}
|
||||
|
||||
static int node_link_viewer(const bContext &C, bNode &bnode_to_view, bNodeSocket *bsocket_to_view)
|
||||
struct ViewerSocketTrait {
|
||||
std::function<std::pair<bNode *, bNodeSocket *>(bNodeTree &)> finalize;
|
||||
|
||||
eNodeSocketDatatype type;
|
||||
StringRef socket_name;
|
||||
StringRef node_name;
|
||||
|
||||
bool node_is_connected = false;
|
||||
|
||||
float prioriti = 1.0f;
|
||||
};
|
||||
|
||||
static void traits_for_viewer(Vector<ViewerSocketTrait> &r_traits)
|
||||
{
|
||||
static const Array<eNodeSocketDatatype> viewer_types = {
|
||||
SOCK_BOOLEAN, SOCK_FLOAT, SOCK_RGBA, SOCK_INT, SOCK_ROTATION, SOCK_VECTOR};
|
||||
|
||||
static const auto new_viewer = [](bNodeTree &tree) -> bNode & {
|
||||
return *nodeAddStaticNode(nullptr, &tree, GEO_NODE_VIEWER);
|
||||
};
|
||||
|
||||
ViewerSocketTrait trait;
|
||||
trait.type = SOCK_GEOMETRY;
|
||||
trait.socket_name = "Geometry";
|
||||
trait.node_name = "Viewer";
|
||||
trait.prioriti = 1.0f;
|
||||
|
||||
trait.finalize = [=](bNodeTree &tree) -> std::pair<bNode *, bNodeSocket *> {
|
||||
bNode &viewer = new_viewer(tree);
|
||||
tree.ensure_topology_cache();
|
||||
return {&viewer, viewer.input_sockets().first()};
|
||||
};
|
||||
|
||||
r_traits.append(std::move(trait));
|
||||
|
||||
for (const eNodeSocketDatatype socket_type : viewer_types) {
|
||||
ViewerSocketTrait trait;
|
||||
trait.type = socket_type;
|
||||
trait.socket_name = "Value";
|
||||
trait.node_name = "Viewer";
|
||||
trait.prioriti = 0.5f;
|
||||
|
||||
trait.finalize = [=](bNodeTree &tree) -> std::pair<bNode *, bNodeSocket *> {
|
||||
bNode &viewer = new_viewer(tree);
|
||||
tree.ensure_topology_cache();
|
||||
|
||||
for (bNodeSocket *socket : viewer.input_sockets().drop_front(1)) {
|
||||
const eNodeSocketDatatype other_socket_type = eNodeSocketDatatype(socket->type);
|
||||
if (socket_type == other_socket_type) {
|
||||
NodeGeometryViewer &storage = *static_cast<NodeGeometryViewer *>(viewer.storage);
|
||||
storage.data_type = *bke::socket_type_to_custom_data_type(other_socket_type);
|
||||
viewer.typeinfo->updatefunc(&tree, &viewer);
|
||||
return {&viewer, socket};
|
||||
}
|
||||
}
|
||||
|
||||
BLI_assert_unreachable();
|
||||
return {};
|
||||
};
|
||||
|
||||
r_traits.append(std::move(trait));
|
||||
}
|
||||
}
|
||||
|
||||
static void traits_for_viewers(const Span<const bNode *> viewers,
|
||||
const Span<bool> depend_on_node,
|
||||
Vector<ViewerSocketTrait> &r_traits)
|
||||
{
|
||||
static const Array<eNodeSocketDatatype> viewer_types = {
|
||||
SOCK_BOOLEAN, SOCK_FLOAT, SOCK_RGBA, SOCK_INT, SOCK_ROTATION, SOCK_VECTOR};
|
||||
for (const bNode *viewer : viewers) {
|
||||
|
||||
if (!viewer->input_sockets().first()->is_directly_linked()) {
|
||||
ViewerSocketTrait trait;
|
||||
trait.type = SOCK_GEOMETRY;
|
||||
trait.socket_name = "Geometry";
|
||||
trait.node_name = viewer->name;
|
||||
trait.prioriti = 1.0f;
|
||||
|
||||
trait.node_is_connected = depend_on_node[viewer->index()];
|
||||
|
||||
const int32_t identifiers = viewer->identifier;
|
||||
trait.finalize = [=](bNodeTree &tree) -> std::pair<bNode *, bNodeSocket *> {
|
||||
tree.ensure_topology_cache();
|
||||
bNode &viewer = *tree.node_by_id(identifiers);
|
||||
return {&viewer, viewer.input_sockets().first()};
|
||||
};
|
||||
|
||||
r_traits.append(std::move(trait));
|
||||
}
|
||||
|
||||
bool value_is_linked = false;
|
||||
|
||||
for (const bNodeSocket *socket : viewer->input_sockets().drop_front(1)) {
|
||||
value_is_linked |= socket->is_directly_linked();
|
||||
}
|
||||
|
||||
if (!value_is_linked) {
|
||||
for (const eNodeSocketDatatype socket_type : viewer_types) {
|
||||
ViewerSocketTrait trait;
|
||||
trait.type = socket_type;
|
||||
trait.socket_name = "Value";
|
||||
trait.node_name = viewer->name;
|
||||
trait.prioriti = 1.0f;
|
||||
|
||||
trait.node_is_connected = depend_on_node[viewer->index()];
|
||||
|
||||
const int32_t identifiers = viewer->identifier;
|
||||
NodeGeometryViewer &storage = *static_cast<NodeGeometryViewer *>(viewer->storage);
|
||||
|
||||
if (storage.data_type == *bke::socket_type_to_custom_data_type(socket_type)) {
|
||||
trait.prioriti = 2.0f;
|
||||
}
|
||||
|
||||
trait.finalize = [=](bNodeTree &tree) -> std::pair<bNode *, bNodeSocket *> {
|
||||
tree.ensure_topology_cache();
|
||||
bNode &viewer = *tree.node_by_id(identifiers);
|
||||
for (bNodeSocket *socket : viewer.input_sockets().drop_front(1)) {
|
||||
const eNodeSocketDatatype other_socket_type = eNodeSocketDatatype(socket->type);
|
||||
if (socket_type == other_socket_type) {
|
||||
NodeGeometryViewer &storage = *static_cast<NodeGeometryViewer *>(viewer.storage);
|
||||
storage.data_type = *bke::socket_type_to_custom_data_type(other_socket_type);
|
||||
viewer.typeinfo->updatefunc(&tree, &viewer);
|
||||
return {&viewer, socket};
|
||||
}
|
||||
}
|
||||
BLI_assert_unreachable();
|
||||
return {};
|
||||
};
|
||||
|
||||
r_traits.append(std::move(trait));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void traits_for_groups(Main &bmain, Vector<ViewerSocketTrait> &r_traits)
|
||||
{
|
||||
LISTBASE_FOREACH (bNodeTree *, group, &bmain.nodetrees) {
|
||||
if (!group->is_viewer()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
group->ensure_topology_cache();
|
||||
group->ensure_interface_cache();
|
||||
|
||||
const Span<const bNodeTreeInterfaceSocket *> inputs = group->interface_inputs();
|
||||
for (const int index : inputs.index_range()) {
|
||||
const bNodeTreeInterfaceSocket &input = *inputs[index];
|
||||
|
||||
ViewerSocketTrait trait;
|
||||
trait.type = eNodeSocketDatatype(input.socket_typeinfo()->type);
|
||||
trait.socket_name = input.name;
|
||||
trait.node_name = group->id.name;
|
||||
trait.prioriti = 3.0f;
|
||||
|
||||
trait.finalize = [=](bNodeTree &tree) -> std::pair<bNode *, bNodeSocket *> {
|
||||
tree.ensure_topology_cache();
|
||||
|
||||
bNode *node_group = nodeAddStaticNode(nullptr, &tree, NODE_GROUP);
|
||||
node_group->id = &group->id;
|
||||
id_us_plus(&group->id);
|
||||
tree.ensure_topology_cache();
|
||||
bke::node_field_inferencing::update_field_inferencing(*group);
|
||||
nodes::update_node_declaration_and_sockets(tree, *node_group);
|
||||
tree.ensure_topology_cache();
|
||||
|
||||
return {node_group, node_group->input_sockets()[index]};
|
||||
};
|
||||
|
||||
r_traits.append(std::move(trait));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void traits_for_exist_groups(const Span<const bNode *> groups,
|
||||
Vector<ViewerSocketTrait> &r_traits)
|
||||
{
|
||||
}
|
||||
|
||||
int get_link_type_priority(const eNodeSocketDatatype from, const eNodeSocketDatatype to)
|
||||
{
|
||||
switch (to) {
|
||||
case SOCK_RGBA:
|
||||
switch (from) {
|
||||
case SOCK_RGBA:
|
||||
return 4;
|
||||
case SOCK_FLOAT:
|
||||
return 3;
|
||||
case SOCK_INT:
|
||||
return 2;
|
||||
case SOCK_BOOLEAN:
|
||||
return 1;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return -1;
|
||||
case SOCK_VECTOR:
|
||||
switch (from) {
|
||||
case SOCK_VECTOR:
|
||||
return 4;
|
||||
case SOCK_FLOAT:
|
||||
return 3;
|
||||
case SOCK_INT:
|
||||
return 2;
|
||||
case SOCK_BOOLEAN:
|
||||
return 1;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return -1;
|
||||
case SOCK_FLOAT:
|
||||
switch (from) {
|
||||
case SOCK_FLOAT:
|
||||
return 5;
|
||||
case SOCK_INT:
|
||||
return 4;
|
||||
case SOCK_BOOLEAN:
|
||||
return 3;
|
||||
case SOCK_RGBA:
|
||||
return 2;
|
||||
case SOCK_VECTOR:
|
||||
return 1;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return -1;
|
||||
case SOCK_INT:
|
||||
switch (from) {
|
||||
case SOCK_INT:
|
||||
return 5;
|
||||
case SOCK_FLOAT:
|
||||
return 4;
|
||||
case SOCK_BOOLEAN:
|
||||
return 3;
|
||||
case SOCK_RGBA:
|
||||
return 2;
|
||||
case SOCK_VECTOR:
|
||||
return 1;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return -1;
|
||||
case SOCK_BOOLEAN:
|
||||
switch (from) {
|
||||
case SOCK_BOOLEAN:
|
||||
return 5;
|
||||
case SOCK_INT:
|
||||
return 4;
|
||||
case SOCK_FLOAT:
|
||||
return 3;
|
||||
case SOCK_RGBA:
|
||||
return 2;
|
||||
case SOCK_VECTOR:
|
||||
return 1;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return -1;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (to == from) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int node_link_viewer(const bContext &C, bNode &bnode_to_view, bNodeSocket *node_socket)
|
||||
{
|
||||
SpaceNode &snode = *CTX_wm_space_node(&C);
|
||||
bNodeTree *btree = snode.edittree;
|
||||
btree->ensure_topology_cache();
|
||||
|
||||
if (bsocket_to_view == nullptr) {
|
||||
bsocket_to_view = determine_socket_to_view(bnode_to_view);
|
||||
const Span<const bNode *> viewers = btree->nodes_by_type("GeometryNodeViewer");
|
||||
const Span<const bNode *> groups = btree->group_nodes();
|
||||
// const Array<const bNode *> connected_viewers = all_connected_viewer(*btree, bnode_to_view);
|
||||
const bNode *active_viewer = active_viewer_in_tree(*btree);
|
||||
|
||||
if (node_socket == nullptr) {
|
||||
node_socket = determine_socket_to_view(bnode_to_view);
|
||||
}
|
||||
|
||||
if (bsocket_to_view == nullptr) {
|
||||
if (node_socket == nullptr) {
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
|
||||
return view_socket(C, snode, *btree, bnode_to_view, *bsocket_to_view);
|
||||
const Span<const bNode *> left_to_right = btree->toposort_left_to_right();
|
||||
Array<bool> depend_on_node(left_to_right.size(), false);
|
||||
for (const bNode *node : left_to_right) {
|
||||
for (const bNodeSocket *input : node->input_sockets()) {
|
||||
for (const bNodeSocket *output_socket : input->directly_linked_sockets()) {
|
||||
const bNode &other = output_socket->owner_node();
|
||||
if (&other == &bnode_to_view) {
|
||||
depend_on_node[node->index()] = true;
|
||||
}
|
||||
depend_on_node[node->index()] |= depend_on_node[other.index()];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Vector<ViewerSocketTrait> traits;
|
||||
traits_for_viewer(traits);
|
||||
traits_for_viewers(viewers, depend_on_node, traits);
|
||||
// traits_for_viewers({active_viewer}, traits);
|
||||
traits_for_exist_groups(groups, traits);
|
||||
traits_for_groups(*CTX_data_main(&C), traits);
|
||||
|
||||
if (traits.is_empty()) {
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
|
||||
const ViewerSocketTrait &viewer_trait = *std::max_element(
|
||||
traits.begin(),
|
||||
traits.end(),
|
||||
[&](const ViewerSocketTrait &a, const ViewerSocketTrait &b) -> bool {
|
||||
const bool to_connected = a.node_is_connected != b.node_is_connected;
|
||||
const bool connected_node = b.node_is_connected;
|
||||
|
||||
const int a_type_priority = get_link_type_priority(a.type,
|
||||
eNodeSocketDatatype(node_socket->type));
|
||||
const int b_type_priority = get_link_type_priority(b.type,
|
||||
eNodeSocketDatatype(node_socket->type));
|
||||
if (ELEM(-1, a_type_priority, b_type_priority)) {
|
||||
return a_type_priority < b_type_priority;
|
||||
}
|
||||
/* Avoid conversions if possible. */
|
||||
if (ELEM(4, a_type_priority, b_type_priority) && a_type_priority != b_type_priority) {
|
||||
return a_type_priority < b_type_priority;
|
||||
}
|
||||
|
||||
if (to_connected) {
|
||||
const float connection_factor = connected_node ? 5.0f : 0.2f;
|
||||
return a.prioriti < b.prioriti * connection_factor;
|
||||
}
|
||||
|
||||
return a.prioriti < b.prioriti;
|
||||
});
|
||||
|
||||
if (-1 == get_link_type_priority(viewer_trait.type, eNodeSocketDatatype(node_socket->type))) {
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
|
||||
auto [viewer_node, viewer_socket] = viewer_trait.finalize(*btree);
|
||||
btree->ensure_topology_cache();
|
||||
return link_view_sockets(C, snode, *btree, *node_socket, *viewer_socket);
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
@ -6,6 +6,8 @@
|
||||
* \ingroup spnode
|
||||
*/
|
||||
|
||||
#include <iostream>
|
||||
|
||||
#include <array>
|
||||
#include <cstdlib>
|
||||
#include <iostream>
|
||||
@ -676,14 +678,18 @@ static bool node_mouse_select(bContext *C,
|
||||
return false;
|
||||
}
|
||||
|
||||
std::cout << __func__ << std::endl;
|
||||
|
||||
bool active_texture_changed = false;
|
||||
bool viewer_node_changed = false;
|
||||
if ((node != nullptr) && (node_was_selected == false || params->select_passthrough == false)) {
|
||||
viewer_node_changed = (node->flag & NODE_DO_OUTPUT) == 0 && node->type == GEO_NODE_VIEWER;
|
||||
ED_node_set_active(&bmain, &snode, snode.edittree, node, &active_texture_changed);
|
||||
std::cout << __LINE__ << std::endl;
|
||||
}
|
||||
else if (node != nullptr && node->type == GEO_NODE_VIEWER) {
|
||||
viewer_path::activate_geometry_node(bmain, snode, *node);
|
||||
std::cout << __LINE__ << std::endl;
|
||||
}
|
||||
ED_node_set_active_viewer_key(&snode);
|
||||
tree_draw_order_update(node_tree);
|
||||
@ -691,6 +697,7 @@ static bool node_mouse_select(bContext *C,
|
||||
viewer_node_changed)
|
||||
{
|
||||
DEG_id_tag_update(&snode.edittree->id, ID_RECALC_COPY_ON_WRITE);
|
||||
std::cout << __LINE__ << std::endl;
|
||||
}
|
||||
|
||||
WM_event_add_notifier(C, NC_NODE | NA_SELECTED, nullptr);
|
||||
|
@ -255,8 +255,10 @@ static void spreadsheet_update_context(const bContext *C)
|
||||
case SPREADSHEET_OBJECT_EVAL_STATE_VIEWER_NODE: {
|
||||
WorkSpace *workspace = CTX_wm_workspace(C);
|
||||
if (sspreadsheet->flag & SPREADSHEET_FLAG_PINNED) {
|
||||
ed::viewer_path::ViewerPathMemory memory;
|
||||
const std::optional<ViewerPathForGeometryNodesViewer> parsed_path =
|
||||
blender::ed::viewer_path::parse_geometry_nodes_viewer(sspreadsheet->viewer_path);
|
||||
blender::ed::viewer_path::parse_geometry_nodes_viewer(sspreadsheet->viewer_path,
|
||||
memory);
|
||||
if (parsed_path.has_value()) {
|
||||
if (blender::ed::viewer_path::exists_geometry_nodes_viewer(*parsed_path)) {
|
||||
/* The pinned path is still valid, do nothing. */
|
||||
@ -271,8 +273,9 @@ static void spreadsheet_update_context(const bContext *C)
|
||||
}
|
||||
}
|
||||
/* Now try to update the viewer path from the workspace. */
|
||||
ed::viewer_path::ViewerPathMemory memory;
|
||||
const std::optional<ViewerPathForGeometryNodesViewer> workspace_parsed_path =
|
||||
blender::ed::viewer_path::parse_geometry_nodes_viewer(workspace->viewer_path);
|
||||
blender::ed::viewer_path::parse_geometry_nodes_viewer(workspace->viewer_path, memory);
|
||||
if (workspace_parsed_path.has_value()) {
|
||||
if (BKE_viewer_path_equal(&sspreadsheet->viewer_path, &workspace->viewer_path)) {
|
||||
/* Nothing changed. */
|
||||