330ce25391e8b00c43399970d413ef0250e9cc91
[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   const Standard_Integer aBoxId = !theToIncludeAuxiliary ? 0 : 1;
178   const Graphic3d_Mat4& aProjectionMat = theCamera->ProjectionMatrixF();
179   const Graphic3d_Mat4& aWorldViewMat  = theCamera->OrientationMatrixF();
180   if (myIsBoundingBoxNeedsReset[aBoxId])
181   {
182     // Recompute layer bounding box
183     myBoundingBox[aBoxId].Clear();
184
185     const Standard_Integer aNbPriorities = myArray.Length();
186     for (Standard_Integer aPriorityIter = 0; aPriorityIter < aNbPriorities; ++aPriorityIter)
187     {
188       const OpenGl_IndexedMapOfStructure& aStructures = myArray (aPriorityIter);
189       for (Standard_Integer aStructIdx = 1; aStructIdx <= aStructures.Size(); ++aStructIdx)
190       {
191         const OpenGl_Structure* aStructure = aStructures.FindKey (aStructIdx);
192         if (!aStructure->IsVisible (theViewId))
193         {
194           continue;
195         }
196
197         // "FitAll" operation ignores object with transform persistence parameter
198         // but adds transform persistence point in a bounding box of layer (only zoom pers. objects).
199         if (aStructure->TransformPersistence.Flags != Graphic3d_TMF_None)
200         {
201           if (!theToIncludeAuxiliary
202            && (aStructure->TransformPersistence.Flags & Graphic3d_TMF_ZoomPers) != 0)
203           {
204             BVH_Vec4f aTPPoint (static_cast<float> (aStructure->TransformPersistence.Point.x()),
205                                 static_cast<float> (aStructure->TransformPersistence.Point.y()),
206                                 static_cast<float> (aStructure->TransformPersistence.Point.z()),
207                                 1.0f);
208
209             myBoundingBox[aBoxId].Combine (aTPPoint);
210             continue;
211           }
212           // Panning and 2d persistence apply changes to projection or/and its translation components.
213           // It makes them incompatible with z-fitting algorithm. Ignored by now.
214           else if (!theToIncludeAuxiliary
215                 || (aStructure->TransformPersistence.Flags & (Graphic3d_TMF_2d | Graphic3d_TMF_PanPers | Graphic3d_TMF_TriedronPers)) != 0)
216           {
217             continue;
218           }
219         }
220
221         Graphic3d_BndBox4f aBox = aStructure->BoundingBox();
222         if (!aBox.IsValid())
223         {
224           continue;
225         }
226
227         if (aStructure->IsInfinite
228         && !theToIncludeAuxiliary)
229         {
230           // include center of infinite object
231           aBox = centerOfinfiniteBndBox (aBox);
232         }
233
234         if (aStructure->TransformPersistence.Flags != Graphic3d_TMF_None)
235         {
236           aStructure->TransformPersistence.Apply (theCamera,
237                                                   aProjectionMat,
238                                                   aWorldViewMat,
239                                                   theWindowWidth,
240                                                   theWindowHeight,
241                                                   aBox);
242         }
243
244         // skip too big boxes to prevent float overflow at camera parameters calculation
245         if (!isInfiniteBndBox (aBox))
246         {
247           myBoundingBox[aBoxId].Combine (aBox);
248         }
249       }
250     }
251
252     myIsBoundingBoxNeedsReset[aBoxId] = false;
253   }
254
255   if (!theToIncludeAuxiliary
256     || myAlwaysRenderedMap.IsEmpty())
257   {
258     return myBoundingBox[aBoxId];
259   }
260
261   // add transformation-persistent objects which depend on camera position (and thus can not be cached) for operations like Z-fit
262   Graphic3d_BndBox4f aResBox = myBoundingBox[aBoxId];
263   for (NCollection_IndexedMap<const OpenGl_Structure*>::Iterator aStructIter (myAlwaysRenderedMap); aStructIter.More(); aStructIter.Next())
264   {
265     const OpenGl_Structure* aStructure = aStructIter.Value();
266     if (!aStructure->IsVisible (theViewId))
267     {
268       continue;
269     }
270     else if ((aStructure->TransformPersistence.Flags & Graphic3d_TMF_TriedronPers) == 0)
271     {
272       continue;
273     }
274
275     Graphic3d_BndBox4f aBox = aStructure->BoundingBox();
276     if (!aBox.IsValid())
277     {
278       continue;
279     }
280
281     aStructure->TransformPersistence.Apply (theCamera,
282                                             aProjectionMat,
283                                             aWorldViewMat,
284                                             theWindowWidth,
285                                             theWindowHeight,
286                                             aBox);
287     if (!isInfiniteBndBox (aBox))
288     {
289       aResBox.Combine (aBox);
290     }
291   }
292
293   return aResBox;
294 }
295
296 // =======================================================================
297 // function : considerZoomPersistenceObjects
298 // purpose  :
299 // =======================================================================
300 Standard_Real OpenGl_Layer::considerZoomPersistenceObjects (const Standard_Integer          theViewId,
301                                                             const Handle(Graphic3d_Camera)& theCamera,
302                                                             Standard_Integer                theWindowWidth,
303                                                             Standard_Integer                theWindowHeight) const
304 {
305   if (NbOfTransformPersistenceObjects() == 0)
306   {
307     return 1.0;
308   }
309
310   const Standard_Integer aNbPriorities  = myArray.Length();
311   const Graphic3d_Mat4&  aProjectionMat = theCamera->ProjectionMatrixF();
312   const Graphic3d_Mat4&  aWorldViewMat  = theCamera->OrientationMatrixF();
313   Standard_Real          aMaxCoef       = -std::numeric_limits<double>::max();
314
315   for (Standard_Integer aPriorityIter = 0; aPriorityIter < aNbPriorities; ++aPriorityIter)
316   {
317     const OpenGl_IndexedMapOfStructure& aStructures = myArray (aPriorityIter);
318     for (Standard_Integer aStructIdx = 1; aStructIdx <= aStructures.Size(); ++aStructIdx)
319     {
320       OpenGl_Structure* aStructure = const_cast<OpenGl_Structure*> (aStructures.FindKey (aStructIdx));
321       if (!aStructure->IsVisible (theViewId)
322        || (aStructure->TransformPersistence.Flags & Graphic3d_TMF_ZoomPers) == 0)
323       {
324         continue;
325       }
326
327       Graphic3d_BndBox4f aBox = aStructure->BoundingBox();
328       if (!aBox.IsValid())
329       {
330         continue;
331       }
332
333       aStructure->TransformPersistence.Apply (theCamera, aProjectionMat, aWorldViewMat, theWindowWidth, theWindowHeight, aBox);
334
335       const BVH_Vec4f&       aCornerMin           = aBox.CornerMin();
336       const BVH_Vec4f&       aCornerMax           = aBox.CornerMax();
337       const Standard_Integer aNbOfPoints          = 8;
338       const gp_Pnt           aPoints[aNbOfPoints] = { gp_Pnt (aCornerMin.x(), aCornerMin.y(), aCornerMin.z()),
339                                                       gp_Pnt (aCornerMin.x(), aCornerMin.y(), aCornerMax.z()),
340                                                       gp_Pnt (aCornerMin.x(), aCornerMax.y(), aCornerMin.z()),
341                                                       gp_Pnt (aCornerMin.x(), aCornerMax.y(), aCornerMax.z()),
342                                                       gp_Pnt (aCornerMax.x(), aCornerMin.y(), aCornerMin.z()),
343                                                       gp_Pnt (aCornerMax.x(), aCornerMin.y(), aCornerMax.z()),
344                                                       gp_Pnt (aCornerMax.x(), aCornerMax.y(), aCornerMin.z()),
345                                                       gp_Pnt (aCornerMax.x(), aCornerMax.y(), aCornerMax.z()) };
346       gp_Pnt aConvertedPoints[aNbOfPoints];
347       Standard_Real aConvertedMinX =  std::numeric_limits<double>::max();
348       Standard_Real aConvertedMaxX = -std::numeric_limits<double>::max();
349       Standard_Real aConvertedMinY =  std::numeric_limits<double>::max();
350       Standard_Real aConvertedMaxY = -std::numeric_limits<double>::max();
351       for (Standard_Integer anIdx = 0; anIdx < aNbOfPoints; ++anIdx)
352       {
353         aConvertedPoints[anIdx] = theCamera->Project (aPoints[anIdx]);
354
355         aConvertedMinX          = Min (aConvertedMinX, aConvertedPoints[anIdx].X());
356         aConvertedMaxX          = Max (aConvertedMaxX, aConvertedPoints[anIdx].X());
357
358         aConvertedMinY          = Min (aConvertedMinY, aConvertedPoints[anIdx].Y());
359         aConvertedMaxY          = Max (aConvertedMaxY, aConvertedPoints[anIdx].Y());
360       }
361
362       const Standard_Boolean isBigObject  = (Abs (aConvertedMaxX - aConvertedMinX) > 2.0)  // width  of zoom pers. object greater than width  of window
363                                          || (Abs (aConvertedMaxY - aConvertedMinY) > 2.0); // height of zoom pers. object greater than height of window
364       const Standard_Boolean isAlreadyInScreen = (aConvertedMinX > -1.0 && aConvertedMinX < 1.0)
365                                               && (aConvertedMaxX > -1.0 && aConvertedMaxX < 1.0)
366                                               && (aConvertedMinY > -1.0 && aConvertedMinY < 1.0)
367                                               && (aConvertedMaxY > -1.0 && aConvertedMaxY < 1.0);
368       if (isBigObject || isAlreadyInScreen)
369       {
370         continue;
371       }
372
373       const gp_Pnt aTPPoint (aStructure->TransformPersistence.Point.x(),
374                              aStructure->TransformPersistence.Point.y(),
375                              aStructure->TransformPersistence.Point.z());
376       gp_Pnt aConvertedTPPoint = theCamera->Project (aTPPoint);
377       aConvertedTPPoint.SetZ (0.0);
378
379       if (aConvertedTPPoint.Coord().Modulus() < Precision::Confusion())
380       {
381         continue;
382       }
383
384       Standard_Real aShiftX = 0.0;
385       if (aConvertedMinX < -1.0)
386       {
387         aShiftX = ((aConvertedMaxX < -1.0) ? (-(1.0 + aConvertedMaxX) + (aConvertedMaxX - aConvertedMinX)) : -(1.0 + aConvertedMinX));
388       }
389       else if (aConvertedMaxX > 1.0)
390       {
391         aShiftX = ((aConvertedMinX > 1.0) ? ((aConvertedMinX - 1.0) + (aConvertedMaxX - aConvertedMinX)) : (aConvertedMaxX - 1.0));
392       }
393
394       Standard_Real aShiftY = 0.0;
395       if (aConvertedMinY < -1.0)
396       {
397         aShiftY = ((aConvertedMaxY < -1.0) ? (-(1.0 + aConvertedMaxY) + (aConvertedMaxY - aConvertedMinY)) : -(1.0 + aConvertedMinY));
398       }
399       else if (aConvertedMaxY > 1.0)
400       {
401         aShiftY = ((aConvertedMinY > 1.0) ? ((aConvertedMinY - 1.0) + (aConvertedMaxY - aConvertedMinY)) : (aConvertedMaxY - 1.0));
402       }
403
404       const Standard_Real aDifX = Abs (aConvertedTPPoint.X()) - aShiftX;
405       const Standard_Real aDifY = Abs (aConvertedTPPoint.Y()) - aShiftY;
406       if (aDifX > Precision::Confusion())
407       {
408         aMaxCoef = Max (aMaxCoef, Abs (aConvertedTPPoint.X()) / aDifX);
409       }
410       if (aDifY > Precision::Confusion())
411       {
412         aMaxCoef = Max (aMaxCoef, Abs (aConvertedTPPoint.Y()) / aDifY);
413       }
414     }
415   }
416
417   return (aMaxCoef > 0.0) ? aMaxCoef : 1.0;
418 }
419
420 // =======================================================================
421 // function : renderAll
422 // purpose  :
423 // =======================================================================
424 void OpenGl_Layer::renderAll (const Handle(OpenGl_Workspace)& theWorkspace) const
425 {
426   const Standard_Integer aNbPriorities = myArray.Length();
427   const Standard_Integer aViewId       = theWorkspace->View()->Identification();
428   for (Standard_Integer aPriorityIter = 0; aPriorityIter < aNbPriorities; ++aPriorityIter)
429   {
430     const OpenGl_IndexedMapOfStructure& aStructures = myArray (aPriorityIter);
431     for (Standard_Integer aStructIdx = 1; aStructIdx <= aStructures.Size(); ++aStructIdx)
432     {
433       const OpenGl_Structure* aStruct = aStructures.FindKey (aStructIdx);
434       if (!aStruct->IsVisible())
435       {
436         continue;
437       }
438       else if (!aStruct->ViewAffinity.IsNull()
439             && !aStruct->ViewAffinity->IsVisible (aViewId))
440       {
441         continue;
442       }
443
444       aStruct->Render (theWorkspace);
445     }
446   }
447 }
448
449 // =======================================================================
450 // function : updateBVH
451 // purpose  :
452 // =======================================================================
453 void OpenGl_Layer::updateBVH() const
454 {
455   if (!myIsBVHPrimitivesNeedsReset)
456   {
457     return;
458   }
459
460   myBVHPrimitives.Clear();
461   myBVHPrimitivesTrsfPers.Clear();
462   myIsBVHPrimitivesNeedsReset = Standard_False;
463   for (Standard_Integer aPriorityIdx = 0, aNbPriorities = myArray.Length(); aPriorityIdx < aNbPriorities; ++aPriorityIdx)
464   {
465     for (OpenGl_IndexedMapOfStructure::Iterator aStructIter (myArray (aPriorityIdx)); aStructIter.More(); aStructIter.Next())
466     {
467       const OpenGl_Structure* aStruct = aStructIter.Value();
468       if (aStruct->IsAlwaysRendered())
469       {
470         continue;
471       }
472
473       if (aStruct->TransformPersistence.Flags == Graphic3d_TMF_None)
474       {
475         myBVHPrimitives.Add (aStruct);
476       }
477       else
478       {
479         myBVHPrimitivesTrsfPers.Add (aStruct);
480       }
481     }
482   }
483 }
484
485 // =======================================================================
486 // function : renderTraverse
487 // purpose  :
488 // =======================================================================
489 void OpenGl_Layer::renderTraverse (const Handle(OpenGl_Workspace)& theWorkspace) const
490 {
491   updateBVH();
492
493   OpenGl_BVHTreeSelector& aSelector = theWorkspace->View()->BVHTreeSelector();
494   traverse (aSelector);
495
496   const Standard_Integer aNbPriorities = myArray.Length();
497   const Standard_Integer aViewId       = theWorkspace->View()->Identification();
498   for (Standard_Integer aPriorityIter = 0; aPriorityIter < aNbPriorities; ++aPriorityIter)
499   {
500     const OpenGl_IndexedMapOfStructure& aStructures = myArray (aPriorityIter);
501     for (Standard_Integer aStructIdx = 1; aStructIdx <= aStructures.Size(); ++aStructIdx)
502     {
503       const OpenGl_Structure* aStruct = aStructures.FindKey (aStructIdx);
504       if (aStruct->IsCulled()
505       || !aStruct->IsVisible (aViewId))
506       {
507         continue;
508       }
509
510       aStruct->Render (theWorkspace);
511       aStruct->ResetCullingStatus();
512     }
513   }
514 }
515
516 // =======================================================================
517 // function : traverse
518 // purpose  :
519 // =======================================================================
520 void OpenGl_Layer::traverse (OpenGl_BVHTreeSelector& theSelector) const
521 {
522   // handle a case when all objects are infinite
523   if (myBVHPrimitives        .Size() == 0
524    && myBVHPrimitivesTrsfPers.Size() == 0)
525     return;
526
527   theSelector.CacheClipPtsProjections();
528
529   NCollection_Handle<BVH_Tree<Standard_ShortReal, 4> > aBVHTree;
530
531   for (Standard_Integer aBVHTreeIdx = 0; aBVHTreeIdx < 2; ++aBVHTreeIdx)
532   {
533     const Standard_Boolean isTrsfPers = aBVHTreeIdx == 1;
534     if (isTrsfPers)
535     {
536       if (myBVHPrimitivesTrsfPers.Size() == 0)
537         continue;
538
539       const OpenGl_Mat4& aProjection                = theSelector.ProjectionMatrix();
540       const OpenGl_Mat4& aWorldView                 = theSelector.WorldViewMatrix();
541       const Graphic3d_WorldViewProjState& aWVPState = theSelector.WorldViewProjState();
542       const Standard_Integer aViewportWidth         = theSelector.ViewportWidth();
543       const Standard_Integer aViewportHeight        = theSelector.ViewportHeight();
544
545       aBVHTree = myBVHPrimitivesTrsfPers.BVH (theSelector.Camera(), aProjection, aWorldView, aViewportWidth, aViewportHeight, aWVPState);
546     }
547     else
548     {
549       if (myBVHPrimitives.Size() == 0)
550         continue;
551
552       aBVHTree = myBVHPrimitives.BVH();
553     }
554
555     Standard_Integer aNode = 0; // a root node
556
557     if (!theSelector.Intersect (aBVHTree->MinPoint (0),
558                                 aBVHTree->MaxPoint (0)))
559     {
560       continue;
561     }
562
563     Standard_Integer aStack[32];
564     Standard_Integer aHead = -1;
565     for (;;)
566     {
567       if (!aBVHTree->IsOuter (aNode))
568       {
569         const Standard_Integer aLeftChildIdx  = aBVHTree->Child<0> (aNode);
570         const Standard_Integer aRightChildIdx = aBVHTree->Child<1> (aNode);
571         const Standard_Boolean isLeftChildIn  = theSelector.Intersect (aBVHTree->MinPoint (aLeftChildIdx),
572                                                                        aBVHTree->MaxPoint (aLeftChildIdx));
573         const Standard_Boolean isRightChildIn = theSelector.Intersect (aBVHTree->MinPoint (aRightChildIdx),
574                                                                        aBVHTree->MaxPoint (aRightChildIdx));
575         if (isLeftChildIn
576          && isRightChildIn)
577         {
578           aNode = myBVHIsLeftChildQueuedFirst ? aLeftChildIdx : aRightChildIdx;
579           aStack[++aHead] = myBVHIsLeftChildQueuedFirst ? aRightChildIdx : aLeftChildIdx;
580           myBVHIsLeftChildQueuedFirst = !myBVHIsLeftChildQueuedFirst;
581         }
582         else if (isLeftChildIn
583               || isRightChildIn)
584         {
585           aNode = isLeftChildIn ? aLeftChildIdx : aRightChildIdx;
586         }
587         else
588         {
589           if (aHead < 0)
590           {
591             break;
592           }
593
594           aNode = aStack[aHead--];
595         }
596       }
597       else
598       {
599         Standard_Integer aIdx = aBVHTree->BegPrimitive (aNode);
600         const OpenGl_Structure* aStruct =
601           isTrsfPers ? myBVHPrimitivesTrsfPers.GetStructureById (aIdx)
602                      : myBVHPrimitives.GetStructureById (aIdx);
603         aStruct->MarkAsNotCulled();
604         if (aHead < 0)
605         {
606           break;
607         }
608
609         aNode = aStack[aHead--];
610       }
611     }
612   }
613 }
614
615 // =======================================================================
616 // function : Append
617 // purpose  :
618 // =======================================================================
619 Standard_Boolean OpenGl_Layer::Append (const OpenGl_Layer& theOther)
620 {
621   // the source priority list shouldn't have more priorities
622   const Standard_Integer aNbPriorities = theOther.NbPriorities();
623   if (aNbPriorities > NbPriorities())
624   {
625     return Standard_False;
626   }
627
628   // add all structures to destination priority list
629   for (Standard_Integer aPriorityIter = 0; aPriorityIter < aNbPriorities; ++aPriorityIter)
630   {
631     const OpenGl_IndexedMapOfStructure& aStructures = theOther.myArray (aPriorityIter);
632     for (Standard_Integer aStructIdx = 1; aStructIdx <= aStructures.Size(); ++aStructIdx)
633     {
634       Add (aStructures.FindKey (aStructIdx), aPriorityIter);
635     }
636   }
637
638   return Standard_True;
639 }
640
641 //=======================================================================
642 //function : Render
643 //purpose  :
644 //=======================================================================
645 void OpenGl_Layer::Render (const Handle(OpenGl_Workspace)&   theWorkspace,
646                            const OpenGl_GlobalLayerSettings& theDefaultSettings) const
647 {
648   Graphic3d_PolygonOffset anAppliedOffsetParams = theWorkspace->AppliedPolygonOffset();
649
650   // separate depth buffers
651   if (IsSettingEnabled (Graphic3d_ZLayerDepthClear))
652   {
653     glClear (GL_DEPTH_BUFFER_BIT);
654   }
655
656   // handle depth test
657   if (IsSettingEnabled (Graphic3d_ZLayerDepthTest))
658   {
659     // assuming depth test is enabled by default
660     glDepthFunc (theDefaultSettings.DepthFunc);
661   }
662   else
663   {
664     glDepthFunc (GL_ALWAYS);
665   }
666
667   // save environment texture
668   Handle(OpenGl_Texture) anEnvironmentTexture = theWorkspace->EnvironmentTexture();
669   if (!myLayerSettings.UseEnvironmentTexture)
670   {
671     theWorkspace->SetEnvironmentTexture (Handle(OpenGl_Texture)());
672   }
673
674   // handle depth offset
675   if (IsSettingEnabled (Graphic3d_ZLayerDepthOffset))
676   {
677     Graphic3d_PolygonOffset aLayerPolygonOffset;
678     aLayerPolygonOffset.Mode   = Aspect_POM_Fill;
679     aLayerPolygonOffset.Factor = myLayerSettings.DepthOffsetFactor;
680     aLayerPolygonOffset.Units  = myLayerSettings.DepthOffsetUnits;
681     theWorkspace->SetPolygonOffset (aLayerPolygonOffset);
682   }
683   else
684   {
685     theWorkspace->SetPolygonOffset (anAppliedOffsetParams);
686   }
687
688   // handle depth write
689   theWorkspace->UseDepthWrite() = IsSettingEnabled (Graphic3d_ZLayerDepthWrite);
690   glDepthMask (theWorkspace->UseDepthWrite() ? GL_TRUE : GL_FALSE);
691
692   // render priority list
693   theWorkspace->IsCullingEnabled() ? renderTraverse (theWorkspace) : renderAll (theWorkspace);
694
695   // always restore polygon offset between layers rendering
696   theWorkspace->SetPolygonOffset (anAppliedOffsetParams);
697
698   // restore environment texture
699   if (!myLayerSettings.UseEnvironmentTexture)
700   {
701     theWorkspace->SetEnvironmentTexture (anEnvironmentTexture);
702   }
703 }