-
Notifications
You must be signed in to change notification settings - Fork 402
Graph Editor : Add snapshot capability #2430
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
50a029e
a7c9885
7bb3835
7412715
202c434
a5ac56d
ea709aa
32b171c
9f00de9
55f9b53
5c5cf3a
7b766f3
3fc6e10
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -143,6 +143,7 @@ Graph::Graph(const std::string& materialFilename, | |
_initial(false), | ||
_delete(false), | ||
_fileDialogSave(FileDialog::EnterNewFilename), | ||
_fileDialogSnapshot(FileDialog::EnterNewFilename), | ||
_isNodeGraph(false), | ||
_graphTotalSize(0), | ||
_popup(false), | ||
|
@@ -802,6 +803,10 @@ void Graph::setRenderMaterial(UiNodePtr node) | |
for (const std::string& testPath : testPaths) | ||
{ | ||
mx::ElementPtr testElem = _graphDoc->getDescendant(testPath); | ||
if (!testElem) | ||
{ | ||
continue; | ||
} | ||
mx::NodePtr testNode = testElem->asA<mx::Node>(); | ||
std::vector<mx::PortElementPtr> downstreamPorts; | ||
if (testNode) | ||
|
@@ -3180,6 +3185,40 @@ void Graph::saveGraphToFile() | |
_fileDialogSave.open(); | ||
} | ||
|
||
void Graph::showSnapshotDialog() | ||
{ | ||
if (!_capturedImage) | ||
{ | ||
return; | ||
} | ||
mx::StringVec imageFilter; | ||
imageFilter.push_back(".png"); | ||
_fileDialogSnapshot.setTypeFilters(imageFilter); | ||
_fileDialogSnapshot.setTitle("Save SnapshotAs"); | ||
_fileDialogSnapshot.open(); | ||
} | ||
|
||
void Graph::saveSnapshotToFile() | ||
{ | ||
ed::Suspend(); | ||
_fileDialogSnapshot.display(); | ||
|
||
// Save capture | ||
if (_fileDialogSnapshot.hasSelected()) | ||
{ | ||
std::string captureName = _fileDialogSnapshot.getSelected(); | ||
std::cout << "Save image to: " << captureName << std::endl; | ||
_renderer->getImageHandler()->saveImage(captureName, _capturedImage, true); | ||
_capturedImage = nullptr; | ||
ed::Resume(); | ||
_fileDialogSnapshot.clearSelected(); | ||
} | ||
else | ||
{ | ||
ed::Resume(); | ||
} | ||
} | ||
|
||
void Graph::loadGeometry() | ||
{ | ||
_fileDialogGeom.setTitle("Load Geometry"); | ||
|
@@ -3276,12 +3315,10 @@ void Graph::graphButtons() | |
} | ||
|
||
// Split window into panes for NodeEditor | ||
static float leftPaneWidth = 375.0f; | ||
static float rightPaneWidth = 750.0f; | ||
splitter(true, 4.0f, &leftPaneWidth, &rightPaneWidth, 20.0f, 20.0f); | ||
splitter(true, 4.0f, &_leftPaneWidth, &_rightPaneWidth, 20.0f, 20.0f); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Remove some hard-coded statics and make class members for reuse during snapshot. |
||
|
||
// Create back button and graph hierarchy name display | ||
ImGui::Indent(leftPaneWidth + 15.f); | ||
ImGui::Indent(_leftPaneWidth + _nodeEditorIndent); | ||
if (ImGui::Button("<")) | ||
{ | ||
upNodeGraph(); | ||
|
@@ -3301,12 +3338,12 @@ void Graph::graphButtons() | |
} | ||
} | ||
ImVec2 windowPos2 = ImGui::GetWindowPos(); | ||
ImGui::Unindent(leftPaneWidth + 15.f); | ||
ImGui::Unindent(_leftPaneWidth + _nodeEditorIndent); | ||
ImGui::PopStyleColor(); | ||
ImGui::NewLine(); | ||
|
||
// Create two windows using splitter | ||
float paneWidth = (leftPaneWidth - 2.0f); | ||
float paneWidth = (_leftPaneWidth - 2.0f); | ||
|
||
float aspectRatio = _renderer->getPixelRatio(); | ||
ImVec2 screenSize = ImVec2(paneWidth, paneWidth / aspectRatio); | ||
|
@@ -3735,6 +3772,8 @@ void Graph::showHelp() const | |
ImGui::BulletText("CTRL-F : Find a node by name."); | ||
ImGui::BulletText("CTRL-X : Delete selected nodes and add to clipboard."); | ||
ImGui::BulletText("DELETE : Delete selected nodes or connections."); | ||
ImGui::BulletText("CTRL-I : Capture Editor Panel to disk."); | ||
ImGui::BulletText("CTRL-SHIFT-I : Capture entire window to disk."); | ||
ImGui::TreePop(); | ||
} | ||
} | ||
|
@@ -4031,6 +4070,65 @@ void Graph::handleRenderViewInputs() | |
} | ||
} | ||
|
||
mx::ImagePtr Graph::performSnapshot(bool captureWindow) const | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Snapshot function : takes into account the current splitter layout and extra formatting (indentation). |
||
{ | ||
if (captureWindow) | ||
{ | ||
ImVec2 windowPos = ImGui::GetWindowPos(); | ||
ImVec2 windowSize = ImGui::GetWindowSize(); | ||
unsigned int w = static_cast<unsigned int>(windowSize.x); | ||
unsigned int h = static_cast<unsigned int>(windowSize.y); | ||
|
||
mx::ImagePtr image = mx::Image::create(w, h, 3); | ||
if (image) | ||
{ | ||
image->createResourceBuffer(); | ||
|
||
glFlush(); | ||
glReadPixels(0, 0, image->getWidth(), image->getHeight(), GL_RGB, GL_UNSIGNED_BYTE, image->getResourceBuffer()); | ||
} | ||
return image; | ||
} | ||
|
||
// Get main window information | ||
ImGuiWindow* window = ImGui::GetCurrentWindow(); | ||
ImVec2 windowPos = window->Pos; | ||
ImVec2 windowSize = window->Size; | ||
|
||
// Get editor information | ||
ImVec2 contentSize = ImGui::GetContentRegionAvail(); // Excludes menu bars | ||
|
||
float splitterSize = 4.0f; | ||
float leftOffset = _leftPaneWidth + _nodeEditorIndent; | ||
float topOffset = _nodeEditorIndent; | ||
float rightOffset = _nodeEditorIndent; | ||
|
||
// Calculate the right pane position. Include splitter and indentation from top left corner | ||
ImVec2 rightPanePos; | ||
rightPanePos.x = leftOffset + splitterSize; | ||
rightPanePos.y = topOffset; | ||
|
||
// Calculate the right panel size. Remove left and right editor offsets. | ||
ImVec2 rightPaneSize; | ||
rightPaneSize.x = windowSize.x - (leftOffset + rightOffset); | ||
rightPaneSize.y = contentSize.y - (windowPos.y + 2.0f * topOffset); | ||
|
||
int w = static_cast<int>(rightPaneSize.x); | ||
int h = static_cast<int>(rightPaneSize.y); | ||
mx::ImagePtr image = mx::Image::create(static_cast<unsigned int>(w), static_cast<unsigned int>(h), 3); | ||
if (image) | ||
{ | ||
image->createResourceBuffer(); | ||
|
||
glFlush(); | ||
glReadPixels(static_cast<int>(rightPanePos.x), 0, w, h, | ||
GL_RGB, GL_UNSIGNED_BYTE, | ||
image->getResourceBuffer() | ||
); | ||
} | ||
return image; | ||
} | ||
|
||
void Graph::drawGraph(ImVec2 mousePos) | ||
{ | ||
if (_searchNodeId > 0) | ||
|
@@ -4050,6 +4148,19 @@ void Graph::drawGraph(ImVec2 mousePos) | |
|
||
io2.ConfigFlags = ImGuiConfigFlags_IsSRGB | ImGuiConfigFlags_NavEnableKeyboard; | ||
io2.MouseDoubleClickTime = .5; | ||
|
||
// Capture. Perform before other UI calls which can change window size / positioning. | ||
if (io2.KeyCtrl && ImGui::IsKeyReleased(ImGuiKey_I)) | ||
{ | ||
// Capture entire window if SHIFT, otherwise capture node editor | ||
bool captureWindow = io2.KeyShift; | ||
_capturedImage = performSnapshot(captureWindow); | ||
if (_capturedImage) | ||
{ | ||
showSnapshotDialog(); | ||
} | ||
} | ||
|
||
graphButtons(); | ||
|
||
ed::Begin("My Editor"); | ||
|
@@ -4386,6 +4497,7 @@ void Graph::drawGraph(ImVec2 mousePos) | |
} | ||
} | ||
ed::EndDelete(); | ||
|
||
} | ||
|
||
// Dive into a node that has a subgraph | ||
|
@@ -4488,6 +4600,8 @@ void Graph::drawGraph(ImVec2 mousePos) | |
ed::Resume(); | ||
} | ||
|
||
saveSnapshotToFile(); | ||
|
||
ed::End(); | ||
ImGui::End(); | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -236,6 +236,11 @@ class Graph | |
|
||
void showHelp() const; | ||
|
||
// Methods to capture snapshot to file | ||
mx::ImagePtr performSnapshot(bool captureWindow = false) const; | ||
void showSnapshotDialog(); | ||
void saveSnapshotToFile(); | ||
|
||
private: | ||
mx::StringVec _geomFilter; | ||
mx::StringVec _mtlxFilter; | ||
|
@@ -295,6 +300,7 @@ class Graph | |
FileDialog _fileDialogSave; | ||
FileDialog _fileDialogImage; | ||
FileDialog _fileDialogGeom; | ||
FileDialog _fileDialogSnapshot; | ||
std::string _fileDialogImageInputName; | ||
|
||
bool _isNodeGraph; | ||
|
@@ -326,6 +332,14 @@ class Graph | |
|
||
// Options | ||
bool _saveNodePositions; | ||
|
||
// Panel information | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Make class members to track panel placement / size changes. |
||
float _leftPaneWidth = 375.0f; | ||
float _nodeEditorIndent = 15.0f; | ||
float _rightPaneWidth = 750.0f; | ||
|
||
// Image capture | ||
mx::ImagePtr _capturedImage; | ||
}; | ||
|
||
#endif |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Some file dialog infrastructure. Save uses the current captured image.