diff --git a/meshroom/core/node.py b/meshroom/core/node.py index de43356a..bf68a83a 100644 --- a/meshroom/core/node.py +++ b/meshroom/core/node.py @@ -1124,11 +1124,27 @@ class BaseNode(BaseObject): self.globalExecMode == "LOCAL" and self.statusInThisSession()) def hasImageOutputAttribute(self): + """ + Return True if at least one attribute has the 'image' semantic (and can thus be loaded in the 2D Viewer), False otherwise. + """ for attr in self._attributes: if attr.enabled and attr.isOutput and attr.desc.semantic == "image": return True return False + def has3DOutputAttribute(self): + """ + Return True if at least one attribute is a File that can be loaded in the 3D Viewer, False otherwise. + """ + # List of supported extensions, taken from Viewer3DSettings + supportedExts = ['.obj', '.stl', '.fbx', '.gltf', '.abc'] + for attr in self._attributes: + # If the attribute is a File attribute, it is an instance of str and can be iterated over + hasSupportedExt = isinstance(attr.value, str) and any(ext in attr.value for ext in supportedExts) + if attr.enabled and attr.isOutput and hasSupportedExt: + return True + return False + name = Property(str, getName, constant=True) nodeType = Property(str, nodeType.fget, constant=True) @@ -1174,7 +1190,7 @@ class BaseNode(BaseObject): outputAttrEnabledChanged = Signal() hasImageOutput = Property(bool, hasImageOutputAttribute, notify=outputAttrEnabledChanged) - + has3DOutput = Property(bool, has3DOutputAttribute, notify=outputAttrEnabledChanged) class Node(BaseNode): """ diff --git a/meshroom/ui/qml/GraphEditor/Node.qml b/meshroom/ui/qml/GraphEditor/Node.qml index 955a6d8e..b338055e 100755 --- a/meshroom/ui/qml/GraphEditor/Node.qml +++ b/meshroom/ui/qml/GraphEditor/Node.qml @@ -308,7 +308,8 @@ Item { MaterialLabel { id: nodeImageOutput - visible: node.hasImageOutput && ["SUCCESS"].includes(node.globalStatus) && node.chunks.count > 0 + visible: (node.hasImageOutput || node.has3DOutput) + && ["SUCCESS"].includes(node.globalStatus) && node.chunks.count > 0 text: MaterialIcons.visibility padding: 2 font.pointSize: 7 @@ -317,8 +318,14 @@ Item { id: nodeImageOutputTooltip parent: header visible: nodeImageOutputMA.containsMouse && nodeImageOutput.visible - text: "This node has at least one output that can be loaded in the 2D Viewer.\n" + - "Double-clicking on this node will load it in the 2D Viewer." + text: { + if (node.hasImageOutput && !node.has3DOutput) + return "Double-click on this node to load its outputs in the Image Viewer." + else if (node.has3DOutput && !node.hasImageOutput) + return "Double-click on this node to load its outputs in the 3D Viewer." + else // Handle case where a node might have both 2D and 3D outputs + return "Double-click on this node to load its outputs in the Image or 3D Viewer." + } implicitWidth: 500 delay: 300 diff --git a/meshroom/ui/qml/Viewer/Viewer2D.qml b/meshroom/ui/qml/Viewer/Viewer2D.qml index 9b12d83a..44206cac 100644 --- a/meshroom/ui/qml/Viewer/Viewer2D.qml +++ b/meshroom/ui/qml/Viewer/Viewer2D.qml @@ -181,15 +181,7 @@ FocusScope { } // node must have at least one output attribute with the image semantic - var hasImageOutputAttr = false; - for (var i = 0; i < node.attributes.count; i++) { - var attr = node.attributes.at(i); - if (attr.isOutput && attr.desc.semantic === "image" && attr.enabled) { - hasImageOutputAttr = true; - break; - } - } - if (!hasImageOutputAttr) { + if (!node.hasImageOutput) { return false; }