1 /*=========================================================================
2 
3   Program:   Visualization Toolkit
4   Module:    vtkSynchronizedRenderers.cxx
5 
6   Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
7   All rights reserved.
8   See Copyright.txt or http://www.kitware.com/Copyright.htm for details.
9 
10      This software is distributed WITHOUT ANY WARRANTY; without even
11      the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
12      PURPOSE.  See the above copyright notice for more information.
13 
14 =========================================================================*/
15 #include "vtkSynchronizedRenderers.h"
16 
17 #include "vtkBoundingBox.h"
18 #include "vtkCamera.h"
19 #include "vtkCommand.h"
20 #include "vtkCommunicator.h"
21 #include "vtkFXAAOptions.h"
22 #include "vtkHardwareSelector.h"
23 #include "vtkImageData.h"
24 #include "vtkMatrix4x4.h"
25 #include "vtkMultiProcessController.h"
26 #include "vtkMultiProcessStream.h"
27 #include "vtkObjectFactory.h"
28 #include "vtkOpenGLRenderUtilities.h"
29 #include "vtkParallelRenderManager.h"
30 #include "vtkPNGWriter.h"
31 #include "vtkRenderWindow.h"
32 #include "vtkOpenGLRenderer.h"
33 #include "vtkOpenGLRenderWindow.h"
34 #include "vtkOpenGLState.h"
35 #include "vtkOpenGLError.h"
36 
37 #include "vtkOpenGLFXAAFilter.h"
38 
39 #include <cassert>
40 
41 //----------------------------------------------------------------------------
42 class vtkSynchronizedRenderers::vtkObserver : public vtkCommand
43 {
44 public:
New()45   static vtkObserver* New()
46   {
47     vtkObserver* obs = new vtkObserver();
48     obs->Target = nullptr;
49     return obs;
50   }
51 
Execute(vtkObject *,unsigned long eventId,void *)52   void Execute(vtkObject *, unsigned long eventId, void *) override
53   {
54     if (this->Target && this->Target->GetAutomaticEventHandling())
55     {
56       switch (eventId)
57       {
58       case vtkCommand::StartEvent:
59         this->Target->HandleStartRender();
60         break;
61 
62       case vtkCommand::EndEvent:
63         this->Target->HandleEndRender();
64         break;
65 
66       case vtkCommand::AbortCheckEvent:
67         this->Target->HandleAbortRender();
68         break;
69       }
70     }
71   }
72 
73   vtkSynchronizedRenderers* Target;
74 };
75 
76 vtkStandardNewMacro(vtkSynchronizedRenderers);
77 vtkCxxSetObjectMacro(vtkSynchronizedRenderers, ParallelController,
78   vtkMultiProcessController);
79 vtkCxxSetObjectMacro(vtkSynchronizedRenderers, CaptureDelegate,
80   vtkSynchronizedRenderers);
81 //----------------------------------------------------------------------------
vtkSynchronizedRenderers()82 vtkSynchronizedRenderers::vtkSynchronizedRenderers()
83 {
84   this->Observer = vtkSynchronizedRenderers::vtkObserver::New();
85   this->Observer->Target = this;
86 
87   this->UseFXAA = false;
88   this->FXAAFilter = nullptr;
89 
90   this->Renderer = nullptr;
91   this->ParallelController = nullptr;
92   this->ParallelRendering = true;
93   this->ImageReductionFactor = 1;
94 
95   this->WriteBackImages = true;
96   this->RootProcessId = 0;
97 
98   this->CaptureDelegate = nullptr;
99   this->AutomaticEventHandling = true;
100 }
101 
102 //----------------------------------------------------------------------------
~vtkSynchronizedRenderers()103 vtkSynchronizedRenderers::~vtkSynchronizedRenderers()
104 {
105   this->SetCaptureDelegate(nullptr);
106 
107   this->Observer->Target = nullptr;
108 
109   this->SetRenderer(nullptr);
110   this->SetParallelController(nullptr);
111   this->Observer->Delete();
112   this->Observer = nullptr;
113 
114   // vtkOpenGLFXAAFilter is only available on opengl2:
115   if (this->FXAAFilter)
116   {
117     this->FXAAFilter->Delete();
118     this->FXAAFilter = nullptr;
119   }
120 }
121 
122 //----------------------------------------------------------------------------
SetRenderer(vtkRenderer * renderer)123 void vtkSynchronizedRenderers::SetRenderer(vtkRenderer* renderer)
124 {
125   if (this->Renderer  != renderer)
126   {
127     if (this->Renderer)
128     {
129       this->Renderer->RemoveObserver(this->Observer);
130     }
131 
132     // The renderer should be OpenGL ...
133     vtkOpenGLRenderer *glRenderer = vtkOpenGLRenderer::SafeDownCast(renderer);
134 
135     if(renderer && !glRenderer)
136     {
137         vtkErrorMacro("Received non OpenGL renderer");
138         assert(false);
139     }
140 
141     vtkSetObjectBodyMacro(Renderer, vtkOpenGLRenderer, glRenderer);
142     if (this->Renderer)
143     {
144       this->Renderer->AddObserver(vtkCommand::StartEvent, this->Observer);
145       this->Renderer->AddObserver(vtkCommand::EndEvent, this->Observer);
146       // this->Renderer->AddObserver(vtkCommand::AbortCheckEvent, this->Observer);
147     }
148   }
149 }
150 
151 //----------------------------------------------------------------------------
HandleStartRender()152 void vtkSynchronizedRenderers::HandleStartRender()
153 {
154   if (!this->Renderer || !this->ParallelRendering ||
155     !this->ParallelController)
156   {
157     if (this->CaptureDelegate &&
158       this->CaptureDelegate->GetAutomaticEventHandling() == false)
159     {
160       this->CaptureDelegate->HandleStartRender();
161     }
162     return;
163   }
164 
165   this->ReducedImage.MarkInValid();
166   this->FullImage.MarkInValid();
167 
168   // disable FXAA when parallel rendering. We'll do the FXAA pass after the
169   // compositing stage. This avoid any seam artifacts from creeping in.
170   this->UseFXAA = this->Renderer->GetUseFXAA();
171   this->Renderer->SetUseFXAA(false);
172 
173   if (this->ParallelController->GetLocalProcessId() == this->RootProcessId)
174   {
175     this->MasterStartRender();
176   }
177   else
178   {
179     this->SlaveStartRender();
180   }
181 
182   this->Renderer->GetViewport(this->LastViewport);
183   if (this->ImageReductionFactor > 1)
184   {
185     this->Renderer->SetViewport(
186       this->LastViewport[0]/this->ImageReductionFactor,
187       this->LastViewport[1]/this->ImageReductionFactor,
188       this->LastViewport[2]/this->ImageReductionFactor,
189       this->LastViewport[3]/this->ImageReductionFactor);
190   }
191 
192   if (this->CaptureDelegate &&
193     this->CaptureDelegate->GetAutomaticEventHandling() == false)
194   {
195     this->CaptureDelegate->HandleStartRender();
196   }
197 }
198 
199 //----------------------------------------------------------------------------
MasterStartRender()200 void vtkSynchronizedRenderers::MasterStartRender()
201 {
202   RendererInfo renInfo;
203   renInfo.ImageReductionFactor = this->GetImageReductionFactor();
204   renInfo.CopyFrom(this->Renderer);
205   vtkMultiProcessStream stream;
206   renInfo.Save(stream);
207 
208   this->ParallelController->Broadcast(stream, this->RootProcessId);
209 }
210 
211 //----------------------------------------------------------------------------
SlaveStartRender()212 void vtkSynchronizedRenderers::SlaveStartRender()
213 {
214   vtkMultiProcessStream stream;
215   this->ParallelController->Broadcast(stream, this->RootProcessId);
216 
217   RendererInfo renInfo;
218   renInfo.Restore(stream);
219   renInfo.CopyTo(this->Renderer);
220   this->SetImageReductionFactor(renInfo.ImageReductionFactor);
221 }
222 
223 //----------------------------------------------------------------------------
HandleEndRender()224 void vtkSynchronizedRenderers::HandleEndRender()
225 {
226   if (this->CaptureDelegate &&
227     this->CaptureDelegate->GetAutomaticEventHandling() == false)
228   {
229     this->CaptureDelegate->HandleEndRender();
230   }
231 
232   if (!this->Renderer || !this->ParallelRendering ||
233     !this->ParallelController)
234   {
235     return;
236   }
237 
238   if (this->ParallelController->GetLocalProcessId() == this->RootProcessId)
239   {
240     this->MasterEndRender();
241   }
242   else
243   {
244     this->SlaveEndRender();
245   }
246 
247   if (this->WriteBackImages)
248   {
249     if (this->ImageReductionFactor > 1 && this->ParallelRendering)
250     {
251       this->CaptureRenderedImage();
252     }
253 
254     this->PushImageToScreen();
255   }
256 
257   // restore viewport
258   this->Renderer->SetViewport(this->LastViewport);
259 
260   // restore FXAA state.
261   this->Renderer->SetUseFXAA(this->UseFXAA);
262   this->UseFXAA = false;
263 }
264 
265 //----------------------------------------------------------------------------
MasterEndRender()266 void vtkSynchronizedRenderers::MasterEndRender()
267 {
268 }
269 
270 //----------------------------------------------------------------------------
SlaveEndRender()271 void vtkSynchronizedRenderers::SlaveEndRender()
272 {
273 }
274 
275 //----------------------------------------------------------------------------
276 vtkSynchronizedRenderers::vtkRawImage&
CaptureRenderedImage()277 vtkSynchronizedRenderers::CaptureRenderedImage()
278 {
279   vtkRawImage& rawImage =
280     (this->ImageReductionFactor == 1)?
281     this->FullImage : this->ReducedImage;
282 
283   if (!rawImage.IsValid())
284   {
285     if (this->CaptureDelegate)
286     {
287       rawImage = this->CaptureDelegate->CaptureRenderedImage();
288     }
289     else
290     {
291       rawImage.Capture(this->Renderer);
292     }
293   }
294 
295   return rawImage;
296 }
297 
298 //----------------------------------------------------------------------------
PushImageToScreen()299 void vtkSynchronizedRenderers::PushImageToScreen()
300 {
301   vtkRawImage& rawImage =
302     (this->ImageReductionFactor == 1)?
303     this->FullImage : this->ReducedImage;
304 
305   if (!rawImage.IsValid())
306   {
307     return;
308   }
309 
310   rawImage.PushToViewport(this->Renderer);
311 
312   vtkHardwareSelector *sel = this->Renderer->GetSelector();
313   if (sel)
314   {
315     sel->SavePixelBuffer(sel->GetCurrentPass());
316   }
317 
318   if (this->UseFXAA)
319   {
320     if (!this->FXAAFilter)
321     {
322       this->FXAAFilter = vtkOpenGLFXAAFilter::New();
323     }
324     this->FXAAFilter->UpdateConfiguration(this->Renderer->GetFXAAOptions());
325     this->FXAAFilter->Execute(this->Renderer);
326   }
327 }
328 
329 ////----------------------------------------------------------------------------
330 //void vtkSynchronizedRenderers::ResetCamera()
331 //{
332 //  if (!this->ParallelController)
333 //    {
334 //    vtkErrorMacro("No controller set.");
335 //    return;
336 //    }
337 //
338 //  if (this->ParallelController->GetLocalProcessId() == this->RootProcessId)
339 //    {
340 //    // TODO: gather information about bounds from every one and then reset the
341 //    // camera on the root node alone. Other processes will get the updated
342 //    // camera position when render gets called.
343 //    }
344 //}
345 
346 //----------------------------------------------------------------------------
CollectiveExpandForVisiblePropBounds(double bounds[6])347 void vtkSynchronizedRenderers::CollectiveExpandForVisiblePropBounds(
348   double bounds[6])
349 {
350   // get local bounds.
351   double local_bounds[6];
352   this->Renderer->ComputeVisiblePropBounds(local_bounds);
353 
354   // merge local bounds into the bounds passed in to this function call.
355   vtkBoundingBox box;
356   box.AddBounds(local_bounds);
357   box.AddBounds(bounds);
358   box.GetBounds(bounds);
359 
360   if (this->ParallelController->IsA("vtkMPIController"))
361   {
362     double min_bounds[3] = {bounds[0], bounds[2], bounds[4]};
363     double max_bounds[3] = {bounds[1], bounds[3], bounds[5]};
364     double min_result[3], max_result[3];
365     this->ParallelController->AllReduce(min_bounds, min_result, 3,
366       vtkCommunicator::MIN_OP);
367     this->ParallelController->AllReduce(max_bounds, max_result, 3,
368       vtkCommunicator::MAX_OP);
369     bounds[0] = min_result[0];
370     bounds[2] = min_result[1];
371     bounds[4] = min_result[2];
372     bounds[1] = max_result[0];
373     bounds[3] = max_result[1];
374     bounds[5] = max_result[2];
375   }
376   else
377   {
378     // since vtkSocketController does not support such reduction operation, we
379     // simply use point-to-point communication.
380     double other_bounds[6];
381     if (this->ParallelController->GetLocalProcessId() == this->RootProcessId)
382     {
383       this->ParallelController->Send(bounds, 6, 1, COMPUTE_BOUNDS_TAG);
384       this->ParallelController->Receive(other_bounds, 6, 1, COMPUTE_BOUNDS_TAG);
385     }
386     else
387     {
388       this->ParallelController->Receive(other_bounds, 6, 1, COMPUTE_BOUNDS_TAG);
389       this->ParallelController->Send(bounds, 6, 1, COMPUTE_BOUNDS_TAG);
390     }
391 
392     vtkBoundingBox bbox;
393     bbox.AddBounds(bounds);
394     bbox.AddBounds(other_bounds);
395     bbox.GetBounds(bounds);
396   }
397 }
398 
399 //----------------------------------------------------------------------------
PrintSelf(ostream & os,vtkIndent indent)400 void vtkSynchronizedRenderers::PrintSelf(ostream& os, vtkIndent indent)
401 {
402   this->Superclass::PrintSelf(os, indent);
403 
404   os << indent << "ImageReductionFactor: "
405     << this->ImageReductionFactor << endl;
406   os << indent << "WriteBackImages: " << this->WriteBackImages << endl;
407   os << indent << "RootProcessId: " << this->RootProcessId << endl;
408   os << indent << "ParallelRendering: " << this->ParallelRendering << endl;
409   os << indent << "AutomaticEventHandling: "
410     << this->AutomaticEventHandling << endl;
411   os << indent << "CaptureDelegate: ";
412   if(this->CaptureDelegate==nullptr)
413   {
414     os << "(none)" << endl;
415   }
416   else
417   {
418     os << this->CaptureDelegate << endl;
419   }
420 
421   os << indent << "Renderer: ";
422   if(this->Renderer==nullptr)
423   {
424     os << "(none)" << endl;
425   }
426   else
427   {
428     os << this->Renderer << endl;
429   }
430 
431   os << indent << "ParallelController: ";
432   if(this->ParallelController==nullptr)
433   {
434     os << "(none)" << endl;
435   }
436   else
437   {
438     os << this->ParallelController << endl;
439   }
440 
441 }
442 
443 //----------------------------------------------------------------------------
444 // ** INFO OBJECT METHODS ***
445 //----------------------------------------------------------------------------
Save(vtkMultiProcessStream & stream)446 void vtkSynchronizedRenderers::RendererInfo::Save(vtkMultiProcessStream& stream)
447 {
448   stream << 1023
449          << this->ImageReductionFactor
450          << this->Draw
451          << this->CameraParallelProjection
452          << this->Viewport[0] << this->Viewport[1]
453          << this->Viewport[2] << this->Viewport[3]
454          << this->CameraPosition[0]
455          << this->CameraPosition[1]
456          << this->CameraPosition[2]
457          << this->CameraFocalPoint[0]
458          << this->CameraFocalPoint[1]
459          << this->CameraFocalPoint[2]
460          << this->CameraViewUp[0]
461          << this->CameraViewUp[1]
462          << this->CameraViewUp[2]
463          << this->CameraWindowCenter[0]
464          << this->CameraWindowCenter[1]
465          << this->CameraClippingRange[0]
466          << this->CameraClippingRange[1]
467          << this->CameraViewAngle
468          << this->CameraParallelScale
469          << this->EyeTransformMatrix[0]
470          << this->EyeTransformMatrix[1]
471          << this->EyeTransformMatrix[2]
472          << this->EyeTransformMatrix[3]
473          << this->EyeTransformMatrix[4]
474          << this->EyeTransformMatrix[5]
475          << this->EyeTransformMatrix[6]
476          << this->EyeTransformMatrix[7]
477          << this->EyeTransformMatrix[8]
478          << this->EyeTransformMatrix[9]
479          << this->EyeTransformMatrix[10]
480          << this->EyeTransformMatrix[11]
481          << this->EyeTransformMatrix[12]
482          << this->EyeTransformMatrix[13]
483          << this->EyeTransformMatrix[14]
484          << this->EyeTransformMatrix[15]
485          << this->ModelTransformMatrix[0]
486          << this->ModelTransformMatrix[1]
487          << this->ModelTransformMatrix[2]
488          << this->ModelTransformMatrix[3]
489          << this->ModelTransformMatrix[4]
490          << this->ModelTransformMatrix[5]
491          << this->ModelTransformMatrix[6]
492          << this->ModelTransformMatrix[7]
493          << this->ModelTransformMatrix[8]
494          << this->ModelTransformMatrix[9]
495          << this->ModelTransformMatrix[10]
496          << this->ModelTransformMatrix[11]
497          << this->ModelTransformMatrix[12]
498          << this->ModelTransformMatrix[13]
499          << this->ModelTransformMatrix[14]
500          << this->ModelTransformMatrix[15];
501 }
502 
503 //----------------------------------------------------------------------------
Restore(vtkMultiProcessStream & stream)504 bool vtkSynchronizedRenderers::RendererInfo::Restore(vtkMultiProcessStream& stream)
505 {
506   int tag;
507   stream >> tag;
508   if (tag != 1023)
509   {
510     return false;
511   }
512   stream >> this->ImageReductionFactor
513          >> this->Draw
514          >> this->CameraParallelProjection
515          >> this->Viewport[0]
516          >> this->Viewport[1]
517          >> this->Viewport[2]
518          >> this->Viewport[3]
519          >> this->CameraPosition[0]
520          >> this->CameraPosition[1]
521          >> this->CameraPosition[2]
522          >> this->CameraFocalPoint[0]
523          >> this->CameraFocalPoint[1]
524          >> this->CameraFocalPoint[2]
525          >> this->CameraViewUp[0]
526          >> this->CameraViewUp[1]
527          >> this->CameraViewUp[2]
528          >> this->CameraWindowCenter[0]
529          >> this->CameraWindowCenter[1]
530          >> this->CameraClippingRange[0]
531          >> this->CameraClippingRange[1]
532          >> this->CameraViewAngle
533          >> this->CameraParallelScale
534          >> this->EyeTransformMatrix[0]
535          >> this->EyeTransformMatrix[1]
536          >> this->EyeTransformMatrix[2]
537          >> this->EyeTransformMatrix[3]
538          >> this->EyeTransformMatrix[4]
539          >> this->EyeTransformMatrix[5]
540          >> this->EyeTransformMatrix[6]
541          >> this->EyeTransformMatrix[7]
542          >> this->EyeTransformMatrix[8]
543          >> this->EyeTransformMatrix[9]
544          >> this->EyeTransformMatrix[10]
545          >> this->EyeTransformMatrix[11]
546          >> this->EyeTransformMatrix[12]
547          >> this->EyeTransformMatrix[13]
548          >> this->EyeTransformMatrix[14]
549          >> this->EyeTransformMatrix[15]
550          >> this->ModelTransformMatrix[0]
551          >> this->ModelTransformMatrix[1]
552          >> this->ModelTransformMatrix[2]
553          >> this->ModelTransformMatrix[3]
554          >> this->ModelTransformMatrix[4]
555          >> this->ModelTransformMatrix[5]
556          >> this->ModelTransformMatrix[6]
557          >> this->ModelTransformMatrix[7]
558          >> this->ModelTransformMatrix[8]
559          >> this->ModelTransformMatrix[9]
560          >> this->ModelTransformMatrix[10]
561          >> this->ModelTransformMatrix[11]
562          >> this->ModelTransformMatrix[12]
563          >> this->ModelTransformMatrix[13]
564          >> this->ModelTransformMatrix[14]
565          >> this->ModelTransformMatrix[15];
566   return true;
567 }
568 
569 //----------------------------------------------------------------------------
CopyFrom(vtkRenderer * ren)570 void vtkSynchronizedRenderers::RendererInfo::CopyFrom(vtkRenderer* ren)
571 {
572   vtkCamera* cam = ren->GetActiveCamera();
573   this->Draw = ren->GetDraw();
574   this->CameraParallelProjection = cam->GetParallelProjection();
575   ren->GetViewport(this->Viewport);
576   cam->GetPosition(this->CameraPosition);
577   cam->GetFocalPoint(this->CameraFocalPoint);
578   cam->GetViewUp(this->CameraViewUp);
579   cam->GetWindowCenter(this->CameraWindowCenter);
580   cam->GetClippingRange(this->CameraClippingRange);
581   this->CameraViewAngle = cam->GetViewAngle();
582   this->CameraParallelScale = cam->GetParallelScale();
583 
584   vtkMatrix4x4 *eyeTransformationMatrix = cam->GetEyeTransformMatrix();
585   vtkMatrix4x4 *modelTransformationMatrix = cam->GetModelTransformMatrix();
586   for(int i=0; i < 4; ++i)
587   {
588     for(int j=0; j < 4; ++j)
589     {
590        this->EyeTransformMatrix[i*4 + j] = eyeTransformationMatrix->GetElement(i, j);
591        this->ModelTransformMatrix[i*4 + j] = modelTransformationMatrix->GetElement(i, j);
592     }
593   }
594 }
595 
596 //----------------------------------------------------------------------------
CopyTo(vtkRenderer * ren)597 void vtkSynchronizedRenderers::RendererInfo::CopyTo(vtkRenderer* ren)
598 {
599   vtkCamera* cam = ren->GetActiveCamera();
600   ren->SetDraw(this->Draw);
601   cam->SetParallelProjection(this->CameraParallelProjection);
602   //ren->SetViewport(this->Viewport);
603   cam->SetPosition(this->CameraPosition);
604   cam->SetFocalPoint(this->CameraFocalPoint);
605   cam->SetViewUp(this->CameraViewUp);
606   cam->SetWindowCenter(this->CameraWindowCenter[0],
607                        this->CameraWindowCenter[1]);
608   cam->SetClippingRange(this->CameraClippingRange);
609   cam->SetViewAngle(this->CameraViewAngle);
610   cam->SetParallelScale(this->CameraParallelScale);
611 
612   // We reuse vtkMatrix4x4 objects present on the camera and then use
613   // vtkMatrix4x4::SetElement(). This avoids modifying the mtime of the
614   // camera unless anything truly changed.
615   vtkMatrix4x4 *eyeTransformationMatrix = cam->GetEyeTransformMatrix();
616   vtkMatrix4x4 *modelTransformationMatrix = cam->GetModelTransformMatrix();
617   assert(eyeTransformationMatrix && modelTransformationMatrix);
618   for(int i=0; i < 4; ++i)
619   {
620     for(int j=0; j < 4; ++j)
621     {
622       eyeTransformationMatrix->SetElement(i, j, this->EyeTransformMatrix[i * 4 + j]);
623       modelTransformationMatrix->SetElement(i, j, this->ModelTransformMatrix[i * 4 + j]);
624     }
625   }
626 }
627 
628 //****************************************************************************
629 // vtkSynchronizedRenderers::vtkRawImage Methods
630 //****************************************************************************
631 
632 //----------------------------------------------------------------------------
Initialize(int dx,int dy,vtkUnsignedCharArray * data)633 void vtkSynchronizedRenderers::vtkRawImage::Initialize(
634   int dx, int dy, vtkUnsignedCharArray* data)
635 {
636   this->Data = data;
637   this->Size[0] = dx;
638   this->Size[1] = dy;
639 }
640 
641 //----------------------------------------------------------------------------
Allocate(int dx,int dy,int numcomps)642 void vtkSynchronizedRenderers::vtkRawImage::Allocate(int dx, int dy, int numcomps)
643 {
644   if (dx*dy <= this->Data->GetNumberOfTuples() &&
645     this->Data->GetNumberOfComponents() == numcomps)
646   {
647     this->Size[0] = dx;
648     this->Size[1] = dy;
649     return;
650   }
651 
652   this->Data = vtkSmartPointer<vtkUnsignedCharArray>::New();
653   this->Data->SetNumberOfComponents(numcomps);
654   this->Data->SetNumberOfTuples(dx*dy);
655   this->Size[0] = dx;
656   this->Size[1] = dy;
657 }
658 
659 //----------------------------------------------------------------------------
SaveAsPNG(const char * filename)660 void vtkSynchronizedRenderers::vtkRawImage::SaveAsPNG(const char* filename)
661 {
662   if (!this->IsValid())
663   {
664     vtkGenericWarningMacro("Image is not valid. Cannot save PNG.");
665     return;
666   }
667 
668   vtkImageData* img = vtkImageData::New();
669   img->SetDimensions(this->Size[0], this->Size[1], 1);
670   img->AllocateScalars(VTK_UNSIGNED_CHAR,
671                        this->Data->GetNumberOfComponents());
672   memcpy(img->GetScalarPointer(),
673     this->GetRawPtr()->GetVoidPointer(0),
674     sizeof(unsigned char)*this->Size[0]*this->Size[1]*
675     this->Data->GetNumberOfComponents());
676 
677   vtkPNGWriter* writer = vtkPNGWriter::New();
678   writer->SetFileName(filename);
679   writer->SetInputData(img);
680   writer->Write();
681   writer->Delete();
682   img->Delete();
683 }
684 
685 //----------------------------------------------------------------------------
PushToViewport(vtkRenderer * ren)686 bool vtkSynchronizedRenderers::vtkRawImage::PushToViewport(vtkRenderer* ren)
687 {
688   if (!this->IsValid())
689   {
690     vtkGenericWarningMacro("Image not valid. Cannot push to screen.");
691     return false;
692   }
693 
694   double viewport[4];
695   ren->GetViewport(viewport);
696   const int* window_size = ren->GetVTKWindow()->GetActualSize();
697 
698   vtkOpenGLState *ostate =
699     static_cast<vtkOpenGLRenderWindow *>(ren->GetVTKWindow())->GetState();
700   ostate->vtkglEnable(GL_SCISSOR_TEST);
701   ostate->vtkglViewport(
702     static_cast<GLint>(viewport[0]*window_size[0]),
703     static_cast<GLint>(viewport[1]*window_size[1]),
704     static_cast<GLsizei>((viewport[2]-viewport[0])*window_size[0]),
705     static_cast<GLsizei>((viewport[3]-viewport[1])*window_size[1]));
706   ostate->vtkglScissor(
707     static_cast<GLint>(viewport[0]*window_size[0]),
708     static_cast<GLint>(viewport[1]*window_size[1]),
709     static_cast<GLsizei>((viewport[2]-viewport[0])*window_size[0]),
710     static_cast<GLsizei>((viewport[3]-viewport[1])*window_size[1]));
711   ren->Clear();
712   return this->PushToFrameBuffer(ren);
713 }
714 
715 //----------------------------------------------------------------------------
PushToFrameBuffer(vtkRenderer * ren)716 bool vtkSynchronizedRenderers::vtkRawImage::PushToFrameBuffer(vtkRenderer *ren)
717 {
718   if (!this->IsValid())
719   {
720     vtkGenericWarningMacro("Image not valid. Cannot push to screen.");
721     return false;
722   }
723 
724   vtkOpenGLClearErrorMacro();
725   vtkOpenGLRenderUtilities::MarkDebugEvent("vtkRawImage::PushToViewport begin");
726   vtkOpenGLRenderWindow *renWin = vtkOpenGLRenderWindow::SafeDownCast(ren->GetVTKWindow());
727   vtkOpenGLState *ostate = renWin->GetState();
728   vtkOpenGLState::ScopedglBlendFuncSeparate bfsaver(ostate);
729 
730   // framebuffers have their color premultiplied by alpha.
731   ostate->vtkglEnable(GL_BLEND);
732   ostate->vtkglBlendFuncSeparate(GL_ONE,GL_ONE_MINUS_SRC_ALPHA,
733     GL_ONE,GL_ONE_MINUS_SRC_ALPHA);
734 
735   // always draw the entire image on the entire viewport
736   vtkOpenGLState::ScopedglViewport vsaver(ostate);
737   int renSize[2];
738   ren->GetTiledSize(renSize, renSize + 1);
739   ostate->vtkglViewport(0, 0, renSize[0], renSize[1]);
740 
741   renWin->DrawPixels(this->GetWidth(), this->GetHeight(),
742     this->Data->GetNumberOfComponents(), VTK_UNSIGNED_CHAR,
743     this->GetRawPtr()->GetVoidPointer(0));
744 
745   vtkOpenGLStaticCheckErrorMacro("failed after PushToFrameBuffer");
746   vtkOpenGLRenderUtilities::MarkDebugEvent("vtkRawImage::PushToViewport end");
747   return true;
748 }
749 
750 //----------------------------------------------------------------------------
Capture(vtkRenderer * ren)751 bool vtkSynchronizedRenderers::vtkRawImage::Capture(vtkRenderer* ren)
752 {
753   double viewport[4];
754   ren->GetViewport(viewport);
755 
756   int window_size[2];
757   window_size[0] = ren->GetVTKWindow()->GetActualSize()[0];
758   window_size[1] = ren->GetVTKWindow()->GetActualSize()[1];
759 
760   int viewport_in_pixels[4];
761   viewport_in_pixels[0] = static_cast<int>(window_size[0] * viewport[0]);
762   viewport_in_pixels[1] = static_cast<int>(window_size[1] * viewport[1]);
763   viewport_in_pixels[2] = static_cast<int>(window_size[0] * viewport[2])-1;
764   viewport_in_pixels[3] = static_cast<int>(window_size[1] * viewport[3])-1;
765 
766   // we need to ensure that the size computation is always done in pixels,
767   // otherwise we end up with rounding issues. In short, avoid doing
768   // additions/subtractions using normalized viewport coordinates. Those are
769   // better done in pixels.
770   int image_size[2];
771   image_size[0] = viewport_in_pixels[2] - viewport_in_pixels[0] + 1;
772   image_size[1] = viewport_in_pixels[3] - viewport_in_pixels[1] + 1;
773 
774   // using RGBA always?
775   this->Resize(image_size[0], image_size[1], 4);
776 
777   ren->GetRenderWindow()->GetRGBACharPixelData(
778     viewport_in_pixels[0], viewport_in_pixels[1],
779     viewport_in_pixels[2], viewport_in_pixels[3],
780     ren->GetRenderWindow()->GetDoubleBuffer()? 0 : 1,
781     this->GetRawPtr());
782 
783   // if selecting then pass the processed pixel buffer
784   vtkHardwareSelector *sel = ren->GetSelector();
785   if (sel)
786   {
787     unsigned char *passdata = sel->GetPixelBuffer(sel->GetCurrentPass());
788     unsigned char *destdata = static_cast<unsigned char *>(
789       this->GetRawPtr()->GetVoidPointer(0));
790     if (passdata && destdata)
791     {
792       unsigned int *area = sel->GetArea();
793       unsigned int passwidth = area[2] - area[0] + 1;
794       for (int y = 0; y < image_size[1]; ++y)
795       {
796         for (int x = 0; x < image_size[0]; ++x)
797         {
798           unsigned char *pdptr = passdata + (y * passwidth + x) * 3;
799           destdata[0] = pdptr[0];
800           destdata[1] = pdptr[1];
801           destdata[2] = pdptr[2];
802           destdata += 4;
803         }
804       }
805     }
806   }
807 
808   this->MarkValid();
809   return true;
810 }
811 
GetRenderer()812 vtkRenderer* vtkSynchronizedRenderers::GetRenderer()
813 {
814   vtkDebugMacro(<< this->GetClassName() << " (" << this << "): returning Render of " << this->Renderer );
815   return this->Renderer;
816 }
817