1 // Created on: 2014-03-31
2 // Created by: Danila ULYANOV
3 // Copyright (c) 2014 OPEN CASCADE SAS
5 // This file is part of Open CASCADE Technology software library.
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.
13 // Alternatively, this file may be used under the terms of Open CASCADE
14 // commercial license or contractual agreement.
16 #include <OpenGl_Layer.hxx>
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>
24 // =======================================================================
25 // function : OpenGl_Layer
27 // =======================================================================
28 OpenGl_Layer::OpenGl_Layer (const Standard_Integer theNbPriorities)
29 : myArray (0, theNbPriorities - 1),
31 myBVHIsLeftChildQueuedFirst (Standard_True),
32 myIsBVHPrimitivesNeedsReset (Standard_False)
34 myIsBoundingBoxNeedsReset[0] = myIsBoundingBoxNeedsReset[1] = true;
37 // =======================================================================
38 // function : ~OpenGl_Layer
40 // =======================================================================
41 OpenGl_Layer::~OpenGl_Layer()
46 // =======================================================================
49 // =======================================================================
50 void OpenGl_Layer::Add (const OpenGl_Structure* theStruct,
51 const Standard_Integer thePriority,
52 Standard_Boolean isForChangePriority)
54 const Standard_Integer anIndex = Min (Max (thePriority, 0), myArray.Length() - 1);
55 if (theStruct == NULL)
60 myArray (anIndex).Add (theStruct);
61 if (theStruct->IsAlwaysRendered())
63 theStruct->MarkAsNotCulled();
64 if (!isForChangePriority)
66 myAlwaysRenderedMap.Add (theStruct);
69 else if (!isForChangePriority)
71 if (theStruct->TransformPersistence.Flags == Graphic3d_TMF_None)
73 myBVHPrimitives.Add (theStruct);
77 myBVHPrimitivesTrsfPers.Add (theStruct);
83 // =======================================================================
86 // =======================================================================
87 bool OpenGl_Layer::Remove (const OpenGl_Structure* theStruct,
88 Standard_Integer& thePriority,
89 Standard_Boolean isForChangePriority)
91 if (theStruct == NULL)
97 const Standard_Integer aNbPriorities = myArray.Length();
98 for (Standard_Integer aPriorityIter = 0; aPriorityIter < aNbPriorities; ++aPriorityIter)
100 OpenGl_IndexedMapOfStructure& aStructures = myArray (aPriorityIter);
102 const Standard_Integer anIndex = aStructures.FindIndex (theStruct);
105 aStructures.Swap (anIndex, aStructures.Size());
106 aStructures.RemoveLast();
108 if (!isForChangePriority)
110 if (theStruct->IsAlwaysRendered())
112 const Standard_Integer anIndex2 = myAlwaysRenderedMap.FindIndex (theStruct);
115 myAlwaysRenderedMap.Swap (myAlwaysRenderedMap.Size(), anIndex2);
116 myAlwaysRenderedMap.RemoveLast();
121 if (!myBVHPrimitives.Remove (theStruct))
123 myBVHPrimitivesTrsfPers.Remove (theStruct);
128 thePriority = aPriorityIter;
137 // =======================================================================
138 // function : InvalidateBVHData
140 // =======================================================================
141 void OpenGl_Layer::InvalidateBVHData() const
143 myIsBVHPrimitivesNeedsReset = Standard_True;
146 //! Calculate a finite bounding box of infinite object as its middle point.
147 inline Graphic3d_BndBox4f centerOfinfiniteBndBox (const Graphic3d_BndBox4f& theBndBox)
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();
156 //! Return true if at least one vertex coordinate out of float range.
157 inline bool isInfiniteBndBox (const Graphic3d_BndBox4f& theBndBox)
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();
167 // =======================================================================
168 // function : BoundingBox
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
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])
184 // Recompute layer bounding box
185 myBoundingBox[aBoxId].Clear();
187 const Standard_Integer aNbPriorities = myArray.Length();
188 for (Standard_Integer aPriorityIter = 0; aPriorityIter < aNbPriorities; ++aPriorityIter)
190 const OpenGl_IndexedMapOfStructure& aStructures = myArray (aPriorityIter);
191 for (Standard_Integer aStructIdx = 1; aStructIdx <= aStructures.Size(); ++aStructIdx)
193 const OpenGl_Structure* aStructure = aStructures.FindKey (aStructIdx);
194 if (!aStructure->IsVisible (theViewId))
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)
203 if (!theToIncludeAuxiliary
204 && (aStructure->TransformPersistence.Flags & Graphic3d_TMF_ZoomPers) != 0)
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()),
211 myBoundingBox[aBoxId].Combine (aTPPoint);
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)
223 Graphic3d_BndBox4f aBox = aStructure->BoundingBox();
229 if (aStructure->IsInfinite
230 && !theToIncludeAuxiliary)
232 // include center of infinite object
233 aBox = centerOfinfiniteBndBox (aBox);
236 if (aStructure->TransformPersistence.Flags != Graphic3d_TMF_None)
238 aStructure->TransformPersistence.Apply (theCamera,
246 // skip too big boxes to prevent float overflow at camera parameters calculation
247 if (!isInfiniteBndBox (aBox))
249 myBoundingBox[aBoxId].Combine (aBox);
254 myIsBoundingBoxNeedsReset[aBoxId] = false;
257 if (!theToIncludeAuxiliary
258 || myAlwaysRenderedMap.IsEmpty())
260 return myBoundingBox[aBoxId];
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())
267 const OpenGl_Structure* aStructure = aStructIter.Value();
268 if (!aStructure->IsVisible (theViewId))
272 else if ((aStructure->TransformPersistence.Flags & (Graphic3d_TMF_TriedronPers | Graphic3d_TMF_2d)) == 0)
277 Graphic3d_BndBox4f aBox = aStructure->BoundingBox();
283 aStructure->TransformPersistence.Apply (theCamera,
289 if (!isInfiniteBndBox (aBox))
291 aResBox.Combine (aBox);
298 // =======================================================================
299 // function : considerZoomPersistenceObjects
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
307 if (NbOfTransformPersistenceObjects() == 0)
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();
317 for (Standard_Integer aPriorityIter = 0; aPriorityIter < aNbPriorities; ++aPriorityIter)
319 const OpenGl_IndexedMapOfStructure& aStructures = myArray (aPriorityIter);
320 for (Standard_Integer aStructIdx = 1; aStructIdx <= aStructures.Size(); ++aStructIdx)
322 OpenGl_Structure* aStructure = const_cast<OpenGl_Structure*> (aStructures.FindKey (aStructIdx));
323 if (!aStructure->IsVisible (theViewId)
324 || (aStructure->TransformPersistence.Flags & Graphic3d_TMF_ZoomPers) == 0)
329 Graphic3d_BndBox4f aBox = aStructure->BoundingBox();
335 aStructure->TransformPersistence.Apply (theCamera, aProjectionMat, aWorldViewMat, theWindowWidth, theWindowHeight, aBox);
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)
355 aConvertedPoints[anIdx] = theCamera->Project (aPoints[anIdx]);
357 aConvertedMinX = Min (aConvertedMinX, aConvertedPoints[anIdx].X());
358 aConvertedMaxX = Max (aConvertedMaxX, aConvertedPoints[anIdx].X());
360 aConvertedMinY = Min (aConvertedMinY, aConvertedPoints[anIdx].Y());
361 aConvertedMaxY = Max (aConvertedMaxY, aConvertedPoints[anIdx].Y());
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)
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);
381 if (aConvertedTPPoint.Coord().Modulus() < Precision::Confusion())
386 Standard_Real aShiftX = 0.0;
387 if (aConvertedMinX < -1.0)
389 aShiftX = ((aConvertedMaxX < -1.0) ? (-(1.0 + aConvertedMaxX) + (aConvertedMaxX - aConvertedMinX)) : -(1.0 + aConvertedMinX));
391 else if (aConvertedMaxX > 1.0)
393 aShiftX = ((aConvertedMinX > 1.0) ? ((aConvertedMinX - 1.0) + (aConvertedMaxX - aConvertedMinX)) : (aConvertedMaxX - 1.0));
396 Standard_Real aShiftY = 0.0;
397 if (aConvertedMinY < -1.0)
399 aShiftY = ((aConvertedMaxY < -1.0) ? (-(1.0 + aConvertedMaxY) + (aConvertedMaxY - aConvertedMinY)) : -(1.0 + aConvertedMinY));
401 else if (aConvertedMaxY > 1.0)
403 aShiftY = ((aConvertedMinY > 1.0) ? ((aConvertedMinY - 1.0) + (aConvertedMaxY - aConvertedMinY)) : (aConvertedMaxY - 1.0));
406 const Standard_Real aDifX = Abs (aConvertedTPPoint.X()) - aShiftX;
407 const Standard_Real aDifY = Abs (aConvertedTPPoint.Y()) - aShiftY;
408 if (aDifX > Precision::Confusion())
410 aMaxCoef = Max (aMaxCoef, Abs (aConvertedTPPoint.X()) / aDifX);
412 if (aDifY > Precision::Confusion())
414 aMaxCoef = Max (aMaxCoef, Abs (aConvertedTPPoint.Y()) / aDifY);
419 return (aMaxCoef > 0.0) ? aMaxCoef : 1.0;
422 // =======================================================================
423 // function : renderAll
425 // =======================================================================
426 void OpenGl_Layer::renderAll (const Handle(OpenGl_Workspace)& theWorkspace) const
428 const Standard_Integer aNbPriorities = myArray.Length();
429 const Standard_Integer aViewId = theWorkspace->View()->Identification();
430 for (Standard_Integer aPriorityIter = 0; aPriorityIter < aNbPriorities; ++aPriorityIter)
432 const OpenGl_IndexedMapOfStructure& aStructures = myArray (aPriorityIter);
433 for (Standard_Integer aStructIdx = 1; aStructIdx <= aStructures.Size(); ++aStructIdx)
435 const OpenGl_Structure* aStruct = aStructures.FindKey (aStructIdx);
436 if (!aStruct->IsVisible())
440 else if (!aStruct->ViewAffinity.IsNull()
441 && !aStruct->ViewAffinity->IsVisible (aViewId))
446 aStruct->Render (theWorkspace);
451 // =======================================================================
452 // function : updateBVH
454 // =======================================================================
455 void OpenGl_Layer::updateBVH() const
457 if (!myIsBVHPrimitivesNeedsReset)
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)
468 for (OpenGl_IndexedMapOfStructure::Iterator aStructIter (myArray (aPriorityIdx)); aStructIter.More(); aStructIter.Next())
470 const OpenGl_Structure* aStruct = aStructIter.Value();
471 if (aStruct->IsAlwaysRendered())
473 aStruct->MarkAsNotCulled();
474 myAlwaysRenderedMap.Add (aStruct);
476 else if (aStruct->TransformPersistence.Flags == Graphic3d_TMF_None)
478 myBVHPrimitives.Add (aStruct);
482 myBVHPrimitivesTrsfPers.Add (aStruct);
488 // =======================================================================
489 // function : renderTraverse
491 // =======================================================================
492 void OpenGl_Layer::renderTraverse (const Handle(OpenGl_Workspace)& theWorkspace) const
496 OpenGl_BVHTreeSelector& aSelector = theWorkspace->View()->BVHTreeSelector();
497 traverse (aSelector);
499 const Standard_Integer aNbPriorities = myArray.Length();
500 const Standard_Integer aViewId = theWorkspace->View()->Identification();
501 for (Standard_Integer aPriorityIter = 0; aPriorityIter < aNbPriorities; ++aPriorityIter)
503 const OpenGl_IndexedMapOfStructure& aStructures = myArray (aPriorityIter);
504 for (Standard_Integer aStructIdx = 1; aStructIdx <= aStructures.Size(); ++aStructIdx)
506 const OpenGl_Structure* aStruct = aStructures.FindKey (aStructIdx);
507 if (aStruct->IsCulled()
508 || !aStruct->IsVisible (aViewId))
513 aStruct->Render (theWorkspace);
514 aStruct->ResetCullingStatus();
519 // =======================================================================
520 // function : traverse
522 // =======================================================================
523 void OpenGl_Layer::traverse (OpenGl_BVHTreeSelector& theSelector) const
525 // handle a case when all objects are infinite
526 if (myBVHPrimitives .Size() == 0
527 && myBVHPrimitivesTrsfPers.Size() == 0)
530 theSelector.CacheClipPtsProjections();
532 NCollection_Handle<BVH_Tree<Standard_ShortReal, 4> > aBVHTree;
534 for (Standard_Integer aBVHTreeIdx = 0; aBVHTreeIdx < 2; ++aBVHTreeIdx)
536 const Standard_Boolean isTrsfPers = aBVHTreeIdx == 1;
539 if (myBVHPrimitivesTrsfPers.Size() == 0)
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();
548 aBVHTree = myBVHPrimitivesTrsfPers.BVH (theSelector.Camera(), aProjection, aWorldView, aViewportWidth, aViewportHeight, aWVPState);
552 if (myBVHPrimitives.Size() == 0)
555 aBVHTree = myBVHPrimitives.BVH();
558 Standard_Integer aNode = 0; // a root node
560 if (!theSelector.Intersect (aBVHTree->MinPoint (0),
561 aBVHTree->MaxPoint (0)))
566 Standard_Integer aStack[32];
567 Standard_Integer aHead = -1;
570 if (!aBVHTree->IsOuter (aNode))
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));
581 aNode = myBVHIsLeftChildQueuedFirst ? aLeftChildIdx : aRightChildIdx;
582 aStack[++aHead] = myBVHIsLeftChildQueuedFirst ? aRightChildIdx : aLeftChildIdx;
583 myBVHIsLeftChildQueuedFirst = !myBVHIsLeftChildQueuedFirst;
585 else if (isLeftChildIn
588 aNode = isLeftChildIn ? aLeftChildIdx : aRightChildIdx;
597 aNode = aStack[aHead--];
602 Standard_Integer aIdx = aBVHTree->BegPrimitive (aNode);
603 const OpenGl_Structure* aStruct =
604 isTrsfPers ? myBVHPrimitivesTrsfPers.GetStructureById (aIdx)
605 : myBVHPrimitives.GetStructureById (aIdx);
606 aStruct->MarkAsNotCulled();
612 aNode = aStack[aHead--];
618 // =======================================================================
621 // =======================================================================
622 Standard_Boolean OpenGl_Layer::Append (const OpenGl_Layer& theOther)
624 // the source priority list shouldn't have more priorities
625 const Standard_Integer aNbPriorities = theOther.NbPriorities();
626 if (aNbPriorities > NbPriorities())
628 return Standard_False;
631 // add all structures to destination priority list
632 for (Standard_Integer aPriorityIter = 0; aPriorityIter < aNbPriorities; ++aPriorityIter)
634 const OpenGl_IndexedMapOfStructure& aStructures = theOther.myArray (aPriorityIter);
635 for (Standard_Integer aStructIdx = 1; aStructIdx <= aStructures.Size(); ++aStructIdx)
637 Add (aStructures.FindKey (aStructIdx), aPriorityIter);
641 return Standard_True;
644 //=======================================================================
647 //=======================================================================
648 void OpenGl_Layer::Render (const Handle(OpenGl_Workspace)& theWorkspace,
649 const OpenGl_GlobalLayerSettings& theDefaultSettings) const
651 Graphic3d_PolygonOffset anAppliedOffsetParams = theWorkspace->AppliedPolygonOffset();
653 // separate depth buffers
654 if (IsSettingEnabled (Graphic3d_ZLayerDepthClear))
656 glClear (GL_DEPTH_BUFFER_BIT);
660 if (IsSettingEnabled (Graphic3d_ZLayerDepthTest))
662 // assuming depth test is enabled by default
663 glDepthFunc (theDefaultSettings.DepthFunc);
667 glDepthFunc (GL_ALWAYS);
670 // save environment texture
671 Handle(OpenGl_Texture) anEnvironmentTexture = theWorkspace->EnvironmentTexture();
672 if (!myLayerSettings.UseEnvironmentTexture)
674 theWorkspace->SetEnvironmentTexture (Handle(OpenGl_Texture)());
677 // handle depth offset
678 if (IsSettingEnabled (Graphic3d_ZLayerDepthOffset))
680 Graphic3d_PolygonOffset aLayerPolygonOffset;
681 aLayerPolygonOffset.Mode = Aspect_POM_Fill;
682 aLayerPolygonOffset.Factor = myLayerSettings.DepthOffsetFactor;
683 aLayerPolygonOffset.Units = myLayerSettings.DepthOffsetUnits;
684 theWorkspace->SetPolygonOffset (aLayerPolygonOffset);
688 theWorkspace->SetPolygonOffset (anAppliedOffsetParams);
691 // handle depth write
692 theWorkspace->UseDepthWrite() = IsSettingEnabled (Graphic3d_ZLayerDepthWrite);
693 glDepthMask (theWorkspace->UseDepthWrite() ? GL_TRUE : GL_FALSE);
695 // render priority list
696 theWorkspace->IsCullingEnabled() ? renderTraverse (theWorkspace) : renderAll (theWorkspace);
698 // always restore polygon offset between layers rendering
699 theWorkspace->SetPolygonOffset (anAppliedOffsetParams);
701 // restore environment texture
702 if (!myLayerSettings.UseEnvironmentTexture)
704 theWorkspace->SetEnvironmentTexture (anEnvironmentTexture);