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