0025180: Visualization - Homogeneous transformation API in TKV3d
[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 : SetTransformation
143 // purpose  :
144 // =======================================================================
145 void OpenGl_Structure::SetTransformation (const Handle(Geom_Transformation)& theTrsf)
146 {
147   myTrsf = theTrsf;
148   myIsMirrored = Standard_False;
149   if (!myTrsf.IsNull())
150   {
151     // Determinant of transform matrix less then 0 means that mirror transform applied.
152     const Standard_Real aDet = myTrsf->Value(1, 1) * (myTrsf->Value (2, 2) * myTrsf->Value (3, 3) - myTrsf->Value (3, 2) * myTrsf->Value (2, 3))
153                              - myTrsf->Value(1, 2) * (myTrsf->Value (2, 1) * myTrsf->Value (3, 3) - myTrsf->Value (3, 1) * myTrsf->Value (2, 3))
154                              + myTrsf->Value(1, 3) * (myTrsf->Value (2, 1) * myTrsf->Value (3, 2) - myTrsf->Value (3, 1) * myTrsf->Value (2, 2));
155     myIsMirrored = aDet < 0.0;
156   }
157
158   if (IsRaytracable())
159   {
160     ++myModificationState;
161   }
162 }
163
164 // =======================================================================
165 // function : clearHighlightBox
166 // purpose  :
167 // =======================================================================
168 void OpenGl_Structure::clearHighlightBox (const Handle(OpenGl_Context)& theGlCtx)
169 {
170   if (!myHighlightBox.IsNull())
171   {
172     myHighlightBox->Release (theGlCtx);
173     myHighlightBox.Nullify();
174   }
175 }
176
177 // =======================================================================
178 // function : HighlightWithColor
179 // purpose  :
180 // =======================================================================
181 void OpenGl_Structure::HighlightWithColor (const Graphic3d_Vec3&  theColor,
182                                            const Standard_Boolean theToCreate)
183 {
184   const Handle(OpenGl_Context)& aContext = GlDriver()->GetSharedContext();
185   if (theToCreate)
186     setHighlightColor   (aContext, theColor);
187   else
188     clearHighlightColor (aContext);
189 }
190
191 // =======================================================================
192 // function : HighlightWithBndBox
193 // purpose  :
194 // =======================================================================
195 void OpenGl_Structure::HighlightWithBndBox (const Handle(Graphic3d_Structure)& theStruct,
196                                             const Standard_Boolean             theToCreate)
197 {
198   const Handle(OpenGl_Context)& aContext = GlDriver()->GetSharedContext();
199   if (!theToCreate)
200   {
201     clearHighlightBox (aContext);
202     return;
203   }
204
205   if (!myHighlightBox.IsNull())
206   {
207     myHighlightBox->Release (aContext);
208   }
209   else
210   {
211     myHighlightBox = new OpenGl_Group (theStruct);
212   }
213
214   myHighlightBox->SetGroupPrimitivesAspect (new Graphic3d_AspectLine3d (HighlightColor, Aspect_TOL_SOLID, 1.0));
215
216   OpenGl_BndBoxPrs* aBndBoxPrs = new OpenGl_BndBoxPrs (myBndBox);
217   myHighlightBox->AddElement (aBndBoxPrs);
218 }
219
220 // =======================================================================
221 // function : setHighlightColor
222 // purpose  :
223 // =======================================================================
224 void OpenGl_Structure::setHighlightColor (const Handle(OpenGl_Context)& theGlCtx,
225                                           const Graphic3d_Vec3&         theColor)
226 {
227   clearHighlightBox (theGlCtx);
228   if (myHighlightColor == NULL)
229   {
230     myHighlightColor = new OpenGl_Vec4 (theColor, 1.0f);
231   }
232   else
233   {
234     myHighlightColor->xyz() = theColor;
235   }
236 }
237
238 // =======================================================================
239 // function : clearHighlightColor
240 // purpose  :
241 // =======================================================================
242 void OpenGl_Structure::clearHighlightColor (const Handle(OpenGl_Context)& theGlCtx)
243 {
244   clearHighlightBox(theGlCtx);
245   delete myHighlightColor;
246   myHighlightColor = NULL;
247 }
248
249 // =======================================================================
250 // function : OnVisibilityChanged
251 // purpose  :
252 // =======================================================================
253 void OpenGl_Structure::OnVisibilityChanged()
254 {
255   if (IsRaytracable())
256   {
257     ++myModificationState;
258   }
259 }
260
261 // =======================================================================
262 // function : IsRaytracable
263 // purpose  :
264 // =======================================================================
265 Standard_Boolean OpenGl_Structure::IsRaytracable() const
266 {
267   if (!myGroups.IsEmpty()
268     && myIsRaytracable)
269   {
270     return Standard_True;
271   }
272
273   return myInstancedStructure != NULL
274      &&  myInstancedStructure->IsRaytracable();
275 }
276
277 // =======================================================================
278 // function : UpdateRaytracableState
279 // purpose  :
280 // =======================================================================
281 void OpenGl_Structure::UpdateStateIfRaytracable (const Standard_Boolean toCheck) const
282 {
283   myIsRaytracable = !toCheck;
284   if (!myIsRaytracable)
285   {
286     for (OpenGl_Structure::GroupIterator anIter (myGroups); anIter.More(); anIter.Next())
287     {
288       if (anIter.Value()->IsRaytracable())
289       {
290         myIsRaytracable = Standard_True;
291         break;
292       }
293     }
294   }
295
296   if (IsRaytracable())
297   {
298     ++myModificationState;
299   }
300 }
301
302 // =======================================================================
303 // function : Connect
304 // purpose  :
305 // =======================================================================
306 void OpenGl_Structure::Connect (Graphic3d_CStructure& theStructure)
307 {
308   OpenGl_Structure* aStruct = static_cast<OpenGl_Structure*> (&theStructure);
309
310   Standard_ASSERT_RAISE (myInstancedStructure == NULL || myInstancedStructure == aStruct,
311     "Error! Instanced structure is already defined");
312
313   myInstancedStructure = aStruct;
314
315   if (aStruct->IsRaytracable())
316   {
317     UpdateStateIfRaytracable (Standard_False);
318   }
319 }
320
321 // =======================================================================
322 // function : Disconnect
323 // purpose  :
324 // =======================================================================
325 void OpenGl_Structure::Disconnect (Graphic3d_CStructure& theStructure)
326 {
327   OpenGl_Structure* aStruct = static_cast<OpenGl_Structure*> (&theStructure);
328
329   if (myInstancedStructure == aStruct)
330   {
331     myInstancedStructure = NULL;
332
333     if (aStruct->IsRaytracable())
334     {
335       UpdateStateIfRaytracable();
336     }
337   }
338 }
339
340 // =======================================================================
341 // function : NewGroup
342 // purpose  :
343 // =======================================================================
344 Handle(Graphic3d_Group) OpenGl_Structure::NewGroup (const Handle(Graphic3d_Structure)& theStruct)
345 {
346   Handle(OpenGl_Group) aGroup = new OpenGl_Group (theStruct);
347   myGroups.Append (aGroup);
348   return aGroup;
349 }
350
351 // =======================================================================
352 // function : RemoveGroup
353 // purpose  :
354 // =======================================================================
355 void OpenGl_Structure::RemoveGroup (const Handle(Graphic3d_Group)& theGroup)
356 {
357   if (theGroup.IsNull())
358   {
359     return;
360   }
361
362   for (Graphic3d_SequenceOfGroup::Iterator aGroupIter (myGroups); aGroupIter.More(); aGroupIter.Next())
363   {
364     // Check for the given group
365     if (aGroupIter.Value() == theGroup)
366     {
367       const Standard_Boolean wasRaytracable =
368         static_cast<const OpenGl_Group&> (*theGroup).IsRaytracable();
369
370       theGroup->Clear (Standard_False);
371
372       if (wasRaytracable)
373       {
374         UpdateStateIfRaytracable();
375       }
376
377       myGroups.Remove (aGroupIter);
378       return;
379     }
380   }
381 }
382
383 // =======================================================================
384 // function : Clear
385 // purpose  :
386 // =======================================================================
387 void OpenGl_Structure::Clear()
388 {
389   Clear (GlDriver()->GetSharedContext());
390 }
391
392 // =======================================================================
393 // function : Clear
394 // purpose  :
395 // =======================================================================
396 void OpenGl_Structure::Clear (const Handle(OpenGl_Context)& theGlCtx)
397 {
398   Standard_Boolean aRaytracableGroupDeleted (Standard_False);
399
400   // Release groups
401   for (OpenGl_Structure::GroupIterator aGroupIter (myGroups); aGroupIter.More(); aGroupIter.Next())
402   {
403     aRaytracableGroupDeleted |= aGroupIter.Value()->IsRaytracable();
404
405     // Delete objects
406     aGroupIter.ChangeValue()->Release (theGlCtx);
407   }
408   myGroups.Clear();
409
410   if (aRaytracableGroupDeleted)
411   {
412     myIsRaytracable = Standard_False;
413   }
414
415   Is2dText       = Standard_False;
416   IsForHighlight = Standard_False;
417 }
418
419 // =======================================================================
420 // function : renderGeometry
421 // purpose  :
422 // =======================================================================
423 void OpenGl_Structure::renderGeometry (const Handle(OpenGl_Workspace)& theWorkspace,
424                                        bool&                           theHasClosed) const
425 {
426   if (myInstancedStructure != NULL)
427   {
428     myInstancedStructure->renderGeometry (theWorkspace, theHasClosed);
429   }
430
431   for (OpenGl_Structure::GroupIterator aGroupIter (myGroups); aGroupIter.More(); aGroupIter.Next())
432   {
433     theHasClosed = theHasClosed || aGroupIter.Value()->IsClosed();
434     aGroupIter.Value()->Render (theWorkspace);
435   }
436 }
437
438 // =======================================================================
439 // function : Render
440 // purpose  :
441 // =======================================================================
442 void OpenGl_Structure::Render (const Handle(OpenGl_Workspace) &theWorkspace) const
443 {
444   // Process the structure only if visible
445   if (!visible)
446   {
447     return;
448   }
449
450   const Handle(OpenGl_Context)& aCtx = theWorkspace->GetGlContext();
451
452   // Render named status
453   if (highlight)
454   {
455     theWorkspace->SetHighlight (true);
456   }
457
458   // Apply local transformation
459   aCtx->ModelWorldState.Push();
460   OpenGl_Mat4& aModelWorld = aCtx->ModelWorldState.ChangeCurrent();
461   if (!myTrsf.IsNull())
462   {
463     myTrsf->Trsf().GetMat4 (aModelWorld);
464   }
465   else
466   {
467     aModelWorld.InitIdentity();
468   }
469
470   const Standard_Boolean anOldGlNormalize = aCtx->IsGlNormalizeEnabled();
471
472 #if !defined(GL_ES_VERSION_2_0)
473   // detect scale transform
474   if (aCtx->core11 != NULL
475   && !myTrsf.IsNull())
476   {
477     const Standard_Real aScale = myTrsf->ScaleFactor();
478     if (Abs (aScale - 1.0) > Precision::Confusion())
479     {
480       aCtx->SetGlNormalizeEnabled (Standard_True);
481     }
482   }
483 #endif
484
485   if (!myTrsfPers.IsNull())
486   {
487     OpenGl_Mat4 aWorldView = aCtx->WorldViewState.Current();
488     myTrsfPers->Apply (theWorkspace->View()->Camera(), aCtx->ProjectionState.Current(), aWorldView,
489                        aCtx->Viewport()[2], aCtx->Viewport()[3]);
490
491     aCtx->WorldViewState.Push();
492     aCtx->WorldViewState.SetCurrent (aWorldView);
493
494   #if !defined(GL_ES_VERSION_2_0)
495     if (!aCtx->IsGlNormalizeEnabled()
496       && aCtx->core11 != NULL)
497     {
498       const Standard_Real aScale = Graphic3d_TransformUtils::ScaleFactor<Standard_ShortReal> (aWorldView);
499       if (Abs (aScale - 1.0f) > Precision::Confusion())
500       {
501         aCtx->SetGlNormalizeEnabled (Standard_True);
502       }
503     }
504   #endif
505   }
506
507   // Take into account transform persistence
508   aCtx->ApplyModelViewMatrix();
509
510   // remember aspects
511   const OpenGl_AspectLine*   aPrevAspectLine   = theWorkspace->AspectLine();
512   const OpenGl_AspectFace*   aPrevAspectFace   = theWorkspace->AspectFace();
513   const OpenGl_AspectMarker* aPrevAspectMarker = theWorkspace->AspectMarker();
514   const OpenGl_AspectText*   aPrevAspectText   = theWorkspace->AspectText();
515
516   // Apply correction for mirror transform
517   if (myIsMirrored)
518   {
519     aCtx->core11fwd->glFrontFace (GL_CW);
520   }
521
522   // Apply highlight color
523   const OpenGl_Vec4* aHighlightColor = theWorkspace->HighlightColor;
524   if (myHighlightColor)
525     theWorkspace->HighlightColor = myHighlightColor;
526
527   // Collect clipping planes of structure scope
528   aCtx->ChangeClipping().SetLocalPlanes (aCtx, myClipPlanes);
529
530   // True if structure is fully clipped
531   bool isClipped = false;
532   bool hasDisabled = false;
533   if (aCtx->Clipping().IsClippingOrCappingOn())
534   {
535     const Graphic3d_BndBox4f& aBBox = BoundingBox();
536     if ((!myTrsfPers.IsNull() && myTrsfPers->IsTrihedronOr2d())
537      || (!myClipPlanes.IsNull() && myClipPlanes->ToOverrideGlobal()))
538     {
539       aCtx->ChangeClipping().DisableGlobal (aCtx);
540       hasDisabled = aCtx->Clipping().HasDisabled();
541     }
542
543     // Set of clipping planes that do not intersect the structure,
544     // and thus can be disabled to improve rendering performance
545     if (aBBox.IsValid()
546      && myTrsfPers.IsNull())
547     {
548       for (OpenGl_ClippingIterator aPlaneIt (aCtx->Clipping()); aPlaneIt.More(); aPlaneIt.Next())
549       {
550         const Handle(Graphic3d_ClipPlane)& aPlane = aPlaneIt.Value();
551         if (!aPlane->IsOn())
552         {
553           continue;
554         }
555
556         // check for clipping
557         const Graphic3d_Vec4d& aPlaneEquation = aPlane->GetEquation();
558         const Graphic3d_Vec4d aMaxPnt (aPlaneEquation.x() > 0.0 ? aBBox.CornerMax().x() : aBBox.CornerMin().x(),
559                                        aPlaneEquation.y() > 0.0 ? aBBox.CornerMax().y() : aBBox.CornerMin().y(),
560                                        aPlaneEquation.z() > 0.0 ? aBBox.CornerMax().z() : aBBox.CornerMin().z(),
561                                        1.0);
562         if (aPlaneEquation.Dot (aMaxPnt) < 0.0) // max vertex is outside the half-space
563         {
564           isClipped = true;
565           break;
566         }
567
568         // check for no intersection (e.g. object is "entirely not clipped")
569         const Graphic3d_Vec4d aMinPnt (aPlaneEquation.x() > 0.0 ? aBBox.CornerMin().x() : aBBox.CornerMax().x(),
570                                        aPlaneEquation.y() > 0.0 ? aBBox.CornerMin().y() : aBBox.CornerMax().y(),
571                                        aPlaneEquation.z() > 0.0 ? aBBox.CornerMin().z() : aBBox.CornerMax().z(),
572                                        1.0);
573         if (aPlaneEquation.Dot (aMinPnt) > 0.0) // min vertex is inside the half-space
574         {
575           aCtx->ChangeClipping().SetEnabled (aCtx, aPlaneIt, Standard_False);
576           hasDisabled = true;
577         }
578       }
579     }
580
581     if ((!myClipPlanes.IsNull() && !myClipPlanes->IsEmpty())
582      || hasDisabled)
583     {
584       // Set OCCT state uniform variables
585       aCtx->ShaderManager()->UpdateClippingState();
586     }
587   }
588
589   // Render groups
590   bool hasClosedPrims = false;
591   if (!isClipped)
592   {
593     renderGeometry (theWorkspace, hasClosedPrims);
594   }
595
596   // Reset correction for mirror transform
597   if (myIsMirrored)
598   {
599     aCtx->core11fwd->glFrontFace (GL_CCW);
600   }
601
602   // Render capping for structure groups
603   if (hasClosedPrims
604    && aCtx->Clipping().IsCappingOn())
605   {
606     OpenGl_CappingAlgo::RenderCapping (theWorkspace, *this);
607   }
608
609   // Revert structure clippings
610   if (hasDisabled)
611   {
612     // enable planes that were previously disabled
613     aCtx->ChangeClipping().RestoreDisabled (aCtx);
614   }
615   aCtx->ChangeClipping().SetLocalPlanes (aCtx, Handle(Graphic3d_SequenceOfHClipPlane)());
616   if ((!myClipPlanes.IsNull() && !myClipPlanes->IsEmpty())
617     || hasDisabled)
618   {
619     // Set OCCT state uniform variables
620     aCtx->ShaderManager()->RevertClippingState();
621   }
622
623   // Restore local transformation
624   aCtx->ModelWorldState.Pop();
625   aCtx->SetGlNormalizeEnabled (anOldGlNormalize);
626   if (!myTrsfPers.IsNull())
627   {
628     aCtx->WorldViewState.Pop();
629   }
630
631   // Restore highlight color
632   theWorkspace->HighlightColor = aHighlightColor;
633
634   // Restore aspects
635   theWorkspace->SetAspectLine   (aPrevAspectLine);
636   theWorkspace->SetAspectFace   (aPrevAspectFace);
637   theWorkspace->SetAspectMarker (aPrevAspectMarker);
638   theWorkspace->SetAspectText   (aPrevAspectText);
639
640   // Apply highlight box
641   if (!myHighlightBox.IsNull())
642   {
643     myHighlightBox->Render (theWorkspace);
644   }
645
646   // Restore named status
647   theWorkspace->SetHighlight (false);
648 }
649
650 // =======================================================================
651 // function : Release
652 // purpose  :
653 // =======================================================================
654 void OpenGl_Structure::Release (const Handle(OpenGl_Context)& theGlCtx)
655 {
656   // Release groups
657   Clear (theGlCtx);
658   clearHighlightColor (theGlCtx);
659 }
660
661 // =======================================================================
662 // function : ReleaseGlResources
663 // purpose  :
664 // =======================================================================
665 void OpenGl_Structure::ReleaseGlResources (const Handle(OpenGl_Context)& theGlCtx)
666 {
667   for (OpenGl_Structure::GroupIterator aGroupIter (myGroups); aGroupIter.More(); aGroupIter.Next())
668   {
669     aGroupIter.ChangeValue()->Release (theGlCtx);
670   }
671   if (!myHighlightBox.IsNull())
672   {
673     myHighlightBox->Release (theGlCtx.operator->());
674   }
675 }
676
677 //=======================================================================
678 //function : ShadowLink
679 //purpose  :
680 //=======================================================================
681 Handle(Graphic3d_CStructure) OpenGl_Structure::ShadowLink (const Handle(Graphic3d_StructureManager)& theManager) const
682 {
683   return new OpenGl_StructureShadow (theManager, this);
684 }