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