0030635: Visualization - move OpenGl_Layer to Graphic3d_Layer
[occt.git] / src / Graphic3d / Graphic3d_Layer.cxx
1 // Copyright (c) 2011-2019 OPEN CASCADE SAS
2 //
3 // This file is part of Open CASCADE Technology software library.
4 //
5 // This library is free software; you can redistribute it and/or modify it under
6 // the terms of the GNU Lesser General Public License version 2.1 as published
7 // by the Free Software Foundation, with special exception defined in the file
8 // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
9 // distribution for complete text of the license and disclaimer of any warranty.
10 //
11 // Alternatively, this file may be used under the terms of Open CASCADE
12 // commercial license or contractual agreement.
13
14 #include <Graphic3d_Layer.hxx>
15
16 #include <Graphic3d_CStructure.hxx>
17 #include <Graphic3d_CullingTool.hxx>
18
19 IMPLEMENT_STANDARD_RTTIEXT(Graphic3d_Layer, Standard_Transient)
20
21 // =======================================================================
22 // function : Graphic3d_Layer
23 // purpose  :
24 // =======================================================================
25 Graphic3d_Layer::Graphic3d_Layer (Standard_Integer theNbPriorities,
26                                   const Handle(Select3D_BVHBuilder3d)& theBuilder)
27 : myArray                     (0, theNbPriorities - 1),
28   myNbStructures              (0),
29   myNbStructuresNotCulled     (0),
30   myBVHPrimitivesTrsfPers     (theBuilder),
31   myBVHIsLeftChildQueuedFirst (Standard_True),
32   myIsBVHPrimitivesNeedsReset (Standard_False)
33 {
34   myIsBoundingBoxNeedsReset[0] = myIsBoundingBoxNeedsReset[1] = true;
35 }
36
37 // =======================================================================
38 // function : ~Graphic3d_Layer
39 // purpose  :
40 // =======================================================================
41 Graphic3d_Layer::~Graphic3d_Layer()
42 {
43   //
44 }
45
46 // =======================================================================
47 // function : Add
48 // purpose  :
49 // =======================================================================
50 void Graphic3d_Layer::Add (const Graphic3d_CStructure* theStruct,
51                            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().IsNull())
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 Graphic3d_Layer::Remove (const Graphic3d_CStructure* 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     Graphic3d_IndexedMapOfStructure& aStructures = myArray (aPriorityIter);
101     const Standard_Integer anIndex = aStructures.FindIndex (theStruct);
102     if (anIndex == 0)
103     {
104       continue;
105     }
106
107     aStructures.Swap (anIndex, aStructures.Size());
108     aStructures.RemoveLast();
109
110     if (!isForChangePriority)
111     {
112       Standard_Boolean isAlwaysRend = theStruct->IsAlwaysRendered();
113       if (!isAlwaysRend)
114       {
115         if (!myBVHPrimitives.Remove (theStruct))
116         {
117           if (!myBVHPrimitivesTrsfPers.Remove (theStruct))
118           {
119             isAlwaysRend = Standard_True;
120           }
121         }
122       }
123       if (isAlwaysRend)
124       {
125         const Standard_Integer anIndex2 = myAlwaysRenderedMap.FindIndex (theStruct);
126         if (anIndex2 != 0)
127         {
128           myAlwaysRenderedMap.Swap (myAlwaysRenderedMap.Size(), anIndex2);
129           myAlwaysRenderedMap.RemoveLast();
130         }
131       }
132     }
133     --myNbStructures;
134     thePriority = aPriorityIter;
135     return true;
136   }
137
138   thePriority = -1;
139   return false;
140 }
141
142 // =======================================================================
143 // function : InvalidateBVHData
144 // purpose  :
145 // =======================================================================
146 void Graphic3d_Layer::InvalidateBVHData()
147 {
148   myIsBVHPrimitivesNeedsReset = Standard_True;
149 }
150
151 //! Calculate a finite bounding box of infinite object as its middle point.
152 inline Graphic3d_BndBox3d centerOfinfiniteBndBox (const Graphic3d_BndBox3d& theBndBox)
153 {
154   // bounding borders of infinite line has been calculated as own point in center of this line
155   const Graphic3d_Vec3d aDiagVec = theBndBox.CornerMax() - theBndBox.CornerMin();
156   return aDiagVec.SquareModulus() >= 500000.0 * 500000.0
157        ? Graphic3d_BndBox3d ((theBndBox.CornerMin() + theBndBox.CornerMax()) * 0.5)
158        : Graphic3d_BndBox3d();
159 }
160
161 //! Return true if at least one vertex coordinate out of float range.
162 inline bool isInfiniteBndBox (const Graphic3d_BndBox3d& theBndBox)
163 {
164   return Abs (theBndBox.CornerMax().x()) >= ShortRealLast()
165       || Abs (theBndBox.CornerMax().y()) >= ShortRealLast()
166       || Abs (theBndBox.CornerMax().z()) >= ShortRealLast()
167       || Abs (theBndBox.CornerMin().x()) >= ShortRealLast()
168       || Abs (theBndBox.CornerMin().y()) >= ShortRealLast()
169       || Abs (theBndBox.CornerMin().z()) >= ShortRealLast();
170 }
171
172 // =======================================================================
173 // function : BoundingBox
174 // purpose  :
175 // =======================================================================
176 Bnd_Box Graphic3d_Layer::BoundingBox (Standard_Integer theViewId,
177                                       const Handle(Graphic3d_Camera)& theCamera,
178                                       Standard_Integer theWindowWidth,
179                                       Standard_Integer theWindowHeight,
180                                       Standard_Boolean theToIncludeAuxiliary) const
181 {
182   updateBVH();
183
184   const Standard_Integer aBoxId = !theToIncludeAuxiliary ? 0 : 1;
185   const Graphic3d_Mat4d& aProjectionMat = theCamera->ProjectionMatrix();
186   const Graphic3d_Mat4d& aWorldViewMat  = theCamera->OrientationMatrix();
187   if (myIsBoundingBoxNeedsReset[aBoxId])
188   {
189     // Recompute layer bounding box
190     myBoundingBox[aBoxId].SetVoid();
191
192     for (Graphic3d_ArrayOfIndexedMapOfStructure::Iterator aMapIter (myArray); aMapIter.More(); aMapIter.Next())
193     {
194       const Graphic3d_IndexedMapOfStructure& aStructures = aMapIter.Value();
195       for (Graphic3d_IndexedMapOfStructure::Iterator aStructIter (aStructures); aStructIter.More(); aStructIter.Next())
196       {
197         const Graphic3d_CStructure* aStructure = aStructIter.Value();
198         if (!aStructure->IsVisible (theViewId))
199         {
200           continue;
201         }
202
203         // "FitAll" operation ignores object with transform persistence parameter
204         // but adds transform persistence point in a bounding box of layer (only zoom pers. objects).
205         if (!aStructure->TransformPersistence().IsNull())
206         {
207           if (!theToIncludeAuxiliary
208             && aStructure->TransformPersistence()->IsZoomOrRotate())
209           {
210             const gp_Pnt anAnchor = aStructure->TransformPersistence()->AnchorPoint();
211             myBoundingBox[aBoxId].Add (anAnchor);
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()->IsTrihedronOr2d())
218           {
219             continue;
220           }
221         }
222
223         Graphic3d_BndBox3d 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().IsNull())
237         {
238           aStructure->TransformPersistence()->Apply (theCamera, aProjectionMat, aWorldViewMat, theWindowWidth, theWindowHeight, aBox);
239         }
240
241         // skip too big boxes to prevent float overflow at camera parameters calculation
242         if (aBox.IsValid()
243         && !isInfiniteBndBox (aBox))
244         {
245           myBoundingBox[aBoxId].Add (gp_Pnt (aBox.CornerMin().x(), aBox.CornerMin().y(), aBox.CornerMin().z()));
246           myBoundingBox[aBoxId].Add (gp_Pnt (aBox.CornerMax().x(), aBox.CornerMax().y(), aBox.CornerMax().z()));
247         }
248       }
249     }
250
251     myIsBoundingBoxNeedsReset[aBoxId] = false;
252   }
253
254   Bnd_Box aResBox = myBoundingBox[aBoxId];
255   if (!theToIncludeAuxiliary
256     || myAlwaysRenderedMap.IsEmpty())
257   {
258     return aResBox;
259   }
260
261   // add transformation-persistent objects which depend on camera position (and thus can not be cached) for operations like Z-fit
262   for (NCollection_IndexedMap<const Graphic3d_CStructure*>::Iterator aStructIter (myAlwaysRenderedMap); aStructIter.More(); aStructIter.Next())
263   {
264     const Graphic3d_CStructure* aStructure = aStructIter.Value();
265     if (!aStructure->IsVisible (theViewId))
266     {
267       continue;
268     }
269     else if (aStructure->TransformPersistence().IsNull()
270          || !aStructure->TransformPersistence()->IsTrihedronOr2d())
271     {
272       continue;
273     }
274
275     Graphic3d_BndBox3d aBox = aStructure->BoundingBox();
276     if (!aBox.IsValid())
277     {
278       continue;
279     }
280
281     aStructure->TransformPersistence()->Apply (theCamera, aProjectionMat, aWorldViewMat, theWindowWidth, theWindowHeight, aBox);
282     if (aBox.IsValid()
283     && !isInfiniteBndBox (aBox))
284     {
285       aResBox.Add (gp_Pnt (aBox.CornerMin().x(), aBox.CornerMin().y(), aBox.CornerMin().z()));
286       aResBox.Add (gp_Pnt (aBox.CornerMax().x(), aBox.CornerMax().y(), aBox.CornerMax().z()));
287     }
288   }
289
290   return aResBox;
291 }
292
293 // =======================================================================
294 // function : considerZoomPersistenceObjects
295 // purpose  :
296 // =======================================================================
297 Standard_Real Graphic3d_Layer::considerZoomPersistenceObjects (Standard_Integer theViewId,
298                                                                const Handle(Graphic3d_Camera)& theCamera,
299                                                                Standard_Integer theWindowWidth,
300                                                                Standard_Integer theWindowHeight) const
301 {
302   if (NbOfTransformPersistenceObjects() == 0)
303   {
304     return 1.0;
305   }
306
307   const Graphic3d_Mat4d& aProjectionMat = theCamera->ProjectionMatrix();
308   const Graphic3d_Mat4d& aWorldViewMat  = theCamera->OrientationMatrix();
309   Standard_Real          aMaxCoef       = -std::numeric_limits<double>::max();
310
311   for (Graphic3d_ArrayOfIndexedMapOfStructure::Iterator aMapIter (myArray); aMapIter.More(); aMapIter.Next())
312   {
313     const Graphic3d_IndexedMapOfStructure& aStructures = aMapIter.Value();
314     for (Graphic3d_IndexedMapOfStructure::Iterator aStructIter (aStructures); aStructIter.More(); aStructIter.Next())
315     {
316       const Graphic3d_CStructure* aStructure = aStructIter.Value();
317       if (!aStructure->IsVisible (theViewId)
318        ||  aStructure->TransformPersistence().IsNull()
319        || !aStructure->TransformPersistence()->IsZoomOrRotate())
320       {
321         continue;
322       }
323
324       Graphic3d_BndBox3d aBox = aStructure->BoundingBox();
325       if (!aBox.IsValid())
326       {
327         continue;
328       }
329
330       aStructure->TransformPersistence()->Apply (theCamera, aProjectionMat, aWorldViewMat, theWindowWidth, theWindowHeight, aBox);
331
332       const BVH_Vec3d&       aCornerMin           = aBox.CornerMin();
333       const BVH_Vec3d&       aCornerMax           = aBox.CornerMax();
334       const Standard_Integer aNbOfPoints          = 8;
335       const gp_Pnt           aPoints[aNbOfPoints] = { gp_Pnt (aCornerMin.x(), aCornerMin.y(), aCornerMin.z()),
336                                                       gp_Pnt (aCornerMin.x(), aCornerMin.y(), aCornerMax.z()),
337                                                       gp_Pnt (aCornerMin.x(), aCornerMax.y(), aCornerMin.z()),
338                                                       gp_Pnt (aCornerMin.x(), aCornerMax.y(), aCornerMax.z()),
339                                                       gp_Pnt (aCornerMax.x(), aCornerMin.y(), aCornerMin.z()),
340                                                       gp_Pnt (aCornerMax.x(), aCornerMin.y(), aCornerMax.z()),
341                                                       gp_Pnt (aCornerMax.x(), aCornerMax.y(), aCornerMin.z()),
342                                                       gp_Pnt (aCornerMax.x(), aCornerMax.y(), aCornerMax.z()) };
343       gp_Pnt aConvertedPoints[aNbOfPoints];
344       Standard_Real aConvertedMinX =  std::numeric_limits<double>::max();
345       Standard_Real aConvertedMaxX = -std::numeric_limits<double>::max();
346       Standard_Real aConvertedMinY =  std::numeric_limits<double>::max();
347       Standard_Real aConvertedMaxY = -std::numeric_limits<double>::max();
348       for (Standard_Integer anIdx = 0; anIdx < aNbOfPoints; ++anIdx)
349       {
350         aConvertedPoints[anIdx] = theCamera->Project (aPoints[anIdx]);
351
352         aConvertedMinX          = Min (aConvertedMinX, aConvertedPoints[anIdx].X());
353         aConvertedMaxX          = Max (aConvertedMaxX, aConvertedPoints[anIdx].X());
354
355         aConvertedMinY          = Min (aConvertedMinY, aConvertedPoints[anIdx].Y());
356         aConvertedMaxY          = Max (aConvertedMaxY, aConvertedPoints[anIdx].Y());
357       }
358
359       const Standard_Boolean isBigObject  = (Abs (aConvertedMaxX - aConvertedMinX) > 2.0)  // width  of zoom pers. object greater than width  of window
360                                          || (Abs (aConvertedMaxY - aConvertedMinY) > 2.0); // height of zoom pers. object greater than height of window
361       const Standard_Boolean isAlreadyInScreen = (aConvertedMinX > -1.0 && aConvertedMinX < 1.0)
362                                               && (aConvertedMaxX > -1.0 && aConvertedMaxX < 1.0)
363                                               && (aConvertedMinY > -1.0 && aConvertedMinY < 1.0)
364                                               && (aConvertedMaxY > -1.0 && aConvertedMaxY < 1.0);
365       if (isBigObject || isAlreadyInScreen)
366       {
367         continue;
368       }
369
370       const gp_Pnt aTPPoint = aStructure->TransformPersistence()->AnchorPoint();
371       gp_Pnt aConvertedTPPoint = theCamera->Project (aTPPoint);
372       aConvertedTPPoint.SetZ (0.0);
373
374       if (aConvertedTPPoint.Coord().Modulus() < Precision::Confusion())
375       {
376         continue;
377       }
378
379       Standard_Real aShiftX = 0.0;
380       if (aConvertedMinX < -1.0)
381       {
382         aShiftX = ((aConvertedMaxX < -1.0) ? (-(1.0 + aConvertedMaxX) + (aConvertedMaxX - aConvertedMinX)) : -(1.0 + aConvertedMinX));
383       }
384       else if (aConvertedMaxX > 1.0)
385       {
386         aShiftX = ((aConvertedMinX > 1.0) ? ((aConvertedMinX - 1.0) + (aConvertedMaxX - aConvertedMinX)) : (aConvertedMaxX - 1.0));
387       }
388
389       Standard_Real aShiftY = 0.0;
390       if (aConvertedMinY < -1.0)
391       {
392         aShiftY = ((aConvertedMaxY < -1.0) ? (-(1.0 + aConvertedMaxY) + (aConvertedMaxY - aConvertedMinY)) : -(1.0 + aConvertedMinY));
393       }
394       else if (aConvertedMaxY > 1.0)
395       {
396         aShiftY = ((aConvertedMinY > 1.0) ? ((aConvertedMinY - 1.0) + (aConvertedMaxY - aConvertedMinY)) : (aConvertedMaxY - 1.0));
397       }
398
399       const Standard_Real aDifX = Abs (aConvertedTPPoint.X()) - aShiftX;
400       const Standard_Real aDifY = Abs (aConvertedTPPoint.Y()) - aShiftY;
401       if (aDifX > Precision::Confusion())
402       {
403         aMaxCoef = Max (aMaxCoef, Abs (aConvertedTPPoint.X()) / aDifX);
404       }
405       if (aDifY > Precision::Confusion())
406       {
407         aMaxCoef = Max (aMaxCoef, Abs (aConvertedTPPoint.Y()) / aDifY);
408       }
409     }
410   }
411
412   return (aMaxCoef > 0.0) ? aMaxCoef : 1.0;
413 }
414
415 // =======================================================================
416 // function : updateBVH
417 // purpose  :
418 // =======================================================================
419 void Graphic3d_Layer::updateBVH() const
420 {
421   if (!myIsBVHPrimitivesNeedsReset)
422   {
423     return;
424   }
425
426   myBVHPrimitives.Clear();
427   myBVHPrimitivesTrsfPers.Clear();
428   myAlwaysRenderedMap.Clear();
429   myIsBVHPrimitivesNeedsReset = Standard_False;
430   for (Graphic3d_ArrayOfIndexedMapOfStructure::Iterator aMapIter (myArray); aMapIter.More(); aMapIter.Next())
431   {
432     const Graphic3d_IndexedMapOfStructure& aStructures = aMapIter.Value();
433     for (Graphic3d_IndexedMapOfStructure::Iterator aStructIter (aStructures); aStructIter.More(); aStructIter.Next())
434     {
435       const Graphic3d_CStructure* aStruct = aStructIter.Value();
436       if (aStruct->IsAlwaysRendered())
437       {
438         aStruct->MarkAsNotCulled();
439         myAlwaysRenderedMap.Add (aStruct);
440       }
441       else if (aStruct->TransformPersistence().IsNull())
442       {
443         myBVHPrimitives.Add (aStruct);
444       }
445       else
446       {
447         myBVHPrimitivesTrsfPers.Add (aStruct);
448       }
449     }
450   }
451 }
452
453 // =======================================================================
454 // function : UpdateCulling
455 // purpose  :
456 // =======================================================================
457 void Graphic3d_Layer::UpdateCulling (Standard_Integer theViewId,
458                                      const Graphic3d_CullingTool& theSelector,
459                                      const Graphic3d_RenderingParams::FrustumCulling theFrustumCullingState)
460 {
461   updateBVH();
462
463   myNbStructuresNotCulled = myNbStructures;
464   if (theFrustumCullingState != Graphic3d_RenderingParams::FrustumCulling_NoUpdate)
465   {
466     Standard_Boolean toTraverse = (theFrustumCullingState == Graphic3d_RenderingParams::FrustumCulling_On);
467     for (Graphic3d_IndexedMapOfStructure::Iterator aStructIter (myBVHPrimitives.Structures()); aStructIter.More(); aStructIter.Next())
468     {
469       const Graphic3d_CStructure* aStruct = aStructIter.Value();
470       aStruct->SetCulled (toTraverse);
471     }
472     for (Graphic3d_IndexedMapOfStructure::Iterator aStructIter (myBVHPrimitivesTrsfPers.Structures()); aStructIter.More(); aStructIter.Next())
473     {
474       const Graphic3d_CStructure* aStruct = aStructIter.Value();
475       aStruct->SetCulled (toTraverse);
476     }
477   }
478
479   if (theFrustumCullingState != Graphic3d_RenderingParams::FrustumCulling_On)
480   {
481     return;
482   }
483   if (myBVHPrimitives        .Size() == 0
484    && myBVHPrimitivesTrsfPers.Size() == 0)
485   {
486     return;
487   }
488
489   myNbStructuresNotCulled = myAlwaysRenderedMap.Extent();
490   Graphic3d_CullingTool::CullingContext aCullCtx;
491   theSelector.SetCullingDistance(aCullCtx, myLayerSettings.CullingDistance());
492   theSelector.SetCullingSize    (aCullCtx, myLayerSettings.CullingSize());
493   for (Standard_Integer aBVHTreeIdx = 0; aBVHTreeIdx < 2; ++aBVHTreeIdx)
494   {
495     const Standard_Boolean isTrsfPers = aBVHTreeIdx == 1;
496     opencascade::handle<BVH_Tree<Standard_Real, 3> > aBVHTree;
497     if (isTrsfPers)
498     {
499       if (myBVHPrimitivesTrsfPers.Size() == 0)
500         continue;
501
502       const Graphic3d_Mat4d& aProjection            = theSelector.ProjectionMatrix();
503       const Graphic3d_Mat4d& aWorldView             = theSelector.WorldViewMatrix();
504       const Graphic3d_WorldViewProjState& aWVPState = theSelector.WorldViewProjState();
505       const Standard_Integer aViewportWidth         = theSelector.ViewportWidth();
506       const Standard_Integer aViewportHeight        = theSelector.ViewportHeight();
507
508       aBVHTree = myBVHPrimitivesTrsfPers.BVH (theSelector.Camera(), aProjection, aWorldView, aViewportWidth, aViewportHeight, aWVPState);
509     }
510     else
511     {
512       if (myBVHPrimitives.Size() == 0)
513         continue;
514
515       aBVHTree = myBVHPrimitives.BVH();
516     }
517
518     if (theSelector.IsCulled (aCullCtx, aBVHTree->MinPoint (0), aBVHTree->MaxPoint (0)))
519     {
520       continue;
521     }
522
523     Standard_Integer aStack[BVH_Constants_MaxTreeDepth];
524     Standard_Integer aHead = -1;
525     Standard_Integer aNode = 0; // a root node
526     for (;;)
527     {
528       if (!aBVHTree->IsOuter (aNode))
529       {
530         const Standard_Integer aLeftChildIdx  = aBVHTree->Child<0> (aNode);
531         const Standard_Integer aRightChildIdx = aBVHTree->Child<1> (aNode);
532         const Standard_Boolean isLeftChildIn  = !theSelector.IsCulled (aCullCtx, aBVHTree->MinPoint (aLeftChildIdx),  aBVHTree->MaxPoint (aLeftChildIdx));
533         const Standard_Boolean isRightChildIn = !theSelector.IsCulled (aCullCtx, aBVHTree->MinPoint (aRightChildIdx), aBVHTree->MaxPoint (aRightChildIdx));
534         if (isLeftChildIn
535          && isRightChildIn)
536         {
537           aNode = myBVHIsLeftChildQueuedFirst ? aLeftChildIdx : aRightChildIdx;
538           aStack[++aHead] = myBVHIsLeftChildQueuedFirst ? aRightChildIdx : aLeftChildIdx;
539           myBVHIsLeftChildQueuedFirst = !myBVHIsLeftChildQueuedFirst;
540         }
541         else if (isLeftChildIn
542               || isRightChildIn)
543         {
544           aNode = isLeftChildIn ? aLeftChildIdx : aRightChildIdx;
545         }
546         else
547         {
548           if (aHead < 0)
549           {
550             break;
551           }
552
553           aNode = aStack[aHead--];
554         }
555       }
556       else
557       {
558         Standard_Integer aIdx = aBVHTree->BegPrimitive (aNode);
559         const Graphic3d_CStructure* aStruct = isTrsfPers
560                                             ? myBVHPrimitivesTrsfPers.GetStructureById (aIdx)
561                                             : myBVHPrimitives.GetStructureById (aIdx);
562         if (aStruct->IsVisible (theViewId))
563         {
564           aStruct->MarkAsNotCulled();
565           ++myNbStructuresNotCulled;
566         }
567         if (aHead < 0)
568         {
569           break;
570         }
571
572         aNode = aStack[aHead--];
573       }
574     }
575   }
576 }
577
578 // =======================================================================
579 // function : Append
580 // purpose  :
581 // =======================================================================
582 Standard_Boolean Graphic3d_Layer::Append (const Graphic3d_Layer& theOther)
583 {
584   // the source priority list shouldn't have more priorities
585   const Standard_Integer aNbPriorities = theOther.NbPriorities();
586   if (aNbPriorities > NbPriorities())
587   {
588     return Standard_False;
589   }
590
591   // add all structures to destination priority list
592   for (Standard_Integer aPriorityIter = 0; aPriorityIter < aNbPriorities; ++aPriorityIter)
593   {
594     const Graphic3d_IndexedMapOfStructure& aStructures = theOther.myArray (aPriorityIter);
595     for (Graphic3d_IndexedMapOfStructure::Iterator aStructIter (aStructures); aStructIter.More(); aStructIter.Next())
596     {
597       Add (aStructIter.Value(), aPriorityIter);
598     }
599   }
600
601   return Standard_True;
602 }
603
604 //=======================================================================
605 //function : SetLayerSettings
606 //purpose  :
607 //=======================================================================
608 void Graphic3d_Layer::SetLayerSettings (const Graphic3d_ZLayerSettings& theSettings)
609 {
610   const Standard_Boolean toUpdateTrsf = !myLayerSettings.Origin().IsEqual (theSettings.Origin(), gp::Resolution());
611   myLayerSettings = theSettings;
612   if (!toUpdateTrsf)
613   {
614     return;
615   }
616
617   for (Graphic3d_ArrayOfIndexedMapOfStructure::Iterator aMapIter (myArray); aMapIter.More(); aMapIter.Next())
618   {
619     Graphic3d_IndexedMapOfStructure& aStructures = aMapIter.ChangeValue();
620     for (Graphic3d_IndexedMapOfStructure::Iterator aStructIter (aStructures); aStructIter.More(); aStructIter.Next())
621     {
622       Graphic3d_CStructure* aStructure = const_cast<Graphic3d_CStructure* >(aStructIter.Value());
623       aStructure->updateLayerTransformation();
624     }
625   }
626 }