Skip to content
Snippets Groups Projects
Commit 2dc4d59a authored by Utkarsh Ayachit's avatar Utkarsh Ayachit
Browse files

vtkSMSaveScreenshotProxy: support stereo both eyes

vtkSMSaveScreenshotProxy can now save both eyes for stereo images at the
same time. The filenames are suffixed with "_left" and "_right" to
distinguish the two images generated.
parent b68b1ac6
No related branches found
No related tags found
No related merge requests found
......@@ -2448,6 +2448,7 @@
<Entry text="Interlaced" value="3" />
<Entry text="Left Eye Only" value="4" />
<Entry text="Right Eye Only" value="5" />
<Entry text="Both Eyes" value="11" />
<Entry text="Dresden" value="6" />
<Entry text="Anaglyph" value="7" />
<Entry text="Checkerboard" value="8" />
......
......@@ -21,6 +21,7 @@
#include "vtkObjectFactory.h"
#include "vtkPVXMLElement.h"
#include "vtkProcessModule.h"
#include "vtkRenderWindow.h"
#include "vtkSMParaViewPipelineControllerWithRendering.h"
#include "vtkSMProperty.h"
#include "vtkSMPropertyHelper.h"
......@@ -113,6 +114,7 @@ private:
protected:
vtkVector2i Magnification;
vtkVector2i OriginalSize;
bool BothEyes;
public:
vtkState(vtkSMSessionProxyManager* pxm)
......@@ -120,6 +122,7 @@ public:
, TransparentBackground(false)
, Magnification(1, 1)
, OriginalSize(0, 0)
, BothEyes(false)
{
this->TransparentBackground = vtkSMViewProxy::GetTransparentBackground();
}
......@@ -196,38 +199,72 @@ public:
}
}
void SetStereoMode(int mode)
{
if (mode == VTK_STEREO_EMULATE)
{
this->BothEyes = true;
this->UpdateStereoMode(VTK_STEREO_LEFT, /*restoreable=*/true);
}
else
{
this->BothEyes = false;
this->UpdateStereoMode(mode, /*restoreable=*/true);
}
}
void SetTransparentBackground(bool val) { vtkSMViewProxy::SetTransparentBackground(val); }
std::pair<vtkSmartPointer<vtkImageData>, vtkSmartPointer<vtkImageData> > CaptureImages()
{
std::pair<vtkSmartPointer<vtkImageData>, vtkSmartPointer<vtkImageData> > result;
if (this->BothEyes)
{
this->UpdateStereoMode(VTK_STEREO_LEFT, /*restoreable=*/false);
result.first = this->CaptureImage();
this->UpdateStereoMode(VTK_STEREO_RIGHT, /*restoreable=*/false);
result.second = this->CaptureImage();
}
else
{
result.first = this->CaptureImage();
}
return result;
}
virtual vtkSmartPointer<vtkImageData> CaptureImage() = 0;
virtual void SetStereoMode(int mode) = 0;
virtual void SetFontScaling(int mode) = 0;
virtual void SetSeparatorWidth(int) {}
virtual void SetSeparatorColor(double[3]) {}
protected:
virtual void Resize(const vtkVector2i& size) = 0;
virtual void UpdateStereoMode(int mode, bool restoreable) = 0;
void SetViewStereoMode(vtkSMViewProxy* view, int stereoMode)
void SetViewStereoMode(vtkSMViewProxy* view, int stereoMode, bool restoreable = true)
{
assert(view);
if (stereoMode <= -1)
{
return;
}
const int stereo_render = stereoMode == 0 ? 0 : 1;
vtkSMPropertyHelper srender(view, "StereoRender", true);
vtkSMPropertyHelper stype(view, "StereoType", true);
if (stype.GetAsInt() != stereoMode)
// Save it so we can restore at the end.
if (restoreable)
{
// if mode changed, then we save it so we can restore at the end.
ViewStereoState svalue;
svalue.View = view;
svalue.StereoType = stype.GetAsInt();
svalue.StereoRender = srender.GetAsInt();
this->SavedStereoValues.push_back(svalue);
stype.Set(stereoMode);
srender.Set(stereoMode == 0 ? 0 : 1);
view->UpdateVTKObjects();
}
stype.Set(stereoMode);
srender.Set(stereo_render);
view->UpdateVTKObjects();
}
void SetViewFontScaling(vtkSMViewProxy* view, int mode)
......@@ -290,10 +327,13 @@ public:
return img;
}
void SetStereoMode(int mode) override { this->SetViewStereoMode(this->View, mode); }
void SetFontScaling(int mode) override { this->SetViewFontScaling(this->View, mode); }
protected:
void UpdateStereoMode(int mode, bool restoreable) override
{
this->SetViewStereoMode(this->View, mode, restoreable);
}
void Resize(const vtkVector2i& size) override
{
vtkSMPropertyHelper(this->View, "ViewSize").Set(size.GetData(), 2);
......@@ -347,15 +387,6 @@ public:
return img;
}
void SetStereoMode(int mode) override
{
const std::vector<vtkSMViewProxy*> views = this->Layout->GetViews();
for (auto iter = views.begin(); iter != views.end(); ++iter)
{
this->SetViewStereoMode(*iter, mode);
}
}
void SetFontScaling(int mode) override
{
const std::vector<vtkSMViewProxy*> views = this->Layout->GetViews();
......@@ -379,6 +410,14 @@ public:
protected:
void Resize(const vtkVector2i& size) override { this->Layout->SetSize(size.GetData()); }
void UpdateStereoMode(int mode, bool restoreable) override
{
const std::vector<vtkSMViewProxy*> views = this->Layout->GetViews();
for (auto iter = views.begin(); iter != views.end(); ++iter)
{
this->SetViewStereoMode(*iter, mode, restoreable);
}
}
};
//============================================================================
......@@ -398,8 +437,15 @@ vtkSMSaveScreenshotProxy::~vtkSMSaveScreenshotProxy()
}
//----------------------------------------------------------------------------
bool vtkSMSaveScreenshotProxy::WriteImage(const char* filename)
bool vtkSMSaveScreenshotProxy::WriteImage(const char* fname)
{
if (fname == nullptr)
{
return false;
}
const std::string filename(fname);
vtkSMViewLayoutProxy* layout = this->GetLayout();
vtkSMViewProxy* view = this->GetView();
......@@ -414,7 +460,7 @@ bool vtkSMSaveScreenshotProxy::WriteImage(const char* filename)
auto format = this->GetFormatProxy(filename);
if (!format)
{
vtkErrorMacro("Failed to determine format for '" << filename << "'");
vtkErrorMacro("Failed to determine format for '" << filename.c_str() << "'");
return false;
}
......@@ -423,55 +469,85 @@ bool vtkSMSaveScreenshotProxy::WriteImage(const char* filename)
SM_SCOPED_TRACE(SaveScreenshotOrAnimation)
.arg("helper", this)
.arg("filename", filename)
.arg("filename", filename.c_str())
.arg("view", view)
.arg("layout", layout)
.arg("mode_screenshot", 1);
vtkSmartPointer<vtkImageData> img = this->CaptureImage();
if (img && vtkProcessModule::GetProcessModule()->GetPartitionId() == 0)
if (!this->Prepare())
{
auto writer = vtkImageWriter::SafeDownCast(format->GetClientSideObject());
if (writer)
{
vtkTimerLog::MarkStartEvent("Write image to disk");
writer->SetFileName(filename);
writer->SetInputData(img);
writer->Write();
writer->SetInputData(nullptr);
vtkTimerLog::MarkEndEvent("Write image to disk");
return writer->GetErrorCode() == vtkErrorCode::NoError;
}
else
{
vtkErrorMacro("Format writer not a 'vtkImageWriter'. "
" Failed to write '"
<< filename << "'.");
}
vtkErrorMacro("Failed to prepare to capture image.");
return false;
}
return false;
auto image_pair = this->CapturePreppedImages();
this->Cleanup();
if (image_pair.first == nullptr || vtkProcessModule::GetProcessModule()->GetPartitionId() != 0)
{
return false;
}
auto writer = vtkImageWriter::SafeDownCast(format->GetClientSideObject());
if (writer == nullptr)
{
vtkErrorMacro(
"Format writer not a 'vtkImageWriter'. Failed to write '" << filename.c_str() << "'.");
return false;
}
vtkTimerLog::MarkStartEvent("Write image to disk");
writer->SetFileName(filename.c_str());
// write right-eye image first.
if (image_pair.second)
{
writer->SetFileName(this->GetStereoFileName(filename, /*left=*/false).c_str());
writer->SetInputData(image_pair.second);
writer->Write();
// change left-eye filename too
writer->SetFileName(this->GetStereoFileName(filename, /*left=*/true).c_str());
}
// now write left-eye.
writer->SetInputData(image_pair.first);
writer->Write();
writer->SetInputData(nullptr);
vtkTimerLog::MarkEndEvent("Write image to disk");
return writer->GetErrorCode() == vtkErrorCode::NoError;
}
//----------------------------------------------------------------------------
vtkSmartPointer<vtkImageData> vtkSMSaveScreenshotProxy::CaptureImage()
{
if (vtkSMPropertyHelper(this, "StereoMode").GetAsInt() == VTK_STEREO_EMULATE)
{
vtkErrorMacro("StereoMode is set to 'VTK_STEREO_EMULATE' (aka Both Eyes). "
"`CaptureImage` does not support capturing both eyes at the same time."
"Please set stereo mode to one eye at a time.");
return nullptr;
}
if (!this->Prepare())
{
vtkErrorMacro("Failed to prepare to capture image.");
return NULL;
}
vtkSmartPointer<vtkImageData> img = this->CapturePreppedImage();
assert(this->State != NULL);
vtkSmartPointer<vtkImageData> img = this->CapturePreppedImages().first;
this->Cleanup();
return img;
}
//----------------------------------------------------------------------------
vtkSmartPointer<vtkImageData> vtkSMSaveScreenshotProxy::CapturePreppedImage()
std::pair<vtkSmartPointer<vtkImageData>, vtkSmartPointer<vtkImageData> >
vtkSMSaveScreenshotProxy::CapturePreppedImages()
{
assert(this->State != NULL);
return this->State->CaptureImage();
return this->State->CaptureImages();
}
//----------------------------------------------------------------------------
......@@ -835,6 +911,20 @@ vtkSMProxy* vtkSMSaveScreenshotProxy::GetFormatProxy(const std::string& filename
return nullptr;
}
//----------------------------------------------------------------------------
std::string vtkSMSaveScreenshotProxy::GetStereoFileName(const std::string& filename, bool left)
{
const auto dot_pos = filename.rfind('.');
if (dot_pos == std::string::npos)
{
return filename + (left ? "_left" : "_right");
}
else
{
return filename.substr(0, dot_pos) + (left ? "_left" : "_right") + filename.substr(dot_pos);
}
}
//----------------------------------------------------------------------------
void vtkSMSaveScreenshotProxy::PrintSelf(ostream& os, vtkIndent indent)
{
......
......@@ -55,7 +55,7 @@ public:
/**
* Capture the rendered image but doesn't save it out to any file.
*/
virtual vtkSmartPointer<vtkImageData> CaptureImage();
vtkSmartPointer<vtkImageData> CaptureImage();
/**
* Updates default property values for saving the given file.
......@@ -114,10 +114,10 @@ protected:
~vtkSMSaveScreenshotProxy() override;
/**
* Captures rendered image, but assumes that the `Prepare` has already been
* called successfully.
* When StereoMode is set to VTK_STEREO_EMULATE, both eyes are captures. In
* that case, this method may be used to return images for each of the eyes.
*/
virtual vtkSmartPointer<vtkImageData> CapturePreppedImage();
std::pair<vtkSmartPointer<vtkImageData>, vtkSmartPointer<vtkImageData> > CapturePreppedImages();
/**
* Prepares for saving an image. This will do any changes to view properties
......@@ -140,6 +140,11 @@ protected:
*/
vtkSMProxy* GetFormatProxy(const std::string& filename);
/**
* Adds a stereo filename suffix to the given filename.
*/
std::string GetStereoFileName(const std::string& filename, bool left);
friend class pqCatalystExportReaction; // access to GetView,FormatProxy
friend class pqImmediateExportReaction; // access to GetView,FormatProxy
friend class pqTemporalExportReaction; // access to GetView,FormatProxy
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment