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