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