Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'source/blender/editors/util/ed_viewer_path.cc')
-rw-r--r--source/blender/editors/util/ed_viewer_path.cc365
1 files changed, 365 insertions, 0 deletions
diff --git a/source/blender/editors/util/ed_viewer_path.cc b/source/blender/editors/util/ed_viewer_path.cc
new file mode 100644
index 00000000000..4da1559b726
--- /dev/null
+++ b/source/blender/editors/util/ed_viewer_path.cc
@@ -0,0 +1,365 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#include "ED_viewer_path.hh"
+#include "ED_screen.h"
+
+#include "BKE_context.h"
+#include "BKE_main.h"
+#include "BKE_node_runtime.hh"
+#include "BKE_workspace.h"
+
+#include "BLI_listbase.h"
+#include "BLI_vector.hh"
+
+#include "DNA_modifier_types.h"
+#include "DNA_windowmanager_types.h"
+
+#include "DEG_depsgraph.h"
+
+#include "WM_api.h"
+
+namespace blender::ed::viewer_path {
+
+static void viewer_path_for_geometry_node(const SpaceNode &snode,
+ const bNode &node,
+ ViewerPath &r_dst)
+{
+ BKE_viewer_path_init(&r_dst);
+
+ Object *ob = reinterpret_cast<Object *>(snode.id);
+ IDViewerPathElem *id_elem = BKE_viewer_path_elem_new_id();
+ id_elem->id = &ob->id;
+ BLI_addtail(&r_dst.path, id_elem);
+
+ NodesModifierData *modifier = nullptr;
+ LISTBASE_FOREACH (ModifierData *, md, &ob->modifiers) {
+ if (md->type != eModifierType_Nodes) {
+ continue;
+ }
+ NodesModifierData *nmd = reinterpret_cast<NodesModifierData *>(md);
+ if (nmd->node_group != snode.nodetree) {
+ continue;
+ }
+ if (snode.flag & SNODE_PIN) {
+ /* If the node group is pinned, use the first matching modifier. This can be improved by
+ * storing the modifier name in the node editor when the context is pinned. */
+ modifier = nmd;
+ break;
+ }
+ if (md->flag & eModifierFlag_Active) {
+ modifier = nmd;
+ }
+ }
+
+ 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 bNodeTreePath *tree_path_elem : tree_path.as_span().drop_front(1)) {
+ NodeViewerPathElem *node_elem = BKE_viewer_path_elem_new_node();
+ node_elem->node_name = BLI_strdup(tree_path_elem->node_name);
+ BLI_addtail(&r_dst.path, node_elem);
+ }
+
+ NodeViewerPathElem *viewer_node_elem = BKE_viewer_path_elem_new_node();
+ viewer_node_elem->node_name = BLI_strdup(node.name);
+ BLI_addtail(&r_dst.path, viewer_node_elem);
+}
+
+void activate_geometry_node(Main &bmain, SpaceNode &snode, bNode &node)
+{
+ wmWindowManager *wm = (wmWindowManager *)bmain.wm.first;
+ if (wm == nullptr) {
+ return;
+ }
+ LISTBASE_FOREACH (bNode *, iter_node, &snode.edittree->nodes) {
+ if (iter_node->type == GEO_NODE_VIEWER) {
+ SET_FLAG_FROM_TEST(iter_node->flag, iter_node == &node, NODE_DO_OUTPUT);
+ }
+ }
+ ViewerPath new_viewer_path{};
+ BLI_SCOPED_DEFER([&]() { BKE_viewer_path_clear(&new_viewer_path); });
+ viewer_path_for_geometry_node(snode, node, new_viewer_path);
+
+ bool found_view3d_with_enabled_viewer = false;
+ View3D *any_view3d_without_viewer = nullptr;
+ LISTBASE_FOREACH (wmWindow *, window, &wm->windows) {
+ WorkSpace *workspace = BKE_workspace_active_get(window->workspace_hook);
+ bScreen *screen = BKE_workspace_active_screen_get(window->workspace_hook);
+ LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
+ SpaceLink *sl = static_cast<SpaceLink *>(area->spacedata.first);
+ if (sl->spacetype == SPACE_SPREADSHEET) {
+ SpaceSpreadsheet &sspreadsheet = *reinterpret_cast<SpaceSpreadsheet *>(sl);
+ if (!(sspreadsheet.flag & SPREADSHEET_FLAG_PINNED)) {
+ sspreadsheet.object_eval_state = SPREADSHEET_OBJECT_EVAL_STATE_VIEWER_NODE;
+ }
+ }
+ else if (sl->spacetype == SPACE_VIEW3D) {
+ View3D &v3d = *reinterpret_cast<View3D *>(sl);
+ if (v3d.flag2 & V3D_SHOW_VIEWER) {
+ found_view3d_with_enabled_viewer = true;
+ }
+ else {
+ any_view3d_without_viewer = &v3d;
+ }
+ }
+ }
+
+ /* Enable viewer in one viewport if it is disable in all of them. */
+ if (!found_view3d_with_enabled_viewer && any_view3d_without_viewer != nullptr) {
+ any_view3d_without_viewer->flag2 |= V3D_SHOW_VIEWER;
+ }
+
+ BKE_viewer_path_clear(&workspace->viewer_path);
+ BKE_viewer_path_copy(&workspace->viewer_path, &new_viewer_path);
+
+ /* Make sure the viewed data becomes available. */
+ DEG_id_tag_update(snode.id, ID_RECALC_GEOMETRY);
+ WM_main_add_notifier(NC_VIEWER_PATH, nullptr);
+ }
+}
+
+Object *parse_object_only(const ViewerPath &viewer_path)
+{
+ if (BLI_listbase_count(&viewer_path.path) != 1) {
+ return nullptr;
+ }
+ const ViewerPathElem *elem = static_cast<ViewerPathElem *>(viewer_path.path.first);
+ if (elem->type != VIEWER_PATH_ELEM_TYPE_ID) {
+ return nullptr;
+ }
+ ID *id = reinterpret_cast<const IDViewerPathElem *>(elem)->id;
+ if (id == nullptr) {
+ return nullptr;
+ }
+ if (GS(id->name) != ID_OB) {
+ return nullptr;
+ }
+ return reinterpret_cast<Object *>(id);
+}
+
+std::optional<ViewerPathForGeometryNodesViewer> parse_geometry_nodes_viewer(
+ const ViewerPath &viewer_path)
+{
+ const Vector<const ViewerPathElem *, 16> elems_vec = viewer_path.path;
+ if (elems_vec.size() < 3) {
+ /* Need at least the object, modifier and viewer node name. */
+ return std::nullopt;
+ }
+ Span<const ViewerPathElem *> remaining_elems = elems_vec;
+ const ViewerPathElem &id_elem = *remaining_elems[0];
+ if (id_elem.type != VIEWER_PATH_ELEM_TYPE_ID) {
+ return std::nullopt;
+ }
+ ID *root_id = reinterpret_cast<const IDViewerPathElem &>(id_elem).id;
+ if (root_id == nullptr) {
+ return std::nullopt;
+ }
+ if (GS(root_id->name) != ID_OB) {
+ return std::nullopt;
+ }
+ Object *root_ob = reinterpret_cast<Object *>(root_id);
+ remaining_elems = remaining_elems.drop_front(1);
+ const ViewerPathElem &modifier_elem = *remaining_elems[0];
+ if (modifier_elem.type != VIEWER_PATH_ELEM_TYPE_MODIFIER) {
+ return std::nullopt;
+ }
+ const char *modifier_name =
+ reinterpret_cast<const ModifierViewerPathElem &>(modifier_elem).modifier_name;
+ if (modifier_name == nullptr) {
+ return std::nullopt;
+ }
+ remaining_elems = remaining_elems.drop_front(1);
+ Vector<StringRefNull> node_names;
+ for (const ViewerPathElem *elem : remaining_elems) {
+ if (elem->type != VIEWER_PATH_ELEM_TYPE_NODE) {
+ return std::nullopt;
+ }
+ const char *node_name = reinterpret_cast<const NodeViewerPathElem *>(elem)->node_name;
+ if (node_name == nullptr) {
+ return std::nullopt;
+ }
+ node_names.append(node_name);
+ }
+ const StringRefNull viewer_node_name = node_names.pop_last();
+ return ViewerPathForGeometryNodesViewer{root_ob, modifier_name, node_names, viewer_node_name};
+}
+
+bool exists_geometry_nodes_viewer(const ViewerPathForGeometryNodesViewer &parsed_viewer_path)
+{
+ const NodesModifierData *modifier = nullptr;
+ LISTBASE_FOREACH (const ModifierData *, md, &parsed_viewer_path.object->modifiers) {
+ if (md->type != eModifierType_Nodes) {
+ continue;
+ }
+ if (md->name != parsed_viewer_path.modifier_name) {
+ continue;
+ }
+ modifier = reinterpret_cast<const NodesModifierData *>(md);
+ break;
+ }
+ if (modifier == nullptr) {
+ return false;
+ }
+ if (modifier->node_group == nullptr) {
+ return false;
+ }
+ const bNodeTree *ngroup = modifier->node_group;
+ ngroup->ensure_topology_cache();
+ for (const StringRefNull group_node_name : parsed_viewer_path.group_node_names) {
+ const bNode *group_node = nullptr;
+ for (const bNode *node : ngroup->group_nodes()) {
+ if (node->name != group_node_name) {
+ continue;
+ }
+ 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->name != parsed_viewer_path.viewer_node_name) {
+ continue;
+ }
+ viewer_node = node;
+ break;
+ }
+ if (viewer_node == nullptr) {
+ return false;
+ }
+ return true;
+}
+
+bool is_active_geometry_nodes_viewer(const bContext &C,
+ const ViewerPathForGeometryNodesViewer &parsed_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) {
+ return false;
+ }
+ if (modifier->node_group == nullptr) {
+ return false;
+ }
+ const bool modifier_is_active = modifier->modifier.flag & eModifierFlag_Active;
+
+ const Main *bmain = CTX_data_main(&C);
+ const wmWindowManager *wm = static_cast<wmWindowManager *>(bmain->wm.first);
+ if (wm == nullptr) {
+ return false;
+ }
+ LISTBASE_FOREACH (const wmWindow *, window, &wm->windows) {
+ const bScreen *active_screen = BKE_workspace_active_screen_get(window->workspace_hook);
+ Vector<const bScreen *> screens = {active_screen};
+ if (ELEM(active_screen->state, SCREENMAXIMIZED, SCREENFULL)) {
+ const ScrArea *area = static_cast<ScrArea *>(active_screen->areabase.first);
+ screens.append(area->full);
+ }
+ for (const bScreen *screen : screens) {
+ LISTBASE_FOREACH (const ScrArea *, area, &screen->areabase) {
+ const SpaceLink *sl = static_cast<SpaceLink *>(area->spacedata.first);
+ if (sl == nullptr) {
+ continue;
+ }
+ if (sl->spacetype != SPACE_NODE) {
+ 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) {
+ continue;
+ }
+ if (snode.nodetree != modifier->node_group) {
+ continue;
+ }
+ Vector<const bNodeTreePath *, 16> tree_path = snode.treepath;
+ if (tree_path.size() != parsed_viewer_path.group_node_names.size() + 1) {
+ continue;
+ }
+ bool valid_path = true;
+ for (const int i : parsed_viewer_path.group_node_names.index_range()) {
+ if (parsed_viewer_path.group_node_names[i] != tree_path[i + 1]->node_name) {
+ valid_path = false;
+ break;
+ }
+ }
+ if (!valid_path) {
+ continue;
+ }
+ const bNodeTree *ngroup = snode.edittree;
+ ngroup->ensure_topology_cache();
+ const bNode *viewer_node = nullptr;
+ for (const bNode *node : ngroup->nodes_by_type("GeometryNodeViewer")) {
+ if (node->name != parsed_viewer_path.viewer_node_name) {
+ continue;
+ }
+ viewer_node = node;
+ }
+ if (viewer_node == nullptr) {
+ continue;
+ }
+ if (!(viewer_node->flag & NODE_DO_OUTPUT)) {
+ continue;
+ }
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+bNode *find_geometry_nodes_viewer(const ViewerPath &viewer_path, SpaceNode &snode)
+{
+ const std::optional<ViewerPathForGeometryNodesViewer> parsed_viewer_path =
+ parse_geometry_nodes_viewer(viewer_path);
+ if (!parsed_viewer_path.has_value()) {
+ return nullptr;
+ }
+
+ snode.edittree->ensure_topology_cache();
+ bNode *possible_viewer = nullptr;
+ for (bNode *node : snode.edittree->nodes_by_type("GeometryNodeViewer")) {
+ if (node->name == parsed_viewer_path->viewer_node_name) {
+ possible_viewer = node;
+ break;
+ }
+ }
+ if (possible_viewer == nullptr) {
+ return nullptr;
+ }
+ ViewerPath tmp_viewer_path;
+ BLI_SCOPED_DEFER([&]() { BKE_viewer_path_clear(&tmp_viewer_path); });
+ viewer_path_for_geometry_node(snode, *possible_viewer, tmp_viewer_path);
+
+ if (BKE_viewer_path_equal(&viewer_path, &tmp_viewer_path)) {
+ return possible_viewer;
+ }
+ return nullptr;
+}
+
+} // namespace blender::ed::viewer_path