/*========================================================================= Program: Visualization Toolkit Module: vtkRenderWindow.cxx Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen All rights reserved. See Copyright.txt or http://www.kitware.com/Copyright.htm 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 "vtkRenderWindow.h" #include "vtkCamera.h" #include "vtkCollection.h" #include "vtkCommand.h" #include "vtkMath.h" #include "vtkNew.h" #include "vtkPropCollection.h" #include "vtkRenderWindowInteractor.h" #include "vtkRendererCollection.h" #include "vtkRenderTimerLog.h" #include "vtkTimerLog.h" #include "vtkTransform.h" #include "vtkGraphicsFactory.h" #include "vtkObjectFactory.h" #include #ifndef VTK_LEGACY_REMOVE #ifdef VTK_OPENGL2 class vtkPainterDeviceAdapter : public vtkObject {}; #else #include "vtkPainterDeviceAdapter.h" #endif #endif //---------------------------------------------------------------------------- // Use the vtkAbstractObjectFactoryNewMacro to allow the object factory overrides. vtkAbstractObjectFactoryNewMacro(vtkRenderWindow) //---------------------------------------------------------------------------- // Construct an instance of vtkRenderWindow with its screen size // set to 300x300, borders turned on, positioned at (0,0), double // buffering turned on, stereo capable off. vtkRenderWindow::vtkRenderWindow() { this->IsPicking = 0; this->Borders = 1; this->FullScreen = 0; this->OldScreen[0] = this->OldScreen[1] = 0; this->OldScreen[2] = this->OldScreen[3] = 300; this->OldScreen[4] = 1; this->DoubleBuffer = 1; this->PointSmoothing = 0; this->LineSmoothing = 0; this->PolygonSmoothing = 0; this->StereoRender = 0; this->StereoType = VTK_STEREO_RED_BLUE; this->StereoCapableWindow = 0; this->AlphaBitPlanes = 0; this->StencilCapable = 0; this->Interactor = nullptr; this->AAFrames = 0; this->FDFrames = 0; this->UseConstantFDOffsets = 0; this->ConstantFDOffsets[0] = nullptr; this->ConstantFDOffsets[1] = nullptr; this->SubFrames = 0; this->AccumulationBuffer = nullptr; this->AccumulationBufferSize = 0; this->CurrentSubFrame = 0; this->DesiredUpdateRate = 0.0001; this->ResultFrame = nullptr; this->SwapBuffers = 1; this->AbortRender = 0; this->InAbortCheck = 0; this->InRender = 0; this->NeverRendered = 1; this->Renderers = vtkRendererCollection::New(); this->NumberOfLayers = 1; this->CurrentCursor = VTK_CURSOR_DEFAULT; this->AnaglyphColorSaturation = 0.65f; this->AnaglyphColorMask[0] = 4; // red this->AnaglyphColorMask[1] = 3; // cyan #ifndef VTK_LEGACY_REMOVE this->PainterDeviceAdapter = nullptr; #endif this->AbortCheckTime = 0.0; this->CapturingGL2PSSpecialProps = 0; this->MultiSamples = 0; this->UseSRGBColorSpace = false; #ifdef VTK_DEFAULT_RENDER_WINDOW_OFFSCREEN this->OffScreenRendering = 1; #endif this->DeviceIndex = 0; } //---------------------------------------------------------------------------- vtkRenderWindow::~vtkRenderWindow() { this->SetInteractor(nullptr); delete [] this->AccumulationBuffer; this->AccumulationBuffer = nullptr; this->AccumulationBufferSize = 0; delete [] this->ResultFrame; this->ResultFrame = nullptr; for (int i = 0; i < 2; ++i) { delete [] this->ConstantFDOffsets[i]; this->ConstantFDOffsets[i] = nullptr; } if (this->Renderers) { vtkCollectionSimpleIterator rsit; this->Renderers->InitTraversal(rsit); vtkRenderer *aren; while ( (aren = this->Renderers->GetNextRenderer(rsit)) ) { if (aren->GetRenderWindow() == this) { vtkErrorMacro("Window destructed with renderer still associated with it!"); } } this->Renderers->Delete(); } #ifndef VTK_LEGACY_REMOVE if (this->PainterDeviceAdapter) { this->PainterDeviceAdapter->Delete(); } #endif } //---------------------------------------------------------------------------- // Create an interactor that will work with this renderer. vtkRenderWindowInteractor *vtkRenderWindow::MakeRenderWindowInteractor() { this->Interactor = vtkRenderWindowInteractor::New(); this->Interactor->SetRenderWindow(this); return this->Interactor; } //---------------------------------------------------------------------------- // Set the interactor that will work with this renderer. void vtkRenderWindow::SetInteractor(vtkRenderWindowInteractor *rwi) { if (this->Interactor != rwi) { // to avoid destructor recursion vtkRenderWindowInteractor *temp = this->Interactor; this->Interactor = rwi; if (temp != nullptr) {temp->UnRegister(this);} if (this->Interactor != nullptr) { this->Interactor->Register(this); int isize[2]; this->Interactor->GetSize(isize); if (0 == isize[0] && 0 == isize[1]) { this->Interactor->SetSize(this->GetSize()); } if (this->Interactor->GetRenderWindow() != this) { this->Interactor->SetRenderWindow(this); } } } } //---------------------------------------------------------------------------- #if !defined(VTK_LEGACY_REMOVE) void vtkRenderWindow::SetFDFrames(int fdFrames) { VTK_LEGACY_BODY(SetFDFrames, "VTK 8.1"); if (this->FDFrames != fdFrames) { this->FDFrames = fdFrames; for (int i = 0; i < 2; i++) { delete [] this->ConstantFDOffsets[i]; this->ConstantFDOffsets[i] = nullptr; if (this->FDFrames > 0) { this->ConstantFDOffsets[i] = new double[this->FDFrames]; for (int fi = 0; fi < this->FDFrames; fi++) { this->ConstantFDOffsets[i][fi] = vtkMath::Random(); } } } vtkDebugMacro(<< this->GetClassName() << " (" << this << "): setting FDFrames to " << fdFrames); this->Modified(); } } //---------------------------------------------------------------------------- void vtkRenderWindow::SetSubFrames(int subFrames) { VTK_LEGACY_BODY(SetSubFrames, "VTK 8.1"); if (this->SubFrames != subFrames) { this->SubFrames = subFrames; if (this->CurrentSubFrame >= this->SubFrames) { this->CurrentSubFrame = 0; } vtkDebugMacro(<< this->GetClassName() << " (" << this << "): setting SubFrames to " << subFrames); this->Modified(); } } #endif //---------------------------------------------------------------------------- void vtkRenderWindow::SetDesiredUpdateRate(double rate) { vtkRenderer *aren; if (this->DesiredUpdateRate != rate) { vtkCollectionSimpleIterator rsit; for (this->Renderers->InitTraversal(rsit); (aren = this->Renderers->GetNextRenderer(rsit)); ) { aren->SetAllocatedRenderTime(1.0/ (rate*this->Renderers->GetNumberOfItems())); } this->DesiredUpdateRate = rate; this->Modified(); } } //---------------------------------------------------------------------------- // // Set the variable that indicates that we want a stereo capable window // be created. This method can only be called before a window is realized. // void vtkRenderWindow::SetStereoCapableWindow(int capable) { if (this->StereoCapableWindow != capable) { this->StereoCapableWindow = capable; this->Modified(); } } //---------------------------------------------------------------------------- // Turn on stereo rendering void vtkRenderWindow::SetStereoRender(int stereo) { if (stereo == this->StereoRender) { return; } if (this->StereoCapableWindow || (this->StereoType != VTK_STEREO_CRYSTAL_EYES)) { this->StereoRender = stereo; this->Modified(); } else { vtkWarningMacro(<< "Adjusting stereo mode on a window that does not " << "support stereo type " << this->GetStereoTypeAsString() << " is not possible."); } } //---------------------------------------------------------------------------- // Ask each renderer owned by this RenderWindow to render its image and // synchronize this process. void vtkRenderWindow::Render() { int *size; int x,y; float *p1; // if we are in the middle of an abort check then return now if (this->InAbortCheck) { return; } // if we are in a render already from somewhere else abort now if (this->InRender) { return; } // if SetSize has not yet been called (from a script, possible off // screen use, other scenarios?) then call it here with reasonable // default values if (0 == this->Size[0] && 0 == this->Size[1]) { this->SetSize(300, 300); } // reset the Abort flag this->AbortRender = 0; this->InRender = 1; vtkDebugMacro(<< "Starting Render Method.\n"); this->InvokeEvent(vtkCommand::StartEvent,nullptr); this->NeverRendered = 0; if ( this->Interactor && ! this->Interactor->GetInitialized() ) { this->Interactor->Initialize(); } vtkRenderTimerLog::ScopedEventLogger event; if (this->RenderTimer->GetLoggingEnabled()) { this->Start(); // Ensure context exists this->RenderTimer->MarkFrame(); event = this->RenderTimer->StartScopedEvent("vtkRenderWindow::Render"); } // CAUTION: // This method uses this->GetSize() and allocates buffers using that size. // Remember that GetSize() will returns a size scaled by the TileScale factor. // We should use GetActualSize() when we don't want the size to be scaled. // if there is a reason for an AccumulationBuffer if ( this->SubFrames || this->AAFrames || this->FDFrames) { // check the current size size = this->GetSize(); unsigned int bufferSize = 3*size[0]*size[1]; // If there is not a buffer or the size is too small // re-allocate it if( !this->AccumulationBuffer || bufferSize > this->AccumulationBufferSize) { // it is OK to delete null, no sense in two if's delete [] this->AccumulationBuffer; // Save the size of the buffer this->AccumulationBufferSize = 3*size[0]*size[1]; this->AccumulationBuffer = new float [this->AccumulationBufferSize]; memset(this->AccumulationBuffer,0,this->AccumulationBufferSize*sizeof(float)); } } // handle any sub frames if (this->SubFrames) { // get the size size = this->GetSize(); // draw the images this->DoAARender(); // now accumulate the images if ((!this->AAFrames) && (!this->FDFrames)) { p1 = this->AccumulationBuffer; unsigned char *p2; unsigned char *p3 = nullptr; if (this->ResultFrame) { p2 = this->ResultFrame; } else { p2 = this->GetPixelData(0,0,size[0]-1,size[1]-1,!this->DoubleBuffer); p3 = p2; } for (y = 0; y < size[1]; y++) { for (x = 0; x < size[0]; x++) { *p1 += *p2; p1++; p2++; *p1 += *p2; p1++; p2++; *p1 += *p2; p1++; p2++; } } delete [] p3; } // if this is the last sub frame then convert back into unsigned char this->CurrentSubFrame++; if (this->CurrentSubFrame >= this->SubFrames) { double num; unsigned char *p2 = new unsigned char [3*size[0]*size[1]]; num = this->SubFrames; if (this->AAFrames) { num *= this->AAFrames; } if (this->FDFrames) { num *= this->FDFrames; } this->ResultFrame = p2; p1 = this->AccumulationBuffer; for (y = 0; y < size[1]; y++) { for (x = 0; x < size[0]; x++) { *p2 = static_cast(*p1/num); p1++; p2++; *p2 = static_cast(*p1/num); p1++; p2++; *p2 = static_cast(*p1/num); p1++; p2++; } } this->CurrentSubFrame = 0; this->CopyResultFrame(); // free any memory delete [] this->AccumulationBuffer; this->AccumulationBuffer = nullptr; } } else // no subframes { // get the size size = this->GetSize(); this->DoAARender(); // if we had some accumulation occur if (this->AccumulationBuffer) { double num; unsigned char *p2 = new unsigned char [3*size[0]*size[1]]; if (this->AAFrames) { num = this->AAFrames; } else { num = 1; } if (this->FDFrames) { num *= this->FDFrames; } this->ResultFrame = p2; p1 = this->AccumulationBuffer; for (y = 0; y < size[1]; y++) { for (x = 0; x < size[0]; x++) { *p2 = static_cast(*p1/num); p1++; p2++; *p2 = static_cast(*p1/num); p1++; p2++; *p2 = static_cast(*p1/num); p1++; p2++; } } delete [] this->AccumulationBuffer; this->AccumulationBuffer = nullptr; } this->CopyResultFrame(); } delete [] this->ResultFrame; this->ResultFrame = nullptr; // Stop the render timer before invoking the EndEvent. event.Stop(); this->InRender = 0; this->InvokeEvent(vtkCommand::EndEvent,nullptr); } //---------------------------------------------------------------------------- // Handle rendering any antialiased frames. void vtkRenderWindow::DoAARender() { int i; // handle any anti aliasing if (this->AAFrames) { int *size; int x,y; float *p1; vtkRenderer *aren; vtkCamera *acam; double *dpoint; double offsets[2]; double origfocus[4]; double worldOffset[3]; // get the size size = this->GetSize(); origfocus[3] = 1.0; for (i = 0; i < this->AAFrames; i++) { // jitter the cameras offsets[0] = vtkMath::Random() - 0.5; offsets[1] = vtkMath::Random() - 0.5; vtkCollectionSimpleIterator rsit; for (this->Renderers->InitTraversal(rsit); (aren = this->Renderers->GetNextRenderer(rsit)); ) { acam = aren->GetActiveCamera(); // calculate the amount to jitter acam->GetFocalPoint(origfocus); aren->SetWorldPoint(origfocus); aren->WorldToDisplay(); dpoint = aren->GetDisplayPoint(); aren->SetDisplayPoint(dpoint[0] + offsets[0], dpoint[1] + offsets[1], dpoint[2]); aren->DisplayToWorld(); dpoint = aren->GetWorldPoint(); dpoint[0] /= dpoint[3]; dpoint[1] /= dpoint[3]; dpoint[2] /= dpoint[3]; acam->SetFocalPoint(dpoint); worldOffset[0] = dpoint[0] - origfocus[0]; worldOffset[1] = dpoint[1] - origfocus[1]; worldOffset[2] = dpoint[2] - origfocus[2]; acam->GetPosition(dpoint); acam->SetPosition(dpoint[0]+worldOffset[0], dpoint[1]+worldOffset[1], dpoint[2]+worldOffset[2]); } // draw the images this->DoFDRender(); // restore the jitter to normal for (this->Renderers->InitTraversal(rsit); (aren = this->Renderers->GetNextRenderer(rsit)); ) { acam = aren->GetActiveCamera(); // calculate the amount to jitter acam->GetFocalPoint(origfocus); aren->SetWorldPoint(origfocus); aren->WorldToDisplay(); dpoint = aren->GetDisplayPoint(); aren->SetDisplayPoint(dpoint[0] - offsets[0], dpoint[1] - offsets[1], dpoint[2]); aren->DisplayToWorld(); dpoint = aren->GetWorldPoint(); dpoint[0] /= dpoint[3]; dpoint[1] /= dpoint[3]; dpoint[2] /= dpoint[3]; acam->SetFocalPoint(dpoint); worldOffset[0] = dpoint[0] - origfocus[0]; worldOffset[1] = dpoint[1] - origfocus[1]; worldOffset[2] = dpoint[2] - origfocus[2]; acam->GetPosition(dpoint); acam->SetPosition(dpoint[0]+worldOffset[0], dpoint[1]+worldOffset[1], dpoint[2]+worldOffset[2]); } // now accumulate the images p1 = this->AccumulationBuffer; if (!this->FDFrames) { unsigned char *p2; unsigned char *p3; if (this->ResultFrame) { p2 = this->ResultFrame; } else { p2 = this->GetPixelData(0,0,size[0]-1,size[1]-1,!this->DoubleBuffer); } p3 = p2; for (y = 0; y < size[1]; y++) { for (x = 0; x < size[0]; x++) { *p1 += static_cast(*p2); p1++; p2++; *p1 += static_cast(*p2); p1++; p2++; *p1 += static_cast(*p2); p1++; p2++; } } delete [] p3; } } } else { this->DoFDRender(); } } //---------------------------------------------------------------------------- // Handle rendering any focal depth frames. void vtkRenderWindow::DoFDRender() { int i; // handle any focal depth if (this->FDFrames) { int *size; int x,y; unsigned char *p2; unsigned char *p3; float *p1; vtkRenderer *aren; vtkCamera *acam; double focalDisk; double *vpn, *dpoint; double vec[3]; vtkTransform *aTrans = vtkTransform::New(); double offsets[2]; double *orig; vtkCollectionSimpleIterator rsit; // get the size size = this->GetSize(); orig = new double [3*this->Renderers->GetNumberOfItems()]; for (i = 0; i < this->FDFrames; i++) { int j = 0; if (this->UseConstantFDOffsets) { offsets[0] = this->ConstantFDOffsets[0][i]; // radius offsets[1] = this->ConstantFDOffsets[1][i]*360.0; // angle } else { offsets[0] = vtkMath::Random(); // radius offsets[1] = vtkMath::Random()*360.0; // angle } // store offsets for each renderer for (this->Renderers->InitTraversal(rsit); (aren = this->Renderers->GetNextRenderer(rsit)); ) { acam = aren->GetActiveCamera(); focalDisk = acam->GetFocalDisk()*offsets[0]; vpn = acam->GetViewPlaneNormal(); aTrans->Identity(); aTrans->Scale(focalDisk,focalDisk,focalDisk); aTrans->RotateWXYZ(-offsets[1],vpn[0],vpn[1],vpn[2]); aTrans->TransformVector(acam->GetViewUp(),vec); dpoint = acam->GetPosition(); // store the position for later memcpy(orig + j*3,dpoint,3 * sizeof (double)); j++; acam->SetPosition(dpoint[0]+vec[0], dpoint[1]+vec[1], dpoint[2]+vec[2]); } // draw the images this->DoStereoRender(); // restore the jitter to normal j = 0; for (this->Renderers->InitTraversal(rsit); (aren = this->Renderers->GetNextRenderer(rsit)); ) { acam = aren->GetActiveCamera(); acam->SetPosition(orig + j*3); j++; } // get the pixels for accumulation // now accumulate the images p1 = this->AccumulationBuffer; if (this->ResultFrame) { p2 = this->ResultFrame; } else { p2 = this->GetPixelData(0,0,size[0]-1,size[1]-1,!this->DoubleBuffer); } p3 = p2; for (y = 0; y < size[1]; y++) { for (x = 0; x < size[0]; x++) { *p1 += static_cast(*p2); p1++; p2++; *p1 += static_cast(*p2); p1++; p2++; *p1 += static_cast(*p2); p1++; p2++; } } delete [] p3; } // free memory delete [] orig; aTrans->Delete(); } else { this->DoStereoRender(); } } //---------------------------------------------------------------------------- // Handle rendering the two different views for stereo rendering. void vtkRenderWindow::DoStereoRender() { vtkCollectionSimpleIterator rsit; this->Start(); this->StereoUpdate(); if (this->StereoType != VTK_STEREO_RIGHT) { // render the left eye vtkRenderer *aren; for (this->Renderers->InitTraversal(rsit); (aren = this->Renderers->GetNextRenderer(rsit)); ) { // Ugly piece of code - we need to know if the camera already // exists or not. If it does not yet exist, we must reset the // camera here - otherwise it will never be done (missing its // oppportunity to be reset in the Render method of the // vtkRenderer because it will already exist by that point...) if ( !aren->IsActiveCameraCreated() ) { aren->ResetCamera(); } aren->GetActiveCamera()->SetLeftEye(1); } this->Renderers->Render(); } if (this->StereoRender) { this->StereoMidpoint(); if (this->StereoType != VTK_STEREO_LEFT) { // render the right eye vtkRenderer *aren; for (this->Renderers->InitTraversal(rsit); (aren = this->Renderers->GetNextRenderer(rsit)); ) { // Duplicate the ugly code here too. Of course, most // times the left eye will have been rendered before // the right eye, but it is possible that the user sets // everything up and renders just the right eye - so we // need this check here too. if ( !aren->IsActiveCameraCreated() ) { aren->ResetCamera(); } if (this->StereoType != VTK_STEREO_FAKE) { aren->GetActiveCamera()->SetLeftEye(0); } } this->Renderers->Render(); } this->StereoRenderComplete(); } } //---------------------------------------------------------------------------- // Add a renderer to the list of renderers. void vtkRenderWindow::AddRenderer(vtkRenderer *ren) { if (this->HasRenderer(ren)) { return; } // we are its parent this->MakeCurrent(); ren->SetRenderWindow(this); this->Renderers->AddItem(ren); vtkRenderer *aren; vtkCollectionSimpleIterator rsit; for (this->Renderers->InitTraversal(rsit); (aren = this->Renderers->GetNextRenderer(rsit)); ) { aren->SetAllocatedRenderTime (1.0/(this->DesiredUpdateRate*this->Renderers->GetNumberOfItems())); } } //---------------------------------------------------------------------------- // Remove a renderer from the list of renderers. void vtkRenderWindow::RemoveRenderer(vtkRenderer *ren) { // we are its parent if (ren->GetRenderWindow() == this) { ren->ReleaseGraphicsResources(this); ren->SetRenderWindow(nullptr); } this->Renderers->RemoveItem(ren); } int vtkRenderWindow::HasRenderer(vtkRenderer *ren) { return (ren && this->Renderers->IsItemPresent(ren)); } //---------------------------------------------------------------------------- int vtkRenderWindow::CheckAbortStatus() { if (!this->InAbortCheck) { // Only check for abort at most 5 times per second. if (vtkTimerLog::GetUniversalTime() - this->AbortCheckTime > 0.2) { this->InAbortCheck = 1; this->InvokeEvent(vtkCommand::AbortCheckEvent,nullptr); this->InAbortCheck = 0; this->AbortCheckTime = vtkTimerLog::GetUniversalTime(); } } return this->AbortRender; } //---------------------------------------------------------------------------- void vtkRenderWindow::PrintSelf(ostream& os, vtkIndent indent) { this->Superclass::PrintSelf(os,indent); os << indent << "Borders: " << (this->Borders ? "On\n":"Off\n"); os << indent << "IsPicking: " << (this->IsPicking ? "On\n":"Off\n"); os << indent << "Double Buffer: " << (this->DoubleBuffer ? "On\n":"Off\n"); os << indent << "Full Screen: " << (this->FullScreen ? "On\n":"Off\n"); os << indent << "Renderers:\n"; this->Renderers->PrintSelf(os,indent.GetNextIndent()); os << indent << "Stereo Capable Window Requested: " << (this->StereoCapableWindow ? "Yes\n":"No\n"); os << indent << "Stereo Render: " << (this->StereoRender ? "On\n":"Off\n"); os << indent << "Point Smoothing: " << (this->PointSmoothing ? "On\n":"Off\n"); os << indent << "Line Smoothing: " << (this->LineSmoothing ? "On\n":"Off\n"); os << indent << "Polygon Smoothing: " << (this->PolygonSmoothing ? "On\n":"Off\n"); os << indent << "Anti Aliased Frames: " << this->AAFrames << "\n"; os << indent << "Abort Render: " << this->AbortRender << "\n"; os << indent << "Current Cursor: " << this->CurrentCursor << "\n"; os << indent << "Desired Update Rate: " << this->DesiredUpdateRate << "\n"; os << indent << "Focal Depth Frames: " << this->FDFrames << "\n"; os << indent << "In Abort Check: " << this->InAbortCheck << "\n"; os << indent << "NeverRendered: " << this->NeverRendered << "\n"; os << indent << "Interactor: " << this->Interactor << "\n"; os << indent << "Motion Blur Frames: " << this->SubFrames << "\n"; os << indent << "Swap Buffers: " << (this->SwapBuffers ? "On\n":"Off\n"); os << indent << "Stereo Type: " << this->GetStereoTypeAsString() << "\n"; os << indent << "Number of Layers: " << this->NumberOfLayers << "\n"; os << indent << "AccumulationBuffer Size " << this->AccumulationBufferSize << "\n"; os << indent << "AlphaBitPlanes: " << (this->AlphaBitPlanes ? "On" : "Off") << endl; os << indent << "UseSRGBColorSpace: " << (this->UseSRGBColorSpace ? "On" : "Off") << endl; os << indent << "AnaglyphColorSaturation: " << this->AnaglyphColorSaturation << "\n"; os << indent << "AnaglyphColorMask: " << this->AnaglyphColorMask[0] << " , " << this->AnaglyphColorMask[1] << "\n"; #ifndef VTK_LEGACY_REMOVE os << indent << "PainterDeviceAdapter: "; if (this->PainterDeviceAdapter) { os << endl; this->PainterDeviceAdapter->PrintSelf(os, indent.GetNextIndent()); } else { os << "(none)" << endl; } #endif os << indent << "MultiSamples: " << this->MultiSamples << "\n"; os << indent << "StencilCapable: " << (this->StencilCapable ? "True" : "False") << endl; } //---------------------------------------------------------------------------- // Update the system, if needed, due to stereo rendering. For some stereo // methods, subclasses might need to switch some hardware settings here. void vtkRenderWindow::StereoUpdate(void) { } //---------------------------------------------------------------------------- // Intermediate method performs operations required between the rendering // of the left and right eye. void vtkRenderWindow::StereoMidpoint(void) { vtkRenderer * aren; /* For IceT stereo */ for (Renderers->InitTraversal() ; (aren = Renderers->GetNextItem()) ; ) { aren->StereoMidpoint(); } if ((this->StereoType == VTK_STEREO_RED_BLUE) || (this->StereoType == VTK_STEREO_INTERLACED) || (this->StereoType == VTK_STEREO_DRESDEN) || (this->StereoType == VTK_STEREO_ANAGLYPH) || (this->StereoType == VTK_STEREO_CHECKERBOARD) || (this->StereoType == VTK_STEREO_SPLITVIEWPORT_HORIZONTAL)) { int *size; // get the size size = this->GetSize(); // get the data this->StereoBuffer = this->GetPixelData(0,0,size[0]-1,size[1]-1,!this->DoubleBuffer); } } //---------------------------------------------------------------------------- // Handles work required once both views have been rendered when using // stereo rendering. void vtkRenderWindow::StereoRenderComplete(void) { switch (this->StereoType) { case VTK_STEREO_RED_BLUE: { unsigned char *buff; unsigned char *p1, *p2, *p3; unsigned char* result; int *size; int x,y; int res; // get the size size = this->GetSize(); // get the data buff = this->GetPixelData(0,0,size[0]-1,size[1]-1,!this->DoubleBuffer); p1 = this->StereoBuffer; p2 = buff; // allocate the result result = new unsigned char [size[0]*size[1]*3]; if (!result) { vtkErrorMacro(<<"Couldn't allocate memory for RED BLUE stereo."); return; } p3 = result; // now merge the two images for (x = 0; x < size[0]; x++) { for (y = 0; y < size[1]; y++) { res = p1[0] + p1[1] + p1[2]; p3[0] = res/3; res = p2[0] + p2[1] + p2[2]; p3[1] = 0; p3[2] = res/3; p1 += 3; p2 += 3; p3 += 3; } } this->ResultFrame = result; delete [] this->StereoBuffer; this->StereoBuffer = nullptr; delete [] buff; } break; case VTK_STEREO_ANAGLYPH: { unsigned char *buff; unsigned char *p0, *p1, *p2; unsigned char* result; int *size; int x,y; int m0, m1, ave0, ave1; int avecolor[256][3], satcolor[256]; float a; // get the size size = this->GetSize(); // get the data buff = this->GetPixelData(0,0,size[0]-1,size[1]-1,!this->DoubleBuffer); p0 = this->StereoBuffer; p1 = buff; // allocate the result result = new unsigned char [size[0]*size[1]*3]; if (!result) { vtkErrorMacro(<<"Couldn't allocate memory for ANAGLYPH stereo."); return; } p2 = result; // build some tables a = this->AnaglyphColorSaturation; m0 = this->AnaglyphColorMask[0]; m1 = this->AnaglyphColorMask[1]; for(x = 0; x < 256; x++) { avecolor[x][0] = int((1.0-a)*x*0.3086); avecolor[x][1] = int((1.0-a)*x*0.6094); avecolor[x][2] = int((1.0-a)*x*0.0820); satcolor[x] = int(a*x); } // now merge the two images for (x = 0; x < size[0]; x++) { for (y = 0; y < size[1]; y++) { ave0 = avecolor[p0[0]][0] + avecolor[p0[1]][1] + avecolor[p0[2]][2]; ave1 = avecolor[p1[0]][0] + avecolor[p1[1]][1] + avecolor[p1[2]][2]; if (m0 & 0x4) { p2[0] = satcolor[p0[0]] + ave0; } if (m0 & 0x2) { p2[1] = satcolor[p0[1]] + ave0; } if (m0 & 0x1) { p2[2] = satcolor[p0[2]] + ave0; } if (m1 & 0x4) { p2[0] = satcolor[p1[0]] + ave1; } if (m1 & 0x2) { p2[1] = satcolor[p1[1]] + ave1; } if (m1 & 0x1) { p2[2] = satcolor[p1[2]] + ave1; } p0 += 3; p1 += 3; p2 += 3; } } this->ResultFrame = result; delete [] this->StereoBuffer; this->StereoBuffer = nullptr; delete [] buff; } break; case VTK_STEREO_INTERLACED: { unsigned char *buff; unsigned char *p1, *p2, *p3; unsigned char* result; int *size, line; int x,y; // get the size size = this->GetSize(); // get the data buff = this->GetPixelData(0,0,size[0]-1,size[1]-1,!this->DoubleBuffer); p1 = this->StereoBuffer; p2 = buff; line = size[0] * 3; // allocate the result result = new unsigned char [size[0]*size[1]*3]; if (!result) { vtkErrorMacro(<<"Couldn't allocate memory for interlaced stereo."); return; } // now merge the two images p3 = result; for (y = 0; y < size[1]; y += 2) { for (x = 0; x < size[0]; x++) { *p3++ = *p1++; *p3++ = *p1++; *p3++ = *p1++; } // skip a line p3 += line; p1 += line; } // now the other eye p3 = result + line; p2 += line; for (y = 1; y < size[1]; y += 2) { for (x = 0; x < size[0]; x++) { *p3++ = *p2++; *p3++ = *p2++; *p3++ = *p2++; } // skip a line p3 += line; p2 += line; } this->ResultFrame = result; delete [] this->StereoBuffer; this->StereoBuffer = nullptr; delete [] buff; } break; case VTK_STEREO_DRESDEN: { unsigned char *buff; unsigned char *p1, *p2, *p3; unsigned char* result; int *size; int x,y; // get the size size = this->GetSize(); // get the data buff = this->GetPixelData(0,0,size[0]-1,size[1]-1,!this->DoubleBuffer); p1 = this->StereoBuffer; p2 = buff; // allocate the result result = new unsigned char [size[0]*size[1]*3]; if (!result) { vtkErrorMacro( <<"Couldn't allocate memory for dresden display stereo."); return; } // now merge the two images p3 = result; for (y = 0; y < size[1]; y++ ) { for (x = 0; x < size[0]; x+=2) { *p3++ = *p1++; *p3++ = *p1++; *p3++ = *p1++; p3+=3; p1+=3; } if( size[0] % 2 == 1 ) { p3 -= 3; p1 -= 3; } } // now the other eye p3 = result + 3; p2 += 3; for (y = 0; y < size[1]; y++) { for (x = 1; x < size[0]; x+=2) { *p3++ = *p2++; *p3++ = *p2++; *p3++ = *p2++; p3+=3; p2+=3; } if( size[0] % 2 == 1 ) { p3 += 3; p2 += 3; } } this->ResultFrame = result; delete [] this->StereoBuffer; this->StereoBuffer = nullptr; delete [] buff; } break; case VTK_STEREO_CHECKERBOARD: { unsigned char *left, *right; unsigned char *sleft, *sright; int *size; // get the size size = this->GetSize(); // get the data sleft = this->StereoBuffer; sright = this->GetPixelData(0, 0, size[0] - 1, size[1] - 1, !this->DoubleBuffer); // copy right pixels onto the left pixel buffer for(int y = 0; y < size[1]; y = y + 1) { // set up the pointers // right starts on x = 1 on even scanlines // right starts on x = 0 on odd scanlines if(y % 2) { left = sleft + y * 3 * size[0] + 3; right = sright + y * 3 * size[0] + 3; } else { left = sleft + y * 3 * size[0]; right = sright + y * 3 * size[0]; } // skip every other pixel for(int x = (y + 1) % 2; x < size[0]; x = x + 2) { *left++ = *right++; *left++ = *right++; *left++ = *right++; // skip pixel left = left + 3; right = right + 3; } } // cleanup this->ResultFrame = sleft; this->StereoBuffer = nullptr; delete [] sright; } break; case VTK_STEREO_SPLITVIEWPORT_HORIZONTAL: { unsigned char *left, *leftTemp, *right; unsigned char *sleft, *sright; int *size; // get the size size = this->GetSize(); // get the data sleft = this->StereoBuffer; sright = this->GetPixelData(0, 0, size[0] - 1, size[1] - 1, !this->DoubleBuffer); int midX = static_cast(size[0] / 2.0); // If the row size is even, reduce the row copy by // one. Otherwise the pointer will overflow when we fill the // right hand part of the stereo. if (size[0] % 2 == 0) { midX--; } int offsetX = static_cast(ceil(size[0] / 2.0)); // copy pixel data for (int y = 0; y <= (size[1] - 1); ++y) { for (int x = 1; x <= midX; ++x) { left = sleft + (x * 3) + (y * size[0] * 3); leftTemp = sleft + ((2 * x) * 3) + (y * size[0] * 3); *left++ = *leftTemp++; *left++ = *leftTemp++; *left++ = *leftTemp++; } } for (int y = 0; y <= (size[1] - 1); ++y) { for (int x = 0; x < midX; ++x) { left = sleft + ((x + offsetX) * 3) + (y * size[0] * 3); right = sright + ((2 * x) * 3) + (y * size[0] * 3); *left++ = *right++; *left++ = *right++; *left++ = *right++; } } // cleanup this->ResultFrame = sleft; this->StereoBuffer = nullptr; delete [] sright; } break; } } //---------------------------------------------------------------------------- void vtkRenderWindow::CopyResultFrame(void) { if (this->ResultFrame) { int *size; // get the size size = this->GetSize(); this->SetPixelData(0,0,size[0]-1,size[1]-1,this->ResultFrame,!this->DoubleBuffer); } // Just before we swap buffers (in case of double buffering), we fire the // RenderEvent marking that a render call has concluded successfully. We // separate this from EndEvent since some applications may want to put some // more elements on the "draw-buffer" before calling the rendering complete. // This event gives them that opportunity. this->InvokeEvent(vtkCommand::RenderEvent); this->Frame(); } //---------------------------------------------------------------------------- // treat renderWindow and interactor as one object. // it might be easier if the GetReference count method were redefined. void vtkRenderWindow::UnRegister(vtkObjectBase *o) { if (this->Interactor && this->Interactor->GetRenderWindow() == this && this->Interactor != o) { if (this->GetReferenceCount() + this->Interactor->GetReferenceCount() == 3) { this->vtkObject::UnRegister(o); vtkRenderWindowInteractor *tmp = this->Interactor; tmp->Register(nullptr); this->Interactor->SetRenderWindow(nullptr); tmp->UnRegister(nullptr); return; } } this->vtkObject::UnRegister(o); } //---------------------------------------------------------------------------- const char *vtkRenderWindow::GetRenderLibrary() { return vtkGraphicsFactory::GetRenderLibrary(); } //---------------------------------------------------------------------------- const char *vtkRenderWindow::GetRenderingBackend() { return "Unknown"; } //---------------------------------------------------------------------------- void vtkRenderWindow::CaptureGL2PSSpecialProps(vtkCollection *result) { if (result == nullptr) { vtkErrorMacro(<<"CaptureGL2PSSpecialProps was passed a nullptr pointer."); return; } result->RemoveAllItems(); if (this->CapturingGL2PSSpecialProps) { vtkDebugMacro(<<"Called recursively.") return; } this->CapturingGL2PSSpecialProps = 1; vtkRenderer *ren; for (Renderers->InitTraversal(); (ren = Renderers->GetNextItem());) { vtkNew props; result->AddItem(props); ren->SetGL2PSSpecialPropCollection(props); } this->Render(); for (Renderers->InitTraversal(); (ren = Renderers->GetNextItem());) { ren->SetGL2PSSpecialPropCollection(nullptr); } this->CapturingGL2PSSpecialProps = 0; } // Description: Return the stereo type as a character string. // when this method was inlined, static linking on BlueGene failed // (symbol referenced which is defined in discarded section) const char *vtkRenderWindow::GetStereoTypeAsString() { switch ( this->StereoType ) { case VTK_STEREO_CRYSTAL_EYES: return "CrystalEyes"; case VTK_STEREO_RED_BLUE: return "RedBlue"; case VTK_STEREO_LEFT: return "Left"; case VTK_STEREO_RIGHT: return "Right"; case VTK_STEREO_DRESDEN: return "DresdenDisplay"; case VTK_STEREO_ANAGLYPH: return "Anaglyph"; case VTK_STEREO_CHECKERBOARD: return "Checkerboard"; case VTK_STEREO_SPLITVIEWPORT_HORIZONTAL: return "SplitViewportHorizontal"; case VTK_STEREO_FAKE: return "Fake"; default: return ""; } } //---------------------------------------------------------------------------- #if !defined(VTK_LEGACY_REMOVE) vtkPainterDeviceAdapter *vtkRenderWindow::GetPainterDeviceAdapter() { VTK_LEGACY_BODY(vtkRenderWindow::GetPainterDeviceAdapter, "VTK 8.1"); return this->PainterDeviceAdapter; } int vtkRenderWindow::GetAAFrames() { VTK_LEGACY_BODY(vtkRenderWindow::GetAAFrames, "VTK 8.1"); return this->AAFrames; } void vtkRenderWindow::SetAAFrames(int val) { VTK_LEGACY_BODY(vtkRenderWindow::SetAAFrames, "VTK 8.1"); if (this->AAFrames != val) { this->AAFrames = val; this->Modified(); } } int vtkRenderWindow::GetFDFrames() { VTK_LEGACY_BODY(vtkRenderWindow::GetFDFrames, "VTK 8.1"); return this->FDFrames; } int vtkRenderWindow::GetUseConstantFDOffsets() { VTK_LEGACY_BODY(vtkRenderWindow::GetUseConstantFDOffsets, "VTK 8.1"); return this->UseConstantFDOffsets; } void vtkRenderWindow::SetUseConstantFDOffsets(int val) { VTK_LEGACY_BODY(vtkRenderWindow::SetUseConstantFDOffsets, "VTK 8.1"); if (this->UseConstantFDOffsets != val) { this->UseConstantFDOffsets = val; this->Modified(); } } int vtkRenderWindow::GetSubFrames() { VTK_LEGACY_BODY(vtkRenderWindow::GetSubFrames, "VTK 8.1"); return this->SubFrames; } #endif