1 /*=========================================================================
2 
3 Program:   Visualization Toolkit
4 Module:    vtkVRRenderWindow.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 Parts Copyright Valve Coproration from hellovr_opengl_main.cpp
15 under their BSD license found here:
16 https://github.com/ValveSoftware/openvr/blob/master/LICENSE
17 
18 =========================================================================*/
19 #include "vtkVRRenderWindow.h"
20 
21 #include "vtkMatrix4x4.h"
22 #include "vtkObjectFactory.h"
23 #include "vtkOpenGLError.h"
24 #include "vtkOpenGLRenderWindow.h"
25 #include "vtkOpenGLState.h"
26 #include "vtkRenderWindowInteractor.h"
27 #include "vtkRenderer.h"
28 #include "vtkRendererCollection.h"
29 #include "vtkTransform.h"
30 #include "vtkVRCamera.h"
31 #include "vtkVRModel.h"
32 #include "vtkVRRenderer.h"
33 
34 #include <cstring>
35 #include <memory>
36 
37 // include what we need for the helper window
38 #ifdef WIN32
39 #include "vtkWin32OpenGLRenderWindow.h"
40 #endif
41 #ifdef VTK_USE_X
42 #include "vtkXOpenGLRenderWindow.h"
43 #endif
44 #ifdef VTK_USE_COCOA
45 #include "vtkCocoaRenderWindow.h"
46 #endif
47 
48 #if !defined(_WIN32) || defined(__CYGWIN__)
49 #define stricmp strcasecmp
50 #endif
51 
52 //------------------------------------------------------------------------------
vtkVRRenderWindow()53 vtkVRRenderWindow::vtkVRRenderWindow()
54 {
55   this->SetPhysicalViewDirection(0.0, 0.0, -1.0);
56   this->SetPhysicalViewUp(0.0, 1.0, 0.0);
57   this->SetPhysicalTranslation(0.0, 0.0, 0.0);
58   this->PhysicalScale = 1.0;
59 
60   this->StereoCapableWindow = 1;
61   this->StereoRender = 1;
62   this->UseOffScreenBuffers = true;
63   this->Size[0] = 640;
64   this->Size[1] = 720;
65   this->Position[0] = 100;
66   this->Position[1] = 100;
67   this->HMDTransform = vtkTransform::New();
68 
69 #ifdef WIN32
70   this->HelperWindow = vtkWin32OpenGLRenderWindow::New();
71 #endif
72 #ifdef VTK_USE_X
73   this->HelperWindow = vtkXOpenGLRenderWindow::New();
74 #endif
75 #ifdef VTK_USE_COCOA
76   this->HelperWindow = vtkCocoaRenderWindow::New();
77 #endif
78 }
79 
80 //------------------------------------------------------------------------------
~vtkVRRenderWindow()81 vtkVRRenderWindow::~vtkVRRenderWindow()
82 {
83   this->Finalize();
84 
85   vtkRenderer* ren;
86   vtkCollectionSimpleIterator rit;
87   this->Renderers->InitTraversal(rit);
88   while ((ren = this->Renderers->GetNextRenderer(rit)))
89   {
90     ren->SetRenderWindow(nullptr);
91   }
92 
93   if (this->HelperWindow)
94   {
95     this->HelperWindow->Delete();
96     this->HelperWindow = nullptr;
97   }
98 }
99 
100 //------------------------------------------------------------------------------
PrintSelf(ostream & os,vtkIndent indent)101 void vtkVRRenderWindow::PrintSelf(ostream& os, vtkIndent indent)
102 {
103   this->Superclass::PrintSelf(os, indent);
104 
105   os << indent << "ContextId: " << this->HelperWindow->GetGenericContext() << "\n";
106   os << indent << "Window Id: " << this->HelperWindow->GetGenericWindowId() << "\n";
107   os << indent << "Initialized: " << this->Initialized << "\n";
108   os << indent << "PhysicalViewDirection: (" << this->PhysicalViewDirection[0] << ", "
109      << this->PhysicalViewDirection[1] << ", " << this->PhysicalViewDirection[2] << ")"
110      << "\n";
111   os << indent << "PhysicalViewUp: (" << this->PhysicalViewUp[0] << ", " << this->PhysicalViewUp[1]
112      << ", " << this->PhysicalViewUp[2] << ")"
113      << "\n";
114   os << indent << "PhysicalTranslation: (" << this->PhysicalTranslation[0] << ", "
115      << this->PhysicalTranslation[1] << ", " << this->PhysicalTranslation[2] << ")"
116      << "\n";
117   os << indent << "PhysicalScale: " << this->PhysicalScale << "\n";
118 }
119 
120 //------------------------------------------------------------------------------
ReleaseGraphicsResources(vtkWindow * renWin)121 void vtkVRRenderWindow::ReleaseGraphicsResources(vtkWindow* renWin)
122 {
123   this->Superclass::ReleaseGraphicsResources(renWin);
124 
125   for (FramebufferDesc& fbo : this->FramebufferDescs)
126   {
127     glDeleteFramebuffers(1, &fbo.ResolveFramebufferId);
128   }
129 
130   for (std::vector<vtkVRModel*>::iterator i = this->VTKRenderModels.begin();
131        i != this->VTKRenderModels.end(); ++i)
132   {
133     (*i)->ReleaseGraphicsResources(renWin);
134   }
135 }
136 
137 //------------------------------------------------------------------------------
SetHelperWindow(vtkOpenGLRenderWindow * win)138 void vtkVRRenderWindow::SetHelperWindow(vtkOpenGLRenderWindow* win)
139 {
140   if (this->HelperWindow == win)
141   {
142     return;
143   }
144 
145   if (this->HelperWindow)
146   {
147     this->ReleaseGraphicsResources(this);
148     this->HelperWindow->Delete();
149     this->HelperWindow = nullptr;
150   }
151 
152   this->HelperWindow = win;
153   if (win)
154   {
155     win->Register(this);
156   }
157 
158   this->Modified();
159 }
160 
161 //------------------------------------------------------------------------------
InitializeViewFromCamera(vtkCamera * srccam)162 void vtkVRRenderWindow::InitializeViewFromCamera(vtkCamera* srccam)
163 {
164   vtkRenderer* ren = static_cast<vtkRenderer*>(this->GetRenderers()->GetItemAsObject(0));
165   if (!ren)
166   {
167     vtkErrorMacro("The renderer must be set prior to calling InitializeViewFromCamera");
168     return;
169   }
170 
171   vtkVRCamera* cam = static_cast<vtkVRCamera*>(ren->GetActiveCamera());
172   if (!cam)
173   {
174     vtkErrorMacro(
175       "The renderer's active camera must be set prior to calling InitializeViewFromCamera");
176     return;
177   }
178 
179   // make sure the view up is reasonable based on the view up
180   // that was set in PV
181   double distance = sin(vtkMath::RadiansFromDegrees(srccam->GetViewAngle()) / 2.0) *
182     srccam->GetDistance() / sin(vtkMath::RadiansFromDegrees(cam->GetViewAngle()) / 2.0);
183 
184   double* oldVup = srccam->GetViewUp();
185   int maxIdx = fabs(oldVup[0]) > fabs(oldVup[1]) ? (fabs(oldVup[0]) > fabs(oldVup[2]) ? 0 : 2)
186                                                  : (fabs(oldVup[1]) > fabs(oldVup[2]) ? 1 : 2);
187 
188   cam->SetViewUp((maxIdx == 0 ? (oldVup[0] > 0 ? 1 : -1) : 0.0),
189     (maxIdx == 1 ? (oldVup[1] > 0 ? 1 : -1) : 0.0), (maxIdx == 2 ? (oldVup[2] > 0 ? 1 : -1) : 0.0));
190   this->SetPhysicalViewUp((maxIdx == 0 ? (oldVup[0] > 0 ? 1 : -1) : 0.0),
191     (maxIdx == 1 ? (oldVup[1] > 0 ? 1 : -1) : 0.0), (maxIdx == 2 ? (oldVup[2] > 0 ? 1 : -1) : 0.0));
192 
193   double* oldFP = srccam->GetFocalPoint();
194   double* cvup = cam->GetViewUp();
195   cam->SetFocalPoint(oldFP);
196   this->SetPhysicalTranslation(
197     cvup[0] * distance - oldFP[0], cvup[1] * distance - oldFP[1], cvup[2] * distance - oldFP[2]);
198   this->SetPhysicalScale(distance);
199 
200   double* oldDOP = srccam->GetDirectionOfProjection();
201   int dopMaxIdx = fabs(oldDOP[0]) > fabs(oldDOP[1]) ? (fabs(oldDOP[0]) > fabs(oldDOP[2]) ? 0 : 2)
202                                                     : (fabs(oldDOP[1]) > fabs(oldDOP[2]) ? 1 : 2);
203   this->SetPhysicalViewDirection((dopMaxIdx == 0 ? (oldDOP[0] > 0 ? 1 : -1) : 0.0),
204     (dopMaxIdx == 1 ? (oldDOP[1] > 0 ? 1 : -1) : 0.0),
205     (dopMaxIdx == 2 ? (oldDOP[2] > 0 ? 1 : -1) : 0.0));
206   double* idop = this->GetPhysicalViewDirection();
207   cam->SetPosition(
208     -idop[0] * distance + oldFP[0], -idop[1] * distance + oldFP[1], -idop[2] * distance + oldFP[2]);
209 
210   ren->ResetCameraClippingRange();
211 }
212 
213 //------------------------------------------------------------------------------
MakeCurrent()214 void vtkVRRenderWindow::MakeCurrent()
215 {
216   if (this->HelperWindow)
217   {
218     this->HelperWindow->MakeCurrent();
219   }
220 }
221 
222 //------------------------------------------------------------------------------
ReleaseCurrent()223 void vtkVRRenderWindow::ReleaseCurrent()
224 {
225   if (this->HelperWindow)
226   {
227     this->HelperWindow->ReleaseCurrent();
228   }
229 }
230 
231 //------------------------------------------------------------------------------
GetState()232 vtkOpenGLState* vtkVRRenderWindow::GetState()
233 {
234   if (this->HelperWindow)
235   {
236     return this->HelperWindow->GetState();
237   }
238   return this->Superclass::GetState();
239 }
240 
241 //------------------------------------------------------------------------------
242 // Description:
243 // Tells if this window is the current OpenGL context for the calling thread.
IsCurrent()244 bool vtkVRRenderWindow::IsCurrent()
245 {
246   return this->HelperWindow ? this->HelperWindow->IsCurrent() : false;
247 }
248 
249 //------------------------------------------------------------------------------
250 // Add a renderer to the list of renderers.
AddRenderer(vtkRenderer * ren)251 void vtkVRRenderWindow::AddRenderer(vtkRenderer* ren)
252 {
253   if (ren && !vtkVRRenderer::SafeDownCast(ren))
254   {
255     vtkErrorMacro("vtkVRRenderWindow::AddRenderer: Failed to add renderer of type "
256       << ren->GetClassName() << ": A subclass of vtkVRRenderer is expected");
257     return;
258   }
259   this->Superclass::AddRenderer(ren);
260 }
261 
262 //------------------------------------------------------------------------------
263 // Begin the rendering process.
Start()264 void vtkVRRenderWindow::Start()
265 {
266   // if the renderer has not been initialized, do so now
267   if (this->HelperWindow && !this->Initialized)
268   {
269     this->Initialize();
270   }
271 
272   this->Superclass::Start();
273 }
274 
275 //------------------------------------------------------------------------------
276 // Initialize the rendering window.
Initialize()277 void vtkVRRenderWindow::Initialize()
278 {
279   if (this->Initialized)
280   {
281     return;
282   }
283   this->Initialized = false;
284 
285   this->GetSizeFromAPI();
286 
287   this->HelperWindow->SetDisplayId(this->GetGenericDisplayId());
288   this->HelperWindow->SetShowWindow(false);
289   this->HelperWindow->Initialize();
290 
291   this->MakeCurrent();
292 
293   this->OpenGLInit();
294 
295   // some classes override the ivar in a getter :-(
296   this->MaximumHardwareLineWidth = this->HelperWindow->GetMaximumHardwareLineWidth();
297 
298   glDepthRange(0., 1.);
299 
300   // TODO: make sure vsync is off
301   // this->HelperWindow->SetSwapControl(0);
302 
303   this->SetWindowName(this->GetWindowTitleFromAPI().c_str());
304 
305   this->CreateFramebuffers();
306 
307   this->Initialized = true;
308   vtkDebugMacro(<< "End of VRRenderWindow Initialization");
309 }
310 
311 //------------------------------------------------------------------------------
Finalize()312 void vtkVRRenderWindow::Finalize()
313 {
314   this->ReleaseGraphicsResources(this);
315 
316   for (std::vector<vtkVRModel*>::iterator i = this->VTKRenderModels.begin();
317        i != this->VTKRenderModels.end(); ++i)
318   {
319     (*i)->Delete();
320   }
321   this->VTKRenderModels.clear();
322 
323   if (this->HelperWindow && this->HelperWindow->GetGenericContext())
324   {
325     this->HelperWindow->Finalize();
326   }
327 }
328 
329 //------------------------------------------------------------------------------
Render()330 void vtkVRRenderWindow::Render()
331 {
332   this->MakeCurrent();
333   this->GetState()->ResetGLViewportState();
334   this->Superclass::Render();
335 }
336 
337 //------------------------------------------------------------------------------
RenderFramebuffer(FramebufferDesc & framebufferDesc)338 void vtkVRRenderWindow::RenderFramebuffer(FramebufferDesc& framebufferDesc)
339 {
340   this->GetState()->PushDrawFramebufferBinding();
341   this->GetState()->vtkglBindFramebuffer(GL_DRAW_FRAMEBUFFER, framebufferDesc.ResolveFramebufferId);
342 
343   glBlitFramebuffer(0, 0, this->Size[0], this->Size[1], 0, 0, this->Size[0], this->Size[1],
344     GL_COLOR_BUFFER_BIT, GL_LINEAR);
345 
346   if (framebufferDesc.ResolveDepthTextureId != 0)
347   {
348     glBlitFramebuffer(0, 0, this->Size[0], this->Size[1], 0, 0, this->Size[0], this->Size[1],
349       GL_DEPTH_BUFFER_BIT, GL_NEAREST);
350   }
351 
352   this->GetState()->PopDrawFramebufferBinding();
353 }
354 
355 //------------------------------------------------------------------------------
SetPhysicalViewDirection(double x,double y,double z)356 void vtkVRRenderWindow::SetPhysicalViewDirection(double x, double y, double z)
357 {
358   if (this->PhysicalViewDirection[0] != x || this->PhysicalViewDirection[1] != y ||
359     this->PhysicalViewDirection[2] != z)
360   {
361     this->PhysicalViewDirection[0] = x;
362     this->PhysicalViewDirection[1] = y;
363     this->PhysicalViewDirection[2] = z;
364     this->InvokeEvent(vtkVRRenderWindow::PhysicalToWorldMatrixModified);
365     this->Modified();
366   }
367 }
368 
369 //------------------------------------------------------------------------------
SetPhysicalViewDirection(double dir[3])370 void vtkVRRenderWindow::SetPhysicalViewDirection(double dir[3])
371 {
372   this->SetPhysicalViewDirection(dir[0], dir[1], dir[2]);
373 }
374 
375 //------------------------------------------------------------------------------
SetPhysicalViewUp(double x,double y,double z)376 void vtkVRRenderWindow::SetPhysicalViewUp(double x, double y, double z)
377 {
378   if (this->PhysicalViewUp[0] != x || this->PhysicalViewUp[1] != y || this->PhysicalViewUp[2] != z)
379   {
380     this->PhysicalViewUp[0] = x;
381     this->PhysicalViewUp[1] = y;
382     this->PhysicalViewUp[2] = z;
383     this->InvokeEvent(vtkVRRenderWindow::PhysicalToWorldMatrixModified);
384     this->Modified();
385   }
386 }
387 
388 //------------------------------------------------------------------------------
SetPhysicalViewUp(double dir[3])389 void vtkVRRenderWindow::SetPhysicalViewUp(double dir[3])
390 {
391   this->SetPhysicalViewUp(dir[0], dir[1], dir[2]);
392 }
393 
394 //------------------------------------------------------------------------------
SetPhysicalTranslation(double x,double y,double z)395 void vtkVRRenderWindow::SetPhysicalTranslation(double x, double y, double z)
396 {
397   if (this->PhysicalTranslation[0] != x || this->PhysicalTranslation[1] != y ||
398     this->PhysicalTranslation[2] != z)
399   {
400     this->PhysicalTranslation[0] = x;
401     this->PhysicalTranslation[1] = y;
402     this->PhysicalTranslation[2] = z;
403     this->InvokeEvent(vtkVRRenderWindow::PhysicalToWorldMatrixModified);
404     this->Modified();
405   }
406 }
407 
408 //------------------------------------------------------------------------------
SetPhysicalTranslation(double trans[3])409 void vtkVRRenderWindow::SetPhysicalTranslation(double trans[3])
410 {
411   this->SetPhysicalTranslation(trans[0], trans[1], trans[2]);
412 }
413 
414 //------------------------------------------------------------------------------
SetPhysicalScale(double scale)415 void vtkVRRenderWindow::SetPhysicalScale(double scale)
416 {
417   if (this->PhysicalScale != scale)
418   {
419     this->PhysicalScale = scale;
420     this->InvokeEvent(vtkVRRenderWindow::PhysicalToWorldMatrixModified);
421     this->Modified();
422   }
423 }
424 
425 //------------------------------------------------------------------------------
SetPhysicalToWorldMatrix(vtkMatrix4x4 * matrix)426 void vtkVRRenderWindow::SetPhysicalToWorldMatrix(vtkMatrix4x4* matrix)
427 {
428   if (!matrix)
429   {
430     return;
431   }
432   vtkNew<vtkMatrix4x4> currentPhysicalToWorldMatrix;
433   this->GetPhysicalToWorldMatrix(currentPhysicalToWorldMatrix);
434   bool matrixDifferent = false;
435   for (int i = 0; i < 4; i++)
436   {
437     for (int j = 0; j < 4; j++)
438     {
439       if (fabs(matrix->GetElement(i, j) - currentPhysicalToWorldMatrix->GetElement(i, j)) >= 1e-3)
440       {
441         matrixDifferent = true;
442         break;
443       }
444     }
445   }
446   if (!matrixDifferent)
447   {
448     return;
449   }
450 
451   vtkNew<vtkTransform> hmdToWorldTransform;
452   hmdToWorldTransform->SetMatrix(matrix);
453 
454   double translation[3] = { 0.0 };
455   hmdToWorldTransform->GetPosition(translation);
456   this->PhysicalTranslation[0] = (-1.0) * translation[0];
457   this->PhysicalTranslation[1] = (-1.0) * translation[1];
458   this->PhysicalTranslation[2] = (-1.0) * translation[2];
459 
460   double scale[3] = { 0.0 };
461   hmdToWorldTransform->GetScale(scale);
462   this->PhysicalScale = scale[0];
463 
464   this->PhysicalViewUp[0] = matrix->GetElement(0, 1);
465   this->PhysicalViewUp[1] = matrix->GetElement(1, 1);
466   this->PhysicalViewUp[2] = matrix->GetElement(2, 1);
467   vtkMath::Normalize(this->PhysicalViewUp);
468   this->PhysicalViewDirection[0] = (-1.0) * matrix->GetElement(0, 2);
469   this->PhysicalViewDirection[1] = (-1.0) * matrix->GetElement(1, 2);
470   this->PhysicalViewDirection[2] = (-1.0) * matrix->GetElement(2, 2);
471   vtkMath::Normalize(this->PhysicalViewDirection);
472 
473   this->InvokeEvent(vtkVRRenderWindow::PhysicalToWorldMatrixModified);
474   this->Modified();
475 }
476 
477 //------------------------------------------------------------------------------
GetPhysicalToWorldMatrix(vtkMatrix4x4 * physicalToWorldMatrix)478 void vtkVRRenderWindow::GetPhysicalToWorldMatrix(vtkMatrix4x4* physicalToWorldMatrix)
479 {
480   if (!physicalToWorldMatrix)
481   {
482     return;
483   }
484 
485   physicalToWorldMatrix->Identity();
486 
487   // construct physical to non-scaled world axes (scaling is applied later)
488   double physicalZ_NonscaledWorld[3] = { -this->PhysicalViewDirection[0],
489     -this->PhysicalViewDirection[1], -this->PhysicalViewDirection[2] };
490   double* physicalY_NonscaledWorld = this->PhysicalViewUp;
491   double physicalX_NonscaledWorld[3] = { 0.0 };
492   vtkMath::Cross(physicalY_NonscaledWorld, physicalZ_NonscaledWorld, physicalX_NonscaledWorld);
493 
494   for (int row = 0; row < 3; ++row)
495   {
496     physicalToWorldMatrix->SetElement(row, 0, physicalX_NonscaledWorld[row] * this->PhysicalScale);
497     physicalToWorldMatrix->SetElement(row, 1, physicalY_NonscaledWorld[row] * this->PhysicalScale);
498     physicalToWorldMatrix->SetElement(row, 2, physicalZ_NonscaledWorld[row] * this->PhysicalScale);
499     physicalToWorldMatrix->SetElement(row, 3, -this->PhysicalTranslation[row]);
500   }
501 }
502 
503 //------------------------------------------------------------------------------
504 // Get the size of the whole screen.
GetScreenSize()505 int* vtkVRRenderWindow::GetScreenSize()
506 {
507   if (this->GetSizeFromAPI())
508   {
509     this->ScreenSize[0] = this->Size[0];
510     this->ScreenSize[1] = this->Size[1];
511   }
512   return this->ScreenSize;
513 }
514 
515 //------------------------------------------------------------------------------
SetSize(int width,int height)516 void vtkVRRenderWindow::SetSize(int width, int height)
517 {
518   if ((this->Size[0] != width) || (this->Size[1] != height))
519   {
520     this->Superclass::SetSize(width, height);
521 
522     if (this->Interactor)
523     {
524       this->Interactor->SetSize(width, height);
525     }
526   }
527 }
528