0032978: Visualization - AIS_ViewController::PickPoint() includes objects invisible...
[occt.git] / src / Graphic3d / Graphic3d_CView.cxx
1 // Copyright (c) 2015 OPEN CASCADE SAS
2 //
3 // This file is part of Open CASCADE Technology software library.
4 //
5 // This library is free software; you can redistribute it and/or modify it under
6 // the terms of the GNU Lesser General Public License version 2.1 as published
7 // by the Free Software Foundation, with special exception defined in the file
8 // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
9 // distribution for complete text of the license and disclaimer of any warranty.
10 //
11 // Alternatively, this file may be used under the terms of Open CASCADE
12 // commercial license or contractual agreement.
13
14 #include <Graphic3d_CView.hxx>
15
16 #include <Aspect_NeutralWindow.hxx>
17 #include <Aspect_OpenVRSession.hxx>
18 #include <Graphic3d_CubeMapPacked.hxx>
19 #include <Graphic3d_Layer.hxx>
20 #include <Graphic3d_MapIteratorOfMapOfStructure.hxx>
21 #include <Graphic3d_StructureManager.hxx>
22
23 IMPLEMENT_STANDARD_RTTIEXT(Graphic3d_CView,Graphic3d_DataStructureManager)
24
25 //=======================================================================
26 //function : Constructor
27 //purpose  :
28 //=======================================================================
29 Graphic3d_CView::Graphic3d_CView (const Handle(Graphic3d_StructureManager)& theMgr)
30 : myId (0),
31   //
32   myParentView (nullptr),
33   myIsSubviewComposer (Standard_False),
34   mySubviewCorner (Aspect_TOTP_LEFT_UPPER),
35   mySubviewSize (1.0, 1.0),
36   //
37   myStructureManager (theMgr),
38   myCamera (new Graphic3d_Camera()),
39   myIsInComputedMode (Standard_False),
40   myIsActive (Standard_False),
41   myIsRemoved (Standard_False),
42   myBackfacing (Graphic3d_TypeOfBackfacingModel_Auto),
43   myVisualization (Graphic3d_TOV_WIREFRAME),
44   //
45   myBgColor (Quantity_NOC_BLACK),
46   myBackgroundType (Graphic3d_TOB_NONE),
47   myToUpdateSkydome (Standard_False),
48   //
49   myUnitFactor (1.0)
50 {
51   myId = myStructureManager->Identification (this);
52 }
53
54 //=======================================================================
55 //function : Destructor
56 //purpose  :
57 //=======================================================================
58 Graphic3d_CView::~Graphic3d_CView()
59 {
60   myXRSession.Nullify();
61   if (!IsRemoved())
62   {
63     myStructureManager->UnIdentification (this);
64   }
65 }
66
67 // =======================================================================
68 // function : SetBackgroundSkydome
69 // purpose  :
70 // =======================================================================
71 void Graphic3d_CView::SetBackgroundSkydome (const Aspect_SkydomeBackground& theAspect,
72                                             Standard_Boolean theToUpdatePBREnv)
73 {
74   myToUpdateSkydome = true;
75   mySkydomeAspect = theAspect;
76   myCubeMapBackground = new Graphic3d_CubeMapPacked ("");
77   SetBackgroundType (Graphic3d_TOB_CUBEMAP);
78   if (theToUpdatePBREnv
79       && !myCubeMapIBL.IsNull())
80   {
81     SetImageBasedLighting (false);
82     SetImageBasedLighting (true);
83   }
84 }
85
86 // =======================================================================
87 // function : Activate
88 // purpose  :
89 // =======================================================================
90 void Graphic3d_CView::Activate()
91 {
92   if (!IsActive())
93   {
94     myIsActive = Standard_True;
95
96     // Activation of a new view =>
97     // Display structures that can be displayed in this new view.
98     // All structures with status
99     // Displayed in ViewManager are returned and displayed in
100     // the view directly, if the structure is not already
101     // displayed and if the view accepts it in its context.
102     Graphic3d_MapOfStructure aDisplayedStructs;
103     myStructureManager->DisplayedStructures (aDisplayedStructs);
104     for (Graphic3d_MapIteratorOfMapOfStructure aStructIter (aDisplayedStructs); aStructIter.More(); aStructIter.Next())
105     {
106       const Handle(Graphic3d_Structure)& aStruct = aStructIter.Key();
107       if (IsDisplayed (aStruct))
108       {
109         continue;
110       }
111
112       // If the structure can be displayed in the new context of the view, it is displayed.
113       const Graphic3d_TypeOfAnswer anAnswer = acceptDisplay (aStruct->Visual());
114       if (anAnswer == Graphic3d_TOA_YES
115        || anAnswer == Graphic3d_TOA_COMPUTE)
116       {
117         Display (aStruct);
118       }
119     }
120   }
121
122   Update();
123 }
124
125 // =======================================================================
126 // function : Deactivate
127 // purpose  :
128 // =======================================================================
129 void Graphic3d_CView::Deactivate()
130 {
131   if (IsActive())
132   {
133     // Deactivation of a view =>
134     // Removal of structures displayed in this view.
135     // All structures with status
136     // Displayed in ViewManager are returned and removed from
137     // the view directly, if the structure is not already
138     // displayed and if the view accepts it in its context.
139     Graphic3d_MapOfStructure aDisplayedStructs;
140     myStructureManager->DisplayedStructures (aDisplayedStructs);
141     for (Graphic3d_MapIteratorOfMapOfStructure aStructIter (aDisplayedStructs); aStructIter.More(); aStructIter.Next())
142     {
143       const Handle(Graphic3d_Structure)& aStruct = aStructIter.Key();
144       if (!IsDisplayed (aStruct))
145       {
146         continue;
147       }
148
149       const Graphic3d_TypeOfAnswer anAnswer = acceptDisplay (aStruct->Visual());
150       if (anAnswer == Graphic3d_TOA_YES
151        || anAnswer == Graphic3d_TOA_COMPUTE)
152       {
153         Erase (aStruct);
154       }
155     }
156
157     Update();
158     myIsActive = Standard_False;
159   }
160 }
161
162 // ========================================================================
163 // function : Remove
164 // purpose  :
165 // ========================================================================
166 void Graphic3d_CView::Remove()
167 {
168   if (IsRemoved())
169   {
170     return;
171   }
172
173   if (myParentView != nullptr)
174   {
175     myParentView->RemoveSubview (this);
176     myParentView = nullptr;
177   }
178   {
179     NCollection_Sequence<Handle(Graphic3d_CView)> aSubviews = mySubviews;
180     mySubviews.Clear();
181     for (const Handle(Graphic3d_CView)& aViewIter : aSubviews)
182     {
183       aViewIter->Remove();
184     }
185   }
186
187   Graphic3d_MapOfStructure aDisplayedStructs (myStructsDisplayed);
188   for (Graphic3d_MapIteratorOfMapOfStructure aStructIter (aDisplayedStructs); aStructIter.More(); aStructIter.Next())
189   {
190     Erase (aStructIter.Value());
191   }
192
193   myStructsToCompute.Clear();
194   myStructsComputed .Clear();
195   myStructsDisplayed.Clear();
196
197   if (!myStructureManager.IsNull())
198   {
199     myStructureManager->UnIdentification (this);
200   }
201
202   myIsActive  = Standard_False;
203   myIsRemoved = Standard_True;
204 }
205
206 // ========================================================================
207 // function : AddSubview
208 // purpose  :
209 // ========================================================================
210 void Graphic3d_CView::AddSubview (const Handle(Graphic3d_CView)& theView)
211 {
212   mySubviews.Append (theView);
213 }
214
215 // ========================================================================
216 // function : RemoveSubview
217 // purpose  :
218 // ========================================================================
219 bool Graphic3d_CView::RemoveSubview (const Graphic3d_CView* theView)
220 {
221   for (NCollection_Sequence<Handle(Graphic3d_CView)>::Iterator aViewIter (mySubviews); aViewIter.More(); aViewIter.Next())
222   {
223     if (aViewIter.Value() == theView)
224     {
225       mySubviews.Remove (aViewIter);
226       return true;
227     }
228   }
229   return false;
230 }
231
232 // ========================================================================
233 // function : Resized
234 // purpose  :
235 // ========================================================================
236 void Graphic3d_CView::Resized()
237 {
238   if (IsSubview())
239   {
240     Handle(Aspect_NeutralWindow) aWindow = Handle(Aspect_NeutralWindow)::DownCast(Window());
241     SubviewResized (aWindow);
242   }
243 }
244
245 //! Calculate offset in pixels from fraction.
246 static int getSubViewOffset (double theOffset, int theWinSize)
247 {
248   if (theOffset >= 1.0)
249   {
250     return int(theOffset);
251   }
252   else
253   {
254     return int(theOffset * theWinSize);
255   }
256 }
257
258 // ========================================================================
259 // function : SubviewResized
260 // purpose  :
261 // ========================================================================
262 void Graphic3d_CView::SubviewResized (const Handle(Aspect_NeutralWindow)& theWindow)
263 {
264   if (!IsSubview()
265    || theWindow.IsNull())
266   {
267     return;
268   }
269
270   const Graphic3d_Vec2i aWinSize (myParentView->Window()->Dimensions());
271   Graphic3d_Vec2i aViewSize (Graphic3d_Vec2d(aWinSize) * mySubviewSize);
272   if (mySubviewSize.x() > 1.0)
273   {
274     aViewSize.x() = (int)mySubviewSize.x();
275   }
276   if (mySubviewSize.y() > 1.0)
277   {
278     aViewSize.y() = (int)mySubviewSize.y();
279   }
280
281   Graphic3d_Vec2i anOffset (getSubViewOffset (mySubviewOffset.x(), aWinSize.x()),
282                             getSubViewOffset (mySubviewOffset.y(), aWinSize.y()));
283   mySubviewTopLeft = (aWinSize - aViewSize) / 2; // Aspect_TOTP_CENTER
284   if ((mySubviewCorner & Aspect_TOTP_LEFT) != 0)
285   {
286     mySubviewTopLeft.x() = anOffset.x();
287   }
288   else if ((mySubviewCorner & Aspect_TOTP_RIGHT) != 0)
289   {
290     mySubviewTopLeft.x() = Max (aWinSize.x() - anOffset.x() - aViewSize.x(), 0);
291   }
292
293   if ((mySubviewCorner & Aspect_TOTP_TOP) != 0)
294   {
295     mySubviewTopLeft.y() = anOffset.y();
296   }
297   else if ((mySubviewCorner & Aspect_TOTP_BOTTOM) != 0)
298   {
299     mySubviewTopLeft.y() = Max (aWinSize.y() - anOffset.y() - aViewSize.y(), 0);
300   }
301
302   mySubviewTopLeft += mySubviewMargins;
303   aViewSize -= mySubviewMargins * 2;
304
305   const int aRight = Min(mySubviewTopLeft.x() + aViewSize.x(), aWinSize.x());
306   aViewSize.x() = aRight - mySubviewTopLeft.x();
307
308   const int aBot = Min(mySubviewTopLeft.y() + aViewSize.y(), aWinSize.y());
309   aViewSize.y() = aBot - mySubviewTopLeft.y();
310
311   theWindow->SetSize (aViewSize.x(), aViewSize.y());
312 }
313
314 // ========================================================================
315 // function : SetComputedMode
316 // purpose  :
317 // ========================================================================
318 void Graphic3d_CView::SetComputedMode (const Standard_Boolean theMode)
319 {
320   if (( theMode &&  myIsInComputedMode)
321    || (!theMode && !myIsInComputedMode))
322   {
323     return;
324   }
325
326   myIsInComputedMode = theMode;
327   if (!myIsInComputedMode)
328   {
329     for (Graphic3d_MapOfStructure::Iterator aStructIter (myStructsDisplayed); aStructIter.More(); aStructIter.Next())
330     {
331       const Handle(Graphic3d_Structure)& aStruct  = aStructIter.Key();
332       const Graphic3d_TypeOfAnswer        anAnswer = acceptDisplay (aStruct->Visual());
333       if (anAnswer != Graphic3d_TOA_COMPUTE)
334       {
335         continue;
336       }
337
338       const Standard_Integer anIndex = IsComputed (aStruct);
339       if (anIndex != 0)
340       {
341         const Handle(Graphic3d_Structure)& aStructComp = myStructsComputed.Value (anIndex);
342         eraseStructure   (aStructComp->CStructure());
343         displayStructure (aStruct->CStructure(), aStruct->DisplayPriority());
344         Update (aStruct->GetZLayer());
345       }
346     }
347     return;
348   }
349
350   for (Graphic3d_MapOfStructure::Iterator aDispStructIter (myStructsDisplayed); aDispStructIter.More(); aDispStructIter.Next())
351   {
352     Handle(Graphic3d_Structure) aStruct  = aDispStructIter.Key();
353     const Graphic3d_TypeOfAnswer anAnswer = acceptDisplay (aStruct->Visual());
354     if (anAnswer != Graphic3d_TOA_COMPUTE)
355     {
356       continue;
357     }
358
359     const Standard_Integer anIndex = IsComputed (aStruct);
360     if (anIndex != 0)
361     {
362       eraseStructure   (aStruct->CStructure());
363       displayStructure (myStructsComputed.Value (anIndex)->CStructure(), aStruct->DisplayPriority());
364
365       Display (aStruct);
366       if (aStruct->IsHighlighted())
367       {
368         const Handle(Graphic3d_Structure)& aCompStruct = myStructsComputed.Value (anIndex);
369         if (!aCompStruct->IsHighlighted())
370         {
371           aCompStruct->Highlight (aStruct->HighlightStyle(), Standard_False);
372         }
373       }
374     }
375     else
376     {
377       Handle(Graphic3d_Structure) aCompStruct;
378       aStruct->computeHLR (myCamera, aCompStruct);
379       if (aCompStruct.IsNull())
380       {
381         continue;
382       }
383       aCompStruct->SetHLRValidation (Standard_True);
384
385       const Standard_Boolean toComputeWireframe = myVisualization == Graphic3d_TOV_WIREFRAME
386                                                 && aStruct->ComputeVisual() != Graphic3d_TOS_SHADING;
387       const Standard_Boolean toComputeShading   = myVisualization == Graphic3d_TOV_SHADING
388                                                 && aStruct->ComputeVisual() != Graphic3d_TOS_WIREFRAME;
389       if (toComputeWireframe) aCompStruct->SetVisual (Graphic3d_TOS_WIREFRAME);
390       if (toComputeShading  ) aCompStruct->SetVisual (Graphic3d_TOS_SHADING);
391
392       if (aStruct->IsHighlighted())
393       {
394         aCompStruct->Highlight (aStruct->HighlightStyle(), Standard_False);
395       }
396
397       Standard_Boolean hasResult = Standard_False;
398       const Standard_Integer aNbToCompute = myStructsToCompute.Length();
399       const Standard_Integer aStructId    = aStruct->Identification();
400       for (Standard_Integer aToCompStructIter = 1; aToCompStructIter <= aNbToCompute; ++aToCompStructIter)
401       {
402         if (myStructsToCompute.Value (aToCompStructIter)->Identification() == aStructId)
403         {
404           hasResult = Standard_True;
405           myStructsComputed.ChangeValue (aToCompStructIter) = aCompStruct;
406           break;
407         }
408       }
409
410       if (!hasResult)
411       {
412         myStructsToCompute.Append (aStruct);
413         myStructsComputed .Append (aCompStruct);
414       }
415
416       aCompStruct->CalculateBoundBox();
417       eraseStructure   (aStruct->CStructure());
418       displayStructure (aCompStruct->CStructure(), aStruct->DisplayPriority());
419     }
420   }
421   Update();
422 }
423
424 // =======================================================================
425 // function : ReCompute
426 // purpose  :
427 // =======================================================================
428 void Graphic3d_CView::ReCompute (const Handle(Graphic3d_Structure)& theStruct)
429 {
430   theStruct->CalculateBoundBox();
431   if (!theStruct->IsMutable()
432    && !theStruct->CStructure()->IsForHighlight
433    && !theStruct->CStructure()->IsInfinite)
434   {
435     const Graphic3d_ZLayerId aLayerId = theStruct->GetZLayer();
436     InvalidateBVHData (aLayerId);
437   }
438
439   if (!ComputedMode()
440    || !IsActive()
441    || !theStruct->IsDisplayed())
442   {
443     return;
444   }
445
446   const Graphic3d_TypeOfAnswer anAnswer = acceptDisplay (theStruct->Visual());
447   if (anAnswer != Graphic3d_TOA_COMPUTE)
448   {
449     return;
450   }
451
452   const Standard_Integer anIndex = IsComputed (theStruct);
453   if (anIndex == 0)
454   {
455     return;
456   }
457
458   // compute + validation
459   Handle(Graphic3d_Structure) aCompStructOld = myStructsComputed.ChangeValue (anIndex);
460   Handle(Graphic3d_Structure) aCompStruct    = aCompStructOld;
461   aCompStruct->SetTransformation (Handle(TopLoc_Datum3D)());
462   theStruct->computeHLR (myCamera, aCompStruct);
463   if (aCompStruct.IsNull())
464   {
465     return;
466   }
467
468   aCompStruct->SetHLRValidation (Standard_True);
469   aCompStruct->CalculateBoundBox();
470
471   // of which type will be the computed?
472   const Standard_Boolean toComputeWireframe = myVisualization == Graphic3d_TOV_WIREFRAME
473                                            && theStruct->ComputeVisual() != Graphic3d_TOS_SHADING;
474   const Standard_Boolean toComputeShading   = myVisualization == Graphic3d_TOV_SHADING
475                                            && theStruct->ComputeVisual() != Graphic3d_TOS_WIREFRAME;
476   if (toComputeWireframe)
477   {
478     aCompStruct->SetVisual (Graphic3d_TOS_WIREFRAME);
479   }
480   else if (toComputeShading)
481   {
482     aCompStruct->SetVisual (Graphic3d_TOS_SHADING);
483   }
484
485   if (theStruct->IsHighlighted())
486   {
487     aCompStruct->Highlight (theStruct->HighlightStyle(), Standard_False);
488   }
489
490   // The previous calculation is removed and the new one is displayed
491   eraseStructure   (aCompStructOld->CStructure());
492   displayStructure (aCompStruct->CStructure(), theStruct->DisplayPriority());
493
494   // why not just replace existing items?
495   //myStructsToCompute.ChangeValue (anIndex) = theStruct;
496   //myStructsComputed .ChangeValue (anIndex) = aCompStruct;
497
498   // hlhsr and the new associated compute are added
499   myStructsToCompute.Append (theStruct);
500   myStructsComputed .Append (aCompStruct);
501
502   // hlhsr and the new associated compute are removed
503   myStructsToCompute.Remove (anIndex);
504   myStructsComputed .Remove (anIndex);
505 }
506
507 // =======================================================================
508 // function : Update
509 // purpose  :
510 // =======================================================================
511 void Graphic3d_CView::Update (const Graphic3d_ZLayerId theLayerId)
512 {
513   InvalidateZLayerBoundingBox (theLayerId);
514 }
515
516 // =======================================================================
517 // function : InvalidateZLayerBoundingBox
518 // purpose  :
519 // =======================================================================
520 void Graphic3d_CView::InvalidateZLayerBoundingBox (const Graphic3d_ZLayerId theLayerId)
521 {
522   if (Handle(Graphic3d_Layer) aLayer = Layer (theLayerId))
523   {
524     aLayer->InvalidateBoundingBox();
525     return;
526   }
527
528   for (NCollection_List<Handle(Graphic3d_Layer)>::Iterator aLayerIter (Layers()); aLayerIter.More(); aLayerIter.Next())
529   {
530     const Handle(Graphic3d_Layer)& aLayer = aLayerIter.Value();
531     if (aLayer->NbOfTransformPersistenceObjects() > 0)
532     {
533       aLayer->InvalidateBoundingBox();
534     }
535   }
536 }
537
538 // =======================================================================
539 // function : DisplayedStructures
540 // purpose  :
541 // =======================================================================
542 void Graphic3d_CView::DisplayedStructures (Graphic3d_MapOfStructure& theStructures) const
543 {
544   for (Graphic3d_MapOfStructure::Iterator aStructIter (myStructsDisplayed); aStructIter.More(); aStructIter.Next())
545   {
546     theStructures.Add (aStructIter.Key());
547   }
548 }
549
550 // =======================================================================
551 // function : MinMaxValues
552 // purpose  :
553 // =======================================================================
554 Bnd_Box Graphic3d_CView::MinMaxValues (const Standard_Boolean theToIncludeAuxiliary) const
555 {
556   if (!IsDefined())
557   {
558     return Bnd_Box();
559   }
560
561   const Handle(Graphic3d_Camera)& aCamera = Camera();
562   Graphic3d_Vec2i aWinSize;
563   Window()->Size (aWinSize.x(), aWinSize.y());
564
565   Bnd_Box aResult;
566   for (NCollection_List<Handle(Graphic3d_Layer)>::Iterator aLayerIter (Layers()); aLayerIter.More(); aLayerIter.Next())
567   {
568     const Handle(Graphic3d_Layer)& aLayer = aLayerIter.Value();
569     Bnd_Box aBox = aLayer->BoundingBox (Identification(),
570                                         aCamera,
571                                         aWinSize.x(), aWinSize.y(),
572                                         theToIncludeAuxiliary);
573     aResult.Add (aBox);
574   }
575   return aResult;
576 }
577
578 // =======================================================================
579 // function : ConsiderZoomPersistenceObjects
580 // purpose  :
581 // =======================================================================
582 Standard_Real Graphic3d_CView::ConsiderZoomPersistenceObjects()
583 {
584   if (!IsDefined())
585   {
586     return 1.0;
587   }
588
589   const Handle(Graphic3d_Camera)& aCamera = Camera();
590   Graphic3d_Vec2i aWinSize;
591   Window()->Size (aWinSize.x(), aWinSize.y());
592
593   Standard_Real aMaxCoef = 1.0;
594   for (NCollection_List<Handle(Graphic3d_Layer)>::Iterator aLayerIter (Layers()); aLayerIter.More(); aLayerIter.Next())
595   {
596     const Handle(Graphic3d_Layer)& aLayer = aLayerIter.Value();
597     aMaxCoef = Max (aMaxCoef, aLayer->considerZoomPersistenceObjects (Identification(), aCamera, aWinSize.x(), aWinSize.y()));
598   }
599
600   return aMaxCoef;
601 }
602
603 // =======================================================================
604 // function : MinMaxValues
605 // purpose  :
606 // =======================================================================
607 Bnd_Box Graphic3d_CView::MinMaxValues (const Graphic3d_MapOfStructure& theSet,
608                                        const Standard_Boolean theToIgnoreInfiniteFlag) const
609 {
610   Bnd_Box aResult;
611   const Standard_Integer aViewId = Identification();
612
613   Handle(Graphic3d_Camera) aCamera = Camera();
614   Standard_Integer aWinWidth  = 0;
615   Standard_Integer aWinHeight = 0;
616   if (IsDefined())
617   {
618     Window()->Size (aWinWidth, aWinHeight);
619   }
620
621   for (Graphic3d_MapIteratorOfMapOfStructure aStructIter (theSet); aStructIter.More(); aStructIter.Next())
622   {
623     const Handle(Graphic3d_Structure)& aStructure = aStructIter.Key();
624     if (aStructure->IsEmpty()
625     || !aStructure->CStructure()->IsVisible (aViewId))
626     {
627       continue;
628     }
629
630     // "FitAll" operation ignores object with transform persistence parameter
631     if (!aStructure->TransformPersistence().IsNull())
632     {
633       // Panning and 2d persistence apply changes to projection or/and its translation components.
634       // It makes them incompatible with z-fitting algorithm. Ignored by now.
635       if (!theToIgnoreInfiniteFlag
636        || aStructure->TransformPersistence()->IsTrihedronOr2d())
637       {
638         continue;
639       }
640     }
641
642     Bnd_Box aBox = aStructure->MinMaxValues (theToIgnoreInfiniteFlag);
643
644     if (aBox.IsWhole() || aBox.IsVoid())
645     {
646       continue;
647     }
648
649     if (!aStructure->TransformPersistence().IsNull())
650     {
651       const Graphic3d_Mat4d& aProjectionMat = aCamera->ProjectionMatrix();
652       const Graphic3d_Mat4d& aWorldViewMat  = aCamera->OrientationMatrix();
653       aStructure->TransformPersistence()->Apply (aCamera, aProjectionMat, aWorldViewMat, aWinWidth, aWinHeight, aBox);
654     }
655
656     // To prevent float overflow at camera parameters calculation and further
657     // rendering, bounding boxes with at least one vertex coordinate out of
658     // float range are skipped by view fit algorithms
659     if (Abs (aBox.CornerMax().X()) >= ShortRealLast() ||
660         Abs (aBox.CornerMax().Y()) >= ShortRealLast() ||
661         Abs (aBox.CornerMax().Z()) >= ShortRealLast() ||
662         Abs (aBox.CornerMin().X()) >= ShortRealLast() ||
663         Abs (aBox.CornerMin().Y()) >= ShortRealLast() ||
664         Abs (aBox.CornerMin().Z()) >= ShortRealLast())
665     {
666       continue;
667     }
668
669     aResult.Add (aBox);
670   }
671   return aResult;
672 }
673
674 // =======================================================================
675 // function : acceptDisplay
676 // purpose  :
677 // =======================================================================
678 Graphic3d_TypeOfAnswer Graphic3d_CView::acceptDisplay (const Graphic3d_TypeOfStructure theStructType) const
679 {
680   switch (theStructType)
681   {
682     case Graphic3d_TOS_ALL:
683     {
684       return Graphic3d_TOA_YES; // The structure accepts any type of view
685     }
686     case Graphic3d_TOS_SHADING:
687     {
688       return myVisualization == Graphic3d_TOV_SHADING
689            ? Graphic3d_TOA_YES
690            : Graphic3d_TOA_NO;
691     }
692     case Graphic3d_TOS_WIREFRAME:
693     {
694       return myVisualization == Graphic3d_TOV_WIREFRAME
695            ? Graphic3d_TOA_YES
696            : Graphic3d_TOA_NO;
697     }
698     case Graphic3d_TOS_COMPUTED:
699     {
700       return (myVisualization == Graphic3d_TOV_SHADING || myVisualization == Graphic3d_TOV_WIREFRAME)
701            ?  Graphic3d_TOA_COMPUTE
702            :  Graphic3d_TOA_NO;
703     }
704   }
705   return Graphic3d_TOA_NO;
706 }
707
708 // =======================================================================
709 // function : Compute
710 // purpose  :
711 // =======================================================================
712 void Graphic3d_CView::Compute()
713 {
714   // force HLRValidation to False on all structures calculated in the view
715   for (Graphic3d_SequenceOfStructure::Iterator aStructIter (myStructsComputed); aStructIter.More(); aStructIter.Next())
716   {
717     aStructIter.Value()->SetHLRValidation (Standard_False);
718   }
719
720   if (!ComputedMode())
721   {
722     return;
723   }
724
725   // Change of orientation or of projection type =>
726   // Remove structures that were calculated for the previous orientation.
727   // Recalculation of new structures.
728   NCollection_Sequence<Handle(Graphic3d_Structure)> aStructsSeq;
729   for (Graphic3d_MapOfStructure::Iterator aStructIter (myStructsDisplayed); aStructIter.More(); aStructIter.Next())
730   {
731     const Graphic3d_TypeOfAnswer anAnswer = acceptDisplay (aStructIter.Key()->Visual());
732     if (anAnswer == Graphic3d_TOA_COMPUTE)
733     {
734       aStructsSeq.Append (aStructIter.Key()); // if the structure was calculated, it is recalculated
735     }
736   }
737
738   for (NCollection_Sequence<Handle(Graphic3d_Structure)>::Iterator aStructIter (aStructsSeq); aStructIter.More(); aStructIter.Next())
739   {
740     Display (aStructIter.ChangeValue());
741   }
742 }
743
744 // =======================================================================
745 // function : Clear
746 // purpose  :
747 // =======================================================================
748 void Graphic3d_CView::Clear (Graphic3d_Structure* theStructure,
749                              const Standard_Boolean theWithDestruction)
750 {
751   const Standard_Integer anIndex = IsComputed (theStructure);
752   if (anIndex != 0)
753   {
754     const Handle(Graphic3d_Structure)& aCompStruct = myStructsComputed.Value (anIndex);
755     aCompStruct->GraphicClear (theWithDestruction);
756     aCompStruct->SetHLRValidation (Standard_False);
757   }
758 }
759
760 // =======================================================================
761 // function : Connect
762 // purpose  :
763 // =======================================================================
764 void Graphic3d_CView::Connect (const Graphic3d_Structure* theMother,
765                                const Graphic3d_Structure* theDaughter)
766 {
767   Standard_Integer anIndexM = IsComputed (theMother);
768   Standard_Integer anIndexD = IsComputed (theDaughter);
769   if (anIndexM != 0
770    && anIndexD != 0)
771   {
772     const Handle(Graphic3d_Structure)& aStructM = myStructsComputed.Value (anIndexM);
773     const Handle(Graphic3d_Structure)& aStructD = myStructsComputed.Value (anIndexD);
774     aStructM->GraphicConnect (aStructD);
775   }
776 }
777
778 // =======================================================================
779 // function : Disconnect
780 // purpose  :
781 // =======================================================================
782 void Graphic3d_CView::Disconnect (const Graphic3d_Structure* theMother,
783                                   const Graphic3d_Structure* theDaughter)
784 {
785   Standard_Integer anIndexM = IsComputed (theMother);
786   Standard_Integer anIndexD = IsComputed (theDaughter);
787   if (anIndexM != 0
788    && anIndexD != 0)
789   {
790     const Handle(Graphic3d_Structure)& aStructM = myStructsComputed.Value (anIndexM);
791     const Handle(Graphic3d_Structure)& aStructD = myStructsComputed.Value (anIndexD);
792     aStructM->GraphicDisconnect (aStructD);
793   }
794 }
795
796 // =======================================================================
797 // function : Display
798 // purpose  :
799 // =======================================================================
800 void Graphic3d_CView::Display (const Handle(Graphic3d_Structure)& theStructure)
801 {
802   if (!IsActive())
803   {
804     return;
805   }
806
807   // If Display on a structure present in the list of calculated structures while it is not
808   // or more, of calculated type =>
809   // - removes it as well as the associated old computed
810   // THis happens when hlhsr becomes again of type e non computed after SetVisual.
811   Standard_Integer anIndex = IsComputed (theStructure);
812   if (anIndex != 0
813    && theStructure->Visual() != Graphic3d_TOS_COMPUTED)
814   {
815     myStructsToCompute.Remove (anIndex);
816     myStructsComputed .Remove (anIndex);
817     anIndex = 0;
818   }
819
820   Graphic3d_TypeOfAnswer anAnswer = acceptDisplay (theStructure->Visual());
821   if (anAnswer == Graphic3d_TOA_NO)
822   {
823     return;
824   }
825
826   if (!ComputedMode())
827   {
828     anAnswer = Graphic3d_TOA_YES;
829   }
830
831   if (anAnswer == Graphic3d_TOA_YES)
832   {
833     if (!myStructsDisplayed.Add (theStructure))
834     {
835       return;
836     }
837
838     theStructure->CalculateBoundBox();
839     displayStructure (theStructure->CStructure(), theStructure->DisplayPriority());
840     Update (theStructure->GetZLayer());
841     return;
842   }
843   else if (anAnswer != Graphic3d_TOA_COMPUTE)
844   {
845     return;
846   }
847
848   if (anIndex != 0)
849   {
850     // Already computed, is COMPUTED still valid?
851     const Handle(Graphic3d_Structure)& anOldStruct = myStructsComputed.Value (anIndex);
852     if (anOldStruct->HLRValidation())
853     {
854       // Case COMPUTED valid, to be displayed
855       if (!myStructsDisplayed.Add (theStructure))
856       {
857         return;
858       }
859
860       displayStructure (anOldStruct->CStructure(), theStructure->DisplayPriority());
861       Update (anOldStruct->GetZLayer());
862       return;
863     }
864     else
865     {
866       // Case COMPUTED invalid
867       // Is there another valid representation?
868       // Find in the sequence of already calculated structures
869       // 1/ Structure having the same Owner as <AStructure>
870       // 2/ That is not <AStructure>
871       // 3/ The COMPUTED which of is valid
872       const Standard_Integer aNewIndex = HaveTheSameOwner (theStructure);
873       if (aNewIndex != 0)
874       {
875         // Case of COMPUTED invalid, WITH a valid of replacement; to be displayed
876         if (!myStructsDisplayed.Add (theStructure))
877         {
878           return;
879         }
880
881         const Handle(Graphic3d_Structure)& aNewStruct = myStructsComputed.Value (aNewIndex);
882         myStructsComputed.SetValue (anIndex, aNewStruct);
883         displayStructure (aNewStruct->CStructure(), theStructure->DisplayPriority());
884         Update (aNewStruct->GetZLayer());
885         return;
886       }
887       else
888       {
889         // Case COMPUTED invalid, WITHOUT a valid of replacement
890         // COMPUTED is removed if displayed
891         if (myStructsDisplayed.Contains (theStructure))
892         {
893           eraseStructure (anOldStruct->CStructure());
894         }
895       }
896     }
897   }
898
899   // Compute + Validation
900   Handle(Graphic3d_Structure) aStruct;
901   if (anIndex != 0)
902   {
903     aStruct = myStructsComputed.Value (anIndex);
904     aStruct->SetTransformation (Handle(TopLoc_Datum3D)());
905   }
906   theStructure->computeHLR (myCamera, aStruct);
907   if (aStruct.IsNull())
908   {
909     return;
910   }
911   aStruct->SetHLRValidation (Standard_True);
912
913   // TOCOMPUTE and COMPUTED associated to sequences are added
914   myStructsToCompute.Append (theStructure);
915   myStructsComputed .Append (aStruct);
916
917   // The previous are removed if necessary
918   if (anIndex != 0)
919   {
920     myStructsToCompute.Remove (anIndex);
921     myStructsComputed .Remove (anIndex);
922   }
923
924   // Of which type will be the computed?
925   const Standard_Boolean toComputeWireframe = myVisualization == Graphic3d_TOV_WIREFRAME
926                                            && theStructure->ComputeVisual() != Graphic3d_TOS_SHADING;
927   const Standard_Boolean toComputeShading   = myVisualization == Graphic3d_TOV_SHADING
928                                            && theStructure->ComputeVisual() != Graphic3d_TOS_WIREFRAME;
929   if (!toComputeShading && !toComputeWireframe)
930   {
931     anAnswer = Graphic3d_TOA_NO;
932   }
933   else
934   {
935     aStruct->SetVisual (toComputeWireframe ? Graphic3d_TOS_WIREFRAME : Graphic3d_TOS_SHADING);
936     anAnswer = acceptDisplay (aStruct->Visual());
937   }
938
939   if (theStructure->IsHighlighted())
940   {
941     aStruct->Highlight (theStructure->HighlightStyle(), Standard_False);
942   }
943
944   // It is displayed only if the calculated structure
945   // has a proper type corresponding to the one of the view.
946   if (anAnswer == Graphic3d_TOA_NO)
947   {
948     return;
949   }
950
951   myStructsDisplayed.Add (theStructure);
952   displayStructure (aStruct->CStructure(), theStructure->DisplayPriority());
953
954   Update (aStruct->GetZLayer());
955 }
956
957 // =======================================================================
958 // function : Erase
959 // purpose  :
960 // =======================================================================
961 void Graphic3d_CView::Erase (const Handle(Graphic3d_Structure)& theStructure)
962 {
963   if (!IsDisplayed (theStructure))
964   {
965     return;
966   }
967
968   const Graphic3d_TypeOfAnswer anAnswer = myIsInComputedMode ? acceptDisplay (theStructure->Visual()) : Graphic3d_TOA_YES;
969   if (anAnswer != Graphic3d_TOA_COMPUTE)
970   {
971     eraseStructure (theStructure->CStructure());
972   }
973
974   const Standard_Integer anIndex = !myStructsToCompute.IsEmpty() ? IsComputed (theStructure) : 0;
975   if (anIndex != 0)
976   {
977     if (anAnswer == Graphic3d_TOA_COMPUTE
978      && myIsInComputedMode)
979     {
980       const Handle(Graphic3d_Structure)& aCompStruct = myStructsComputed.ChangeValue (anIndex);
981       eraseStructure (aCompStruct->CStructure());
982     }
983     myStructsComputed .Remove (anIndex);
984     myStructsToCompute.Remove (anIndex);
985   }
986
987   myStructsDisplayed.Remove (theStructure);
988   Update (theStructure->GetZLayer());
989 }
990
991 // =======================================================================
992 // function : Highlight
993 // purpose  :
994 // =======================================================================
995 void Graphic3d_CView::Highlight (const Handle(Graphic3d_Structure)& theStructure)
996 {
997   const Standard_Integer anIndex = IsComputed (theStructure);
998   if (anIndex != 0)
999   {
1000     const Handle(Graphic3d_Structure)& aCompStruct = myStructsComputed.ChangeValue (anIndex);
1001     aCompStruct->Highlight (theStructure->HighlightStyle(), Standard_False);
1002   }
1003 }
1004
1005 // =======================================================================
1006 // function : SetTransform
1007 // purpose  :
1008 // =======================================================================
1009 void Graphic3d_CView::SetTransform (const Handle(Graphic3d_Structure)& theStructure,
1010                                     const Handle(TopLoc_Datum3D)& theTrsf)
1011 {
1012   const Standard_Integer anIndex = IsComputed (theStructure);
1013   if (anIndex != 0)
1014   {
1015     // Test is somewhat light !
1016     // trsf is transferred only if it is :
1017     // a translation
1018     // a scale
1019     if (!theTrsf.IsNull()
1020       && (theTrsf->Form() == gp_Translation
1021        || theTrsf->Form() == gp_Scale
1022        || theTrsf->Form() == gp_CompoundTrsf))
1023     {
1024       ReCompute (theStructure);
1025     }
1026     else
1027     {
1028       const Handle(Graphic3d_Structure)& aCompStruct = myStructsComputed.ChangeValue (anIndex);
1029       aCompStruct->GraphicTransform (theTrsf);
1030     }
1031   }
1032
1033   theStructure->CalculateBoundBox();
1034   if (!theStructure->IsMutable()
1035    && !theStructure->CStructure()->IsForHighlight
1036    && !theStructure->CStructure()->IsInfinite)
1037   {
1038     const Graphic3d_ZLayerId aLayerId = theStructure->GetZLayer();
1039     InvalidateBVHData (aLayerId);
1040   }
1041 }
1042
1043 // =======================================================================
1044 // function : UnHighlight
1045 // purpose  :
1046 // =======================================================================
1047 void Graphic3d_CView::UnHighlight (const Handle(Graphic3d_Structure)& theStructure)
1048 {
1049   Standard_Integer anIndex = IsComputed (theStructure);
1050   if (anIndex != 0)
1051   {
1052     const Handle(Graphic3d_Structure)& aCompStruct = myStructsComputed.ChangeValue (anIndex);
1053     aCompStruct->CStructure()->GraphicUnhighlight();
1054   }
1055 }
1056
1057 // ========================================================================
1058 // function : IsComputed
1059 // purpose  :
1060 // ========================================================================
1061 Standard_Boolean Graphic3d_CView::IsComputed (const Standard_Integer theStructId,
1062                                               Handle(Graphic3d_Structure)& theComputedStruct) const
1063 {
1064   theComputedStruct.Nullify();
1065   if (!ComputedMode())
1066     return Standard_False;
1067
1068   const Standard_Integer aNbStructs = myStructsToCompute.Length();
1069   for (Standard_Integer aStructIter = 1; aStructIter <= aNbStructs; ++aStructIter)
1070   {
1071     if (myStructsToCompute.Value (aStructIter)->Identification() == theStructId)
1072     {
1073       theComputedStruct = myStructsComputed (aStructIter);
1074       return Standard_True;
1075     }
1076   }
1077   return Standard_False;
1078 }
1079
1080 // =======================================================================
1081 // function : IsComputed
1082 // purpose  :
1083 // =======================================================================
1084 Standard_Integer Graphic3d_CView::IsComputed (const Graphic3d_Structure* theStructure) const
1085 {
1086   const Standard_Integer aStructId  = theStructure->Identification();
1087   Standard_Integer aStructIndex = 1;
1088   for (Graphic3d_SequenceOfStructure::Iterator aStructIter (myStructsToCompute); aStructIter.More(); aStructIter.Next(), ++aStructIndex)
1089   {
1090     const Handle(Graphic3d_Structure)& aStruct = aStructIter.Value();
1091     if (aStruct->Identification() == aStructId)
1092     {
1093       return aStructIndex;
1094     }
1095   }
1096   return 0;
1097 }
1098
1099 // =======================================================================
1100 // function : IsDisplayed
1101 // purpose  :
1102 // =======================================================================
1103 Standard_Boolean Graphic3d_CView::IsDisplayed (const Handle(Graphic3d_Structure)& theStructure) const
1104 {
1105   return myStructsDisplayed.Contains (theStructure);
1106 }
1107
1108 // =======================================================================
1109 // function : ChangePriority
1110 // purpose  :
1111 // =======================================================================
1112 void Graphic3d_CView::ChangePriority (const Handle(Graphic3d_Structure)& theStructure,
1113                                       const Graphic3d_DisplayPriority /*theOldPriority*/,
1114                                       const Graphic3d_DisplayPriority theNewPriority)
1115 {
1116   if (!IsActive()
1117   ||  !IsDisplayed (theStructure))
1118   {
1119     return;
1120   }
1121
1122   if (!myIsInComputedMode)
1123   {
1124     changePriority (theStructure->CStructure(), theNewPriority);
1125     return;
1126   }
1127
1128   const Standard_Integer              anIndex  = IsComputed (theStructure);
1129   const Handle(Graphic3d_CStructure)& aCStruct = anIndex != 0
1130                                                ? myStructsComputed.Value (anIndex)->CStructure()
1131                                                : theStructure->CStructure();
1132
1133   changePriority (aCStruct, theNewPriority);
1134 }
1135
1136 // =======================================================================
1137 // function : ChangeZLayer
1138 // purpose  :
1139 // =======================================================================
1140 void Graphic3d_CView::ChangeZLayer (const Handle(Graphic3d_Structure)& theStructure,
1141                                     const Graphic3d_ZLayerId theLayerId)
1142 {
1143   if (!IsActive()
1144   ||  !IsDisplayed (theStructure))
1145   {
1146     return;
1147   }
1148
1149   if (!myIsInComputedMode)
1150   {
1151     changeZLayer (theStructure->CStructure(), theLayerId);
1152     return;
1153   }
1154
1155   const Standard_Integer       anIndex  = IsComputed (theStructure);
1156   Handle(Graphic3d_CStructure) aCStruct = anIndex != 0
1157                                        ? myStructsComputed.Value (anIndex)->CStructure()
1158                                        : theStructure->CStructure();
1159
1160   changeZLayer (aCStruct, theLayerId);
1161 }
1162
1163 // =======================================================================
1164 // function : HaveTheSameOwner
1165 // purpose  :
1166 // =======================================================================
1167 Standard_Integer Graphic3d_CView::HaveTheSameOwner (const Handle(Graphic3d_Structure)& theStructure) const
1168 {
1169   // Find in the sequence of already calculated structures
1170   // 1/ Structure with the same Owner as <AStructure>
1171   // 2/ Which is not <AStructure>
1172   // 3/ COMPUTED which of is valid
1173   const Standard_Integer aNbToCompStructs = myStructsToCompute.Length();
1174   for (Standard_Integer aStructIter = 1; aStructIter <= aNbToCompStructs; ++aStructIter)
1175   {
1176     const Handle(Graphic3d_Structure)& aStructToComp = myStructsToCompute.Value (aStructIter);
1177     if (aStructToComp->Owner()          == theStructure->Owner()
1178      && aStructToComp->Identification() != theStructure->Identification())
1179     {
1180       const Handle(Graphic3d_Structure)& aStructComp = myStructsComputed.Value (aStructIter);
1181       if (aStructComp->HLRValidation())
1182       {
1183         return aStructIter;
1184       }
1185     }
1186   }
1187   return 0;
1188 }
1189
1190 // =======================================================================
1191 // function : CopySettings
1192 // purpose  :
1193 // =======================================================================
1194 void Graphic3d_CView::CopySettings (const Handle(Graphic3d_CView)& theOther)
1195 {
1196   ChangeRenderingParams() = theOther->RenderingParams();
1197   SetBackground            (theOther->Background());
1198   SetGradientBackground    (theOther->GradientBackground());
1199   SetBackgroundImage       (theOther->BackgroundImage());
1200   SetBackgroundImageStyle  (theOther->BackgroundImageStyle());
1201   SetTextureEnv            (theOther->TextureEnv());
1202   SetShadingModel          (theOther->ShadingModel());
1203   SetBackfacingModel       (theOther->BackfacingModel());
1204   SetCamera                (new Graphic3d_Camera (theOther->Camera()));
1205   SetLights                (theOther->Lights());
1206   SetClipPlanes            (theOther->ClipPlanes());
1207 }
1208
1209 // =======================================================================
1210 // function : SetShadingModel
1211 // purpose  :
1212 // =======================================================================
1213 void Graphic3d_CView::SetShadingModel (Graphic3d_TypeOfShadingModel theModel)
1214 {
1215   if (theModel == Graphic3d_TypeOfShadingModel_DEFAULT)
1216   {
1217     throw Standard_ProgramError ("Graphic3d_CView::SetShadingModel() - attempt to set invalid Shading Model!");
1218   }
1219
1220   myRenderParams.ShadingModel = theModel;
1221 }
1222
1223 // =======================================================================
1224 // function : SetUnitFactor
1225 // purpose  :
1226 // =======================================================================
1227 void Graphic3d_CView::SetUnitFactor (Standard_Real theFactor)
1228 {
1229   if (theFactor <= 0.0)
1230   {
1231     throw Standard_ProgramError ("Graphic3d_CView::SetUnitFactor() - invalid unit factor");
1232   }
1233   myUnitFactor = theFactor;
1234   if (!myXRSession.IsNull())
1235   {
1236     myXRSession->SetUnitFactor (theFactor);
1237   }
1238 }
1239
1240 // =======================================================================
1241 // function : IsActiveXR
1242 // purpose  :
1243 // =======================================================================
1244 bool Graphic3d_CView::IsActiveXR() const
1245 {
1246   return !myXRSession.IsNull()
1247        && myXRSession->IsOpen();
1248 }
1249
1250 // =======================================================================
1251 // function : InitXR
1252 // purpose  :
1253 // =======================================================================
1254 bool Graphic3d_CView::InitXR()
1255 {
1256   if (myXRSession.IsNull())
1257   {
1258     myXRSession = new Aspect_OpenVRSession();
1259     myXRSession->SetUnitFactor (myUnitFactor);
1260   }
1261   if (!myXRSession->IsOpen())
1262   {
1263     myXRSession->Open();
1264     if (myBackXRCamera.IsNull())
1265     {
1266       // backup camera properties
1267       myBackXRCamera = new Graphic3d_Camera (myCamera);
1268     }
1269   }
1270   return myXRSession->IsOpen();
1271 }
1272
1273 // =======================================================================
1274 // function : ReleaseXR
1275 // purpose  :
1276 // =======================================================================
1277 void Graphic3d_CView::ReleaseXR()
1278 {
1279   if (!myXRSession.IsNull())
1280   {
1281     if (myXRSession->IsOpen()
1282     && !myBackXRCamera.IsNull())
1283     {
1284       // restore projection properties overridden by HMD
1285       myCamera->SetFOV2d (myBackXRCamera->FOV2d());
1286       myCamera->SetFOVy  (myBackXRCamera->FOVy());
1287       myCamera->SetAspect(myBackXRCamera->Aspect());
1288       myCamera->SetIOD   (myBackXRCamera->GetIODType(), myBackXRCamera->IOD());
1289       myCamera->SetZFocus(myBackXRCamera->ZFocusType(), myBackXRCamera->ZFocus());
1290       myCamera->ResetCustomProjection();
1291       myBackXRCamera.Nullify();
1292     }
1293     myXRSession->Close();
1294   }
1295 }
1296
1297 //=======================================================================
1298 //function : ProcessXRInput
1299 //purpose  :
1300 //=======================================================================
1301 void Graphic3d_CView::ProcessXRInput()
1302 {
1303   if (myRenderParams.StereoMode == Graphic3d_StereoMode_OpenVR
1304    && myCamera->ProjectionType() == Graphic3d_Camera::Projection_Stereo)
1305   {
1306     InitXR();
1307   }
1308   else
1309   {
1310     ReleaseXR();
1311   }
1312
1313   if (!IsActiveXR())
1314   {
1315     myBaseXRCamera.Nullify();
1316     myPosedXRCamera.Nullify();
1317     return;
1318   }
1319
1320   myXRSession->ProcessEvents();
1321   Invalidate();
1322
1323   myCamera->SetFOV2d (myRenderParams.HmdFov2d);
1324   myCamera->SetAspect(myXRSession->Aspect());
1325   myCamera->SetFOVy  (myXRSession->FieldOfView());
1326   myCamera->SetIOD   (Graphic3d_Camera::IODType_Absolute, myXRSession->IOD());
1327   myCamera->SetZFocus(Graphic3d_Camera::FocusType_Absolute, 1.0 * myUnitFactor);
1328
1329   // VR APIs tend to decompose camera orientation-projection matrices into the following components:
1330   // @begincode
1331   //   Model * [View * Eye^-1] * [Projection]
1332   // @endcode
1333   // so that Eye position is encoded into Orientation matrix, and there should be 2 Orientation matrices and 2 Projection matrices to make the stereo.
1334   // Graphic3d_Camera historically follows different decomposition, with Eye position encoded into Projection matrix,
1335   // so that there is only 1 Orientation matrix (matching mono view) and 2 Projection matrices.
1336   if (myXRSession->HasProjectionFrustums())
1337   {
1338     // note that this definition does not include a small forward/backward offset from head to eye
1339     myCamera->SetCustomStereoFrustums (myXRSession->ProjectionFrustum (Aspect_Eye_Left),
1340                                        myXRSession->ProjectionFrustum (Aspect_Eye_Right));
1341   }
1342   else
1343   {
1344     const Graphic3d_Mat4d aPoseL = myXRSession->HeadToEyeTransform (Aspect_Eye_Left);
1345     const Graphic3d_Mat4d aPoseR = myXRSession->HeadToEyeTransform (Aspect_Eye_Right);
1346     const Graphic3d_Mat4d aProjL = myXRSession->ProjectionMatrix (Aspect_Eye_Left,  myCamera->ZNear(), myCamera->ZFar());
1347     const Graphic3d_Mat4d aProjR = myXRSession->ProjectionMatrix (Aspect_Eye_Right, myCamera->ZNear(), myCamera->ZFar());
1348     myCamera->SetCustomStereoProjection (aProjL, aPoseL, aProjR, aPoseR);
1349   }
1350   myBaseXRCamera = myCamera;
1351   if (myPosedXRCamera.IsNull())
1352   {
1353     myPosedXRCamera = new Graphic3d_Camera();
1354   }
1355   SynchronizeXRBaseToPosedCamera();
1356 }
1357
1358 //=======================================================================
1359 //function : SynchronizeXRBaseToPosedCamera
1360 //purpose  :
1361 //=======================================================================
1362 void Graphic3d_CView::SynchronizeXRBaseToPosedCamera()
1363 {
1364   if (!myPosedXRCamera.IsNull())
1365   {
1366     ComputeXRPosedCameraFromBase (*myPosedXRCamera, myXRSession->HeadPose());
1367   }
1368 }
1369
1370 //=======================================================================
1371 //function : ComputeXRPosedCameraFromBase
1372 //purpose  :
1373 //=======================================================================
1374 void Graphic3d_CView::ComputeXRPosedCameraFromBase (Graphic3d_Camera& theCam,
1375                                                     const gp_Trsf& theXRTrsf) const
1376 {
1377   theCam.Copy (myBaseXRCamera);
1378
1379   // convert head pose into camera transformation
1380   const gp_Ax3 anAxVr    (gp::Origin(),  gp::DZ(), gp::DX());
1381   const gp_Ax3 aCameraCS (gp::Origin(), -myBaseXRCamera->Direction(), -myBaseXRCamera->SideRight());
1382   gp_Trsf aTrsfCS;
1383   aTrsfCS.SetTransformation (aCameraCS, anAxVr);
1384   const gp_Trsf aTrsfToCamera = aTrsfCS * theXRTrsf * aTrsfCS.Inverted();
1385   gp_Trsf aTrsfToEye;
1386   aTrsfToEye.SetTranslation (myBaseXRCamera->Eye().XYZ());
1387
1388   const gp_Trsf aTrsf = aTrsfToEye * aTrsfToCamera;
1389   const gp_Dir anUpNew  = myBaseXRCamera->Up().Transformed (aTrsf);
1390   const gp_Dir aDirNew  = myBaseXRCamera->Direction().Transformed (aTrsf);
1391   const gp_Pnt anEyeNew = gp::Origin().Translated (aTrsf.TranslationPart());
1392   theCam.SetUp (anUpNew);
1393   theCam.SetDirectionFromEye (aDirNew);
1394   theCam.MoveEyeTo (anEyeNew);
1395 }
1396
1397 //=======================================================================
1398 //function : SynchronizeXRPosedToBaseCamera
1399 //purpose  :
1400 //=======================================================================
1401 void Graphic3d_CView::SynchronizeXRPosedToBaseCamera()
1402 {
1403   if (myPosedXRCameraCopy.IsNull()
1404    || myPosedXRCamera.IsNull()
1405    || myBaseXRCamera.IsNull()
1406    || myCamera != myPosedXRCamera)
1407   {
1408     return;
1409   }
1410
1411   if (myPosedXRCameraCopy->Eye().IsEqual (myPosedXRCamera->Eye(), gp::Resolution())
1412    && (myPosedXRCameraCopy->Distance() - myPosedXRCamera->Distance()) <= gp::Resolution()
1413    && myPosedXRCameraCopy->Direction().IsEqual (myPosedXRCamera->Direction(), gp::Resolution())
1414    && myPosedXRCameraCopy->Up().IsEqual (myPosedXRCamera->Up(), gp::Resolution()))
1415   {
1416     // avoid floating point math in case of no changes
1417     return;
1418   }
1419
1420   // re-compute myBaseXRCamera from myPosedXRCamera by applying reversed head pose transformation
1421   ComputeXRBaseCameraFromPosed (myPosedXRCamera, myXRSession->HeadPose());
1422   myPosedXRCameraCopy->Copy (myPosedXRCamera);
1423 }
1424
1425 //=======================================================================
1426 //function : ComputeXRBaseCameraFromPosed
1427 //purpose  :
1428 //=======================================================================
1429 void Graphic3d_CView::ComputeXRBaseCameraFromPosed (const Graphic3d_Camera& theCamPosed,
1430                                                     const gp_Trsf& thePoseTrsf)
1431 {
1432   const gp_Ax3 anAxVr    (gp::Origin(),  gp::DZ(), gp::DX());
1433   const gp_Ax3 aCameraCS (gp::Origin(), -myBaseXRCamera->Direction(), -myBaseXRCamera->SideRight());
1434   gp_Trsf aTrsfCS;
1435   aTrsfCS.SetTransformation (aCameraCS, anAxVr);
1436   const gp_Trsf aTrsfToCamera  = aTrsfCS * thePoseTrsf * aTrsfCS.Inverted();
1437   const gp_Trsf aTrsfCamToHead = aTrsfToCamera.Inverted();
1438   const gp_Dir anUpNew  = theCamPosed.Up().Transformed (aTrsfCamToHead);
1439   const gp_Dir aDirNew  = theCamPosed.Direction().Transformed (aTrsfCamToHead);
1440   const gp_Pnt anEyeNew = theCamPosed.Eye().Translated (aTrsfToCamera.TranslationPart().Reversed());
1441   myBaseXRCamera->SetUp (anUpNew);
1442   myBaseXRCamera->SetDirectionFromEye (aDirNew);
1443   myBaseXRCamera->MoveEyeTo (anEyeNew);
1444 }
1445
1446 //=======================================================================
1447 //function : TurnViewXRCamera
1448 //purpose  :
1449 //=======================================================================
1450 void Graphic3d_CView::TurnViewXRCamera (const gp_Trsf& theTrsfTurn)
1451 {
1452   // use current eye position as an anchor
1453   const Handle(Graphic3d_Camera)& aCamBase = myBaseXRCamera;
1454   gp_Trsf aHeadTrsfLocal;
1455   aHeadTrsfLocal.SetTranslationPart (myXRSession->HeadPose().TranslationPart());
1456   const gp_Pnt anEyeAnchor = PoseXRToWorld (aHeadTrsfLocal).TranslationPart();
1457
1458   // turn the view
1459   aCamBase->SetDirectionFromEye (aCamBase->Direction().Transformed (theTrsfTurn));
1460
1461   // recompute new eye
1462   const gp_Ax3 anAxVr    (gp::Origin(),  gp::DZ(), gp::DX());
1463   const gp_Ax3 aCameraCS (gp::Origin(), -aCamBase->Direction(), -aCamBase->SideRight());
1464   gp_Trsf aTrsfCS;
1465   aTrsfCS.SetTransformation (aCameraCS, anAxVr);
1466   const gp_Trsf aTrsfToCamera = aTrsfCS * aHeadTrsfLocal * aTrsfCS.Inverted();
1467   const gp_Pnt anEyeNew = anEyeAnchor.Translated (aTrsfToCamera.TranslationPart().Reversed());
1468   aCamBase->MoveEyeTo (anEyeNew);
1469
1470   SynchronizeXRBaseToPosedCamera();
1471 }
1472
1473 //=======================================================================
1474 //function : SetupXRPosedCamera
1475 //purpose  :
1476 //=======================================================================
1477 void Graphic3d_CView::SetupXRPosedCamera()
1478 {
1479   if (!myPosedXRCamera.IsNull())
1480   {
1481     myCamera = myPosedXRCamera;
1482     if (myPosedXRCameraCopy.IsNull())
1483     {
1484       myPosedXRCameraCopy = new Graphic3d_Camera();
1485     }
1486     myPosedXRCameraCopy->Copy (myPosedXRCamera);
1487   }
1488 }
1489
1490 //=======================================================================
1491 //function : UnsetXRPosedCamera
1492 //purpose  :
1493 //=======================================================================
1494 void Graphic3d_CView::UnsetXRPosedCamera()
1495 {
1496   if (myCamera == myPosedXRCamera
1497   && !myBaseXRCamera.IsNull())
1498   {
1499     SynchronizeXRPosedToBaseCamera();
1500     myCamera = myBaseXRCamera;
1501   }
1502 }
1503
1504 //=======================================================================
1505 //function : DiagnosticInformation
1506 //purpose  :
1507 //=======================================================================
1508 void Graphic3d_CView::DiagnosticInformation (TColStd_IndexedDataMapOfStringString& theDict,
1509                                              Graphic3d_DiagnosticInfo theFlags) const
1510 {
1511   if ((theFlags & Graphic3d_DiagnosticInfo_Device) != 0
1512    && !myXRSession.IsNull())
1513   {
1514     TCollection_AsciiString aVendor  = myXRSession->GetString (Aspect_XRSession::InfoString_Vendor);
1515     TCollection_AsciiString aDevice  = myXRSession->GetString (Aspect_XRSession::InfoString_Device);
1516     TCollection_AsciiString aTracker = myXRSession->GetString (Aspect_XRSession::InfoString_Tracker);
1517     TCollection_AsciiString aSerial  = myXRSession->GetString (Aspect_XRSession::InfoString_SerialNumber);
1518     TCollection_AsciiString aDisplay = TCollection_AsciiString()
1519                                      + myXRSession->RecommendedViewport().x() + "x" + myXRSession->RecommendedViewport().y()
1520                                      + "@" + (int )Round (myXRSession->DisplayFrequency())
1521                                      + " [FOVy: " + (int )Round (myXRSession->FieldOfView()) + "]";
1522
1523     theDict.ChangeFromIndex (theDict.Add ("VRvendor",  aVendor))  = aVendor;
1524     theDict.ChangeFromIndex (theDict.Add ("VRdevice",  aDevice))  = aDevice;
1525     theDict.ChangeFromIndex (theDict.Add ("VRtracker", aTracker)) = aTracker;
1526     theDict.ChangeFromIndex (theDict.Add ("VRdisplay", aDisplay)) = aDisplay;
1527     theDict.ChangeFromIndex (theDict.Add ("VRserial",  aSerial))  = aSerial;
1528   }
1529 }
1530
1531 //=======================================================================
1532 //function : DumpJson
1533 //purpose  : 
1534 //=======================================================================
1535 void Graphic3d_CView::DumpJson (Standard_OStream& theOStream, Standard_Integer theDepth) const
1536 {
1537   OCCT_DUMP_TRANSIENT_CLASS_BEGIN (theOStream)
1538   
1539   OCCT_DUMP_BASE_CLASS (theOStream, theDepth, Graphic3d_DataStructureManager);
1540
1541   OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, myId)
1542   OCCT_DUMP_FIELD_VALUES_DUMPED (theOStream, theDepth, &myRenderParams)
1543   OCCT_DUMP_FIELD_VALUES_DUMPED (theOStream, theDepth, &myBgColor)
1544   OCCT_DUMP_FIELD_VALUE_POINTER (theOStream, myStructureManager)
1545   OCCT_DUMP_FIELD_VALUES_DUMPED (theOStream, theDepth, myCamera.get())
1546
1547   for (Graphic3d_SequenceOfStructure::Iterator anIter (myStructsToCompute); anIter.More(); anIter.Next())
1548   {
1549     const Handle(Graphic3d_Structure)& aStructToCompute = anIter.Value();
1550     OCCT_DUMP_FIELD_VALUES_DUMPED (theOStream, theDepth, aStructToCompute.get())
1551   }
1552
1553   for (Graphic3d_SequenceOfStructure::Iterator anIter (myStructsComputed); anIter.More(); anIter.Next())
1554   {
1555     const Handle(Graphic3d_Structure)& aStructComputed = anIter.Value();
1556     OCCT_DUMP_FIELD_VALUES_DUMPED (theOStream, theDepth, aStructComputed.get())
1557   }
1558
1559   OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, myIsInComputedMode)
1560   OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, myIsActive)
1561   OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, myIsRemoved)
1562   
1563   OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, myVisualization)
1564
1565   OCCT_DUMP_FIELD_VALUES_DUMPED (theOStream, theDepth, myBackXRCamera.get())
1566   OCCT_DUMP_FIELD_VALUES_DUMPED (theOStream, theDepth, myBaseXRCamera.get())
1567   OCCT_DUMP_FIELD_VALUES_DUMPED (theOStream, theDepth, myPosedXRCamera.get())
1568   OCCT_DUMP_FIELD_VALUES_DUMPED (theOStream, theDepth, myPosedXRCameraCopy.get())
1569
1570   OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, myUnitFactor)
1571 }