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