/*========================================================================= Program: ParaView Module: $RCSfile$ Copyright (c) Kitware, Inc. All rights reserved. See Copyright.txt or http://www.paraview.org/HTML/Copyright.html for details. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the above copyright notice for more information. =========================================================================*/ #include "vtkSMAnimationScene.h" #include "vtkPVConfig.h" // needed for PARAVIEW_ENABLE_PYTHON #include "vtkCompositeAnimationPlayer.h" #include "vtkEventForwarderCommand.h" #include "vtkNew.h" #include "vtkObjectFactory.h" #include "vtkPVCameraAnimationCue.h" #include "vtkPVGeneralSettings.h" #include "vtkSmartPointer.h" #include "vtkSMProperty.h" #include "vtkSMPropertyHelper.h" #include "vtkSMTransferFunctionManager.h" #include "vtkSMViewProxy.h" #include "vtkVector.h" #ifdef PARAVIEW_ENABLE_PYTHON # include "vtkPythonAnimationCue.h" #endif #include #include #include //---------------------------------------------------------------------------- class vtkSMAnimationScene::vtkInternals { vtkNew TransferFunctionManager; public: typedef std::vector > VectorOfAnimationCues; VectorOfAnimationCues AnimationCues; typedef std::vector > VectorOfViews; VectorOfViews ViewModules; void UpdateAllViews() { vtkSMSessionProxyManager* pxm = NULL; for (VectorOfViews::iterator iter=this->ViewModules.begin(); iter != this->ViewModules.end(); ++iter) { // save the proxy manager for later. if (pxm) { assert(iter->GetPointer()->GetSessionProxyManager() == pxm); } else { pxm = iter->GetPointer()->GetSessionProxyManager(); } iter->GetPointer()->Update(); } // To ensure that LUTs are reset using proper ranges, we need to update all // views first, then reset/grow the LUTs and subsequently render all the views. switch(vtkPVGeneralSettings::GetInstance()->GetTransferFunctionResetMode()) { case vtkPVGeneralSettings::GROW_ON_APPLY_AND_TIMESTEP: this->TransferFunctionManager->ResetAllTransferFunctionRangesUsingCurrentData( pxm, true); break; case vtkPVGeneralSettings::RESET_ON_APPLY_AND_TIMESTEP: this->TransferFunctionManager->ResetAllTransferFunctionRangesUsingCurrentData( pxm, false); // FIXME: Maybe we should warn the user if animation caching is ON and // RESET_ON_APPLY_AND_TIMESTEP is enabled since the ranges will definitely // be wrong if caching gets used. break; default: // nothing to do. break; } } void StillRenderAllViews() { for (VectorOfViews::iterator iter=this->ViewModules.begin(); iter != this->ViewModules.end(); ++iter) { iter->GetPointer()->StillRender(); } } void PassCacheTime(double cachetime) { VectorOfViews::iterator iter = this->ViewModules.begin(); for (; iter != this->ViewModules.end(); ++iter) { vtkSMPropertyHelper((*iter), "CacheKey").Set(cachetime); iter->GetPointer()->UpdateProperty("CacheKey"); } } void PassUseCache(bool usecache) { VectorOfViews::iterator iter = this->ViewModules.begin(); for (; iter != this->ViewModules.end(); ++iter) { vtkSMPropertyHelper((*iter), "UseCache").Set(usecache); iter->GetPointer()->UpdateProperty("UseCache"); } } }; namespace { // Helper class used by for_each() to call Tick on all cues if they are not // one of the "exception" classes. class vtkTickOnGenericCue { double StartTime; double EndTime; double CurrentTime; double DeltaTime; double ClockTime; protected: virtual bool IsAcceptable(vtkAnimationCue* cue) const { return (cue && #ifdef PARAVIEW_ENABLE_PYTHON (vtkPythonAnimationCue::SafeDownCast(cue) == NULL) && #endif (vtkPVCameraAnimationCue::SafeDownCast(cue) == NULL)); } public: vtkTickOnGenericCue( double starttime, double endtime, double currenttime, double deltatime, double clocktime) : StartTime(starttime), EndTime(endtime), CurrentTime(currenttime), DeltaTime(deltatime), ClockTime(clocktime) { } virtual ~vtkTickOnGenericCue() {} void operator()(vtkAnimationCue* cue) const { if (!this->IsAcceptable(cue)) { return; } switch(cue->GetTimeMode()) { case vtkAnimationCue::TIMEMODE_RELATIVE: cue->Tick(this->CurrentTime - this->StartTime, this->DeltaTime, this->ClockTime); break; case vtkAnimationCue::TIMEMODE_NORMALIZED: cue->Tick( (this->CurrentTime - this->StartTime) / (this->EndTime - this->StartTime), this->DeltaTime / (this->EndTime - this->StartTime), this->ClockTime); break; default: vtkGenericWarningMacro("Invalid cue time mode"); } } }; class vtkTickOnCameraCue : public vtkTickOnGenericCue { protected: virtual bool IsAcceptable(vtkAnimationCue* cue) const { return (vtkPVCameraAnimationCue::SafeDownCast(cue) != NULL); } public: vtkTickOnCameraCue( double starttime, double endtime, double currenttime, double deltatime, double clocktime) : vtkTickOnGenericCue(starttime, endtime, currenttime, deltatime, clocktime) { } }; class vtkTickOnPythonCue : public vtkTickOnGenericCue { protected: virtual bool IsAcceptable(vtkAnimationCue* cue) const { (void)cue; return (false #ifdef PARAVIEW_ENABLE_PYTHON || (vtkPythonAnimationCue::SafeDownCast(cue) != NULL) #endif ); } public: vtkTickOnPythonCue( double starttime, double endtime, double currenttime, double deltatime, double clocktime) : vtkTickOnGenericCue(starttime, endtime, currenttime, deltatime, clocktime) { } }; } vtkStandardNewMacro(vtkSMAnimationScene); //---------------------------------------------------------------------------- vtkSMAnimationScene::vtkSMAnimationScene() { this->SceneTime = 0; this->PlaybackTimeWindow[0] = 1.0; this->PlaybackTimeWindow[1] = -1.0; this->ForceDisableCaching = false; this->InTick = false; this->LockEndTime = false; this->LockStartTime = false; this->OverrideStillRender = false; this->TimeKeeper = NULL; this->TimeRangeObserverID = 0; this->TimestepValuesObserverID = 0; this->AnimationPlayer = vtkCompositeAnimationPlayer::New(); // vtkAnimationPlayer::SetAnimationScene() is not reference counted. this->AnimationPlayer->SetAnimationScene(this); this->Internals = new vtkInternals(); this->Forwarder = vtkEventForwarderCommand::New(); this->Forwarder->SetTarget(this); this->AnimationPlayer->AddObserver( vtkCommand::StartEvent, this->Forwarder); this->AnimationPlayer->AddObserver( vtkCommand::EndEvent, this->Forwarder); } //---------------------------------------------------------------------------- vtkSMAnimationScene::~vtkSMAnimationScene() { this->SetTimeKeeper(NULL); this->AnimationPlayer->RemoveObserver(this->Forwarder); this->AnimationPlayer->Delete(); this->AnimationPlayer = NULL; this->Forwarder->SetTarget(NULL); this->Forwarder->Delete(); delete this->Internals; this->Internals = NULL; } //---------------------------------------------------------------------------- void vtkSMAnimationScene::AddCue(vtkAnimationCue* cue) { vtkInternals::VectorOfAnimationCues& cues = this->Internals->AnimationCues; if (std::find(cues.begin(), cues.end(), cue) != cues.end()) { vtkErrorMacro("Animation cue already present in the scene"); return; } cues.push_back(cue); this->Modified(); } //---------------------------------------------------------------------------- void vtkSMAnimationScene::RemoveCue(vtkAnimationCue* cue) { vtkInternals::VectorOfAnimationCues& cues = this->Internals->AnimationCues; vtkInternals::VectorOfAnimationCues::iterator iter = std::find(cues.begin(), cues.end(), cue); if (iter != cues.end()) { cues.erase(iter); this->Modified(); } } //---------------------------------------------------------------------------- void vtkSMAnimationScene::RemoveAllCues() { if (this->Internals->AnimationCues.size() > 0) { this->Internals->AnimationCues.clear(); this->Modified(); } } //---------------------------------------------------------------------------- int vtkSMAnimationScene::GetNumberOfCues() { return static_cast(this->Internals->AnimationCues.size()); } //---------------------------------------------------------------------------- void vtkSMAnimationScene::SetTimeKeeper(vtkSMProxy* tkp) { if (this->TimeKeeper == tkp) { return; } if (this->TimeKeeper && this->TimeRangeObserverID) { this->TimeKeeper->GetProperty("TimeRange")->RemoveObserver( this->TimeRangeObserverID); } if (this->TimeKeeper && this->TimestepValuesObserverID) { this->TimeKeeper->GetProperty("TimestepValues")->RemoveObserver( this->TimestepValuesObserverID); } this->TimeRangeObserverID = 0; this->TimestepValuesObserverID = 0; vtkSetObjectBodyMacro(TimeKeeper, vtkSMProxy, tkp); if (this->TimeKeeper) { this->TimeRangeObserverID = this->TimeKeeper->GetProperty("TimeRange")->AddObserver( vtkCommand::ModifiedEvent, this, &vtkSMAnimationScene::TimeKeeperTimeRangeChanged); this->TimestepValuesObserverID = this->TimeKeeper->GetProperty("TimestepValues")->AddObserver( vtkCommand::ModifiedEvent, this, &vtkSMAnimationScene::TimeKeeperTimestepsChanged); this->TimeKeeperTimestepsChanged(); this->TimeKeeperTimeRangeChanged(); } } //---------------------------------------------------------------------------- void vtkSMAnimationScene::TimeKeeperTimestepsChanged() { this->AnimationPlayer->RemoveAllTimeSteps(); vtkSMPropertyHelper helper(this->TimeKeeper, "TimestepValues"); for (unsigned int cc=0; cc < helper.GetNumberOfElements(); cc++) { this->AnimationPlayer->AddTimeStep(helper.GetAsDouble(cc)); } } //---------------------------------------------------------------------------- void vtkSMAnimationScene::TimeKeeperTimeRangeChanged() { // If time keeper has a non-trivial time range and the times are not locked, // then we change the times to match the time range. vtkVector2d range( vtkSMPropertyHelper(this->TimeKeeper,"TimeRange").GetAsDouble(0), vtkSMPropertyHelper(this->TimeKeeper,"TimeRange").GetAsDouble(1)); if (range[1] > range[0]) { this->InvokeEvent(vtkSMAnimationScene::UpdateStartEndTimesEvent, &range); } } //---------------------------------------------------------------------------- void vtkSMAnimationScene::AddViewProxy(vtkSMViewProxy* view) { vtkInternals::VectorOfViews::iterator iter = this->Internals->ViewModules.begin(); for (; iter != this->Internals->ViewModules.end(); ++iter) { if (iter->GetPointer() == view) { // already added. return; } } this->Internals->ViewModules.push_back(view); } //---------------------------------------------------------------------------- void vtkSMAnimationScene::RemoveViewProxy( vtkSMViewProxy* view) { vtkInternals::VectorOfViews::iterator iter = this->Internals->ViewModules.begin(); for (; iter != this->Internals->ViewModules.end(); ++iter) { if (iter->GetPointer() == view) { this->Internals->ViewModules.erase(iter); break; } } } //---------------------------------------------------------------------------- void vtkSMAnimationScene::RemoveAllViewProxies() { this->Internals->ViewModules.clear(); } //---------------------------------------------------------------------------- unsigned int vtkSMAnimationScene::GetNumberOfViewProxies() { return static_cast(this->Internals->ViewModules.size()); } //---------------------------------------------------------------------------- vtkSMViewProxy* vtkSMAnimationScene::GetViewProxy(unsigned int cc) { if (cc < this->GetNumberOfViewProxies()) { return this->Internals->ViewModules[cc]; } return NULL; } //---------------------------------------------------------------------------- void vtkSMAnimationScene::StartCueInternal() { this->Superclass::StartCueInternal(); // Initialize all the animation cues. vtkInternals::VectorOfAnimationCues& cues = this->Internals->AnimationCues; for (vtkInternals::VectorOfAnimationCues::iterator iter = cues.begin(); iter != cues.end(); ++iter) { iter->GetPointer()->Initialize(); } } //---------------------------------------------------------------------------- void vtkSMAnimationScene::EndCueInternal() { // finalize all the animation cues. vtkInternals::VectorOfAnimationCues& cues = this->Internals->AnimationCues; for (vtkInternals::VectorOfAnimationCues::iterator iter = cues.begin(); iter != cues.end(); ++iter) { iter->GetPointer()->Finalize(); } this->Superclass::EndCueInternal(); } //---------------------------------------------------------------------------- void vtkSMAnimationScene::TickInternal( double currenttime, double deltatime, double clocktime) { assert(!this->InTick); // We see that here we don't check if the cache is full at all. Views have // logic in them to periodically check and synchronize the "fullness" of cache // among all participating processes. So we don't have to manage that here at // all. bool caching_enabled = (!this->ForceDisableCaching) && vtkPVGeneralSettings::GetInstance()->GetCacheGeometryForAnimation(); if (caching_enabled) { this->Internals->PassUseCache(true); this->Internals->PassCacheTime(currenttime); } // this ensures that if this->SetSceneTime() is called, we don't call Tick() // again. this->InTick = true; this->SceneTime = currenttime; vtkInternals::VectorOfAnimationCues& cues = this->Internals->AnimationCues; // Now the animation update loop is as follows: // - Update all cues not explicitly listed here // - Update all Python cues // UpdateAllViews() // - Update all Camera cues // Superclass::TickInternal // RenderAllViews() std::for_each(cues.begin(), cues.end(), vtkTickOnGenericCue(this->StartTime, this->EndTime, currenttime, deltatime, clocktime)); std::for_each(cues.begin(), cues.end(), vtkTickOnPythonCue(this->StartTime, this->EndTime, currenttime, deltatime, clocktime)); this->Internals->UpdateAllViews(); std::for_each(cues.begin(), cues.end(), vtkTickOnCameraCue(this->StartTime, this->EndTime, currenttime, deltatime, clocktime)); this->Superclass::TickInternal(currenttime, deltatime, clocktime); if (!this->OverrideStillRender) { this->Internals->StillRenderAllViews(); } this->InTick = false; if (caching_enabled) { this->Internals->PassUseCache(false); } } //---------------------------------------------------------------------------- void vtkSMAnimationScene::PrintSelf(ostream& os, vtkIndent indent) { this->Superclass::PrintSelf(os, indent); os << indent << "ForceDisableCaching: " << this->ForceDisableCaching << endl; } //---------------------------------------------------------------------------- void vtkSMAnimationScene::SetLoop(int val) { this->AnimationPlayer->SetLoop(val != 0); } //---------------------------------------------------------------------------- int vtkSMAnimationScene::GetLoop() { return this->AnimationPlayer->GetLoop(); } //---------------------------------------------------------------------------- void vtkSMAnimationScene::Play() { this->AnimationPlayer->Play(); } //---------------------------------------------------------------------------- void vtkSMAnimationScene::Stop() { this->AnimationPlayer->Stop(); } //---------------------------------------------------------------------------- void vtkSMAnimationScene::GoToNext() { static_cast(this->AnimationPlayer)->GoToNext(); } //---------------------------------------------------------------------------- void vtkSMAnimationScene::GoToPrevious() { static_cast(this->AnimationPlayer)->GoToPrevious(); } //---------------------------------------------------------------------------- void vtkSMAnimationScene::GoToFirst() { this->AnimationPlayer->GoToFirst(); } //---------------------------------------------------------------------------- void vtkSMAnimationScene::GoToLast() { this->AnimationPlayer->GoToLast(); } //---------------------------------------------------------------------------- void vtkSMAnimationScene::SetPlayMode(int val) { this->AnimationPlayer->SetPlayMode(val); } //---------------------------------------------------------------------------- int vtkSMAnimationScene::GetPlayMode() { return this->AnimationPlayer->GetPlayMode(); } //---------------------------------------------------------------------------- void vtkSMAnimationScene::SetNumberOfFrames(int val) { this->AnimationPlayer->SetNumberOfFrames(val); } //---------------------------------------------------------------------------- void vtkSMAnimationScene::SetDuration(int val) { this->AnimationPlayer->SetDuration(val); } //---------------------------------------------------------------------------- void vtkSMAnimationScene::SetFramesPerTimestep(int val) { this->AnimationPlayer->SetFramesPerTimestep(val); }