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