0027796: Visualization - allow 3D objects with Graphic3d_TMF_2d flag
[occt.git] / src / OpenGl / OpenGl_Layer.cxx
1 // Created on: 2014-03-31
2 // Created by: Danila ULYANOV
3 // Copyright (c) 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 <OpenGl_Layer.hxx>
17
18 #include <OpenGl_BVHTreeSelector.hxx>
19 #include <OpenGl_Structure.hxx>
20 #include <OpenGl_View.hxx>
21 #include <OpenGl_Workspace.hxx>
22 #include <Graphic3d_GraphicDriver.hxx>
23
24 // =======================================================================
25 // function : OpenGl_Layer
26 // purpose  :
27 // =======================================================================
28 OpenGl_Layer::OpenGl_Layer (const Standard_Integer theNbPriorities)
29 : myArray                     (0, theNbPriorities - 1),
30   myNbStructures              (0),
31   myBVHIsLeftChildQueuedFirst (Standard_True),
32   myIsBVHPrimitivesNeedsReset (Standard_False)
33 {
34   myIsBoundingBoxNeedsReset[0] = myIsBoundingBoxNeedsReset[1] = true;
35 }
36
37 // =======================================================================
38 // function : ~OpenGl_Layer
39 // purpose  :
40 // =======================================================================
41 OpenGl_Layer::~OpenGl_Layer()
42 {
43   //
44 }
45
46 // =======================================================================
47 // function : Add
48 // purpose  :
49 // =======================================================================
50 void OpenGl_Layer::Add (const OpenGl_Structure* theStruct,
51                         const Standard_Integer  thePriority,
52                         Standard_Boolean        isForChangePriority)
53 {
54   const Standard_Integer anIndex = Min (Max (thePriority, 0), myArray.Length() - 1);
55   if (theStruct == NULL)
56   {
57     return;
58   }
59
60   myArray (anIndex).Add (theStruct);
61   if (theStruct->IsAlwaysRendered())
62   {
63     theStruct->MarkAsNotCulled();
64     if (!isForChangePriority)
65     {
66       myAlwaysRenderedMap.Add (theStruct);
67     }
68   }
69   else if (!isForChangePriority)
70   {
71     if (theStruct->TransformPersistence.Flags == Graphic3d_TMF_None)
72     {
73       myBVHPrimitives.Add (theStruct);
74     }
75     else
76     {
77       myBVHPrimitivesTrsfPers.Add (theStruct);
78     }
79   }
80   ++myNbStructures;
81 }
82
83 // =======================================================================
84 // function : Remove
85 // purpose  :
86 // =======================================================================
87 bool OpenGl_Layer::Remove (const OpenGl_Structure* theStruct,
88                            Standard_Integer&       thePriority,
89                            Standard_Boolean        isForChangePriority)
90 {
91   if (theStruct == NULL)
92   {
93     thePriority = -1;
94     return false;
95   }
96
97   const Standard_Integer aNbPriorities = myArray.Length();
98   for (Standard_Integer aPriorityIter = 0; aPriorityIter < aNbPriorities; ++aPriorityIter)
99   {
100     OpenGl_IndexedMapOfStructure& aStructures = myArray (aPriorityIter);
101
102     const Standard_Integer anIndex = aStructures.FindIndex (theStruct);
103     if (anIndex != 0)
104     {
105       aStructures.Swap (anIndex, aStructures.Size());
106       aStructures.RemoveLast();
107
108       if (!isForChangePriority)
109       {
110         if (theStruct->IsAlwaysRendered())
111         {
112           const Standard_Integer anIndex2 = myAlwaysRenderedMap.FindIndex (theStruct);
113           if (anIndex2 != 0)
114           {
115             myAlwaysRenderedMap.Swap (myAlwaysRenderedMap.Size(), anIndex2);
116             myAlwaysRenderedMap.RemoveLast();
117           }
118         }
119         else
120         {
121           if (!myBVHPrimitives.Remove (theStruct))
122           {
123             myBVHPrimitivesTrsfPers.Remove (theStruct);
124           }
125         }
126       }
127       --myNbStructures;
128       thePriority = aPriorityIter;
129       return true;
130     }
131   }
132
133   thePriority = -1;
134   return false;
135 }
136
137 // =======================================================================
138 // function : InvalidateBVHData
139 // purpose  :
140 // =======================================================================
141 void OpenGl_Layer::InvalidateBVHData() const
142 {
143   myIsBVHPrimitivesNeedsReset = Standard_True;
144 }
145
146 //! Calculate a finite bounding box of infinite object as its middle point.
147 inline Graphic3d_BndBox4f centerOfinfiniteBndBox (const Graphic3d_BndBox4f& theBndBox)
148 {
149   // bounding borders of infinite line has been calculated as own point in center of this line
150   const Graphic3d_Vec4 aDiagVec = theBndBox.CornerMax() - theBndBox.CornerMin();
151   return aDiagVec.xyz().SquareModulus() >= 500000.0f * 500000.0f
152        ? Graphic3d_BndBox4f ((theBndBox.CornerMin() + theBndBox.CornerMax()) * 0.5f)
153        : Graphic3d_BndBox4f();
154 }
155
156 //! Return true if at least one vertex coordinate out of float range.
157 inline bool isInfiniteBndBox (const Graphic3d_BndBox4f& theBndBox)
158 {
159   return Abs (theBndBox.CornerMax().x()) >= ShortRealLast()
160       || Abs (theBndBox.CornerMax().y()) >= ShortRealLast()
161       || Abs (theBndBox.CornerMax().z()) >= ShortRealLast()
162       || Abs (theBndBox.CornerMin().x()) >= ShortRealLast()
163       || Abs (theBndBox.CornerMin().y()) >= ShortRealLast()
164       || Abs (theBndBox.CornerMin().z()) >= ShortRealLast();
165 }
166
167 // =======================================================================
168 // function : BoundingBox
169 // purpose  :
170 // =======================================================================
171 Graphic3d_BndBox4f OpenGl_Layer::BoundingBox (const Standard_Integer          theViewId,
172                                               const Handle(Graphic3d_Camera)& theCamera,
173                                               const Standard_Integer          theWindowWidth,
174                                               const Standard_Integer          theWindowHeight,
175                                               const Standard_Boolean          theToIncludeAuxiliary) const
176 {
177   updateBVH();
178
179   const Standard_Integer aBoxId = !theToIncludeAuxiliary ? 0 : 1;
180   const Graphic3d_Mat4& aProjectionMat = theCamera->ProjectionMatrixF();
181   const Graphic3d_Mat4& aWorldViewMat  = theCamera->OrientationMatrixF();
182   if (myIsBoundingBoxNeedsReset[aBoxId])
183   {
184     // Recompute layer bounding box
185     myBoundingBox[aBoxId].Clear();
186
187     const Standard_Integer aNbPriorities = myArray.Length();
188     for (Standard_Integer aPriorityIter = 0; aPriorityIter < aNbPriorities; ++aPriorityIter)
189     {
190       const OpenGl_IndexedMapOfStructure& aStructures = myArray (aPriorityIter);
191       for (Standard_Integer aStructIdx = 1; aStructIdx <= aStructures.Size(); ++aStructIdx)
192       {
193         const OpenGl_Structure* aStructure = aStructures.FindKey (aStructIdx);
194         if (!aStructure->IsVisible (theViewId))
195         {
196           continue;
197         }
198
199         // "FitAll" operation ignores object with transform persistence parameter
200         // but adds transform persistence point in a bounding box of layer (only zoom pers. objects).
201         if (aStructure->TransformPersistence.Flags != Graphic3d_TMF_None)
202         {
203           if (!theToIncludeAuxiliary
204            && (aStructure->TransformPersistence.Flags & Graphic3d_TMF_ZoomPers) != 0)
205           {
206             BVH_Vec4f aTPPoint (static_cast<float> (aStructure->TransformPersistence.Point.x()),
207                                 static_cast<float> (aStructure->TransformPersistence.Point.y()),
208                                 static_cast<float> (aStructure->TransformPersistence.Point.z()),
209                                 1.0f);
210
211             myBoundingBox[aBoxId].Combine (aTPPoint);
212             continue;
213           }
214           // Panning and 2d persistence apply changes to projection or/and its translation components.
215           // It makes them incompatible with z-fitting algorithm. Ignored by now.
216           else if (!theToIncludeAuxiliary
217                 || (aStructure->TransformPersistence.Flags & (Graphic3d_TMF_2d | Graphic3d_TMF_PanPers | Graphic3d_TMF_TriedronPers)) != 0)
218           {
219             continue;
220           }
221         }
222
223         Graphic3d_BndBox4f aBox = aStructure->BoundingBox();
224         if (!aBox.IsValid())
225         {
226           continue;
227         }
228
229         if (aStructure->IsInfinite
230         && !theToIncludeAuxiliary)
231         {
232           // include center of infinite object
233           aBox = centerOfinfiniteBndBox (aBox);
234         }
235
236         if (aStructure->TransformPersistence.Flags != Graphic3d_TMF_None)
237         {
238           aStructure->TransformPersistence.Apply (theCamera,
239                                                   aProjectionMat,
240                                                   aWorldViewMat,
241                                                   theWindowWidth,
242                                                   theWindowHeight,
243                                                   aBox);
244         }
245
246         // skip too big boxes to prevent float overflow at camera parameters calculation
247         if (!isInfiniteBndBox (aBox))
248         {
249           myBoundingBox[aBoxId].Combine (aBox);
250         }
251       }
252     }
253
254     myIsBoundingBoxNeedsReset[aBoxId] = false;
255   }
256
257   if (!theToIncludeAuxiliary
258     || myAlwaysRenderedMap.IsEmpty())
259   {
260     return myBoundingBox[aBoxId];
261   }
262
263   // add transformation-persistent objects which depend on camera position (and thus can not be cached) for operations like Z-fit
264   Graphic3d_BndBox4f aResBox = myBoundingBox[aBoxId];
265   for (NCollection_IndexedMap<const OpenGl_Structure*>::Iterator aStructIter (myAlwaysRenderedMap); aStructIter.More(); aStructIter.Next())
266   {
267     const OpenGl_Structure* aStructure = aStructIter.Value();
268     if (!aStructure->IsVisible (theViewId))
269     {
270       continue;
271     }
272     else if ((aStructure->TransformPersistence.Flags & (Graphic3d_TMF_TriedronPers | Graphic3d_TMF_2d)) == 0)
273     {
274       continue;
275     }
276
277     Graphic3d_BndBox4f aBox = aStructure->BoundingBox();
278     if (!aBox.IsValid())
279     {
280       continue;
281     }
282
283     aStructure->TransformPersistence.Apply (theCamera,
284                                             aProjectionMat,
285                                             aWorldViewMat,
286                                             theWindowWidth,
287                                             theWindowHeight,
288                                             aBox);
289     if (!isInfiniteBndBox (aBox))
290     {
291       aResBox.Combine (aBox);
292     }
293   }
294
295   return aResBox;
296 }
297
298 // =======================================================================
299 // function : considerZoomPersistenceObjects
300 // purpose  :
301 // =======================================================================
302 Standard_Real OpenGl_Layer::considerZoomPersistenceObjects (const Standard_Integer          theViewId,
303                                                             const Handle(Graphic3d_Camera)& theCamera,
304                                                             Standard_Integer                theWindowWidth,
305                                                             Standard_Integer                theWindowHeight) const
306 {
307   if (NbOfTransformPersistenceObjects() == 0)
308   {
309     return 1.0;
310   }
311
312   const Standard_Integer aNbPriorities  = myArray.Length();
313   const Graphic3d_Mat4&  aProjectionMat = theCamera->ProjectionMatrixF();
314   const Graphic3d_Mat4&  aWorldViewMat  = theCamera->OrientationMatrixF();
315   Standard_Real          aMaxCoef       = -std::numeric_limits<double>::max();
316
317   for (Standard_Integer aPriorityIter = 0; aPriorityIter < aNbPriorities; ++aPriorityIter)
318   {
319     const OpenGl_IndexedMapOfStructure& aStructures = myArray (aPriorityIter);
320     for (Standard_Integer aStructIdx = 1; aStructIdx <= aStructures.Size(); ++aStructIdx)
321     {
322       OpenGl_Structure* aStructure = const_cast<OpenGl_Structure*> (aStructures.FindKey (aStructIdx));
323       if (!aStructure->IsVisible (theViewId)
324        || (aStructure->TransformPersistence.Flags & Graphic3d_TMF_ZoomPers) == 0)
325       {
326         continue;
327       }
328
329       Graphic3d_BndBox4f aBox = aStructure->BoundingBox();
330       if (!aBox.IsValid())
331       {
332         continue;
333       }
334
335       aStructure->TransformPersistence.Apply (theCamera, aProjectionMat, aWorldViewMat, theWindowWidth, theWindowHeight, aBox);
336
337       const BVH_Vec4f&       aCornerMin           = aBox.CornerMin();
338       const BVH_Vec4f&       aCornerMax           = aBox.CornerMax();
339       const Standard_Integer aNbOfPoints          = 8;
340       const gp_Pnt           aPoints[aNbOfPoints] = { gp_Pnt (aCornerMin.x(), aCornerMin.y(), aCornerMin.z()),
341                                                       gp_Pnt (aCornerMin.x(), aCornerMin.y(), aCornerMax.z()),
342                                                       gp_Pnt (aCornerMin.x(), aCornerMax.y(), aCornerMin.z()),
343                                                       gp_Pnt (aCornerMin.x(), aCornerMax.y(), aCornerMax.z()),
344                                                       gp_Pnt (aCornerMax.x(), aCornerMin.y(), aCornerMin.z()),
345                                                       gp_Pnt (aCornerMax.x(), aCornerMin.y(), aCornerMax.z()),
346                                                       gp_Pnt (aCornerMax.x(), aCornerMax.y(), aCornerMin.z()),
347                                                       gp_Pnt (aCornerMax.x(), aCornerMax.y(), aCornerMax.z()) };
348       gp_Pnt aConvertedPoints[aNbOfPoints];
349       Standard_Real aConvertedMinX =  std::numeric_limits<double>::max();
350       Standard_Real aConvertedMaxX = -std::numeric_limits<double>::max();
351       Standard_Real aConvertedMinY =  std::numeric_limits<double>::max();
352       Standard_Real aConvertedMaxY = -std::numeric_limits<double>::max();
353       for (Standard_Integer anIdx = 0; anIdx < aNbOfPoints; ++anIdx)
354       {
355         aConvertedPoints[anIdx] = theCamera->Project (aPoints[anIdx]);
356
357         aConvertedMinX          = Min (aConvertedMinX, aConvertedPoints[anIdx].X());
358         aConvertedMaxX          = Max (aConvertedMaxX, aConvertedPoints[anIdx].X());
359
360         aConvertedMinY          = Min (aConvertedMinY, aConvertedPoints[anIdx].Y());
361         aConvertedMaxY          = Max (aConvertedMaxY, aConvertedPoints[anIdx].Y());
362       }
363
364       const Standard_Boolean isBigObject  = (Abs (aConvertedMaxX - aConvertedMinX) > 2.0)  // width  of zoom pers. object greater than width  of window
365                                          || (Abs (aConvertedMaxY - aConvertedMinY) > 2.0); // height of zoom pers. object greater than height of window
366       const Standard_Boolean isAlreadyInScreen = (aConvertedMinX > -1.0 && aConvertedMinX < 1.0)
367                                               && (aConvertedMaxX > -1.0 && aConvertedMaxX < 1.0)
368                                               && (aConvertedMinY > -1.0 && aConvertedMinY < 1.0)
369                                               && (aConvertedMaxY > -1.0 && aConvertedMaxY < 1.0);
370       if (isBigObject || isAlreadyInScreen)
371       {
372         continue;
373       }
374
375       const gp_Pnt aTPPoint (aStructure->TransformPersistence.Point.x(),
376                              aStructure->TransformPersistence.Point.y(),
377                              aStructure->TransformPersistence.Point.z());
378       gp_Pnt aConvertedTPPoint = theCamera->Project (aTPPoint);
379       aConvertedTPPoint.SetZ (0.0);
380
381       if (aConvertedTPPoint.Coord().Modulus() < Precision::Confusion())
382       {
383         continue;
384       }
385
386       Standard_Real aShiftX = 0.0;
387       if (aConvertedMinX < -1.0)
388       {
389         aShiftX = ((aConvertedMaxX < -1.0) ? (-(1.0 + aConvertedMaxX) + (aConvertedMaxX - aConvertedMinX)) : -(1.0 + aConvertedMinX));
390       }
391       else if (aConvertedMaxX > 1.0)
392       {
393         aShiftX = ((aConvertedMinX > 1.0) ? ((aConvertedMinX - 1.0) + (aConvertedMaxX - aConvertedMinX)) : (aConvertedMaxX - 1.0));
394       }
395
396       Standard_Real aShiftY = 0.0;
397       if (aConvertedMinY < -1.0)
398       {
399         aShiftY = ((aConvertedMaxY < -1.0) ? (-(1.0 + aConvertedMaxY) + (aConvertedMaxY - aConvertedMinY)) : -(1.0 + aConvertedMinY));
400       }
401       else if (aConvertedMaxY > 1.0)
402       {
403         aShiftY = ((aConvertedMinY > 1.0) ? ((aConvertedMinY - 1.0) + (aConvertedMaxY - aConvertedMinY)) : (aConvertedMaxY - 1.0));
404       }
405
406       const Standard_Real aDifX = Abs (aConvertedTPPoint.X()) - aShiftX;
407       const Standard_Real aDifY = Abs (aConvertedTPPoint.Y()) - aShiftY;
408       if (aDifX > Precision::Confusion())
409       {
410         aMaxCoef = Max (aMaxCoef, Abs (aConvertedTPPoint.X()) / aDifX);
411       }
412       if (aDifY > Precision::Confusion())
413       {
414         aMaxCoef = Max (aMaxCoef, Abs (aConvertedTPPoint.Y()) / aDifY);
415       }
416     }
417   }
418
419   return (aMaxCoef > 0.0) ? aMaxCoef : 1.0;
420 }
421
422 // =======================================================================
423 // function : renderAll
424 // purpose  :
425 // =======================================================================
426 void OpenGl_Layer::renderAll (const Handle(OpenGl_Workspace)& theWorkspace) const
427 {
428   const Standard_Integer aNbPriorities = myArray.Length();
429   const Standard_Integer aViewId       = theWorkspace->View()->Identification();
430   for (Standard_Integer aPriorityIter = 0; aPriorityIter < aNbPriorities; ++aPriorityIter)
431   {
432     const OpenGl_IndexedMapOfStructure& aStructures = myArray (aPriorityIter);
433     for (Standard_Integer aStructIdx = 1; aStructIdx <= aStructures.Size(); ++aStructIdx)
434     {
435       const OpenGl_Structure* aStruct = aStructures.FindKey (aStructIdx);
436       if (!aStruct->IsVisible())
437       {
438         continue;
439       }
440       else if (!aStruct->ViewAffinity.IsNull()
441             && !aStruct->ViewAffinity->IsVisible (aViewId))
442       {
443         continue;
444       }
445
446       aStruct->Render (theWorkspace);
447     }
448   }
449 }
450
451 // =======================================================================
452 // function : updateBVH
453 // purpose  :
454 // =======================================================================
455 void OpenGl_Layer::updateBVH() const
456 {
457   if (!myIsBVHPrimitivesNeedsReset)
458   {
459     return;
460   }
461
462   myBVHPrimitives.Clear();
463   myBVHPrimitivesTrsfPers.Clear();
464   myAlwaysRenderedMap.Clear();
465   myIsBVHPrimitivesNeedsReset = Standard_False;
466   for (Standard_Integer aPriorityIdx = 0, aNbPriorities = myArray.Length(); aPriorityIdx < aNbPriorities; ++aPriorityIdx)
467   {
468     for (OpenGl_IndexedMapOfStructure::Iterator aStructIter (myArray (aPriorityIdx)); aStructIter.More(); aStructIter.Next())
469     {
470       const OpenGl_Structure* aStruct = aStructIter.Value();
471       if (aStruct->IsAlwaysRendered())
472       {
473         aStruct->MarkAsNotCulled();
474         myAlwaysRenderedMap.Add (aStruct);
475       }
476       else if (aStruct->TransformPersistence.Flags == Graphic3d_TMF_None)
477       {
478         myBVHPrimitives.Add (aStruct);
479       }
480       else
481       {
482         myBVHPrimitivesTrsfPers.Add (aStruct);
483       }
484     }
485   }
486 }
487
488 // =======================================================================
489 // function : renderTraverse
490 // purpose  :
491 // =======================================================================
492 void OpenGl_Layer::renderTraverse (const Handle(OpenGl_Workspace)& theWorkspace) const
493 {
494   updateBVH();
495
496   OpenGl_BVHTreeSelector& aSelector = theWorkspace->View()->BVHTreeSelector();
497   traverse (aSelector);
498
499   const Standard_Integer aNbPriorities = myArray.Length();
500   const Standard_Integer aViewId       = theWorkspace->View()->Identification();
501   for (Standard_Integer aPriorityIter = 0; aPriorityIter < aNbPriorities; ++aPriorityIter)
502   {
503     const OpenGl_IndexedMapOfStructure& aStructures = myArray (aPriorityIter);
504     for (Standard_Integer aStructIdx = 1; aStructIdx <= aStructures.Size(); ++aStructIdx)
505     {
506       const OpenGl_Structure* aStruct = aStructures.FindKey (aStructIdx);
507       if (aStruct->IsCulled()
508       || !aStruct->IsVisible (aViewId))
509       {
510         continue;
511       }
512
513       aStruct->Render (theWorkspace);
514       aStruct->ResetCullingStatus();
515     }
516   }
517 }
518
519 // =======================================================================
520 // function : traverse
521 // purpose  :
522 // =======================================================================
523 void OpenGl_Layer::traverse (OpenGl_BVHTreeSelector& theSelector) const
524 {
525   // handle a case when all objects are infinite
526   if (myBVHPrimitives        .Size() == 0
527    && myBVHPrimitivesTrsfPers.Size() == 0)
528     return;
529
530   theSelector.CacheClipPtsProjections();
531
532   NCollection_Handle<BVH_Tree<Standard_ShortReal, 4> > aBVHTree;
533
534   for (Standard_Integer aBVHTreeIdx = 0; aBVHTreeIdx < 2; ++aBVHTreeIdx)
535   {
536     const Standard_Boolean isTrsfPers = aBVHTreeIdx == 1;
537     if (isTrsfPers)
538     {
539       if (myBVHPrimitivesTrsfPers.Size() == 0)
540         continue;
541
542       const OpenGl_Mat4& aProjection                = theSelector.ProjectionMatrix();
543       const OpenGl_Mat4& aWorldView                 = theSelector.WorldViewMatrix();
544       const Graphic3d_WorldViewProjState& aWVPState = theSelector.WorldViewProjState();
545       const Standard_Integer aViewportWidth         = theSelector.ViewportWidth();
546       const Standard_Integer aViewportHeight        = theSelector.ViewportHeight();
547
548       aBVHTree = myBVHPrimitivesTrsfPers.BVH (theSelector.Camera(), aProjection, aWorldView, aViewportWidth, aViewportHeight, aWVPState);
549     }
550     else
551     {
552       if (myBVHPrimitives.Size() == 0)
553         continue;
554
555       aBVHTree = myBVHPrimitives.BVH();
556     }
557
558     Standard_Integer aNode = 0; // a root node
559
560     if (!theSelector.Intersect (aBVHTree->MinPoint (0),
561                                 aBVHTree->MaxPoint (0)))
562     {
563       continue;
564     }
565
566     Standard_Integer aStack[32];
567     Standard_Integer aHead = -1;
568     for (;;)
569     {
570       if (!aBVHTree->IsOuter (aNode))
571       {
572         const Standard_Integer aLeftChildIdx  = aBVHTree->Child<0> (aNode);
573         const Standard_Integer aRightChildIdx = aBVHTree->Child<1> (aNode);
574         const Standard_Boolean isLeftChildIn  = theSelector.Intersect (aBVHTree->MinPoint (aLeftChildIdx),
575                                                                        aBVHTree->MaxPoint (aLeftChildIdx));
576         const Standard_Boolean isRightChildIn = theSelector.Intersect (aBVHTree->MinPoint (aRightChildIdx),
577                                                                        aBVHTree->MaxPoint (aRightChildIdx));
578         if (isLeftChildIn
579          && isRightChildIn)
580         {
581           aNode = myBVHIsLeftChildQueuedFirst ? aLeftChildIdx : aRightChildIdx;
582           aStack[++aHead] = myBVHIsLeftChildQueuedFirst ? aRightChildIdx : aLeftChildIdx;
583           myBVHIsLeftChildQueuedFirst = !myBVHIsLeftChildQueuedFirst;
584         }
585         else if (isLeftChildIn
586               || isRightChildIn)
587         {
588           aNode = isLeftChildIn ? aLeftChildIdx : aRightChildIdx;
589         }
590         else
591         {
592           if (aHead < 0)
593           {
594             break;
595           }
596
597           aNode = aStack[aHead--];
598         }
599       }
600       else
601       {
602         Standard_Integer aIdx = aBVHTree->BegPrimitive (aNode);
603         const OpenGl_Structure* aStruct =
604           isTrsfPers ? myBVHPrimitivesTrsfPers.GetStructureById (aIdx)
605                      : myBVHPrimitives.GetStructureById (aIdx);
606         aStruct->MarkAsNotCulled();
607         if (aHead < 0)
608         {
609           break;
610         }
611
612         aNode = aStack[aHead--];
613       }
614     }
615   }
616 }
617
618 // =======================================================================
619 // function : Append
620 // purpose  :
621 // =======================================================================
622 Standard_Boolean OpenGl_Layer::Append (const OpenGl_Layer& theOther)
623 {
624   // the source priority list shouldn't have more priorities
625   const Standard_Integer aNbPriorities = theOther.NbPriorities();
626   if (aNbPriorities > NbPriorities())
627   {
628     return Standard_False;
629   }
630
631   // add all structures to destination priority list
632   for (Standard_Integer aPriorityIter = 0; aPriorityIter < aNbPriorities; ++aPriorityIter)
633   {
634     const OpenGl_IndexedMapOfStructure& aStructures = theOther.myArray (aPriorityIter);
635     for (Standard_Integer aStructIdx = 1; aStructIdx <= aStructures.Size(); ++aStructIdx)
636     {
637       Add (aStructures.FindKey (aStructIdx), aPriorityIter);
638     }
639   }
640
641   return Standard_True;
642 }
643
644 //=======================================================================
645 //function : Render
646 //purpose  :
647 //=======================================================================
648 void OpenGl_Layer::Render (const Handle(OpenGl_Workspace)&   theWorkspace,
649                            const OpenGl_GlobalLayerSettings& theDefaultSettings) const
650 {
651   Graphic3d_PolygonOffset anAppliedOffsetParams = theWorkspace->AppliedPolygonOffset();
652
653   // separate depth buffers
654   if (IsSettingEnabled (Graphic3d_ZLayerDepthClear))
655   {
656     glClear (GL_DEPTH_BUFFER_BIT);
657   }
658
659   // handle depth test
660   if (IsSettingEnabled (Graphic3d_ZLayerDepthTest))
661   {
662     // assuming depth test is enabled by default
663     glDepthFunc (theDefaultSettings.DepthFunc);
664   }
665   else
666   {
667     glDepthFunc (GL_ALWAYS);
668   }
669
670   // save environment texture
671   Handle(OpenGl_Texture) anEnvironmentTexture = theWorkspace->EnvironmentTexture();
672   if (!myLayerSettings.UseEnvironmentTexture)
673   {
674     theWorkspace->SetEnvironmentTexture (Handle(OpenGl_Texture)());
675   }
676
677   // handle depth offset
678   if (IsSettingEnabled (Graphic3d_ZLayerDepthOffset))
679   {
680     Graphic3d_PolygonOffset aLayerPolygonOffset;
681     aLayerPolygonOffset.Mode   = Aspect_POM_Fill;
682     aLayerPolygonOffset.Factor = myLayerSettings.DepthOffsetFactor;
683     aLayerPolygonOffset.Units  = myLayerSettings.DepthOffsetUnits;
684     theWorkspace->SetPolygonOffset (aLayerPolygonOffset);
685   }
686   else
687   {
688     theWorkspace->SetPolygonOffset (anAppliedOffsetParams);
689   }
690
691   // handle depth write
692   theWorkspace->UseDepthWrite() = IsSettingEnabled (Graphic3d_ZLayerDepthWrite);
693   glDepthMask (theWorkspace->UseDepthWrite() ? GL_TRUE : GL_FALSE);
694
695   // render priority list
696   theWorkspace->IsCullingEnabled() ? renderTraverse (theWorkspace) : renderAll (theWorkspace);
697
698   // always restore polygon offset between layers rendering
699   theWorkspace->SetPolygonOffset (anAppliedOffsetParams);
700
701   // restore environment texture
702   if (!myLayerSettings.UseEnvironmentTexture)
703   {
704     theWorkspace->SetEnvironmentTexture (anEnvironmentTexture);
705   }
706 }