0024739: TKOpenGl - port ray-tracing from OpenCL to GLSL for better integration and...
[occt.git] / src / Graphic3d / Graphic3d_Camera.cxx
1 // Created on: 2013-05-29
2 // Created by: Anton POLETAEV
3 // Copyright (c) 1999-2014 OPEN CASCADE SAS
4 //
5 // This file is part of Open CASCADE Technology software library.
6 //
7 // This library is free software; you can redistribute it and/or modify it under
8 // the terms of the GNU Lesser General Public License version 2.1 as published
9 // by the Free Software Foundation, with special exception defined in the file
10 // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
11 // distribution for complete text of the license and disclaimer of any warranty.
12 //
13 // Alternatively, this file may be used under the terms of Open CASCADE
14 // commercial license or contractual agreement.
15
16 #include <gp_Pln.hxx>
17 #include <Standard_ShortReal.hxx>
18
19 #include <Graphic3d_Vec4.hxx>
20 #include <Graphic3d_Camera.hxx>
21
22 #include <Standard_Atomic.hxx>
23 #include <Standard_Assert.hxx>
24
25 IMPLEMENT_STANDARD_HANDLE(Graphic3d_Camera, Standard_Transient)
26 IMPLEMENT_STANDARD_RTTIEXT(Graphic3d_Camera, Standard_Transient)
27
28 namespace
29 {
30   // (degrees -> radians) * 0.5
31   static const Standard_Real DTR_HALF = 0.5 * 0.0174532925;
32
33   // default property values
34   static const Standard_Real DEFAULT_ZNEAR = 0.001;
35   static const Standard_Real DEFAULT_ZFAR  = 3000.0;
36
37   // atomic state counter
38   static volatile Standard_Integer THE_STATE_COUNTER = 0;
39 };
40
41 // =======================================================================
42 // function : Graphic3d_Camera
43 // purpose  :
44 // =======================================================================
45 Graphic3d_Camera::Graphic3d_Camera()
46 : myUp (0.0, 1.0, 0.0),
47   myEye (0.0, 0.0, -1500.0),
48   myCenter (0.0, 0.0, 0.0),
49   myAxialScale (1.0, 1.0, 1.0),
50   myProjType (Projection_Orthographic),
51   myFOVy (45.0),
52   myZNear (DEFAULT_ZNEAR),
53   myZFar (DEFAULT_ZFAR),
54   myAspect (1.0),
55   myScale (1000.0),
56   myZFocus (1.0),
57   myZFocusType (FocusType_Relative),
58   myIOD (0.05),
59   myIODType (IODType_Relative)
60 {
61   myProjectionState  = (Standard_Size)Standard_Atomic_Increment (&THE_STATE_COUNTER);
62   myOrientationState = (Standard_Size)Standard_Atomic_Increment (&THE_STATE_COUNTER);
63 }
64
65 // =======================================================================
66 // function : Graphic3d_Camera
67 // purpose  :
68 // =======================================================================
69 Graphic3d_Camera::Graphic3d_Camera (const Handle(Graphic3d_Camera)& theOther)
70 {
71   Copy (theOther);
72 }
73
74 // =======================================================================
75 // function : CopyMappingData
76 // purpose  :
77 // =======================================================================
78 void Graphic3d_Camera::CopyMappingData (const Handle(Graphic3d_Camera)& theOtherCamera)
79 {
80   myFOVy            = theOtherCamera->myFOVy;
81   myZNear           = theOtherCamera->myZNear;
82   myZFar            = theOtherCamera->myZFar;
83   myAspect          = theOtherCamera->myAspect;
84   myScale           = theOtherCamera->myScale;
85   myZFocus          = theOtherCamera->myZFocus;
86   myZFocusType      = theOtherCamera->myZFocusType;
87   myIOD             = theOtherCamera->myIOD;
88   myIODType         = theOtherCamera->myIODType;
89   myProjType        = theOtherCamera->myProjType;
90   myProjectionState = theOtherCamera->myProjectionState;
91
92   InvalidateProjection();
93 }
94
95 // =======================================================================
96 // function : CopyOrientationData
97 // purpose  :
98 // =======================================================================
99 void Graphic3d_Camera::CopyOrientationData (const Handle(Graphic3d_Camera)& theOtherCamera)
100 {
101   myUp               = theOtherCamera->myUp;
102   myEye              = theOtherCamera->myEye;
103   myCenter           = theOtherCamera->myCenter;
104   myAxialScale       = theOtherCamera->myAxialScale;
105   myOrientationState = theOtherCamera->myOrientationState;
106
107   InvalidateOrientation();
108 }
109
110 // =======================================================================
111 // function : Copy
112 // purpose  :
113 // =======================================================================
114 void Graphic3d_Camera::Copy (const Handle(Graphic3d_Camera)& theOther)
115 {
116   CopyMappingData (theOther);
117   CopyOrientationData (theOther);
118 }
119
120 // =======================================================================
121 // function : SetEye
122 // purpose  :
123 // =======================================================================
124 void Graphic3d_Camera::SetEye (const gp_Pnt& theEye)
125 {
126   myEye = theEye;
127   InvalidateOrientation();
128 }
129
130 // =======================================================================
131 // function : SetCenter
132 // purpose  :
133 // =======================================================================
134 void Graphic3d_Camera::SetCenter (const gp_Pnt& theCenter)
135 {
136   myCenter = theCenter;
137   InvalidateOrientation();
138 }
139
140 // =======================================================================
141 // function : SetUp
142 // purpose  :
143 // =======================================================================
144 void Graphic3d_Camera::SetUp (const gp_Dir& theUp)
145 {
146   myUp = theUp;
147   InvalidateOrientation();
148 }
149
150 // =======================================================================
151 // function : SetAxialScale
152 // purpose  :
153 // =======================================================================
154 void Graphic3d_Camera::SetAxialScale (const gp_XYZ& theAxialScale)
155 {
156   myAxialScale = theAxialScale;
157   InvalidateOrientation();
158 }
159
160 // =======================================================================
161 // function : SetDistance
162 // purpose  :
163 // =======================================================================
164 void Graphic3d_Camera::SetDistance (const Standard_Real theDistance)
165 {
166   gp_Vec aCenter2Eye (Direction());
167   aCenter2Eye.Reverse();
168   aCenter2Eye.Scale (theDistance);
169   SetEye (Center().Translated (aCenter2Eye));
170 }
171
172 // =======================================================================
173 // function : Distance
174 // purpose  :
175 // =======================================================================
176 Standard_Real Graphic3d_Camera::Distance() const
177 {
178   return myEye.Distance (myCenter);
179 }
180
181 // =======================================================================
182 // function : SetDirection
183 // purpose  :
184 // =======================================================================
185 void Graphic3d_Camera::SetDirection (const gp_Dir& theDir)
186 {
187   gp_Vec aScaledDir (theDir);
188   aScaledDir.Scale (Distance());
189   aScaledDir.Reverse();
190   SetEye (Center().Translated (aScaledDir));
191 }
192
193 // =======================================================================
194 // function : Direction
195 // purpose  :
196 // =======================================================================
197 gp_Dir Graphic3d_Camera::Direction() const
198 {
199   return gp_Dir (gp_Vec (myEye, myCenter));
200 }
201
202 // =======================================================================
203 // function : SetScale
204 // purpose  :
205 // =======================================================================
206 void Graphic3d_Camera::SetScale (const Standard_Real theScale)
207 {
208   myScale = theScale;
209
210   switch (myProjType)
211   {
212     case Projection_Perspective  :
213     case Projection_Stereo       :
214     case Projection_MonoLeftEye  :
215     case Projection_MonoRightEye :
216     {
217       Standard_Real aDistance = theScale * 0.5 / Tan(myFOVy * M_PI / 360.0);
218       SetDistance (aDistance);
219     }
220
221     default :
222       break;
223   }
224
225   InvalidateProjection();
226 }
227
228 // =======================================================================
229 // function : Scale
230 // purpose  :
231 // =======================================================================
232 Standard_Real Graphic3d_Camera::Scale() const
233 {
234   switch (myProjType)
235   {
236     case Projection_Orthographic :
237       return myScale;
238
239     // case Projection_Perspective  :
240     // case Projection_Stereo       :
241     // case Projection_MonoLeftEye  :
242     // case Projection_MonoRightEye :
243     default :
244       return Distance() * 2.0 * Tan (myFOVy * M_PI / 360.0);
245   }
246 }
247
248 // =======================================================================
249 // function : SetProjectionType
250 // purpose  :
251 // =======================================================================
252 void Graphic3d_Camera::SetProjectionType (const Projection theProjectionType)
253 {
254   Projection anOldType = myProjType;
255
256   if (anOldType == theProjectionType)
257   {
258     return;
259   }
260
261   if (anOldType == Projection_Orthographic)
262   {
263     if (myZNear <= RealEpsilon())
264     {
265       myZNear = DEFAULT_ZNEAR;
266     }
267     if (myZFar <= RealEpsilon())
268     {
269       myZFar = DEFAULT_ZFAR;
270     }
271   }
272
273   myProjType = theProjectionType;
274
275   InvalidateProjection();
276 }
277
278 // =======================================================================
279 // function : SetFOVy
280 // purpose  :
281 // =======================================================================
282 void Graphic3d_Camera::SetFOVy (const Standard_Real theFOVy)
283 {
284   myFOVy = theFOVy;
285   InvalidateProjection();
286 }
287
288 // =======================================================================
289 // function : SetZRange
290 // purpose  :
291 // =======================================================================
292 void Graphic3d_Camera::SetZRange (const Standard_Real theZNear,
293                                   const Standard_Real theZFar)
294 {
295   Standard_ASSERT_RAISE (theZFar > theZNear, "ZFar should be greater than ZNear");
296   if (!IsOrthographic())
297   {
298     Standard_ASSERT_RAISE (theZNear > 0.0, "Only positive Z-Near is allowed for perspective camera");
299     Standard_ASSERT_RAISE (theZFar  > 0.0, "Only positive Z-Far is allowed for perspective camera");
300   }
301
302   myZNear = theZNear;
303   myZFar  = theZFar;
304
305   InvalidateProjection();
306 }
307
308 // =======================================================================
309 // function : SetAspect
310 // purpose  :
311 // =======================================================================
312 void Graphic3d_Camera::SetAspect (const Standard_Real theAspect)
313 {
314   myAspect = theAspect;
315   InvalidateProjection();
316 }
317
318 // =======================================================================
319 // function : SetZFocus
320 // purpose  :
321 // =======================================================================
322 void Graphic3d_Camera::SetZFocus(const FocusType theType, const Standard_Real theZFocus)
323 {
324   myZFocusType = theType;
325   myZFocus = theZFocus;
326   InvalidateProjection();
327 }
328
329 // =======================================================================
330 // function : SetIOD
331 // purpose  :
332 // =======================================================================
333 void Graphic3d_Camera::SetIOD (const IODType theType, const Standard_Real theIOD)
334 {
335   myIODType = theType;
336   myIOD = theIOD;
337   InvalidateProjection();
338 }
339
340 // =======================================================================
341 // function : OrthogonalizeUp
342 // purpose  :
343 // =======================================================================
344 void Graphic3d_Camera::OrthogonalizeUp()
345 {
346   SetUp (OrthogonalizedUp());
347 }
348
349 // =======================================================================
350 // function : OrthogonalizedUp
351 // purpose  :
352 // =======================================================================
353 gp_Dir Graphic3d_Camera::OrthogonalizedUp() const
354 {
355   gp_Dir aDir  = Direction();
356   gp_Dir aLeft = aDir.Crossed (Up());
357
358   // recompute up as: up = left x direction
359   return aLeft.Crossed (aDir);
360 }
361
362 // =======================================================================
363 // function : Transform
364 // purpose  :
365 // =======================================================================
366 void Graphic3d_Camera::Transform (const gp_Trsf& theTrsf)
367 {
368   myUp.Transform (theTrsf);
369   myEye.Transform (theTrsf);
370   myCenter.Transform (theTrsf);
371   InvalidateOrientation();
372 }
373
374 // =======================================================================
375 // function : safePointCast
376 // purpose  :
377 // =======================================================================
378 static Graphic3d_Vec4d safePointCast (const gp_Pnt& thePnt)
379 {
380   Standard_Real aLim = 1e15f;
381
382   // have to deal with values greater then max float
383   gp_Pnt aSafePoint = thePnt;
384   const Standard_Real aBigFloat = aLim * 0.1f;
385   if (Abs (aSafePoint.X()) > aLim)
386     aSafePoint.SetX (aSafePoint.X() >= 0 ? aBigFloat : -aBigFloat);
387   if (Abs (aSafePoint.Y()) > aLim)
388     aSafePoint.SetY (aSafePoint.Y() >= 0 ? aBigFloat : -aBigFloat);
389   if (Abs (aSafePoint.Z()) > aLim)
390     aSafePoint.SetZ (aSafePoint.Z() >= 0 ? aBigFloat : -aBigFloat);
391
392   // convert point
393   Graphic3d_Vec4d aPnt (aSafePoint.X(), aSafePoint.Y(), aSafePoint.Z(), 1.0);
394
395   return aPnt;
396 }
397
398 // =======================================================================
399 // function : Project
400 // purpose  :
401 // =======================================================================
402 gp_Pnt Graphic3d_Camera::Project (const gp_Pnt& thePnt) const
403 {
404   const Graphic3d_Mat4d& aViewMx = OrientationMatrix();
405   const Graphic3d_Mat4d& aProjMx = ProjectionMatrix();
406
407   // use compatible type of point
408   Graphic3d_Vec4d aPnt = safePointCast (thePnt);
409
410   aPnt = aViewMx * aPnt; // convert to view coordinate space
411   aPnt = aProjMx * aPnt; // convert to projection coordinate space
412
413   const Standard_Real aInvW = 1.0 / Standard_Real (aPnt.w());
414
415   return gp_Pnt (aPnt.x() * aInvW, aPnt.y() * aInvW, aPnt.z() * aInvW);
416 }
417
418 // =======================================================================
419 // function : UnProject
420 // purpose  :
421 // =======================================================================
422 gp_Pnt Graphic3d_Camera::UnProject (const gp_Pnt& thePnt) const
423 {
424   const Graphic3d_Mat4d& aViewMx = OrientationMatrix();
425   const Graphic3d_Mat4d& aProjMx = ProjectionMatrix();
426
427   Graphic3d_Mat4d aInvView;
428   Graphic3d_Mat4d aInvProj;
429
430   // this case should never happen
431   if (!aViewMx.Inverted (aInvView) || !aProjMx.Inverted (aInvProj))
432   {
433     return gp_Pnt (0.0, 0.0, 0.0);
434   }
435
436   // use compatible type of point
437   Graphic3d_Vec4d aPnt = safePointCast (thePnt);
438
439   aPnt = aInvProj * aPnt; // convert to view coordinate space
440   aPnt = aInvView * aPnt; // convert to world coordinate space
441
442   const Standard_Real aInvW = 1.0 / Standard_Real (aPnt.w());
443
444   return gp_Pnt (aPnt.x() * aInvW, aPnt.y() * aInvW, aPnt.z() * aInvW);
445 }
446
447 // =======================================================================
448 // function : ConvertView2Proj
449 // purpose  :
450 // =======================================================================
451 gp_Pnt Graphic3d_Camera::ConvertView2Proj (const gp_Pnt& thePnt) const
452 {
453   const Graphic3d_Mat4d& aProjMx = ProjectionMatrix();
454
455   // use compatible type of point
456   Graphic3d_Vec4d aPnt = safePointCast (thePnt);
457
458   aPnt = aProjMx * aPnt; // convert to projection coordinate space
459
460   const Standard_Real aInvW = 1.0 / Standard_Real (aPnt.w());
461
462   return gp_Pnt (aPnt.x() * aInvW, aPnt.y() * aInvW, aPnt.z() * aInvW);
463 }
464
465 // =======================================================================
466 // function : ConvertProj2View
467 // purpose  :
468 // =======================================================================
469 gp_Pnt Graphic3d_Camera::ConvertProj2View (const gp_Pnt& thePnt) const
470 {
471   const Graphic3d_Mat4d& aProjMx = ProjectionMatrix();
472
473   Graphic3d_Mat4d aInvProj;
474
475   // this case should never happen, but...
476   if (!aProjMx.Inverted (aInvProj))
477   {
478     return gp_Pnt (0, 0, 0);
479   }
480
481   // use compatible type of point
482   Graphic3d_Vec4d aPnt = safePointCast (thePnt);
483
484   aPnt = aInvProj * aPnt; // convert to view coordinate space
485
486   const Standard_Real aInvW = 1.0 / Standard_Real (aPnt.w());
487
488   return gp_Pnt (aPnt.x() * aInvW, aPnt.y() * aInvW, aPnt.z() * aInvW);
489 }
490
491 // =======================================================================
492 // function : ConvertWorld2View
493 // purpose  :
494 // =======================================================================
495 gp_Pnt Graphic3d_Camera::ConvertWorld2View (const gp_Pnt& thePnt) const
496 {
497   const Graphic3d_Mat4d& aViewMx = OrientationMatrix();
498
499   // use compatible type of point
500   Graphic3d_Vec4d aPnt = safePointCast (thePnt);
501
502   aPnt = aViewMx * aPnt; // convert to view coordinate space
503
504   const Standard_Real aInvW = 1.0 / Standard_Real (aPnt.w());
505
506   return gp_Pnt (aPnt.x() * aInvW, aPnt.y() * aInvW, aPnt.z() * aInvW);
507 }
508
509 // =======================================================================
510 // function : ConvertView2World
511 // purpose  :
512 // =======================================================================
513 gp_Pnt Graphic3d_Camera::ConvertView2World (const gp_Pnt& thePnt) const
514 {
515   const Graphic3d_Mat4d& aViewMx = OrientationMatrix();
516
517   Graphic3d_Mat4d aInvView;
518
519   if (!aViewMx.Inverted (aInvView))
520   {
521     return gp_Pnt(0, 0, 0);
522   }
523
524   // use compatible type of point
525   Graphic3d_Vec4d aPnt = safePointCast (thePnt);
526
527   aPnt = aInvView * aPnt; // convert to world coordinate space
528
529   const Standard_Real aInvW = 1.0 / Standard_Real (aPnt.w());
530
531   return gp_Pnt (aPnt.x() * aInvW, aPnt.y() * aInvW, aPnt.z() * aInvW);
532 }
533
534 // =======================================================================
535 // function : ViewDimensions
536 // purpose  :
537 // =======================================================================
538 gp_XYZ Graphic3d_Camera::ViewDimensions() const
539 {
540   // view plane dimensions
541   Standard_Real aSizeY = IsOrthographic() ? myScale : (2.0 * Distance() * Tan (DTR_HALF * myFOVy));
542   Standard_Real aSizeX = myAspect * aSizeY;
543
544   // and frustum depth
545   return gp_XYZ (aSizeX, aSizeY, myZFar - myZNear);
546 }
547
548 // =======================================================================
549 // function : Frustum
550 // purpose  :
551 // =======================================================================
552 void Graphic3d_Camera::Frustum (gp_Pln& theLeft,
553                                 gp_Pln& theRight,
554                                 gp_Pln& theBottom,
555                                 gp_Pln& theTop,
556                                 gp_Pln& theNear,
557                                 gp_Pln& theFar) const
558 {
559   gp_Vec aProjection = gp_Vec (Direction());
560   gp_Vec anUp        = OrthogonalizedUp();
561   gp_Vec aSide       = aProjection ^ anUp;
562
563   Standard_ASSERT_RAISE (
564     !aProjection.IsParallel (anUp, Precision::Angular()),
565      "Can not derive SIDE = PROJ x UP - directions are parallel");
566
567   theNear = gp_Pln (Eye().Translated (aProjection * ZNear()), aProjection);
568   theFar  = gp_Pln (Eye().Translated (aProjection * ZFar()), -aProjection);
569
570   Standard_Real aHScaleHor = Scale() * 0.5 * Aspect();
571   Standard_Real aHScaleVer = Scale() * 0.5;
572
573   gp_Pnt aPntLeft   = Center().Translated (aHScaleHor * -aSide);
574   gp_Pnt aPntRight  = Center().Translated (aHScaleHor *  aSide);
575   gp_Pnt aPntBottom = Center().Translated (aHScaleVer * -anUp);
576   gp_Pnt aPntTop    = Center().Translated (aHScaleVer *  anUp);
577
578   gp_Vec aDirLeft   =  aSide;
579   gp_Vec aDirRight  = -aSide;
580   gp_Vec aDirBottom =  anUp;
581   gp_Vec aDirTop    = -anUp;
582   if (!IsOrthographic())
583   {
584     Standard_Real aHFOVHor = ATan (Tan (DTR_HALF * FOVy()) * Aspect());
585     Standard_Real aHFOVVer = DTR_HALF * FOVy();
586     aDirLeft.Rotate   (gp_Ax1 (gp::Origin(), anUp),   aHFOVHor);
587     aDirRight.Rotate  (gp_Ax1 (gp::Origin(), anUp),  -aHFOVHor);
588     aDirBottom.Rotate (gp_Ax1 (gp::Origin(), aSide), -aHFOVVer);
589     aDirTop.Rotate    (gp_Ax1 (gp::Origin(), aSide),  aHFOVVer);
590   }
591
592   theLeft   = gp_Pln (aPntLeft,   aDirLeft);
593   theRight  = gp_Pln (aPntRight,  aDirRight);
594   theBottom = gp_Pln (aPntBottom, aDirBottom);
595   theTop    = gp_Pln (aPntTop,    aDirTop);
596 }
597
598 // =======================================================================
599 // function : OrientationMatrix
600 // purpose  :
601 // =======================================================================
602 const Graphic3d_Mat4d& Graphic3d_Camera::OrientationMatrix() const
603 {
604   return *UpdateOrientation (myMatricesD).Orientation;
605 }
606
607 // =======================================================================
608 // function : OrientationMatrixF
609 // purpose  :
610 // =======================================================================
611 const Graphic3d_Mat4& Graphic3d_Camera::OrientationMatrixF() const
612 {
613   return *UpdateOrientation (myMatricesF).Orientation;
614 }
615
616 // =======================================================================
617 // function : ProjectionMatrix
618 // purpose  :
619 // =======================================================================
620 const Graphic3d_Mat4d& Graphic3d_Camera::ProjectionMatrix() const
621 {
622   return *UpdateProjection (myMatricesD).MProjection;
623 }
624
625 // =======================================================================
626 // function : ProjectionMatrixF
627 // purpose  :
628 // =======================================================================
629 const Graphic3d_Mat4& Graphic3d_Camera::ProjectionMatrixF() const
630 {
631   return *UpdateProjection (myMatricesF).MProjection;
632 }
633
634 // =======================================================================
635 // function : ProjectionStereoLeft
636 // purpose  :
637 // =======================================================================
638 const Graphic3d_Mat4d& Graphic3d_Camera::ProjectionStereoLeft() const
639 {
640   return *UpdateProjection (myMatricesD).LProjection;
641 }
642
643 // =======================================================================
644 // function : ProjectionStereoLeftF
645 // purpose  :
646 // =======================================================================
647 const Graphic3d_Mat4& Graphic3d_Camera::ProjectionStereoLeftF() const
648 {
649   return *UpdateProjection (myMatricesF).LProjection;
650 }
651
652 // =======================================================================
653 // function : ProjectionStereoRight
654 // purpose  :
655 // =======================================================================
656 const Graphic3d_Mat4d& Graphic3d_Camera::ProjectionStereoRight() const
657 {
658   return *UpdateProjection (myMatricesD).RProjection;
659 }
660
661 // =======================================================================
662 // function : ProjectionStereoRightF
663 // purpose  :
664 // =======================================================================
665 const Graphic3d_Mat4& Graphic3d_Camera::ProjectionStereoRightF() const
666 {
667   return *UpdateProjection (myMatricesF).RProjection;
668 }
669
670 // =======================================================================
671 // function : UpdateProjection
672 // purpose  :
673 // =======================================================================
674 template <typename Elem_t>
675 Graphic3d_Camera::TransformMatrices<Elem_t>&
676   Graphic3d_Camera::UpdateProjection (TransformMatrices<Elem_t>& theMatrices) const
677 {
678   if (theMatrices.IsProjectionValid())
679   {
680     return theMatrices; // for inline accessors
681   }
682
683   theMatrices.InitProjection();
684
685   // sets top of frustum based on FOVy and near clipping plane
686   Elem_t aScale   = static_cast<Elem_t> (myScale);
687   Elem_t aZNear   = static_cast<Elem_t> (myZNear);
688   Elem_t aZFar    = static_cast<Elem_t> (myZFar);
689   Elem_t anAspect = static_cast<Elem_t> (myAspect);
690   Elem_t aDYHalf = 0.0;
691   if (IsOrthographic())
692   {
693     aDYHalf = aScale * Elem_t (0.5);
694   }
695   else
696   {
697     aDYHalf = aZNear * Elem_t (Tan (DTR_HALF * myFOVy));
698   }
699
700   // sets right of frustum based on aspect ratio
701   Elem_t aDXHalf = anAspect * aDYHalf;
702   Elem_t aLeft   = -aDXHalf;
703   Elem_t aRight  =  aDXHalf;
704   Elem_t aBot    = -aDYHalf;
705   Elem_t aTop    =  aDYHalf;
706
707   Elem_t aIOD  = myIODType == IODType_Relative 
708     ? static_cast<Elem_t> (myIOD * Distance())
709     : static_cast<Elem_t> (myIOD);
710
711   Elem_t aFocus = myZFocusType == FocusType_Relative 
712     ? static_cast<Elem_t> (myZFocus * Distance())
713     : static_cast<Elem_t> (myZFocus);
714
715   switch (myProjType)
716   {
717     case Projection_Orthographic :
718       OrthoProj (aLeft, aRight, aBot, aTop, aZNear, aZFar, *theMatrices.MProjection);
719       break;
720
721     case Projection_Perspective :
722       PerspectiveProj (aLeft, aRight, aBot, aTop, aZNear, aZFar, *theMatrices.MProjection);
723       break;
724
725     case Projection_MonoLeftEye :
726     {
727       StereoEyeProj (aLeft, aRight, aBot, aTop,
728                      aZNear, aZFar, aIOD, aFocus,
729                      Standard_True, *theMatrices.MProjection);
730       break;
731     }
732
733     case Projection_MonoRightEye :
734     {
735       StereoEyeProj (aLeft, aRight, aBot, aTop,
736                      aZNear, aZFar, aIOD, aFocus,
737                      Standard_False, *theMatrices.MProjection);
738       break;
739     }
740
741     case Projection_Stereo :
742     {
743       PerspectiveProj (aLeft, aRight, aBot, aTop, aZNear, aZFar, *theMatrices.MProjection);
744
745       StereoEyeProj (aLeft, aRight, aBot, aTop,
746                      aZNear, aZFar, aIOD, aFocus,
747                      Standard_True,
748                      *theMatrices.LProjection);
749
750       StereoEyeProj (aLeft, aRight, aBot, aTop,
751                      aZNear, aZFar, aIOD, aFocus,
752                      Standard_False,
753                      *theMatrices.RProjection);
754       break;
755     }
756   }
757
758   return theMatrices; // for inline accessors
759 }
760
761 // =======================================================================
762 // function : UpdateOrientation
763 // purpose  :
764 // =======================================================================
765 template <typename Elem_t>
766 Graphic3d_Camera::TransformMatrices<Elem_t>&
767   Graphic3d_Camera::UpdateOrientation (TransformMatrices<Elem_t>& theMatrices) const
768 {
769   if (theMatrices.IsOrientationValid())
770   {
771     return theMatrices; // for inline accessors
772   }
773
774   theMatrices.InitOrientation();
775
776   NCollection_Vec3<Elem_t> anEye (static_cast<Elem_t> (myEye.X()),
777                                   static_cast<Elem_t> (myEye.Y()),
778                                   static_cast<Elem_t> (myEye.Z()));
779
780   NCollection_Vec3<Elem_t> aCenter (static_cast<Elem_t> (myCenter.X()),
781                                     static_cast<Elem_t> (myCenter.Y()),
782                                     static_cast<Elem_t> (myCenter.Z()));
783
784   NCollection_Vec3<Elem_t> anUp (static_cast<Elem_t> (myUp.X()),
785                                  static_cast<Elem_t> (myUp.Y()),
786                                  static_cast<Elem_t> (myUp.Z()));
787
788   NCollection_Vec3<Elem_t> anAxialScale (static_cast<Elem_t> (myAxialScale.X()),
789                                          static_cast<Elem_t> (myAxialScale.Y()),
790                                          static_cast<Elem_t> (myAxialScale.Z()));
791
792   LookOrientation (anEye, aCenter, anUp, anAxialScale, *theMatrices.Orientation);
793
794   return theMatrices; // for inline accessors
795 }
796
797 // =======================================================================
798 // function : InvalidateProjection
799 // purpose  :
800 // =======================================================================
801 void Graphic3d_Camera::InvalidateProjection()
802 {
803   myMatricesD.ResetProjection();
804   myMatricesF.ResetProjection();
805   myProjectionState = (Standard_Size)Standard_Atomic_Increment (&THE_STATE_COUNTER);
806 }
807
808 // =======================================================================
809 // function : InvalidateOrientation
810 // purpose  :
811 // =======================================================================
812 void Graphic3d_Camera::InvalidateOrientation()
813 {
814   myMatricesD.ResetOrientation();
815   myMatricesF.ResetOrientation();
816   myOrientationState = (Standard_Size)Standard_Atomic_Increment (&THE_STATE_COUNTER);
817 }
818
819 // =======================================================================
820 // function : OrthoProj
821 // purpose  :
822 // =======================================================================
823 template <typename Elem_t>
824 void Graphic3d_Camera::OrthoProj (const Elem_t theLeft,
825                                   const Elem_t theRight,
826                                   const Elem_t theBottom,
827                                   const Elem_t theTop,
828                                   const Elem_t theNear,
829                                   const Elem_t theFar,
830                                   NCollection_Mat4<Elem_t>& theOutMx)
831 {
832   // row 0
833   theOutMx.ChangeValue (0, 0) = Elem_t (2.0) / (theRight - theLeft);
834   theOutMx.ChangeValue (0, 1) = Elem_t (0.0);
835   theOutMx.ChangeValue (0, 2) = Elem_t (0.0);
836   theOutMx.ChangeValue (0, 3) = - (theRight + theLeft) / (theRight - theLeft);
837
838   // row 1
839   theOutMx.ChangeValue (1, 0) = Elem_t (0.0);
840   theOutMx.ChangeValue (1, 1) = Elem_t (2.0) / (theTop - theBottom);
841   theOutMx.ChangeValue (1, 2) = Elem_t (0.0);
842   theOutMx.ChangeValue (1, 3) = - (theTop + theBottom) / (theTop - theBottom);
843
844   // row 2
845   theOutMx.ChangeValue (2, 0) = Elem_t (0.0);
846   theOutMx.ChangeValue (2, 1) = Elem_t (0.0);
847   theOutMx.ChangeValue (2, 2) = Elem_t (-2.0) / (theFar - theNear);
848   theOutMx.ChangeValue (2, 3) = - (theFar + theNear) / (theFar - theNear);
849
850   // row 3
851   theOutMx.ChangeValue (3, 0) = Elem_t (0.0);
852   theOutMx.ChangeValue (3, 1) = Elem_t (0.0);
853   theOutMx.ChangeValue (3, 2) = Elem_t (0.0);
854   theOutMx.ChangeValue (3, 3) = Elem_t (1.0);
855 }
856
857 // =======================================================================
858 // function : PerspectiveProj
859 // purpose  :
860 // =======================================================================
861 template <typename Elem_t>
862 void Graphic3d_Camera::PerspectiveProj (const Elem_t theLeft,
863                                         const Elem_t theRight,
864                                         const Elem_t theBottom,
865                                         const Elem_t theTop,
866                                         const Elem_t theNear,
867                                         const Elem_t theFar,
868                                         NCollection_Mat4<Elem_t>& theOutMx)
869 {
870   // column 0
871   theOutMx.ChangeValue (0, 0) = (Elem_t (2.0) * theNear) / (theRight - theLeft);
872   theOutMx.ChangeValue (1, 0) = Elem_t (0.0);
873   theOutMx.ChangeValue (2, 0) = Elem_t (0.0);
874   theOutMx.ChangeValue (3, 0) = Elem_t (0.0);
875
876   // column 1
877   theOutMx.ChangeValue (0, 1) = Elem_t (0.0);
878   theOutMx.ChangeValue (1, 1) = (Elem_t (2.0) * theNear) / (theTop - theBottom);
879   theOutMx.ChangeValue (2, 1) = Elem_t (0.0);
880   theOutMx.ChangeValue (3, 1) = Elem_t (0.0);
881
882   // column 2
883   theOutMx.ChangeValue (0, 2) = (theRight + theLeft) / (theRight - theLeft);
884   theOutMx.ChangeValue (1, 2) = (theTop + theBottom) / (theTop - theBottom);
885   theOutMx.ChangeValue (2, 2) = -(theFar + theNear) / (theFar - theNear);
886   theOutMx.ChangeValue (3, 2) = Elem_t (-1.0);
887
888   // column 3
889   theOutMx.ChangeValue (0, 3) = Elem_t (0.0);
890   theOutMx.ChangeValue (1, 3) = Elem_t (0.0);
891   theOutMx.ChangeValue (2, 3) = -(Elem_t (2.0) * theFar * theNear) / (theFar - theNear);
892   theOutMx.ChangeValue (3, 3) = Elem_t (0.0);
893 }
894
895 // =======================================================================
896 // function : StereoEyeProj
897 // purpose  :
898 // =======================================================================
899 template <typename Elem_t>
900 void Graphic3d_Camera::StereoEyeProj (const Elem_t theLeft,
901                                       const Elem_t theRight,
902                                       const Elem_t theBottom,
903                                       const Elem_t theTop,
904                                       const Elem_t theNear,
905                                       const Elem_t theFar,
906                                       const Elem_t theIOD,
907                                       const Elem_t theZFocus,
908                                       const Standard_Boolean theIsLeft,
909                                       NCollection_Mat4<Elem_t>& theOutMx)
910 {
911   Elem_t aDx = theIsLeft ? Elem_t (0.5) * theIOD : Elem_t (-0.5) * theIOD;
912   Elem_t aDXStereoShift = aDx * theNear / theZFocus;
913
914   // construct eye projection matrix
915   PerspectiveProj (theLeft  + aDXStereoShift,
916                    theRight + aDXStereoShift,
917                    theBottom, theTop, theNear, theFar,
918                    theOutMx);
919
920   if (theIOD != Elem_t (0.0))
921   {
922     // X translation to cancel parallax
923     theOutMx.Translate (NCollection_Vec3<Elem_t> (aDx, Elem_t (0.0), Elem_t (0.0)));
924   }
925 }
926
927 // =======================================================================
928 // function : LookOrientation
929 // purpose  :
930 // =======================================================================
931 template <typename Elem_t>
932 void Graphic3d_Camera::LookOrientation (const NCollection_Vec3<Elem_t>& theEye,
933                                         const NCollection_Vec3<Elem_t>& theLookAt,
934                                         const NCollection_Vec3<Elem_t>& theUpDir,
935                                         const NCollection_Vec3<Elem_t>& theAxialScale,
936                                         NCollection_Mat4<Elem_t>& theOutMx)
937 {
938   NCollection_Vec3<Elem_t> aForward = theLookAt - theEye;
939   aForward.Normalize();
940
941   // side = forward x up
942   NCollection_Vec3<Elem_t> aSide = NCollection_Vec3<Elem_t>::Cross (aForward, theUpDir);
943   aSide.Normalize();
944
945   // recompute up as: up = side x forward
946   NCollection_Vec3<Elem_t> anUp = NCollection_Vec3<Elem_t>::Cross (aSide, aForward);
947
948   NCollection_Mat4<Elem_t> aLookMx;
949   aLookMx.SetRow (0, aSide);
950   aLookMx.SetRow (1, anUp);
951   aLookMx.SetRow (2, -aForward);
952
953   theOutMx.InitIdentity();
954   theOutMx.Multiply (aLookMx);
955   theOutMx.Translate (-theEye);
956
957   NCollection_Mat4<Elem_t> anAxialScaleMx;
958   anAxialScaleMx.ChangeValue (0, 0) = theAxialScale.x();
959   anAxialScaleMx.ChangeValue (1, 1) = theAxialScale.y();
960   anAxialScaleMx.ChangeValue (2, 2) = theAxialScale.z();
961
962   theOutMx.Multiply (anAxialScaleMx);
963 }