05d0dd6b16c1d97841bc3a33d252e521e2e04ce9
[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().rgb);
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   CALL_DEF_CONTEXTLINE& aContextLine = myHighlightBox->ChangeContextLine();
213   aContextLine.IsDef    = 1;
214   aContextLine.Color    = HighlightColor;
215   aContextLine.LineType = Aspect_TOL_SOLID;
216   aContextLine.Width    = 1.0f;
217   myHighlightBox->UpdateAspectLine (Standard_True);
218
219   OpenGl_BndBoxPrs* aBndBoxPrs = new OpenGl_BndBoxPrs (myBndBox);
220   myHighlightBox->AddElement (aBndBoxPrs);
221 }
222
223 // =======================================================================
224 // function : setHighlightColor
225 // purpose  :
226 // =======================================================================
227 void OpenGl_Structure::setHighlightColor (const Handle(OpenGl_Context)& theGlCtx,
228                                           const Graphic3d_Vec3&         theColor)
229 {
230   clearHighlightBox (theGlCtx);
231   if (myHighlightColor == NULL)
232   {
233     myHighlightColor = new TEL_COLOUR();
234   }
235
236   myHighlightColor->rgb[0] = theColor.r();
237   myHighlightColor->rgb[1] = theColor.g();
238   myHighlightColor->rgb[2] = theColor.b();
239   myHighlightColor->rgb[3] = 1.F;
240 }
241
242 // =======================================================================
243 // function : clearHighlightColor
244 // purpose  :
245 // =======================================================================
246 void OpenGl_Structure::clearHighlightColor (const Handle(OpenGl_Context)& theGlCtx)
247 {
248   clearHighlightBox(theGlCtx);
249   delete myHighlightColor;
250   myHighlightColor = NULL;
251 }
252
253 // =======================================================================
254 // function : OnVisibilityChanged
255 // purpose  :
256 // =======================================================================
257 void OpenGl_Structure::OnVisibilityChanged()
258 {
259   if (IsRaytracable())
260   {
261     ++myModificationState;
262   }
263 }
264
265 // =======================================================================
266 // function : IsRaytracable
267 // purpose  :
268 // =======================================================================
269 Standard_Boolean OpenGl_Structure::IsRaytracable() const
270 {
271   if (!myGroups.IsEmpty())
272   {
273     return myIsRaytracable; // geometry structure
274   }
275   else if (myInstancedStructure != NULL)
276   {
277     return myInstancedStructure->IsRaytracable(); // instance structure
278   }
279
280   return Standard_False; // has no any groups or structures
281 }
282
283 // =======================================================================
284 // function : UpdateRaytracableState
285 // purpose  :
286 // =======================================================================
287 void OpenGl_Structure::UpdateStateIfRaytracable (const Standard_Boolean toCheck) const
288 {
289   myIsRaytracable = !toCheck || OpenGl_Raytrace::IsRaytracedStructure (this);
290
291   if (IsRaytracable())
292   {
293     ++myModificationState;
294   }
295 }
296
297 // =======================================================================
298 // function : Connect
299 // purpose  :
300 // =======================================================================
301 void OpenGl_Structure::Connect (Graphic3d_CStructure& theStructure)
302 {
303   OpenGl_Structure* aStruct = static_cast<OpenGl_Structure*> (&theStructure);
304
305   Standard_ASSERT_RAISE (myInstancedStructure == NULL || myInstancedStructure == aStruct,
306     "Error! Instanced structure is already defined");
307
308   myInstancedStructure = aStruct;
309
310   if (aStruct->IsRaytracable())
311   {
312     UpdateStateIfRaytracable (Standard_False);
313   }
314 }
315
316 // =======================================================================
317 // function : Disconnect
318 // purpose  :
319 // =======================================================================
320 void OpenGl_Structure::Disconnect (Graphic3d_CStructure& theStructure)
321 {
322   OpenGl_Structure* aStruct = static_cast<OpenGl_Structure*> (&theStructure);
323
324   if (myInstancedStructure == aStruct)
325   {
326     myInstancedStructure = NULL;
327
328     if (aStruct->IsRaytracable())
329     {
330       UpdateStateIfRaytracable();
331     }
332   }
333 }
334
335 // =======================================================================
336 // function : NewGroup
337 // purpose  :
338 // =======================================================================
339 Handle(Graphic3d_Group) OpenGl_Structure::NewGroup (const Handle(Graphic3d_Structure)& theStruct)
340 {
341   Handle(OpenGl_Group) aGroup = new OpenGl_Group (theStruct);
342   myGroups.Append (aGroup);
343   return aGroup;
344 }
345
346 // =======================================================================
347 // function : RemoveGroup
348 // purpose  :
349 // =======================================================================
350 void OpenGl_Structure::RemoveGroup (const Handle(Graphic3d_Group)& theGroup)
351 {
352   if (theGroup.IsNull())
353   {
354     return;
355   }
356
357   for (Graphic3d_SequenceOfGroup::Iterator aGroupIter (myGroups); aGroupIter.More(); aGroupIter.Next())
358   {
359     // Check for the given group
360     if (aGroupIter.Value() == theGroup)
361     {
362       const Standard_Boolean wasRaytracable =
363         static_cast<const OpenGl_Group&> (*theGroup).IsRaytracable();
364
365       theGroup->Clear (Standard_False);
366
367       if (wasRaytracable)
368       {
369         UpdateStateIfRaytracable();
370       }
371
372       myGroups.Remove (aGroupIter);
373       return;
374     }
375   }
376 }
377
378 // =======================================================================
379 // function : Clear
380 // purpose  :
381 // =======================================================================
382 void OpenGl_Structure::Clear()
383 {
384   Clear (GlDriver()->GetSharedContext());
385 }
386
387 // =======================================================================
388 // function : Clear
389 // purpose  :
390 // =======================================================================
391 void OpenGl_Structure::Clear (const Handle(OpenGl_Context)& theGlCtx)
392 {
393   Standard_Boolean aRaytracableGroupDeleted (Standard_False);
394
395   // Release groups
396   for (OpenGl_Structure::GroupIterator aGroupIter (myGroups); aGroupIter.More(); aGroupIter.Next())
397   {
398     aRaytracableGroupDeleted |= aGroupIter.Value()->IsRaytracable();
399
400     // Delete objects
401     aGroupIter.ChangeValue()->Release (theGlCtx);
402   }
403   myGroups.Clear();
404
405   if (aRaytracableGroupDeleted)
406   {
407     myIsRaytracable = Standard_False;
408   }
409
410   Is2dText       = Standard_False;
411   IsForHighlight = Standard_False;
412 }
413
414 // =======================================================================
415 // function : renderGeometry
416 // purpose  :
417 // =======================================================================
418 void OpenGl_Structure::renderGeometry (const Handle(OpenGl_Workspace)& theWorkspace,
419                                        bool&                           theHasClosed) const
420 {
421   if (myInstancedStructure != NULL)
422   {
423     myInstancedStructure->renderGeometry (theWorkspace, theHasClosed);
424   }
425
426   for (OpenGl_Structure::GroupIterator aGroupIter (myGroups); aGroupIter.More(); aGroupIter.Next())
427   {
428     theHasClosed = theHasClosed || aGroupIter.Value()->IsClosed();
429     aGroupIter.Value()->Render (theWorkspace);
430   }
431 }
432
433 // =======================================================================
434 // function : renderClosedGeometry
435 // purpose  :
436 // =======================================================================
437 void OpenGl_Structure::renderClosedGeometry (const Handle(OpenGl_Workspace)& theWorkspace) const
438 {
439   if (myInstancedStructure != NULL)
440   {
441     myInstancedStructure->renderClosedGeometry (theWorkspace);
442   }
443
444   for (OpenGl_Structure::GroupIterator aGroupIter (myGroups); aGroupIter.More(); aGroupIter.Next())
445   {
446     if (aGroupIter.Value()->IsClosed())
447     {
448       aGroupIter.Value()->Render (theWorkspace);
449     }
450   }
451 }
452
453 // =======================================================================
454 // function : Render
455 // purpose  :
456 // =======================================================================
457 void OpenGl_Structure::Render (const Handle(OpenGl_Workspace) &theWorkspace) const
458 {
459   // Process the structure only if visible
460   if (!visible)
461   {
462     return;
463   }
464
465   const Handle(OpenGl_Context)& aCtx = theWorkspace->GetGlContext();
466
467   // Render named status
468   if (highlight)
469   {
470     theWorkspace->SetHighlight (true);
471   }
472
473   // Apply local transformation
474   aCtx->ModelWorldState.Push();
475   aCtx->ModelWorldState.SetCurrent (Transformation);
476
477   const Standard_Boolean anOldGlNormalize = aCtx->IsGlNormalizeEnabled();
478
479 #if !defined(GL_ES_VERSION_2_0)
480   // detect scale transform
481   if (aCtx->core11 != NULL)
482   {
483     const Standard_ShortReal aScaleX = Transformation.GetRow (0).xyz().SquareModulus();
484     if (Abs (aScaleX - 1.f) > Precision::Confusion())
485     {
486       aCtx->SetGlNormalizeEnabled (Standard_True);
487     }
488   }
489 #endif
490
491   if (TransformPersistence.Flags)
492   {
493     OpenGl_Mat4 aProjection = aCtx->ProjectionState.Current();
494     OpenGl_Mat4 aWorldView  = aCtx->WorldViewState.Current();
495     TransformPersistence.Apply (aProjection, aWorldView, theWorkspace->Width(), theWorkspace->Height());
496
497     aCtx->ProjectionState.Push();
498     aCtx->WorldViewState.Push();
499     aCtx->ProjectionState.SetCurrent (aProjection);
500     aCtx->WorldViewState.SetCurrent (aWorldView);
501     aCtx->ApplyProjectionMatrix();
502
503   #if !defined(GL_ES_VERSION_2_0)
504     if (!aCtx->IsGlNormalizeEnabled()
505       && aCtx->core11 != NULL)
506     {
507       const Standard_Real aScale = Graphic3d_TransformUtils::ScaleFactor<Standard_ShortReal> (aWorldView);
508       if (Abs (aScale - 1.0f) > Precision::Confusion())
509       {
510         aCtx->SetGlNormalizeEnabled (Standard_True);
511       }
512     }
513   #endif
514   }
515
516   // Take into account transform persistence
517   aCtx->ApplyModelViewMatrix();
518
519   // remember aspects
520   const OpenGl_AspectLine*   aPrevAspectLine   = theWorkspace->AspectLine();
521   const OpenGl_AspectFace*   aPrevAspectFace   = theWorkspace->AspectFace();
522   const OpenGl_AspectMarker* aPrevAspectMarker = theWorkspace->AspectMarker();
523   const OpenGl_AspectText*   aPrevAspectText   = theWorkspace->AspectText();
524
525   // Apply correction for mirror transform
526   if (myIsMirrored)
527   {
528     aCtx->core11fwd->glFrontFace (GL_CW);
529   }
530
531   // Apply highlight color
532   const TEL_COLOUR *aHighlightColor = theWorkspace->HighlightColor;
533   if (myHighlightColor)
534     theWorkspace->HighlightColor = myHighlightColor;
535
536   // Set up plane equations for non-structure transformed global model-view matrix
537   // List of planes to be applied to context state
538   NCollection_Handle<Graphic3d_SequenceOfHClipPlane> aUserPlanes;
539
540   // Collect clipping planes of structure scope
541   if (!myClipPlanes.IsEmpty())
542   {
543     Graphic3d_SequenceOfHClipPlane::Iterator aClippingIter (myClipPlanes);
544     for (; aClippingIter.More(); aClippingIter.Next())
545     {
546       const Handle(Graphic3d_ClipPlane)& aClipPlane = aClippingIter.Value();
547       if (!aClipPlane->IsOn())
548       {
549         continue;
550       }
551
552       if (aUserPlanes.IsNull())
553       {
554         aUserPlanes = new Graphic3d_SequenceOfHClipPlane();
555       }
556
557       aUserPlanes->Append (aClipPlane);
558     }
559   }
560
561   if (!aUserPlanes.IsNull() && !aUserPlanes->IsEmpty())
562   {
563     // add planes at loaded view matrix state
564     aCtx->ChangeClipping().AddWorld (aCtx, *aUserPlanes);
565
566     // Set OCCT state uniform variables
567     if (!aCtx->ShaderManager()->IsEmpty())
568     {
569       aCtx->ShaderManager()->UpdateClippingState();
570     }
571   }
572
573   // Render groups
574   bool hasClosedPrims = false;
575   renderGeometry (theWorkspace, hasClosedPrims);
576
577   // Reset correction for mirror transform
578   if (myIsMirrored)
579   {
580     aCtx->core11fwd->glFrontFace (GL_CCW);
581   }
582
583   // Render capping for structure groups
584   if (hasClosedPrims
585   && !aCtx->Clipping().Planes().IsEmpty())
586   {
587     OpenGl_CappingAlgo::RenderCapping (theWorkspace, *this);
588   }
589
590   // Revert structure clippings
591   if (!aUserPlanes.IsNull() && !aUserPlanes->IsEmpty())
592   {
593     aCtx->ChangeClipping().Remove (aCtx, *aUserPlanes);
594
595     // Set OCCT state uniform variables
596     if (!aCtx->ShaderManager()->IsEmpty())
597     {
598       aCtx->ShaderManager()->RevertClippingState();
599     }
600   }
601
602   // Restore local transformation
603   aCtx->ModelWorldState.Pop();
604   aCtx->SetGlNormalizeEnabled (anOldGlNormalize);
605   if (TransformPersistence.Flags)
606   {
607     aCtx->ProjectionState.Pop();
608     aCtx->WorldViewState.Pop();
609     aCtx->ApplyProjectionMatrix();
610   }
611
612   // Restore highlight color
613   theWorkspace->HighlightColor = aHighlightColor;
614
615   // Restore aspects
616   theWorkspace->SetAspectLine   (aPrevAspectLine);
617   theWorkspace->SetAspectFace   (aPrevAspectFace);
618   theWorkspace->SetAspectMarker (aPrevAspectMarker);
619   theWorkspace->SetAspectText   (aPrevAspectText);
620
621   // Apply highlight box
622   if (!myHighlightBox.IsNull())
623   {
624     myHighlightBox->Render (theWorkspace);
625   }
626
627   // Restore named status
628   theWorkspace->SetHighlight (false);
629 }
630
631 // =======================================================================
632 // function : Release
633 // purpose  :
634 // =======================================================================
635 void OpenGl_Structure::Release (const Handle(OpenGl_Context)& theGlCtx)
636 {
637   // Release groups
638   Clear (theGlCtx);
639   clearHighlightColor (theGlCtx);
640 }
641
642 // =======================================================================
643 // function : ReleaseGlResources
644 // purpose  :
645 // =======================================================================
646 void OpenGl_Structure::ReleaseGlResources (const Handle(OpenGl_Context)& theGlCtx)
647 {
648   for (OpenGl_Structure::GroupIterator aGroupIter (myGroups); aGroupIter.More(); aGroupIter.Next())
649   {
650     aGroupIter.ChangeValue()->Release (theGlCtx);
651   }
652   if (!myHighlightBox.IsNull())
653   {
654     myHighlightBox->Release (theGlCtx.operator->());
655   }
656 }
657
658 //=======================================================================
659 //function : ShadowLink
660 //purpose  :
661 //=======================================================================
662 Handle(Graphic3d_CStructure) OpenGl_Structure::ShadowLink (const Handle(Graphic3d_StructureManager)& theManager) const
663 {
664   return new OpenGl_StructureShadow (theManager, this);
665 }