/*========================================================================= Program: ParaView Module: vtkPVContextView.cxx 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 "vtkPVContextView.h" #include "vtkAnnotationLink.h" #include "vtkCamera.h" #include "vtkChart.h" #include "vtkChartRepresentation.h" #include "vtkCommand.h" #include "vtkContextInteractorStyle.h" #include "vtkContextView.h" #include "vtkCSVExporter.h" #include "vtkInformation.h" #include "vtkInformationIntegerKey.h" #include "vtkMultiProcessStream.h" #include "vtkObjectFactory.h" #include "vtkProcessModule.h" #include "vtkPVDataRepresentation.h" #include "vtkPVOptions.h" #include "vtkPVSynchronizedRenderWindows.h" #include "vtkRenderer.h" #include "vtkRenderWindow.h" #include "vtkRenderWindowInteractor.h" #include "vtkScatterPlotMatrix.h" #include "vtkSelection.h" #include "vtkTileDisplayHelper.h" #include "vtkTilesHelper.h" #include "vtkTimerLog.h" //---------------------------------------------------------------------------- vtkPVContextView::vtkPVContextView() : InteractorStyle() { vtkPVOptions* options = vtkProcessModule::GetProcessModule()? vtkProcessModule::GetProcessModule()->GetOptions() : NULL; this->UseOffscreenRenderingForScreenshots = false; this->UseOffscreenRendering = (options? options->GetUseOffscreenRendering() != 0 : false); this->RenderWindow = this->SynchronizedWindows->NewRenderWindow(); this->RenderWindow->SetOffScreenRendering(this->UseOffscreenRendering? 1 : 0); this->ContextView = vtkContextView::New(); // Let the application setup the interactor. this->ContextView->SetRenderWindow(this->RenderWindow); if (this->ContextView->GetInteractor()) { this->ContextView->GetInteractor()->SetInteractorStyle(NULL); } this->ContextView->SetInteractor(NULL); this->ContextView->GetRenderer()->AddObserver( vtkCommand::StartEvent, this, &vtkPVContextView::OnStartRender); this->ContextView->GetRenderer()->AddObserver( vtkCommand::EndEvent, this, &vtkPVContextView::OnEndRender); } //---------------------------------------------------------------------------- vtkPVContextView::~vtkPVContextView() { vtkTileDisplayHelper::GetInstance()->EraseTile(this->Identifier); this->RenderWindow->Delete(); this->ContextView->Delete(); } //---------------------------------------------------------------------------- void vtkPVContextView::Initialize(unsigned int id) { if (this->Identifier == id) { // already initialized return; } this->SynchronizedWindows->AddRenderWindow(id, this->RenderWindow); this->SynchronizedWindows->AddRenderer(id, this->ContextView->GetRenderer()); this->Superclass::Initialize(id); } //---------------------------------------------------------------------------- void vtkPVContextView::SetupInteractor(vtkRenderWindowInteractor* iren) { // Disable interactor on server processes (or batch processes), since // otherwise the vtkContextInteractorStyle triggers renders on changes to the // vtkContextView which is bad and can cause deadlock (BUG #122651). if (this->GetLocalProcessSupportsInteraction() == false) { // We don't setup interactor on non-driver processes. return; } this->ContextView->SetInteractor(iren); this->InteractorStyle->SetScene(this->ContextView->GetScene()); if (iren) { iren->SetInteractorStyle(this->InteractorStyle.GetPointer()); } } //---------------------------------------------------------------------------- vtkRenderWindowInteractor* vtkPVContextView::GetInteractor() { return this->ContextView->GetInteractor(); } //---------------------------------------------------------------------------- void vtkPVContextView::SetUseOffscreenRendering(bool use_offscreen) { if (this->UseOffscreenRendering == use_offscreen) { return; } vtkPVOptions* options = vtkProcessModule::GetProcessModule()->GetOptions(); bool process_use_offscreen = options->GetUseOffscreenRendering() != 0; this->UseOffscreenRendering = use_offscreen || process_use_offscreen; this->GetRenderWindow()->SetOffScreenRendering(this->UseOffscreenRendering); } //---------------------------------------------------------------------------- void vtkPVContextView::Update() { vtkMultiProcessController* s_controller = this->SynchronizedWindows->GetClientServerController(); vtkMultiProcessController* d_controller = this->SynchronizedWindows->GetClientDataServerController(); vtkMultiProcessController* p_controller = vtkMultiProcessController::GetGlobalController(); vtkMultiProcessStream stream; if (this->SynchronizedWindows->GetLocalProcessIsDriver()) { std::vector need_delivery; int num_reprs = this->GetNumberOfRepresentations(); for (int cc=0; cc < num_reprs; cc++) { vtkPVDataRepresentation* repr = vtkPVDataRepresentation::SafeDownCast( this->GetRepresentation(cc)); if (repr && repr->GetNeedUpdate()) { need_delivery.push_back(cc); } } stream << static_cast(need_delivery.size()); for (size_t cc=0; cc < need_delivery.size(); cc++) { stream << need_delivery[cc]; } if (s_controller) { s_controller->Send(stream, 1, 998878); } if (d_controller) { d_controller->Send(stream, 1, 998878); } if (p_controller) { p_controller->Broadcast(stream, 0); } } else { if (s_controller) { s_controller->Receive(stream, 1, 998878); } if (d_controller) { d_controller->Receive(stream, 1, 998878); } if (p_controller) { p_controller->Broadcast(stream, 0); } } int size; stream >> size; for (int cc=0; cc < size; cc++) { int index; stream >> index; vtkPVDataRepresentation* repr = vtkPVDataRepresentation::SafeDownCast( this->GetRepresentation(index)); if (repr) { repr->MarkModified(); } } this->Superclass::Update(); } //---------------------------------------------------------------------------- void vtkPVContextView::StillRender() { vtkTimerLog::MarkStartEvent("Still Render"); this->Render(false); vtkTimerLog::MarkEndEvent("Still Render"); } //---------------------------------------------------------------------------- void vtkPVContextView::InteractiveRender() { vtkTimerLog::MarkStartEvent("Interactive Render"); this->Render(true); vtkTimerLog::MarkEndEvent("Interactive Render"); } //---------------------------------------------------------------------------- void vtkPVContextView::Render(bool vtkNotUsed(interactive)) { this->SynchronizedWindows->SetEnabled(this->InTileDisplayMode()); this->SynchronizedWindows->BeginRender(this->GetIdentifier()); // Call Render() on local render window only on the client (or root node in // batch mode). if (this->SynchronizedWindows->GetLocalProcessIsDriver() || this->InTileDisplayMode()) { vtkTimerLog::MarkStartEvent("vtkPVContextView::PrepareForRender"); // on rendering-nodes call Render-pass so that representations can update the // vtk-charts as needed. this->CallProcessViewRequest(vtkPVView::REQUEST_RENDER(), this->RequestInformation, this->ReplyInformationVector); vtkTimerLog::MarkEndEvent("vtkPVContextView::PrepareForRender"); this->ContextView->Render(); } this->SynchronizedWindows->SetEnabled(false); } //---------------------------------------------------------------------------- void vtkPVContextView::OnStartRender() { vtkTileDisplayHelper::GetInstance()->EraseTile(this->Identifier, this->ContextView->GetRenderer()->GetActiveCamera()->GetLeftEye()); } //---------------------------------------------------------------------------- void vtkPVContextView::OnEndRender() { if (this->SynchronizedWindows->GetLocalProcessIsDriver() || !this->InTileDisplayMode()) { return; } // this code needs to be called on only server-nodes in tile-display mode. double viewport[4]; this->ContextView->GetRenderer()->GetViewport(viewport); int tile_dims[2], tile_mullions[2]; this->SynchronizedWindows->GetTileDisplayParameters(tile_dims, tile_mullions); double tile_viewport[4]; this->GetRenderWindow()->GetTileViewport(tile_viewport); double physical_viewport[4]; vtkSmartPointer tilesHelper = vtkSmartPointer::New(); tilesHelper->SetTileDimensions(tile_dims); tilesHelper->SetTileMullions(tile_mullions); tilesHelper->SetTileWindowSize(this->GetRenderWindow()->GetActualSize()); if (tilesHelper->GetPhysicalViewport(viewport, vtkMultiProcessController::GetGlobalController()->GetLocalProcessId(), physical_viewport)) { // When tiling, vtkContextActor renders the result at the // "physical_viewport" location on the window. So we grab the image only // from that section of the view. vtkSynchronizedRenderers::vtkRawImage image; this->ContextView->GetRenderer()->SetViewport(physical_viewport); image.Capture(this->ContextView->GetRenderer()); this->ContextView->GetRenderer()->SetViewport(viewport); vtkTileDisplayHelper::GetInstance()->SetTile( this->Identifier, physical_viewport, this->ContextView->GetRenderer(), image); } vtkTileDisplayHelper::GetInstance()->FlushTiles(this->Identifier, this->ContextView->GetRenderer()->GetActiveCamera()->GetLeftEye()); } //---------------------------------------------------------------------------- template vtkSelection* vtkPVContextView::GetSelectionImplementation(T* chart) { if (vtkSelection* selection = chart->GetAnnotationLink()->GetCurrentSelection()) { if (this->SelectionClone == NULL || this->SelectionClone->GetMTime() < selection->GetMTime() || this->SelectionClone->GetMTime() < chart->GetAnnotationLink()->GetMTime()) { // we need to treat vtkSelection obtained from vtkAnnotationLink as // constant and not modify it. Hence, we create a clone. this->SelectionClone = vtkSmartPointer::New(); this->SelectionClone->ShallowCopy(selection); // Allow the view to transform the selection as appropriate since the raw // selection created by the VTK view is on the "transformed" data put in // the view and not original input data. if (this->MapSelectionToInput(this->SelectionClone) == false) { this->SelectionClone->Initialize(); } } return this->SelectionClone; } this->SelectionClone = NULL; return NULL; } //---------------------------------------------------------------------------- vtkSelection* vtkPVContextView::GetSelection() { if (vtkChart *chart = vtkChart::SafeDownCast(this->GetContextItem())) { return this->GetSelectionImplementation(chart); } else if (vtkScatterPlotMatrix* schart = vtkScatterPlotMatrix::SafeDownCast(this->GetContextItem())) { return this->GetSelectionImplementation(schart); } vtkWarningMacro("Unsupported context item type."); this->SelectionClone = NULL; return NULL; } //---------------------------------------------------------------------------- bool vtkPVContextView::MapSelectionToInput(vtkSelection* sel) { for (int cc = 0, max = this->GetNumberOfRepresentations(); cc < max; cc++) { vtkChartRepresentation* repr = vtkChartRepresentation::SafeDownCast( this->GetRepresentation(cc)); if (repr && repr->GetVisibility() && repr->MapSelectionToInput(sel)) { return true; } } // error! we cannot have a selection created in the view, there's no visible // representation! return false; } //---------------------------------------------------------------------------- bool vtkPVContextView::Export(vtkCSVExporter* exporter) { exporter->Open(vtkCSVExporter::STREAM_COLUMNS); for (int cc=0, max=this->GetNumberOfRepresentations(); cc < max; cc++) { vtkChartRepresentation* repr = vtkChartRepresentation::SafeDownCast( this->GetRepresentation(cc)); if (repr && repr->GetVisibility() && !repr->Export(exporter)) { exporter->Abort(); vtkErrorMacro("Failed to export to CSV. Exporting may not be supported by this view."); return false; } } exporter->Close(); return true; } //---------------------------------------------------------------------------- void vtkPVContextView::PrintSelf(ostream& os, vtkIndent indent) { this->Superclass::PrintSelf(os, indent); }