0027860: Visualization - clean up Transformation Persistence API
[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 (!myTrsfPers.IsNull())
475   {
476     OpenGl_Mat4 aWorldView = aCtx->WorldViewState.Current();
477     myTrsfPers->Apply (theWorkspace->View()->Camera(), aCtx->ProjectionState.Current(), aWorldView,
478                        aCtx->Viewport()[2], aCtx->Viewport()[3]);
479
480     aCtx->WorldViewState.Push();
481     aCtx->WorldViewState.SetCurrent (aWorldView);
482
483   #if !defined(GL_ES_VERSION_2_0)
484     if (!aCtx->IsGlNormalizeEnabled()
485       && aCtx->core11 != NULL)
486     {
487       const Standard_Real aScale = Graphic3d_TransformUtils::ScaleFactor<Standard_ShortReal> (aWorldView);
488       if (Abs (aScale - 1.0f) > Precision::Confusion())
489       {
490         aCtx->SetGlNormalizeEnabled (Standard_True);
491       }
492     }
493   #endif
494   }
495
496   // Take into account transform persistence
497   aCtx->ApplyModelViewMatrix();
498
499   // remember aspects
500   const OpenGl_AspectLine*   aPrevAspectLine   = theWorkspace->AspectLine();
501   const OpenGl_AspectFace*   aPrevAspectFace   = theWorkspace->AspectFace();
502   const OpenGl_AspectMarker* aPrevAspectMarker = theWorkspace->AspectMarker();
503   const OpenGl_AspectText*   aPrevAspectText   = theWorkspace->AspectText();
504
505   // Apply correction for mirror transform
506   if (myIsMirrored)
507   {
508     aCtx->core11fwd->glFrontFace (GL_CW);
509   }
510
511   // Apply highlight color
512   const OpenGl_Vec4* aHighlightColor = theWorkspace->HighlightColor;
513   if (myHighlightColor)
514     theWorkspace->HighlightColor = myHighlightColor;
515
516   // Collect clipping planes of structure scope
517   aCtx->ChangeClipping().SetLocalPlanes (aCtx, myClipPlanes);
518
519   // True if structure is fully clipped
520   bool isClipped = false;
521   bool hasDisabled = false;
522   if (aCtx->Clipping().IsClippingOrCappingOn())
523   {
524     const Graphic3d_BndBox4f& aBBox = BoundingBox();
525     if ((!myTrsfPers.IsNull() && myTrsfPers->IsTrihedronOr2d())
526      || (!myClipPlanes.IsNull() && myClipPlanes->ToOverrideGlobal()))
527     {
528       aCtx->ChangeClipping().DisableGlobal (aCtx);
529       hasDisabled = aCtx->Clipping().HasDisabled();
530     }
531
532     // Set of clipping planes that do not intersect the structure,
533     // and thus can be disabled to improve rendering performance
534     if (aBBox.IsValid()
535      && myTrsfPers.IsNull())
536     {
537       for (OpenGl_ClippingIterator aPlaneIt (aCtx->Clipping()); aPlaneIt.More(); aPlaneIt.Next())
538       {
539         const Handle(Graphic3d_ClipPlane)& aPlane = aPlaneIt.Value();
540         if (!aPlane->IsOn())
541         {
542           continue;
543         }
544
545         // check for clipping
546         const Graphic3d_Vec4d& aPlaneEquation = aPlane->GetEquation();
547         const Graphic3d_Vec4d aMaxPnt (aPlaneEquation.x() > 0.0 ? aBBox.CornerMax().x() : aBBox.CornerMin().x(),
548                                        aPlaneEquation.y() > 0.0 ? aBBox.CornerMax().y() : aBBox.CornerMin().y(),
549                                        aPlaneEquation.z() > 0.0 ? aBBox.CornerMax().z() : aBBox.CornerMin().z(),
550                                        1.0);
551         if (aPlaneEquation.Dot (aMaxPnt) < 0.0) // max vertex is outside the half-space
552         {
553           isClipped = true;
554           break;
555         }
556
557         // check for no intersection (e.g. object is "entirely not clipped")
558         const Graphic3d_Vec4d aMinPnt (aPlaneEquation.x() > 0.0 ? aBBox.CornerMin().x() : aBBox.CornerMax().x(),
559                                        aPlaneEquation.y() > 0.0 ? aBBox.CornerMin().y() : aBBox.CornerMax().y(),
560                                        aPlaneEquation.z() > 0.0 ? aBBox.CornerMin().z() : aBBox.CornerMax().z(),
561                                        1.0);
562         if (aPlaneEquation.Dot (aMinPnt) > 0.0) // min vertex is inside the half-space
563         {
564           aCtx->ChangeClipping().SetEnabled (aCtx, aPlaneIt, Standard_False);
565           hasDisabled = true;
566         }
567       }
568     }
569
570     if ((!myClipPlanes.IsNull() && !myClipPlanes->IsEmpty())
571      || hasDisabled)
572     {
573       // Set OCCT state uniform variables
574       aCtx->ShaderManager()->UpdateClippingState();
575     }
576   }
577
578   // Render groups
579   bool hasClosedPrims = false;
580   if (!isClipped)
581   {
582     renderGeometry (theWorkspace, hasClosedPrims);
583   }
584
585   // Reset correction for mirror transform
586   if (myIsMirrored)
587   {
588     aCtx->core11fwd->glFrontFace (GL_CCW);
589   }
590
591   // Render capping for structure groups
592   if (hasClosedPrims
593    && aCtx->Clipping().IsCappingOn())
594   {
595     OpenGl_CappingAlgo::RenderCapping (theWorkspace, *this);
596   }
597
598   // Revert structure clippings
599   if (hasDisabled)
600   {
601     // enable planes that were previously disabled
602     aCtx->ChangeClipping().RestoreDisabled (aCtx);
603   }
604   aCtx->ChangeClipping().SetLocalPlanes (aCtx, Handle(Graphic3d_SequenceOfHClipPlane)());
605   if ((!myClipPlanes.IsNull() && !myClipPlanes->IsEmpty())
606     || hasDisabled)
607   {
608     // Set OCCT state uniform variables
609     aCtx->ShaderManager()->RevertClippingState();
610   }
611
612   // Restore local transformation
613   aCtx->ModelWorldState.Pop();
614   aCtx->SetGlNormalizeEnabled (anOldGlNormalize);
615   if (!myTrsfPers.IsNull())
616   {
617     aCtx->WorldViewState.Pop();
618   }
619
620   // Restore highlight color
621   theWorkspace->HighlightColor = aHighlightColor;
622
623   // Restore aspects
624   theWorkspace->SetAspectLine   (aPrevAspectLine);
625   theWorkspace->SetAspectFace   (aPrevAspectFace);
626   theWorkspace->SetAspectMarker (aPrevAspectMarker);
627   theWorkspace->SetAspectText   (aPrevAspectText);
628
629   // Apply highlight box
630   if (!myHighlightBox.IsNull())
631   {
632     myHighlightBox->Render (theWorkspace);
633   }
634
635   // Restore named status
636   theWorkspace->SetHighlight (false);
637 }
638
639 // =======================================================================
640 // function : Release
641 // purpose  :
642 // =======================================================================
643 void OpenGl_Structure::Release (const Handle(OpenGl_Context)& theGlCtx)
644 {
645   // Release groups
646   Clear (theGlCtx);
647   clearHighlightColor (theGlCtx);
648 }
649
650 // =======================================================================
651 // function : ReleaseGlResources
652 // purpose  :
653 // =======================================================================
654 void OpenGl_Structure::ReleaseGlResources (const Handle(OpenGl_Context)& theGlCtx)
655 {
656   for (OpenGl_Structure::GroupIterator aGroupIter (myGroups); aGroupIter.More(); aGroupIter.Next())
657   {
658     aGroupIter.ChangeValue()->Release (theGlCtx);
659   }
660   if (!myHighlightBox.IsNull())
661   {
662     myHighlightBox->Release (theGlCtx.operator->());
663   }
664 }
665
666 //=======================================================================
667 //function : ShadowLink
668 //purpose  :
669 //=======================================================================
670 Handle(Graphic3d_CStructure) OpenGl_Structure::ShadowLink (const Handle(Graphic3d_StructureManager)& theManager) const
671 {
672   return new OpenGl_StructureShadow (theManager, this);
673 }