mirror of
https://github.com/OpenFOAM/ThirdParty-6.git
synced 2025-12-08 06:57:43 +00:00
825 lines
27 KiB
C++
825 lines
27 KiB
C++
/*=========================================================================
|
|
|
|
Program: ParaView
|
|
Module: pqAnimationManager.cxx
|
|
|
|
Copyright (c) 2005-2008 Sandia Corporation, Kitware Inc.
|
|
All rights reserved.
|
|
|
|
ParaView is a free software; you can redistribute it and/or modify it
|
|
under the terms of the ParaView license version 1.2.
|
|
|
|
See License_v1.2.txt for the full ParaView license.
|
|
A copy of this license can be obtained by contacting
|
|
Kitware Inc.
|
|
28 Corporate Drive
|
|
Clifton Park, NY 12065
|
|
USA
|
|
|
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
|
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR
|
|
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
|
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
|
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
|
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
|
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
|
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
|
|
========================================================================*/
|
|
#include "pqAnimationManager.h"
|
|
#include "ui_pqAbortAnimation.h"
|
|
#include "ui_pqAnimationSettings.h"
|
|
|
|
#include "vtkMath.h"
|
|
#include "vtkNew.h"
|
|
#include "vtkProcessModule.h"
|
|
#include "vtkPVServerInformation.h"
|
|
#include "vtkPVXMLElement.h"
|
|
#include "vtkRenderWindow.h"
|
|
#include "vtkSMAnimationSceneGeometryWriter.h"
|
|
#include "vtkSmartPointer.h"
|
|
#include "vtkSMParaViewPipelineController.h"
|
|
#include "vtkSMPropertyHelper.h"
|
|
#include "vtkSMProxy.h"
|
|
#include "vtkSMProxyIterator.h"
|
|
#include "vtkSMProxyManager.h"
|
|
#include "vtkSMProxyProperty.h"
|
|
#include "vtkSMSession.h"
|
|
#include "vtkSMSessionProxyManager.h"
|
|
#include "vtkSMStringVectorProperty.h"
|
|
#include "vtkSMTrace.h"
|
|
#include "vtkSMViewProxy.h"
|
|
#include "vtkWeakPointer.h"
|
|
|
|
#include <QIntValidator>
|
|
#include <QFileInfo>
|
|
#include <QMap>
|
|
#include <QMessageBox>
|
|
#include <QPointer>
|
|
#include <QSize>
|
|
#include <QtDebug>
|
|
|
|
#include "pqAnimationCue.h"
|
|
#include "pqAnimationScene.h"
|
|
#include "pqAnimationSceneImageWriter.h"
|
|
#include "pqApplicationCore.h"
|
|
#include "pqCoreUtilities.h"
|
|
#include "pqEventDispatcher.h"
|
|
#include "pqFileDialog.h"
|
|
#include "pqObjectBuilder.h"
|
|
#include "pqProgressManager.h"
|
|
#include "pqProxy.h"
|
|
#include "pqRenderViewBase.h"
|
|
#include "pqSMAdaptor.h"
|
|
#include "pqServer.h"
|
|
#include "pqServerManagerModel.h"
|
|
#include "pqSettings.h"
|
|
#include "pqTabbedMultiViewWidget.h"
|
|
|
|
#include <sstream>
|
|
|
|
#define SEQUENCE 0
|
|
#define REALTIME 1
|
|
#define SNAP_TO_TIMESTEPS 2
|
|
|
|
//-----------------------------------------------------------------------------
|
|
class pqAnimationManager::pqInternals
|
|
{
|
|
public:
|
|
QPointer<pqServer> ActiveServer;
|
|
typedef QMap<pqServer*, QPointer<pqAnimationScene> > SceneMap;
|
|
SceneMap Scenes;
|
|
Ui::pqAnimationSettingsDialog* AnimationSettingsDialog;
|
|
|
|
QSize OldMaxSize;
|
|
QSize OldSize;
|
|
|
|
double AspectRatio;
|
|
};
|
|
|
|
//-----------------------------------------------------------------------------
|
|
pqAnimationManager::pqAnimationManager(QObject* _parent/*=0*/)
|
|
:QObject(_parent)
|
|
{
|
|
this->Internals = new pqAnimationManager::pqInternals();
|
|
pqServerManagerModel* smmodel =
|
|
pqApplicationCore::instance()->getServerManagerModel();
|
|
QObject::connect(smmodel, SIGNAL(proxyAdded(pqProxy*)),
|
|
this, SLOT(onProxyAdded(pqProxy*)));
|
|
QObject::connect(smmodel, SIGNAL(proxyRemoved(pqProxy*)),
|
|
this, SLOT(onProxyRemoved(pqProxy*)));
|
|
|
|
QObject::connect(smmodel, SIGNAL(viewAdded(pqView*)),
|
|
this, SLOT(updateViewModules()));
|
|
QObject::connect(smmodel, SIGNAL(viewRemoved(pqView*)),
|
|
this, SLOT(updateViewModules()));
|
|
|
|
this->restoreSettings();
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
pqAnimationManager::~pqAnimationManager()
|
|
{
|
|
this->saveSettings();
|
|
delete this->Internals;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
void pqAnimationManager::updateViewModules()
|
|
{
|
|
pqAnimationScene* scene = this->getActiveScene();
|
|
if (!scene)
|
|
{
|
|
return;
|
|
}
|
|
|
|
QList<pqView*> viewModules =
|
|
pqApplicationCore::instance()->getServerManagerModel()->
|
|
findItems<pqView*>(this->Internals->ActiveServer);
|
|
|
|
QList<pqSMProxy> viewList;
|
|
foreach(pqView* view, viewModules)
|
|
{
|
|
viewList.push_back(pqSMProxy(view->getProxy()));
|
|
}
|
|
|
|
emit this->beginNonUndoableChanges();
|
|
|
|
vtkSMProxy* sceneProxy = scene->getProxy();
|
|
pqSMAdaptor::setProxyListProperty(sceneProxy->GetProperty("ViewModules"),
|
|
viewList);
|
|
sceneProxy->UpdateProperty("ViewModules");
|
|
|
|
emit this->endNonUndoableChanges();
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
void pqAnimationManager::onProxyAdded(pqProxy* proxy)
|
|
{
|
|
pqAnimationScene* scene = qobject_cast<pqAnimationScene*>(proxy);
|
|
if (scene && !this->Internals->Scenes.contains(scene->getServer()))
|
|
{
|
|
this->Internals->Scenes[scene->getServer()] = scene;
|
|
if (this->Internals->ActiveServer == scene->getServer())
|
|
{
|
|
emit this->activeSceneChanged(this->getActiveScene());
|
|
}
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
void pqAnimationManager::onProxyRemoved(pqProxy* proxy)
|
|
{
|
|
pqAnimationScene* scene = qobject_cast<pqAnimationScene*>(proxy);
|
|
if (scene)
|
|
{
|
|
this->Internals->Scenes.remove(scene->getServer());
|
|
if (this->Internals->ActiveServer == scene->getServer())
|
|
{
|
|
emit this->activeSceneChanged(this->getActiveScene());
|
|
}
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
void pqAnimationManager::onActiveServerChanged(pqServer* server)
|
|
{
|
|
// In case of multi-server that method can be called when we disconnect
|
|
// from one or our connected server.
|
|
// Check if the server is going to be deleted and if so just skip creation
|
|
if(!server || !server->session() || server->session()->GetReferenceCount() == 1)
|
|
{
|
|
return;
|
|
}
|
|
|
|
this->Internals->ActiveServer = server;
|
|
emit this->activeServerChanged(server);
|
|
emit this->activeSceneChanged(this->getActiveScene());
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
pqAnimationScene* pqAnimationManager::getActiveScene() const
|
|
{
|
|
return this->getScene(this->Internals->ActiveServer);
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
pqAnimationScene* pqAnimationManager::getScene(pqServer* server) const
|
|
{
|
|
if (server && this->Internals->Scenes.contains(server))
|
|
{
|
|
return this->Internals->Scenes.value(server);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
pqAnimationCue* pqAnimationManager::getCue(
|
|
pqAnimationScene* scene, vtkSMProxy* proxy, const char* propertyname,
|
|
int index) const
|
|
{
|
|
return (scene? scene->getCue(proxy, propertyname, index) : 0);
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Called when user changes some property on the save animation dialog.
|
|
void pqAnimationManager::updateGUI()
|
|
{
|
|
double framerate =
|
|
this->Internals->AnimationSettingsDialog->frameRate->value();
|
|
int num_frames =
|
|
this->Internals->AnimationSettingsDialog->spinBoxNumberOfFrames->value();
|
|
double duration =
|
|
this->Internals->AnimationSettingsDialog->animationDuration->value();
|
|
int frames_per_timestep =
|
|
this->Internals->AnimationSettingsDialog->spinBoxFramesPerTimestep->value();
|
|
|
|
vtkSMProxy* sceneProxy = this->getActiveScene()->getProxy();
|
|
int playMode = pqSMAdaptor::getElementProperty(
|
|
sceneProxy->GetProperty("PlayMode")).toInt();
|
|
|
|
switch (playMode)
|
|
{
|
|
case SNAP_TO_TIMESTEPS:
|
|
// get original number of frames.
|
|
num_frames = pqSMAdaptor::getMultipleElementProperty(
|
|
sceneProxy->GetProperty("TimeSteps")).size();
|
|
num_frames = frames_per_timestep*num_frames;
|
|
this->Internals->AnimationSettingsDialog->spinBoxNumberOfFrames->
|
|
blockSignals(true);
|
|
this->Internals->AnimationSettingsDialog->spinBoxNumberOfFrames->
|
|
setValue(num_frames);
|
|
this->Internals->AnimationSettingsDialog->spinBoxNumberOfFrames->
|
|
blockSignals(false);
|
|
// don't break, let it fall through to SEQUENCE.
|
|
|
|
case SEQUENCE:
|
|
this->Internals->AnimationSettingsDialog->animationDuration->
|
|
blockSignals(true);
|
|
this->Internals->AnimationSettingsDialog->animationDuration->setValue(
|
|
num_frames/framerate);
|
|
this->Internals->AnimationSettingsDialog->animationDuration->
|
|
blockSignals(false);
|
|
break;
|
|
|
|
case REALTIME:
|
|
this->Internals->AnimationSettingsDialog->spinBoxNumberOfFrames->
|
|
blockSignals(true);
|
|
this->Internals->AnimationSettingsDialog->spinBoxNumberOfFrames->setValue(
|
|
static_cast<int>(duration*framerate));
|
|
this->Internals->AnimationSettingsDialog->spinBoxNumberOfFrames->
|
|
blockSignals(false);
|
|
break;
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
void pqAnimationManager::onWidthEdited()
|
|
{
|
|
Ui::pqAnimationSettingsDialog *dialog
|
|
= this->Internals->AnimationSettingsDialog;
|
|
if (dialog->lockAspect->isChecked())
|
|
{
|
|
int width = dialog->width->text().toInt();
|
|
int height = static_cast<int>(width/this->Internals->AspectRatio);
|
|
dialog->height->setText(QString::number(height));
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
void pqAnimationManager::onHeightEdited()
|
|
{
|
|
Ui::pqAnimationSettingsDialog *dialog
|
|
= this->Internals->AnimationSettingsDialog;
|
|
if (dialog->lockAspect->isChecked())
|
|
{
|
|
int height = dialog->height->text().toInt();
|
|
int width = static_cast<int>(height*this->Internals->AspectRatio);
|
|
dialog->width->setText(QString::number(width));
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
void pqAnimationManager::onLockAspectRatio(bool lock)
|
|
{
|
|
if (lock)
|
|
{
|
|
Ui::pqAnimationSettingsDialog *dialog
|
|
= this->Internals->AnimationSettingsDialog;
|
|
int width = dialog->width->text().toInt();
|
|
int height = dialog->height->text().toInt();
|
|
this->Internals->AspectRatio
|
|
= static_cast<double>(width)/static_cast<double>(height);
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
#define PADDING_COMPENSATION QSize(16, 16);
|
|
inline void enforceMultiple4(QSize& newSize)
|
|
{
|
|
QSize requested_newSize = newSize;
|
|
int &width = newSize.rwidth();
|
|
int &height = newSize.rheight();
|
|
if ((width % 4) > 0)
|
|
{
|
|
width -= width % 4;
|
|
}
|
|
if ((height % 4) > 0)
|
|
{
|
|
height -= height % 4;
|
|
}
|
|
|
|
if (requested_newSize != newSize)
|
|
{
|
|
QMessageBox::warning(NULL, "Resolution Changed",
|
|
QString("The requested resolution has been changed from (%1, %2)\n").arg(
|
|
requested_newSize.width()).arg(requested_newSize.height()) +
|
|
QString("to (%1, %2) to match format specifications.").arg(
|
|
newSize.width()).arg(newSize.height()));
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
bool pqAnimationManager::saveAnimation()
|
|
{
|
|
pqAnimationScene* scene = this->getActiveScene();
|
|
if (!scene)
|
|
{
|
|
return false;
|
|
}
|
|
// Ensure that GUI is up-to-date so that we get correct sizes.
|
|
pqEventDispatcher::processEventsAndWait(1);
|
|
vtkSMProxy* sceneProxy = scene->getProxy();
|
|
|
|
QDialog dialog;
|
|
Ui::pqAnimationSettingsDialog dialogUI;
|
|
this->Internals->AnimationSettingsDialog = &dialogUI;
|
|
dialogUI.setupUi(&dialog);
|
|
|
|
QIntValidator *intValidator = new QIntValidator(this);
|
|
intValidator->setBottom(50);
|
|
dialogUI.width->setValidator(intValidator);
|
|
intValidator = new QIntValidator(this);
|
|
intValidator->setBottom(50);
|
|
dialogUI.height->setValidator(intValidator);
|
|
|
|
dialogUI.startTime->setValidator(new QIntValidator(this));
|
|
dialogUI.endTime->setValidator(new QIntValidator(this));
|
|
|
|
// Cannot disconnect and save animation unless connected to a remote server.
|
|
dialogUI.checkBoxDisconnect->setEnabled(
|
|
this->Internals->ActiveServer->isRemote() &&
|
|
!this->Internals->ActiveServer->session()->IsMultiClients());
|
|
|
|
// Use viewManager is available.
|
|
pqTabbedMultiViewWidget* viewManager = qobject_cast<pqTabbedMultiViewWidget*>(
|
|
pqApplicationCore::instance()->manager("MULTIVIEW_WIDGET"));
|
|
|
|
// Set current size of the window.
|
|
QSize viewSize = viewManager? viewManager->clientSize() : QSize(800, 600);
|
|
// to avoid some unpredicable padding issues, I am reducing the size by a few
|
|
// pixels.
|
|
QSize padding = PADDING_COMPENSATION;
|
|
if (viewSize.width() > viewSize.height())
|
|
{
|
|
padding.setWidth((padding.width()*viewSize.width())/viewSize.height());
|
|
}
|
|
else
|
|
{
|
|
padding.setHeight((padding.height()*viewSize.height())/viewSize.width());
|
|
}
|
|
viewSize -= padding;
|
|
dialogUI.height->setText(QString::number(viewSize.height()));
|
|
dialogUI.width->setText(QString::number(viewSize.width()));
|
|
|
|
// Frames per timestep is only shown
|
|
// when saving in SNAP_TO_TIMESTEPS mode.
|
|
dialogUI.spinBoxFramesPerTimestep->hide();
|
|
dialogUI.labelFramesPerTimestep->hide();
|
|
dialogUI.labelTimeRange->setText("Frame range");
|
|
|
|
int playMode = pqSMAdaptor::getElementProperty(
|
|
sceneProxy->GetProperty("PlayMode")).toInt();
|
|
|
|
// Set current duration/frame rate/no. of. frames.
|
|
double frame_rate = dialogUI.frameRate->value();
|
|
// Save the current player property values.
|
|
int num_frames = pqSMAdaptor::getElementProperty(
|
|
sceneProxy->GetProperty("NumberOfFrames")).toInt();
|
|
int duration = pqSMAdaptor::getElementProperty(
|
|
sceneProxy->GetProperty("Duration")).toInt();
|
|
int num_steps = pqSMAdaptor::getMultipleElementProperty(
|
|
sceneProxy->GetProperty("TimeSteps")).size();
|
|
int frames_per_timestep = pqSMAdaptor::getElementProperty(
|
|
sceneProxy->GetProperty("FramesPerTimestep")).toInt();
|
|
|
|
int startFrameCount = 0;
|
|
|
|
switch (playMode)
|
|
{
|
|
case SEQUENCE:
|
|
dialogUI.spinBoxNumberOfFrames->setValue(num_frames);
|
|
dialogUI.animationDuration->setEnabled(false);
|
|
dialogUI.animationDuration->setValue(num_frames/frame_rate);
|
|
dialogUI.startTime->setText("0");
|
|
dialogUI.endTime->setText(QString::number(num_frames-1));
|
|
break;
|
|
|
|
case REALTIME:
|
|
dialogUI.animationDuration->setValue(duration);
|
|
dialogUI.spinBoxNumberOfFrames->setValue(
|
|
static_cast<int>(duration*frame_rate));
|
|
dialogUI.spinBoxNumberOfFrames->setEnabled(false);
|
|
break;
|
|
|
|
case SNAP_TO_TIMESTEPS:
|
|
dialogUI.spinBoxNumberOfFrames->setValue(num_steps);
|
|
dialogUI.animationDuration->setValue(num_steps*frame_rate);
|
|
dialogUI.spinBoxNumberOfFrames->setEnabled(false);
|
|
dialogUI.animationDuration->setEnabled(false);
|
|
dialogUI.spinBoxFramesPerTimestep->show();
|
|
dialogUI.spinBoxFramesPerTimestep->setValue(frames_per_timestep);
|
|
dialogUI.labelFramesPerTimestep->show();
|
|
dialogUI.labelTimeRange->setText("Timestep range");
|
|
int nbTimeSteps = scene->getTimeSteps().size() - 1;
|
|
dialogUI.startTime->setText("0");
|
|
dialogUI.endTime->setText(QString::number(nbTimeSteps));
|
|
break;
|
|
}
|
|
|
|
QObject::connect(
|
|
dialogUI.animationDuration, SIGNAL(valueChanged(double)),
|
|
this, SLOT(updateGUI()));
|
|
QObject::connect(
|
|
dialogUI.frameRate, SIGNAL(valueChanged(double)),
|
|
this, SLOT(updateGUI()));
|
|
QObject::connect(
|
|
dialogUI.spinBoxNumberOfFrames, SIGNAL(valueChanged(int)),
|
|
this, SLOT(updateGUI()));
|
|
QObject::connect(
|
|
dialogUI.spinBoxFramesPerTimestep, SIGNAL(valueChanged(int)),
|
|
this, SLOT(updateGUI()));
|
|
|
|
QObject::connect(dialogUI.width, SIGNAL(editingFinished()),
|
|
this, SLOT(onWidthEdited()));
|
|
QObject::connect(dialogUI.height, SIGNAL(editingFinished()),
|
|
this, SLOT(onHeightEdited()));
|
|
QObject::connect(dialogUI.lockAspect, SIGNAL(toggled(bool)),
|
|
this, SLOT(onLockAspectRatio(bool)));
|
|
|
|
if (!dialog.exec())
|
|
{
|
|
this->Internals->AnimationSettingsDialog = 0;
|
|
return false;
|
|
}
|
|
this->Internals->AnimationSettingsDialog = 0;
|
|
|
|
bool disconnect_and_save =
|
|
(dialogUI.checkBoxDisconnect->checkState() == Qt::Checked);
|
|
int stereo = dialogUI.stereoMode->currentIndex();
|
|
if (stereo)
|
|
{
|
|
QString stereoMode = dialogUI.stereoMode->currentText();
|
|
if (stereoMode == "Red-Blue")
|
|
{
|
|
stereo = VTK_STEREO_RED_BLUE;
|
|
}
|
|
else if (stereoMode == "Interlaced")
|
|
{
|
|
stereo = VTK_STEREO_INTERLACED;
|
|
}
|
|
else if (stereoMode == "Checkerboard")
|
|
{
|
|
stereo = VTK_STEREO_CHECKERBOARD;
|
|
}
|
|
else if (stereoMode == "Side By Side Horizontal")
|
|
{
|
|
stereo = VTK_STEREO_SPLITVIEWPORT_HORIZONTAL;
|
|
}
|
|
else if (stereoMode == "Left Eye Only")
|
|
{
|
|
stereo = VTK_STEREO_LEFT;
|
|
}
|
|
else if (stereoMode == "Right Eye Only")
|
|
{
|
|
stereo = VTK_STEREO_RIGHT;
|
|
}
|
|
else
|
|
{
|
|
stereo = 0;
|
|
}
|
|
}
|
|
bool compression = (dialogUI.compression->checkState() == Qt::Checked);
|
|
|
|
// Now obtain filename for the animation.
|
|
vtkSmartPointer<vtkPVServerInformation> serverInfo;
|
|
if (disconnect_and_save)
|
|
{
|
|
serverInfo = sceneProxy->GetSession()->GetServerInformation();
|
|
if (!serverInfo)
|
|
{
|
|
qWarning() << "Failed to locate server information about AVI support.";
|
|
disconnect_and_save = false;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// vtkPVServerInformation initialize AVI support in constructor for the
|
|
// local process.
|
|
serverInfo = vtkSmartPointer<vtkPVServerInformation>::New();
|
|
}
|
|
|
|
QString filters = "";
|
|
if (serverInfo && serverInfo->GetOGVSupport())
|
|
{
|
|
filters += "Ogg/Theora files (*.ogv);;";
|
|
}
|
|
if (serverInfo && serverInfo->GetAVISupport())
|
|
{
|
|
filters += "AVI files (*.avi);;";
|
|
}
|
|
filters +="JPEG images (*.jpg);;TIFF images (*.tif);;PNG images (*.png);;";
|
|
filters +="All files(*)";
|
|
|
|
QWidget* parent_window = pqCoreUtilities::mainWidget();
|
|
|
|
// Create a server dialog is disconnect-and-save is true, else create a client
|
|
// dialog.
|
|
pqFileDialog *file_dialog = new pqFileDialog(
|
|
disconnect_and_save? scene->getServer() : 0,
|
|
parent_window,
|
|
tr("Save Animation"), QString(), filters);
|
|
file_dialog->setRecentlyUsedExtension(this->AnimationExtension);
|
|
file_dialog->setObjectName("FileSaveAnimationDialog");
|
|
file_dialog->setFileMode(pqFileDialog::AnyFile);
|
|
if (file_dialog->exec() != QDialog::Accepted)
|
|
{
|
|
delete file_dialog;
|
|
return false;
|
|
}
|
|
|
|
QStringList files = file_dialog->getSelectedFiles();
|
|
QFileInfo fileInfo = QFileInfo( files[0] );
|
|
this->AnimationExtension = QString("*.") + fileInfo.suffix();
|
|
|
|
// essential to destroy file dialog, before we disconnect from the server, if
|
|
// at all.
|
|
delete file_dialog;
|
|
|
|
if (files.size() == 0)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
QString filename = files[0];
|
|
|
|
// Update Scene properties based on user options.
|
|
emit this->beginNonUndoableChanges();
|
|
|
|
if (stereo)
|
|
{
|
|
pqRenderViewBase::setStereo(stereo);
|
|
}
|
|
|
|
double playbackTimeWindow[2] = {1,-1};
|
|
double start, end;
|
|
int nbFrames = dialogUI.spinBoxNumberOfFrames->value();
|
|
switch (playMode)
|
|
{
|
|
case REALTIME:
|
|
// Since even in real-time mode, while saving animation, it is played back
|
|
// in sequence mode, we change the NumberOfFrames instead of changing the
|
|
// Duration. The spinBoxNumberOfFrames is updated to satisfy
|
|
// duration * frame rate = number of frames.
|
|
pqSMAdaptor::setElementProperty(sceneProxy->GetProperty("PlayMode"), SEQUENCE);
|
|
pqSMAdaptor::setElementProperty(sceneProxy->GetProperty("NumberOfFrames"),nbFrames);
|
|
break; // Break or not break, this is the question...
|
|
|
|
case SEQUENCE:
|
|
pqSMAdaptor::setElementProperty(sceneProxy->GetProperty("NumberOfFrames"), nbFrames);
|
|
start = pqSMAdaptor::getElementProperty(sceneProxy->GetProperty("StartTime")).toDouble();
|
|
end = pqSMAdaptor::getElementProperty(sceneProxy->GetProperty("EndTime")).toDouble();
|
|
startFrameCount = dialogUI.startTime->text().toInt();
|
|
playbackTimeWindow[0] = start + (end-start) * ((double)dialogUI.startTime->text().toInt()) / ((double)(nbFrames-1));
|
|
playbackTimeWindow[1] = start + (end-start) * ((double)dialogUI.endTime->text().toInt()) / ((double)(nbFrames-1));
|
|
break;
|
|
|
|
case SNAP_TO_TIMESTEPS:
|
|
pqSMAdaptor::setElementProperty(sceneProxy->GetProperty("FramesPerTimestep"),
|
|
dialogUI.spinBoxFramesPerTimestep->value());
|
|
startFrameCount = dialogUI.spinBoxFramesPerTimestep->text().toInt() * dialogUI.startTime->text().toInt();
|
|
playbackTimeWindow[0] = scene->getTimeSteps().at(dialogUI.startTime->text().toInt());
|
|
playbackTimeWindow[1] = scene->getTimeSteps().at(dialogUI.endTime->text().toInt());
|
|
break;
|
|
}
|
|
|
|
sceneProxy->UpdateVTKObjects();
|
|
|
|
QSize newSize(dialogUI.width->text().toInt(),
|
|
dialogUI.height->text().toInt());
|
|
|
|
// Enforce any view size conditions (such a multiple of 4).
|
|
::enforceMultiple4(newSize);
|
|
int magnification = viewManager?
|
|
viewManager->prepareForCapture(newSize.width(), newSize.height()): 1;
|
|
|
|
if (disconnect_and_save)
|
|
{
|
|
pqServer* server = this->Internals->ActiveServer;
|
|
vtkSMSessionProxyManager* pxm = server->proxyManager();
|
|
|
|
vtkSMProxy* writer = pxm->NewProxy("writers", "AnimationSceneImageWriter");
|
|
pxm->RegisterProxy("animation", "writer", writer);
|
|
vtkSMPropertyHelper(writer, "FileName").Set(filename.toLatin1().data());
|
|
vtkSMPropertyHelper(writer, "Magnification").Set(magnification);
|
|
vtkSMPropertyHelper(writer, "FrameRate").Set(dialogUI.frameRate->value());
|
|
vtkSMPropertyHelper(writer, "Compression").Set(compression);
|
|
vtkSMPropertyHelper(writer, "PlaybackTimeWindow").Set(playbackTimeWindow, 2);
|
|
vtkSMPropertyHelper(writer, "StartFileCount").Set(startFrameCount);
|
|
writer->UpdateVTKObjects();
|
|
writer->Delete();
|
|
|
|
// Get ProxyManager XML state
|
|
std::ostringstream xmlStringStream;
|
|
vtkSmartPointer<vtkPVXMLElement> state;
|
|
state.TakeReference(pxm->SaveXMLState());
|
|
state->PrintXML(xmlStringStream, vtkIndent(0));
|
|
|
|
// We create a server side proxy that will save the animation at disconnection.
|
|
vtkSMProxy* cleaner = pxm->NewProxy("remote_player", "AnimationPlayer");
|
|
vtkSMPropertyHelper(cleaner, "Writer").Set(writer);
|
|
vtkSMPropertyHelper(cleaner, "XMLState").Set(xmlStringStream.str().c_str());
|
|
cleaner->UpdateVTKObjects();
|
|
pxm->RegisterProxy("animation","cleaner",cleaner);
|
|
cleaner->Delete();
|
|
|
|
// Make sure we delete all the view before disconnecting
|
|
vtkNew<vtkSMProxyIterator> proxyIter;
|
|
proxyIter->SetSession(server->session());
|
|
typedef std::vector<vtkWeakPointer<vtkSMViewProxy> > VectorOfViews;
|
|
VectorOfViews viewToDelete;
|
|
for (proxyIter->Begin(); !proxyIter->IsAtEnd(); proxyIter->Next())
|
|
{
|
|
vtkSMViewProxy* view = vtkSMViewProxy::SafeDownCast(proxyIter->GetProxy());
|
|
// We need to ensure that we skip prototypes.
|
|
if (view)
|
|
{
|
|
viewToDelete.push_back(view);
|
|
}
|
|
}
|
|
|
|
vtkNew<vtkSMParaViewPipelineController> controller;
|
|
foreach (vtkSMViewProxy* view, viewToDelete)
|
|
{
|
|
controller->UnRegisterViewProxy(view, /*unregister_representations*/ false);
|
|
}
|
|
|
|
// Disconnect from the server
|
|
pqApplicationCore* core = pqApplicationCore::instance();
|
|
if (server)
|
|
{
|
|
server->session()->PreDisconnection();
|
|
core->getObjectBuilder()->removeServer(server);
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
// let the world know we are writing an animation.
|
|
emit this->writeAnimation(filename, magnification, dialogUI.frameRate->value());
|
|
|
|
vtkSMAnimationSceneImageWriter* writer = pqAnimationSceneImageWriter::New();
|
|
writer->SetFileName(filename.toLatin1().data());
|
|
writer->SetMagnification(magnification);
|
|
writer->SetAnimationScene(sceneProxy);
|
|
writer->SetFrameRate(dialogUI.frameRate->value());
|
|
writer->SetCompression(compression);
|
|
writer->SetPlaybackTimeWindow(playbackTimeWindow);
|
|
writer->SetStartFileCount(startFrameCount);
|
|
|
|
SM_SCOPED_TRACE(SaveCameras).arg("proxy", sceneProxy);
|
|
SM_SCOPED_TRACE(CallFunction)
|
|
.arg("WriteAnimation")
|
|
.arg(filename.toLatin1().data())
|
|
.arg("Magnification", magnification)
|
|
.arg("Compression", writer->GetCompression())
|
|
.arg("FrameRate", writer->GetFrameRate())
|
|
.arg("comment", "save animation images/movie");
|
|
|
|
pqProgressManager* progress_manager =
|
|
pqApplicationCore::instance()->getProgressManager();
|
|
|
|
progress_manager->setEnableAbort(true);
|
|
progress_manager->setEnableProgress(true);
|
|
QObject::connect(progress_manager, SIGNAL(abort()), scene, SLOT(pause()));
|
|
QObject::connect(scene, SIGNAL(tick(int)), this, SLOT(onTick(int)));
|
|
QObject::connect(this, SIGNAL(saveProgress(const QString&, int)),
|
|
progress_manager, SLOT(setProgress(const QString&, int)));
|
|
progress_manager->lockProgress(this);
|
|
bool status = writer->Save();
|
|
progress_manager->unlockProgress(this);
|
|
QObject::disconnect(progress_manager, 0, scene, 0);
|
|
QObject::disconnect(scene, 0, this, 0);
|
|
QObject::disconnect(this, 0, progress_manager, 0);
|
|
progress_manager->setEnableProgress(false);
|
|
progress_manager->setEnableAbort(false);
|
|
writer->Delete();
|
|
|
|
// Restore, duration and number of frames.
|
|
switch (playMode)
|
|
{
|
|
case SEQUENCE:
|
|
pqSMAdaptor::setElementProperty(sceneProxy->GetProperty("NumberOfFrames"),
|
|
num_frames);
|
|
break;
|
|
|
|
case REALTIME:
|
|
pqSMAdaptor::setElementProperty(sceneProxy->GetProperty("NumberOfFrames"),
|
|
num_frames);
|
|
pqSMAdaptor::setElementProperty(sceneProxy->GetProperty("PlayMode"),
|
|
REALTIME);
|
|
break;
|
|
|
|
case SNAP_TO_TIMESTEPS:
|
|
pqSMAdaptor::setElementProperty(sceneProxy->GetProperty("FramesPerTimestep"),
|
|
frames_per_timestep);
|
|
break;
|
|
}
|
|
sceneProxy->UpdateVTKObjects();
|
|
if (viewManager)
|
|
{
|
|
viewManager->cleanupAfterCapture();
|
|
}
|
|
|
|
if (stereo)
|
|
{
|
|
pqRenderViewBase::setStereo(0);
|
|
}
|
|
emit this->endNonUndoableChanges();
|
|
return status;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
bool pqAnimationManager::saveGeometry(const QString& filename,
|
|
pqView* view)
|
|
{
|
|
if (!view)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
pqAnimationScene* scene = this->getActiveScene();
|
|
if (!scene)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
SM_SCOPED_TRACE(CallFunction)
|
|
.arg("WriteAnimationGeometry")
|
|
.arg(filename.toLatin1().data())
|
|
.arg("view", view->getProxy())
|
|
.arg("comment", "save animation geometry from a view");
|
|
|
|
vtkSMProxy* sceneProxy = scene->getProxy();
|
|
vtkSMAnimationSceneGeometryWriter* writer = vtkSMAnimationSceneGeometryWriter::New();
|
|
writer->SetFileName(filename.toLatin1().data());
|
|
writer->SetAnimationScene(sceneProxy);
|
|
writer->SetViewModule(view->getProxy());
|
|
bool status = writer->Save();
|
|
writer->Delete();
|
|
return status;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
void pqAnimationManager::restoreSettings()
|
|
{
|
|
// Load the most recently used file extension from QSettings, if available.
|
|
pqSettings* settings = pqApplicationCore::instance()->settings();
|
|
|
|
if ( settings->contains("extensions/AnimationExtension") )
|
|
{
|
|
this->AnimationExtension = settings->value("extensions/AnimationExtension").toString();
|
|
}
|
|
else
|
|
{
|
|
this->AnimationExtension = QString();
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
void pqAnimationManager::saveSettings()
|
|
{
|
|
// Save the most recently used file extension to QSettings.
|
|
pqSettings* settings = pqApplicationCore::instance()->settings();
|
|
settings->setValue("extensions/AnimationExtension", this->AnimationExtension);
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
void pqAnimationManager::onTick(int progress)
|
|
{
|
|
emit this->saveProgress("Saving Animation", progress);
|
|
}
|