0029729: Visualization, Graphic3d_ClipPlane - add support of clipping plane chains
[occt.git] / src / OpenGl / OpenGl_Structure.cxx
1 // Created on: 2011-08-01
2 // Created by: Sergey ZERCHANINOV
3 // Copyright (c) 2011-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_CappingAlgo.hxx>
17 #include <OpenGl_Context.hxx>
18 #include <OpenGl_GlCore11.hxx>
19 #include <OpenGl_ClippingIterator.hxx>
20 #include <OpenGl_GraphicDriver.hxx>
21 #include <OpenGl_ShaderManager.hxx>
22 #include <OpenGl_ShaderProgram.hxx>
23 #include <OpenGl_StructureShadow.hxx>
24 #include <OpenGl_Vec.hxx>
25 #include <OpenGl_View.hxx>
26 #include <OpenGl_Workspace.hxx>
27
28 IMPLEMENT_STANDARD_RTTIEXT(OpenGl_Structure,Graphic3d_CStructure)
29
30 //! Auxiliary class for bounding box presentation
31 class OpenGl_BndBoxPrs : public OpenGl_Element
32 {
33
34 public:
35
36   //! Main constructor
37   OpenGl_BndBoxPrs (const Graphic3d_BndBox3d& theBndBox)
38   {
39     const float Xm = (float )theBndBox.CornerMin().x();
40     const float Ym = (float)theBndBox.CornerMin().y();
41     const float Zm = (float)theBndBox.CornerMin().z();
42     const float XM = (float)theBndBox.CornerMax().x();
43     const float YM = (float)theBndBox.CornerMax().y();
44     const float ZM = (float)theBndBox.CornerMax().z();
45
46     myVerts[0]  = OpenGl_Vec3 (Xm, Ym, Zm);
47     myVerts[1]  = OpenGl_Vec3 (Xm, Ym, ZM);
48     myVerts[2]  = OpenGl_Vec3 (Xm, YM, ZM);
49     myVerts[3]  = OpenGl_Vec3 (Xm, YM, Zm);
50     myVerts[4]  = OpenGl_Vec3 (Xm, Ym, Zm);
51     myVerts[5]  = OpenGl_Vec3 (XM, Ym, Zm);
52     myVerts[6]  = OpenGl_Vec3 (XM, Ym, ZM);
53     myVerts[7]  = OpenGl_Vec3 (XM, YM, ZM);
54     myVerts[8]  = OpenGl_Vec3 (XM, YM, Zm);
55     myVerts[9]  = OpenGl_Vec3 (XM, Ym, Zm);
56     myVerts[10] = OpenGl_Vec3 (XM, YM, Zm);
57     myVerts[11] = OpenGl_Vec3 (Xm, YM, Zm);
58     myVerts[12] = OpenGl_Vec3 (Xm, YM, ZM);
59     myVerts[13] = OpenGl_Vec3 (XM, YM, ZM);
60     myVerts[14] = OpenGl_Vec3 (XM, Ym, ZM);
61     myVerts[15] = OpenGl_Vec3 (Xm, Ym, ZM);
62   }
63
64   //! Render presentation
65   virtual void Render  (const Handle(OpenGl_Workspace)& theWorkspace) const
66   {
67   #if !defined(GL_ES_VERSION_2_0)
68     const Handle(OpenGl_Context)& aCtx = theWorkspace->GetGlContext();
69     if (aCtx->core11 == NULL)
70     {
71       return;
72     }
73
74     const Handle(OpenGl_TextureSet) aPrevTexture = aCtx->BindTextures (Handle(OpenGl_TextureSet)());
75     aCtx->BindProgram (Handle(OpenGl_ShaderProgram)());
76     aCtx->ShaderManager()->PushState (Handle(OpenGl_ShaderProgram)());
77
78     glDisable (GL_LIGHTING);
79
80     // Use highlight colors
81     aCtx->core11->glColor3fv (theWorkspace->LineColor().GetData());
82
83     glEnableClientState (GL_VERTEX_ARRAY);
84     glVertexPointer (3, GL_FLOAT, 0, (GLfloat* )&myVerts);
85     glDrawArrays (GL_LINE_STRIP, 0, 16);
86     glDisableClientState (GL_VERTEX_ARRAY);
87
88     // restore aspects
89     if (!aPrevTexture.IsNull())
90     {
91       aCtx->BindTextures (aPrevTexture);
92     }
93   #else
94     (void )theWorkspace;
95   #endif
96   }
97
98   //! Release graphical resources
99   virtual void Release (OpenGl_Context*)
100   {
101     //
102   }
103
104 protected:
105
106   //! Protected destructor
107   virtual ~OpenGl_BndBoxPrs() {}
108
109 private:
110
111   OpenGl_Vec3 myVerts[16]; //!< vertices array
112
113 public:
114
115   DEFINE_STANDARD_ALLOC
116
117 };
118
119 /*----------------------------------------------------------------------*/
120
121 // =======================================================================
122 // function : OpenGl_Structure
123 // purpose  :
124 // =======================================================================
125 OpenGl_Structure::OpenGl_Structure (const Handle(Graphic3d_StructureManager)& theManager)
126 : Graphic3d_CStructure (theManager),
127   myInstancedStructure (NULL),
128   myIsRaytracable      (Standard_False),
129   myModificationState  (0),
130   myIsCulled           (Standard_True),
131   myIsMirrored         (Standard_False)
132 {
133   updateLayerTransformation();
134 }
135
136 // =======================================================================
137 // function : ~OpenGl_Structure
138 // purpose  :
139 // =======================================================================
140 OpenGl_Structure::~OpenGl_Structure()
141 {
142   Release (Handle(OpenGl_Context)());
143 }
144
145 // =======================================================================
146 // function : SetZLayer
147 // purpose  :
148 // =======================================================================
149 void OpenGl_Structure::SetZLayer (const Graphic3d_ZLayerId theLayerIndex)
150 {
151   Graphic3d_CStructure::SetZLayer (theLayerIndex);
152   updateLayerTransformation();
153 }
154
155 // =======================================================================
156 // function : SetTransformation
157 // purpose  :
158 // =======================================================================
159 void OpenGl_Structure::SetTransformation (const Handle(Geom_Transformation)& theTrsf)
160 {
161   myTrsf = theTrsf;
162   myIsMirrored = Standard_False;
163   if (!myTrsf.IsNull())
164   {
165     // Determinant of transform matrix less then 0 means that mirror transform applied.
166     const Standard_Real aDet = myTrsf->Value(1, 1) * (myTrsf->Value (2, 2) * myTrsf->Value (3, 3) - myTrsf->Value (3, 2) * myTrsf->Value (2, 3))
167                              - myTrsf->Value(1, 2) * (myTrsf->Value (2, 1) * myTrsf->Value (3, 3) - myTrsf->Value (3, 1) * myTrsf->Value (2, 3))
168                              + myTrsf->Value(1, 3) * (myTrsf->Value (2, 1) * myTrsf->Value (3, 2) - myTrsf->Value (3, 1) * myTrsf->Value (2, 2));
169     myIsMirrored = aDet < 0.0;
170   }
171
172   updateLayerTransformation();
173   if (IsRaytracable())
174   {
175     ++myModificationState;
176   }
177 }
178
179 // =======================================================================
180 // function : SetTransformPersistence
181 // purpose  :
182 // =======================================================================
183 void OpenGl_Structure::SetTransformPersistence (const Handle(Graphic3d_TransformPers)& theTrsfPers)
184 {
185   myTrsfPers = theTrsfPers;
186   updateLayerTransformation();
187 }
188
189 // =======================================================================
190 // function : updateLayerTransformation
191 // purpose  :
192 // =======================================================================
193 void OpenGl_Structure::updateLayerTransformation()
194 {
195   gp_Trsf aRenderTrsf;
196   if (!myTrsf.IsNull())
197   {
198     aRenderTrsf = myTrsf->Trsf();
199   }
200
201   const Graphic3d_ZLayerSettings& aLayer = myGraphicDriver->ZLayerSettings (myZLayer);
202   if (!aLayer.OriginTransformation().IsNull()
203     && myTrsfPers.IsNull())
204   {
205     aRenderTrsf.SetTranslationPart (aRenderTrsf.TranslationPart() - aLayer.Origin());
206   }
207   aRenderTrsf.GetMat4 (myRenderTrsf);
208 }
209
210 // =======================================================================
211 // function : clearHighlightBox
212 // purpose  :
213 // =======================================================================
214 void OpenGl_Structure::clearHighlightBox (const Handle(OpenGl_Context)& theGlCtx)
215 {
216   if (!myHighlightBox.IsNull())
217   {
218     myHighlightBox->Release (theGlCtx);
219     myHighlightBox.Nullify();
220   }
221 }
222
223 // =======================================================================
224 // function : HighlightWithBndBox
225 // purpose  :
226 // =======================================================================
227 void OpenGl_Structure::highlightWithBndBox (const Handle(Graphic3d_Structure)& theStruct)
228 {
229   const Handle(OpenGl_Context)& aContext = GlDriver()->GetSharedContext();
230
231   if (!myHighlightBox.IsNull())
232   {
233     myHighlightBox->Release (aContext);
234   }
235   else
236   {
237     myHighlightBox = new OpenGl_Group (theStruct);
238   }
239
240   myHighlightBox->SetGroupPrimitivesAspect (new Graphic3d_AspectLine3d (myHighlightStyle->Color(), Aspect_TOL_SOLID, 1.0));
241
242   OpenGl_BndBoxPrs* aBndBoxPrs = new OpenGl_BndBoxPrs (myBndBox);
243   myHighlightBox->AddElement (aBndBoxPrs);
244 }
245
246 // =======================================================================
247 // function : GraphicHighlight
248 // purpose  :
249 // =======================================================================
250 void OpenGl_Structure::GraphicHighlight (const Handle(Graphic3d_PresentationAttributes)& theStyle,
251                                          const Handle(Graphic3d_Structure)& theStruct)
252 {
253   if (!myHighlightStyle.IsNull()
254     && myHighlightStyle->Method() == Aspect_TOHM_BOUNDBOX
255     && theStyle->Method() != Aspect_TOHM_BOUNDBOX)
256   {
257     const Handle(OpenGl_Context)& aContext = GlDriver()->GetSharedContext();
258     clearHighlightBox (aContext);
259   }
260
261   myHighlightStyle = theStyle;
262
263   highlight = 1;
264   if (myHighlightStyle->Method() == Aspect_TOHM_BOUNDBOX)
265   {
266     highlightWithBndBox (theStruct);
267   }
268 }
269
270 // =======================================================================
271 // function : GraphicUnhighlight
272 // purpose  :
273 // =======================================================================
274 void OpenGl_Structure::GraphicUnhighlight()
275 {
276   highlight = 0;
277
278   if (myHighlightStyle->Method() == Aspect_TOHM_BOUNDBOX)
279   {
280     const Handle(OpenGl_Context)& aContext = GlDriver()->GetSharedContext();
281     clearHighlightBox (aContext);
282   }
283
284   myHighlightStyle.Nullify();
285 }
286
287 // =======================================================================
288 // function : OnVisibilityChanged
289 // purpose  :
290 // =======================================================================
291 void OpenGl_Structure::OnVisibilityChanged()
292 {
293   if (IsRaytracable())
294   {
295     ++myModificationState;
296   }
297 }
298
299 // =======================================================================
300 // function : IsRaytracable
301 // purpose  :
302 // =======================================================================
303 Standard_Boolean OpenGl_Structure::IsRaytracable() const
304 {
305   if (!myGroups.IsEmpty()
306     && myIsRaytracable)
307   {
308     return Standard_True;
309   }
310
311   return myInstancedStructure != NULL
312      &&  myInstancedStructure->IsRaytracable();
313 }
314
315 // =======================================================================
316 // function : UpdateRaytracableState
317 // purpose  :
318 // =======================================================================
319 void OpenGl_Structure::UpdateStateIfRaytracable (const Standard_Boolean toCheck) const
320 {
321   myIsRaytracable = !toCheck;
322   if (!myIsRaytracable)
323   {
324     for (OpenGl_Structure::GroupIterator anIter (myGroups); anIter.More(); anIter.Next())
325     {
326       if (anIter.Value()->IsRaytracable())
327       {
328         myIsRaytracable = Standard_True;
329         break;
330       }
331     }
332   }
333
334   if (IsRaytracable())
335   {
336     ++myModificationState;
337   }
338 }
339
340 // =======================================================================
341 // function : Connect
342 // purpose  :
343 // =======================================================================
344 void OpenGl_Structure::Connect (Graphic3d_CStructure& theStructure)
345 {
346   OpenGl_Structure* aStruct = static_cast<OpenGl_Structure*> (&theStructure);
347
348   Standard_ASSERT_RAISE (myInstancedStructure == NULL || myInstancedStructure == aStruct,
349     "Error! Instanced structure is already defined");
350
351   myInstancedStructure = aStruct;
352
353   if (aStruct->IsRaytracable())
354   {
355     UpdateStateIfRaytracable (Standard_False);
356   }
357 }
358
359 // =======================================================================
360 // function : Disconnect
361 // purpose  :
362 // =======================================================================
363 void OpenGl_Structure::Disconnect (Graphic3d_CStructure& theStructure)
364 {
365   OpenGl_Structure* aStruct = static_cast<OpenGl_Structure*> (&theStructure);
366
367   if (myInstancedStructure == aStruct)
368   {
369     myInstancedStructure = NULL;
370
371     if (aStruct->IsRaytracable())
372     {
373       UpdateStateIfRaytracable();
374     }
375   }
376 }
377
378 // =======================================================================
379 // function : NewGroup
380 // purpose  :
381 // =======================================================================
382 Handle(Graphic3d_Group) OpenGl_Structure::NewGroup (const Handle(Graphic3d_Structure)& theStruct)
383 {
384   Handle(OpenGl_Group) aGroup = new OpenGl_Group (theStruct);
385   myGroups.Append (aGroup);
386   return aGroup;
387 }
388
389 // =======================================================================
390 // function : RemoveGroup
391 // purpose  :
392 // =======================================================================
393 void OpenGl_Structure::RemoveGroup (const Handle(Graphic3d_Group)& theGroup)
394 {
395   if (theGroup.IsNull())
396   {
397     return;
398   }
399
400   for (Graphic3d_SequenceOfGroup::Iterator aGroupIter (myGroups); aGroupIter.More(); aGroupIter.Next())
401   {
402     // Check for the given group
403     if (aGroupIter.Value() == theGroup)
404     {
405       const Standard_Boolean wasRaytracable =
406         static_cast<const OpenGl_Group&> (*theGroup).IsRaytracable();
407
408       theGroup->Clear (Standard_False);
409
410       if (wasRaytracable)
411       {
412         UpdateStateIfRaytracable();
413       }
414
415       myGroups.Remove (aGroupIter);
416       return;
417     }
418   }
419 }
420
421 // =======================================================================
422 // function : Clear
423 // purpose  :
424 // =======================================================================
425 void OpenGl_Structure::Clear()
426 {
427   Clear (GlDriver()->GetSharedContext());
428 }
429
430 // =======================================================================
431 // function : Clear
432 // purpose  :
433 // =======================================================================
434 void OpenGl_Structure::Clear (const Handle(OpenGl_Context)& theGlCtx)
435 {
436   Standard_Boolean aRaytracableGroupDeleted (Standard_False);
437
438   // Release groups
439   for (OpenGl_Structure::GroupIterator aGroupIter (myGroups); aGroupIter.More(); aGroupIter.Next())
440   {
441     aRaytracableGroupDeleted |= aGroupIter.Value()->IsRaytracable();
442
443     // Delete objects
444     aGroupIter.ChangeValue()->Release (theGlCtx);
445   }
446   myGroups.Clear();
447
448   if (aRaytracableGroupDeleted)
449   {
450     myIsRaytracable = Standard_False;
451   }
452
453   Is2dText       = Standard_False;
454   IsForHighlight = Standard_False;
455 }
456
457 // =======================================================================
458 // function : renderGeometry
459 // purpose  :
460 // =======================================================================
461 void OpenGl_Structure::renderGeometry (const Handle(OpenGl_Workspace)& theWorkspace,
462                                        bool&                           theHasClosed) const
463 {
464   if (myInstancedStructure != NULL)
465   {
466     myInstancedStructure->renderGeometry (theWorkspace, theHasClosed);
467   }
468
469   for (OpenGl_Structure::GroupIterator aGroupIter (myGroups); aGroupIter.More(); aGroupIter.Next())
470   {
471     theHasClosed = theHasClosed || aGroupIter.Value()->IsClosed();
472     aGroupIter.Value()->Render (theWorkspace);
473   }
474 }
475
476 // =======================================================================
477 // function : Render
478 // purpose  :
479 // =======================================================================
480 void OpenGl_Structure::Render (const Handle(OpenGl_Workspace) &theWorkspace) const
481 {
482   // Process the structure only if visible
483   if (!visible)
484   {
485     return;
486   }
487
488   const Handle(OpenGl_Context)& aCtx = theWorkspace->GetGlContext();
489
490   // Render named status
491   if (highlight && myHighlightBox.IsNull())
492   {
493     theWorkspace->SetHighlightStyle (myHighlightStyle);
494   }
495
496   // Apply local transformation
497   aCtx->ModelWorldState.Push();
498   OpenGl_Mat4& aModelWorld = aCtx->ModelWorldState.ChangeCurrent();
499   aModelWorld = myRenderTrsf;
500
501   const Standard_Boolean anOldGlNormalize = aCtx->IsGlNormalizeEnabled();
502 #if !defined(GL_ES_VERSION_2_0)
503   // detect scale transform
504   if (aCtx->core11 != NULL
505   && !myTrsf.IsNull())
506   {
507     const Standard_Real aScale = myTrsf->ScaleFactor();
508     if (Abs (aScale - 1.0) > Precision::Confusion())
509     {
510       aCtx->SetGlNormalizeEnabled (Standard_True);
511     }
512   }
513 #endif
514
515   if (!myTrsfPers.IsNull())
516   {
517     aCtx->WorldViewState.Push();
518     OpenGl_Mat4& aWorldView = aCtx->WorldViewState.ChangeCurrent();
519     myTrsfPers->Apply (theWorkspace->View()->Camera(),
520                        aCtx->ProjectionState.Current(), aWorldView,
521                        aCtx->VirtualViewport()[2], aCtx->VirtualViewport()[3]);
522
523   #if !defined(GL_ES_VERSION_2_0)
524     if (!aCtx->IsGlNormalizeEnabled()
525       && aCtx->core11 != NULL)
526     {
527       const Standard_Real aScale = Graphic3d_TransformUtils::ScaleFactor<Standard_ShortReal> (aWorldView);
528       if (Abs (aScale - 1.0) > Precision::Confusion())
529       {
530         aCtx->SetGlNormalizeEnabled (Standard_True);
531       }
532     }
533   #endif
534   }
535
536   // Take into account transform persistence
537   aCtx->ApplyModelViewMatrix();
538
539   // remember aspects
540   const OpenGl_AspectLine*   aPrevAspectLine   = theWorkspace->AspectLine();
541   const OpenGl_AspectFace*   aPrevAspectFace   = theWorkspace->AspectFace();
542   const OpenGl_AspectMarker* aPrevAspectMarker = theWorkspace->AspectMarker();
543   const OpenGl_AspectText*   aPrevAspectText   = theWorkspace->AspectText();
544
545   // Apply correction for mirror transform
546   if (myIsMirrored)
547   {
548     aCtx->core11fwd->glFrontFace (GL_CW);
549   }
550
551   // Collect clipping planes of structure scope
552   aCtx->ChangeClipping().SetLocalPlanes (myClipPlanes);
553
554   // True if structure is fully clipped
555   bool isClipped = false;
556   bool hasDisabled = false;
557   if (aCtx->Clipping().IsClippingOrCappingOn())
558   {
559     const Graphic3d_BndBox3d& aBBox = BoundingBox();
560     if (!myClipPlanes.IsNull()
561       && myClipPlanes->ToOverrideGlobal())
562     {
563       aCtx->ChangeClipping().DisableGlobal();
564       hasDisabled = aCtx->Clipping().HasDisabled();
565     }
566     else if (!myTrsfPers.IsNull())
567     {
568       if (myTrsfPers->IsZoomOrRotate())
569       {
570         // Zoom/rotate persistence object lives in two worlds at the same time.
571         // Global clipping planes can not be trivially applied without being converted
572         // into local space of transformation persistence object.
573         // As more simple alternative - just clip entire object by its anchor point defined in the world space.
574         const gp_Pnt anAnchor = myTrsfPers->AnchorPoint();
575         for (OpenGl_ClippingIterator aPlaneIt (aCtx->Clipping()); aPlaneIt.More() && aPlaneIt.IsGlobal(); aPlaneIt.Next())
576         {
577           const Handle(Graphic3d_ClipPlane)& aPlane = aPlaneIt.Value();
578           if (!aPlane->IsOn())
579           {
580             continue;
581           }
582
583           // check for clipping
584           const Graphic3d_Vec4d aCheckPnt (anAnchor.X(), anAnchor.Y(), anAnchor.Z(), 1.0);
585           if (aPlane->ProbePoint (aCheckPnt) == Graphic3d_ClipState_Out)
586           {
587             isClipped = true;
588             break;
589           }
590         }
591       }
592
593       aCtx->ChangeClipping().DisableGlobal();
594       hasDisabled = aCtx->Clipping().HasDisabled();
595     }
596
597     // Set of clipping planes that do not intersect the structure,
598     // and thus can be disabled to improve rendering performance
599     if (aBBox.IsValid()
600      && myTrsfPers.IsNull())
601     {
602       for (OpenGl_ClippingIterator aPlaneIt (aCtx->Clipping()); aPlaneIt.More(); aPlaneIt.Next())
603       {
604         const Handle(Graphic3d_ClipPlane)& aPlane = aPlaneIt.Value();
605         if (aPlaneIt.IsDisabled())
606         {
607           continue;
608         }
609
610         const Graphic3d_ClipState aBoxState = aPlane->ProbeBox (aBBox);
611         if (aBoxState == Graphic3d_ClipState_Out)
612         {
613           isClipped = true;
614           break;
615         }
616         else if (aBoxState == Graphic3d_ClipState_In)
617         {
618           aCtx->ChangeClipping().SetEnabled (aPlaneIt, false);
619           hasDisabled = true;
620         }
621       }
622     }
623
624     if ((!myClipPlanes.IsNull() && !myClipPlanes->IsEmpty())
625      || hasDisabled)
626     {
627       // Set OCCT state uniform variables
628       aCtx->ShaderManager()->UpdateClippingState();
629     }
630   }
631
632   // Render groups
633   bool hasClosedPrims = false;
634   if (!isClipped)
635   {
636     renderGeometry (theWorkspace, hasClosedPrims);
637   }
638
639   // Reset correction for mirror transform
640   if (myIsMirrored)
641   {
642     aCtx->core11fwd->glFrontFace (GL_CCW);
643   }
644
645   // Render capping for structure groups
646   if (hasClosedPrims
647    && aCtx->Clipping().IsCappingOn())
648   {
649     OpenGl_CappingAlgo::RenderCapping (theWorkspace, *this);
650   }
651
652   // Revert structure clippings
653   if (hasDisabled)
654   {
655     // enable planes that were previously disabled
656     aCtx->ChangeClipping().RestoreDisabled();
657   }
658   aCtx->ChangeClipping().SetLocalPlanes (Handle(Graphic3d_SequenceOfHClipPlane)());
659   if ((!myClipPlanes.IsNull() && !myClipPlanes->IsEmpty())
660     || hasDisabled)
661   {
662     // Set OCCT state uniform variables
663     aCtx->ShaderManager()->RevertClippingState();
664   }
665
666   // Restore local transformation
667   aCtx->ModelWorldState.Pop();
668   aCtx->SetGlNormalizeEnabled (anOldGlNormalize);
669   if (!myTrsfPers.IsNull())
670   {
671     aCtx->WorldViewState.Pop();
672   }
673
674   // Restore aspects
675   theWorkspace->SetAspectLine   (aPrevAspectLine);
676   theWorkspace->SetAspectFace   (aPrevAspectFace);
677   theWorkspace->SetAspectMarker (aPrevAspectMarker);
678   theWorkspace->SetAspectText   (aPrevAspectText);
679
680   // Apply highlight box
681   if (!myHighlightBox.IsNull())
682   {
683     theWorkspace->SetHighlightStyle (myHighlightStyle);
684     myHighlightBox->Render (theWorkspace);
685   }
686
687   // Restore named status
688   theWorkspace->SetHighlightStyle (Handle(Graphic3d_PresentationAttributes)());
689 }
690
691 // =======================================================================
692 // function : Release
693 // purpose  :
694 // =======================================================================
695 void OpenGl_Structure::Release (const Handle(OpenGl_Context)& theGlCtx)
696 {
697   // Release groups
698   Clear (theGlCtx);
699   clearHighlightBox (theGlCtx);
700   myHighlightStyle.Nullify();
701 }
702
703 // =======================================================================
704 // function : ReleaseGlResources
705 // purpose  :
706 // =======================================================================
707 void OpenGl_Structure::ReleaseGlResources (const Handle(OpenGl_Context)& theGlCtx)
708 {
709   for (OpenGl_Structure::GroupIterator aGroupIter (myGroups); aGroupIter.More(); aGroupIter.Next())
710   {
711     aGroupIter.ChangeValue()->Release (theGlCtx);
712   }
713   if (!myHighlightBox.IsNull())
714   {
715     myHighlightBox->Release (theGlCtx.operator->());
716   }
717 }
718
719 //=======================================================================
720 //function : ShadowLink
721 //purpose  :
722 //=======================================================================
723 Handle(Graphic3d_CStructure) OpenGl_Structure::ShadowLink (const Handle(Graphic3d_StructureManager)& theManager) const
724 {
725   return new OpenGl_StructureShadow (theManager, this);
726 }