Skip to content

Commit 5f68d1d

Browse files
authored
Add file image preview for Graph Editor (#2710)
## Feature Update For better user feedback on what images are being used from the UI, this change adds image previews for file image nodes ### Details: - Adds a per `filename` input image preview - Default size is `256` px but is settable from the command line using the `--previewWidth` argument. A size of <= 0 will turn off previews. - Preview size will resize to fit up to the maximum property editor panel width if desired preview size is greater than the editor width. ### Implementation notes - Adds fix to use document "resolved" image path otherwise relative path images may not be found (e.g. std surface brick) #### Caveats - There is no software (C++) color management support to display images in the input color space.
1 parent 9875175 commit 5f68d1d

3 files changed

Lines changed: 83 additions & 7 deletions

File tree

source/MaterialXGraphEditor/Graph.cpp

Lines changed: 70 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,8 @@ Graph::Graph(const std::string& materialFilename,
125125
const mx::FileSearchPath& searchPath,
126126
const mx::FilePathVec& libraryFolders,
127127
int viewWidth,
128-
int viewHeight) :
128+
int viewHeight,
129+
float previewWidth) :
129130
_materialFilename(materialFilename),
130131
_searchPath(searchPath),
131132
_libraryFolders(libraryFolders),
@@ -143,6 +144,7 @@ Graph::Graph(const std::string& materialFilename,
143144
_autoLayout(false),
144145
_frameCount(INT_MIN),
145146
_fontScale(1.0f),
147+
_previewSize(previewWidth),
146148
_saveNodePositions(true)
147149
{
148150
loadStandardLibraries();
@@ -903,12 +905,59 @@ void Graph::showPropertyEditorValue(UiNodePtr node, mx::InputPtr input, const mx
903905
}
904906
else if (input->getType() == "filename")
905907
{
906-
mx::ValuePtr val = input->getValue();
908+
mx::ValuePtr val = input->getResolvedValue();
907909

908910
if (val && val->isA<std::string>())
909911
{
910912
std::string prev, temp;
911913
prev = temp = val->asA<std::string>();
914+
mx::FilePath filePath(temp);
915+
916+
bool drawPreview = _previewSize > 0;
917+
if (drawPreview)
918+
{
919+
float previewSize = _previewSize;
920+
// Clamp preview size to width of panel
921+
float panelWidth = ImGui::GetContentRegionAvail().x;
922+
if (previewSize > panelWidth)
923+
{
924+
previewSize = panelWidth;
925+
}
926+
927+
ImGui::BeginChild("imagePreview", ImVec2(previewSize, previewSize), false,
928+
ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoScrollWithMouse);
929+
930+
// Show image preview if file exists and is an image
931+
if (!temp.empty())
932+
{
933+
mx::ImageHandlerPtr imageHandler = _renderer ? _renderer->getImageHandler() : nullptr;
934+
if (imageHandler)
935+
{
936+
unsigned int textureId = 0;
937+
int width = 0, height = 0;
938+
mx::ImagePtr image = imageHandler->acquireImage(filePath);
939+
if (image)
940+
{
941+
textureId = image->getResourceId();
942+
width = image->getWidth();
943+
height = image->getHeight();
944+
}
945+
else
946+
{
947+
std::cout << "Image file not loaded: " << temp << std::endl;
948+
}
949+
if (textureId)
950+
{
951+
float aspect = (height > 0) ? (float)width / (float)height : 1.0f;
952+
ImVec2 imagePreviewSize(previewSize, previewSize / aspect);
953+
954+
ImGui::Image((void*)(intptr_t)textureId, imagePreviewSize);
955+
}
956+
}
957+
}
958+
ImGui::EndChild();
959+
}
960+
912961
ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(.15f, .15f, .15f, 1.0f));
913962
ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImVec4(.2f, .4f, .6f, 1.0f));
914963

@@ -923,7 +972,8 @@ void Graph::showPropertyEditorValue(UiNodePtr node, mx::InputPtr input, const mx
923972
}
924973
ImGui::PopItemWidth();
925974
ImGui::SameLine();
926-
ImGui::Text("%s", mx::FilePath(temp).getBaseName().c_str());
975+
ImGui::Text("%s", filePath.getBaseName().c_str());
976+
927977
ImGui::PopStyleColor();
928978
ImGui::PopStyleColor();
929979

@@ -3382,23 +3432,38 @@ void Graph::propertyEditor()
33823432
{
33833433
_currUiNode->setShowAllInputs(showAllInputs);
33843434
}
3435+
33853436
bool showOutputsInEditor = _currUiNode->getShowOutputsInEditor();
33863437
if (ImGui::Checkbox("Show output connections", &showOutputsInEditor))
33873438
{
33883439
_currUiNode->setShowOutputsInEditor(showOutputsInEditor);
3389-
}
3440+
}
33903441

33913442
int count = 0;
3443+
float totalImagePadding = 0.0f;
3444+
float imagePadding = 0.0f;
3445+
if (_previewSize > 0.0f)
3446+
{
3447+
imagePadding = (_previewSize > availableWidth) ? availableWidth : _previewSize;
3448+
}
3449+
33923450
for (UiPinPtr input : _currUiNode->getInputPins())
33933451
{
33943452
if (_currUiNode->getShowAllInputs() || (input->getConnected() || _currUiNode->getNode()->getInput(input->getName())))
33953453
{
33963454
count++;
3455+
3456+
// Add space for image previews
3457+
if (imagePadding > 0.0f && input->getInput()->getType() == "filename")
3458+
{
3459+
totalImagePadding += imagePadding;
3460+
}
33973461
}
33983462
}
33993463
if (count)
34003464
{
3401-
ImVec2 tableSize(0.0f, TEXT_BASE_HEIGHT * std::min(SCROLL_LINE_COUNT, count));
3465+
float baseHeight = TEXT_BASE_HEIGHT * std::min(SCROLL_LINE_COUNT, count);
3466+
ImVec2 tableSize(0.0f, baseHeight + totalImagePadding);
34023467
bool haveTable = ImGui::BeginTable("inputs_node_table", 2, tableFlags, tableSize);
34033468
if (haveTable)
34043469
{

source/MaterialXGraphEditor/Graph.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,8 @@ class Graph
9292
const mx::FileSearchPath& searchPath,
9393
const mx::FilePathVec& libraryFolders,
9494
int viewWidth,
95-
int viewHeight);
95+
int viewHeight,
96+
float previewWidth);
9697
~Graph() = default;
9798

9899
mx::DocumentPtr loadDocument(const mx::FilePath& filename);
@@ -344,6 +345,9 @@ class Graph
344345
// Layout engine
345346
Layout _layout;
346347

348+
// Preview area size
349+
float _previewSize;
350+
347351
// Options
348352
bool _saveNodePositions;
349353
};

source/MaterialXGraphEditor/Main.cpp

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ const std::string options =
3434
" --font [FILENAME] Specify the name of the custom font file to use. If not specified the default font will be used.\n"
3535
" --fontSize [SIZE] Specify font size to use for the custom font. If not specified a default of 18 will be used.\n"
3636
" --captureFilename [FILENAME] Specify the filename to which the first rendered frame should be written\n"
37+
" --previewWidth [WIDTH] Specify the width for image previews\n"
3738
" --help Display the complete list of command-line options\n";
3839

3940
template <class T> void parseToken(std::string token, std::string type, T& res)
@@ -72,6 +73,7 @@ int main(int argc, char* const argv[])
7273
float uiScale = 0.0f;
7374
std::string fontFilename;
7475
int fontSize = 18;
76+
float previewWidth = 256.0f;
7577
std::string captureFilename;
7678

7779
for (size_t i = 0; i < tokens.size(); i++)
@@ -115,6 +117,10 @@ int main(int argc, char* const argv[])
115117
{
116118
parseToken(nextToken, "integer", fontSize);
117119
}
120+
else if (token == "--previewWidth")
121+
{
122+
parseToken(nextToken, "float", previewWidth);
123+
}
118124
else if (token == "--captureFilename")
119125
{
120126
parseToken(nextToken, "string", captureFilename);
@@ -224,7 +230,8 @@ int main(int argc, char* const argv[])
224230
searchPath,
225231
libraryFolders,
226232
viewWidth,
227-
viewHeight);
233+
viewHeight,
234+
previewWidth);
228235
if (!captureFilename.empty())
229236
{
230237
graph->getRenderer()->requestFrameCapture(captureFilename);

0 commit comments

Comments
 (0)