0026885: Visualization - drop redundant aspects from structure level
[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 OpenGl_AspectLine*     anAspectLine = theWorkspace->AspectLine (Standard_True);
72     const Handle(OpenGl_Texture) aPrevTexture = theWorkspace->DisableTexture();
73
74     glDisable (GL_LIGHTING);
75
76     // Use highlight colors
77     theWorkspace->GetGlContext()->core11->glColor3fv ((theWorkspace->NamedStatus & OPENGL_NS_HIGHLIGHT) ? theWorkspace->HighlightColor->rgb : anAspectLine->Color().rgb);
78
79     glEnableClientState (GL_VERTEX_ARRAY);
80     glVertexPointer (3, GL_FLOAT, 0, (GLfloat* )&myVerts);
81     glDrawArrays (GL_LINE_STRIP, 0, 16);
82     glDisableClientState (GL_VERTEX_ARRAY);
83
84     // restore aspects
85     if (!aPrevTexture.IsNull())
86     {
87       theWorkspace->EnableTexture (aPrevTexture);
88     }
89   #else
90     (void )theWorkspace;
91   #endif
92   }
93
94   //! Release graphical resources
95   virtual void Release (OpenGl_Context*)
96   {
97     //
98   }
99
100 protected:
101
102   //! Protected destructor
103   virtual ~OpenGl_BndBoxPrs() {}
104
105 private:
106
107   OpenGl_Vec3 myVerts[16]; //!< vertices array
108
109 public:
110
111   DEFINE_STANDARD_ALLOC
112
113 };
114
115 /*----------------------------------------------------------------------*/
116
117 // =======================================================================
118 // function : OpenGl_Structure
119 // purpose  :
120 // =======================================================================
121 OpenGl_Structure::OpenGl_Structure (const Handle(Graphic3d_StructureManager)& theManager)
122 : Graphic3d_CStructure (theManager),
123   myHighlightColor     (NULL),
124   myInstancedStructure (NULL),
125   myIsRaytracable      (Standard_False),
126   myModificationState  (0),
127   myIsCulled           (Standard_True),
128   myIsMirrored         (Standard_False)
129 {
130   //
131 }
132
133 // =======================================================================
134 // function : ~OpenGl_Structure
135 // purpose  :
136 // =======================================================================
137 OpenGl_Structure::~OpenGl_Structure()
138 {
139   Release (Handle(OpenGl_Context)());
140 }
141
142 // =======================================================================
143 // function : UpdateTransformation
144 // purpose  :
145 // =======================================================================
146 void OpenGl_Structure::UpdateTransformation()
147 {
148   const OpenGl_Mat4& aMat = Graphic3d_CStructure::Transformation;
149   Standard_ShortReal aDet =
150     aMat.GetValue(0, 0) * (aMat.GetValue(1, 1) * aMat.GetValue(2, 2) - aMat.GetValue(2, 1) * aMat.GetValue(1, 2)) -
151     aMat.GetValue(0, 1) * (aMat.GetValue(1, 0) * aMat.GetValue(2, 2) - aMat.GetValue(2, 0) * aMat.GetValue(1, 2)) +
152     aMat.GetValue(0, 2) * (aMat.GetValue(1, 0) * aMat.GetValue(2, 1) - aMat.GetValue(2, 0) * aMat.GetValue(1, 1));
153
154   // Determinant of transform matrix less then 0 means that mirror transform applied.
155   myIsMirrored = aDet < 0.0f;
156
157   if (IsRaytracable())
158   {
159     ++myModificationState;
160   }
161 }
162
163 // =======================================================================
164 // function : clearHighlightBox
165 // purpose  :
166 // =======================================================================
167 void OpenGl_Structure::clearHighlightBox (const Handle(OpenGl_Context)& theGlCtx)
168 {
169   if (!myHighlightBox.IsNull())
170   {
171     myHighlightBox->Release (theGlCtx);
172     myHighlightBox.Nullify();
173   }
174 }
175
176 // =======================================================================
177 // function : HighlightWithColor
178 // purpose  :
179 // =======================================================================
180 void OpenGl_Structure::HighlightWithColor (const Graphic3d_Vec3&  theColor,
181                                            const Standard_Boolean theToCreate)
182 {
183   const Handle(OpenGl_Context)& aContext = GlDriver()->GetSharedContext();
184   if (theToCreate)
185     setHighlightColor   (aContext, theColor);
186   else
187     clearHighlightColor (aContext);
188 }
189
190 // =======================================================================
191 // function : HighlightWithBndBox
192 // purpose  :
193 // =======================================================================
194 void OpenGl_Structure::HighlightWithBndBox (const Handle(Graphic3d_Structure)& theStruct,
195                                             const Standard_Boolean             theToCreate)
196 {
197   const Handle(OpenGl_Context)& aContext = GlDriver()->GetSharedContext();
198   if (!theToCreate)
199   {
200     clearHighlightBox (aContext);
201     return;
202   }
203
204   if (!myHighlightBox.IsNull())
205   {
206     myHighlightBox->Release (aContext);
207   }
208   else
209   {
210     myHighlightBox = new OpenGl_Group (theStruct);
211   }
212
213   CALL_DEF_CONTEXTLINE& aContextLine = myHighlightBox->ChangeContextLine();
214   aContextLine.IsDef    = 1;
215   aContextLine.Color    = HighlightColor;
216   aContextLine.LineType = Aspect_TOL_SOLID;
217   aContextLine.Width    = 1.0f;
218   myHighlightBox->UpdateAspectLine (Standard_True);
219
220   OpenGl_BndBoxPrs* aBndBoxPrs = new OpenGl_BndBoxPrs (myBndBox);
221   myHighlightBox->AddElement (aBndBoxPrs);
222 }
223
224 // =======================================================================
225 // function : setHighlightColor
226 // purpose  :
227 // =======================================================================
228 void OpenGl_Structure::setHighlightColor (const Handle(OpenGl_Context)& theGlCtx,
229                                           const Graphic3d_Vec3&         theColor)
230 {
231   clearHighlightBox (theGlCtx);
232   if (myHighlightColor == NULL)
233   {
234     myHighlightColor = new TEL_COLOUR();
235   }
236
237   myHighlightColor->rgb[0] = theColor.r();
238   myHighlightColor->rgb[1] = theColor.g();
239   myHighlightColor->rgb[2] = theColor.b();
240   myHighlightColor->rgb[3] = 1.F;
241 }
242
243 // =======================================================================
244 // function : clearHighlightColor
245 // purpose  :
246 // =======================================================================
247 void OpenGl_Structure::clearHighlightColor (const Handle(OpenGl_Context)& theGlCtx)
248 {
249   clearHighlightBox(theGlCtx);
250   delete myHighlightColor;
251   myHighlightColor = NULL;
252 }
253
254 // =======================================================================
255 // function : OnVisibilityChanged
256 // purpose  :
257 // =======================================================================
258 void OpenGl_Structure::OnVisibilityChanged()
259 {
260   if (IsRaytracable())
261   {
262     ++myModificationState;
263   }
264 }
265
266 // =======================================================================
267 // function : IsRaytracable
268 // purpose  :
269 // =======================================================================
270 Standard_Boolean OpenGl_Structure::IsRaytracable() const
271 {
272   if (!myGroups.IsEmpty())
273   {
274     return myIsRaytracable; // geometry structure
275   }
276   else if (myInstancedStructure != NULL)
277   {
278     return myInstancedStructure->IsRaytracable(); // instance structure
279   }
280
281   return Standard_False; // has no any groups or structures
282 }
283
284 // =======================================================================
285 // function : UpdateRaytracableState
286 // purpose  :
287 // =======================================================================
288 void OpenGl_Structure::UpdateStateIfRaytracable (const Standard_Boolean toCheck) const
289 {
290   myIsRaytracable = !toCheck || OpenGl_Raytrace::IsRaytracedStructure (this);
291
292   if (IsRaytracable())
293   {
294     ++myModificationState;
295   }
296 }
297
298 // =======================================================================
299 // function : Connect
300 // purpose  :
301 // =======================================================================
302 void OpenGl_Structure::Connect (Graphic3d_CStructure& theStructure)
303 {
304   OpenGl_Structure* aStruct = static_cast<OpenGl_Structure*> (&theStructure);
305
306   Standard_ASSERT_RAISE (myInstancedStructure == NULL || myInstancedStructure == aStruct,
307     "Error! Instanced structure is already defined");
308
309   myInstancedStructure = aStruct;
310
311   if (aStruct->IsRaytracable())
312   {
313     UpdateStateIfRaytracable (Standard_False);
314   }
315 }
316
317 // =======================================================================
318 // function : Disconnect
319 // purpose  :
320 // =======================================================================
321 void OpenGl_Structure::Disconnect (Graphic3d_CStructure& theStructure)
322 {
323   OpenGl_Structure* aStruct = static_cast<OpenGl_Structure*> (&theStructure);
324
325   if (myInstancedStructure == aStruct)
326   {
327     myInstancedStructure = NULL;
328
329     if (aStruct->IsRaytracable())
330     {
331       UpdateStateIfRaytracable();
332     }
333   }
334 }
335
336 // =======================================================================
337 // function : NewGroup
338 // purpose  :
339 // =======================================================================
340 Handle(Graphic3d_Group) OpenGl_Structure::NewGroup (const Handle(Graphic3d_Structure)& theStruct)
341 {
342   Handle(OpenGl_Group) aGroup = new OpenGl_Group (theStruct);
343   myGroups.Append (aGroup);
344   return aGroup;
345 }
346
347 // =======================================================================
348 // function : RemoveGroup
349 // purpose  :
350 // =======================================================================
351 void OpenGl_Structure::RemoveGroup (const Handle(Graphic3d_Group)& theGroup)
352 {
353   if (theGroup.IsNull())
354   {
355     return;
356   }
357
358   for (Graphic3d_SequenceOfGroup::Iterator aGroupIter (myGroups); aGroupIter.More(); aGroupIter.Next())
359   {
360     // Check for the given group
361     if (aGroupIter.Value() == theGroup)
362     {
363       const Standard_Boolean wasRaytracable =
364         static_cast<const OpenGl_Group&> (*theGroup).IsRaytracable();
365
366       theGroup->Clear (Standard_False);
367
368       if (wasRaytracable)
369       {
370         UpdateStateIfRaytracable();
371       }
372
373       myGroups.Remove (aGroupIter);
374       return;
375     }
376   }
377 }
378
379 // =======================================================================
380 // function : Clear
381 // purpose  :
382 // =======================================================================
383 void OpenGl_Structure::Clear()
384 {
385   Clear (GlDriver()->GetSharedContext());
386 }
387
388 // =======================================================================
389 // function : Clear
390 // purpose  :
391 // =======================================================================
392 void OpenGl_Structure::Clear (const Handle(OpenGl_Context)& theGlCtx)
393 {
394   Standard_Boolean aRaytracableGroupDeleted (Standard_False);
395
396   // Release groups
397   for (OpenGl_Structure::GroupIterator aGroupIter (myGroups); aGroupIter.More(); aGroupIter.Next())
398   {
399     aRaytracableGroupDeleted |= aGroupIter.Value()->IsRaytracable();
400
401     // Delete objects
402     aGroupIter.ChangeValue()->Release (theGlCtx);
403   }
404   myGroups.Clear();
405
406   if (aRaytracableGroupDeleted)
407   {
408     myIsRaytracable = Standard_False;
409   }
410
411   Is2dText       = Standard_False;
412   IsForHighlight = Standard_False;
413 }
414
415 // =======================================================================
416 // function : renderGeometry
417 // purpose  :
418 // =======================================================================
419 void OpenGl_Structure::renderGeometry (const Handle(OpenGl_Workspace)& theWorkspace,
420                                        bool&                           theHasClosed) const
421 {
422   if (myInstancedStructure != NULL)
423   {
424     myInstancedStructure->renderGeometry (theWorkspace, theHasClosed);
425   }
426
427   for (OpenGl_Structure::GroupIterator aGroupIter (myGroups); aGroupIter.More(); aGroupIter.Next())
428   {
429     theHasClosed = theHasClosed || aGroupIter.Value()->IsClosed();
430     aGroupIter.Value()->Render (theWorkspace);
431   }
432 }
433
434 // =======================================================================
435 // function : renderClosedGeometry
436 // purpose  :
437 // =======================================================================
438 void OpenGl_Structure::renderClosedGeometry (const Handle(OpenGl_Workspace)& theWorkspace) const
439 {
440   if (myInstancedStructure != NULL)
441   {
442     myInstancedStructure->renderClosedGeometry (theWorkspace);
443   }
444
445   for (OpenGl_Structure::GroupIterator aGroupIter (myGroups); aGroupIter.More(); aGroupIter.Next())
446   {
447     if (aGroupIter.Value()->IsClosed())
448     {
449       aGroupIter.Value()->Render (theWorkspace);
450     }
451   }
452 }
453
454 // =======================================================================
455 // function : Render
456 // purpose  :
457 // =======================================================================
458 void OpenGl_Structure::Render (const Handle(OpenGl_Workspace) &theWorkspace) const
459 {
460   // Process the structure only if visible
461   if (!visible)
462   {
463     return;
464   }
465
466   const Handle(OpenGl_Context)& aCtx = theWorkspace->GetGlContext();
467
468   // Render named status
469   const Standard_Integer aNamedStatus = theWorkspace->NamedStatus;
470   if (highlight)
471   {
472     theWorkspace->NamedStatus |= OPENGL_NS_HIGHLIGHT;
473   }
474
475   // Apply local transformation
476   aCtx->ModelWorldState.Push();
477   aCtx->ModelWorldState.SetCurrent (Transformation);
478
479   // detect scale transform
480   const Standard_Boolean   anOldGlNormalize = aCtx->IsGlNormalizeEnabled();
481   const Standard_ShortReal aScaleX          = Transformation.GetRow (0).xyz().SquareModulus();
482   if (Abs (aScaleX - 1.f) > Precision::Confusion())
483   {
484     aCtx->SetGlNormalizeEnabled (Standard_True);
485   }
486
487   if (TransformPersistence.Flags)
488   {
489     OpenGl_Mat4 aProjection = aCtx->ProjectionState.Current();
490     OpenGl_Mat4 aWorldView  = aCtx->WorldViewState.Current();
491     TransformPersistence.Apply (aProjection, aWorldView, theWorkspace->Width(), theWorkspace->Height());
492
493     aCtx->ProjectionState.Push();
494     aCtx->WorldViewState.Push();
495     aCtx->ProjectionState.SetCurrent (aProjection);
496     aCtx->WorldViewState.SetCurrent (aWorldView);
497     aCtx->ApplyProjectionMatrix();
498   }
499
500   // Take into account transform persistence
501   aCtx->ApplyModelViewMatrix();
502
503   // Apply aspects
504   const OpenGl_AspectLine *anAspectLine = theWorkspace->AspectLine (Standard_False);
505   const OpenGl_AspectFace *anAspectFace = theWorkspace->AspectFace (Standard_False);
506   const OpenGl_AspectMarker *anAspectMarker = theWorkspace->AspectMarker (Standard_False);
507   const OpenGl_AspectText *anAspectText = theWorkspace->AspectText (Standard_False);
508
509   // Apply correction for mirror transform
510   if (myIsMirrored)
511   {
512     aCtx->core11fwd->glFrontFace (GL_CW);
513   }
514
515   // Apply highlight color
516   const TEL_COLOUR *aHighlightColor = theWorkspace->HighlightColor;
517   if (myHighlightColor)
518     theWorkspace->HighlightColor = myHighlightColor;
519
520   // Set up plane equations for non-structure transformed global model-view matrix
521   // List of planes to be applied to context state
522   NCollection_Handle<Graphic3d_SequenceOfHClipPlane> aUserPlanes;
523
524   // Collect clipping planes of structure scope
525   if (!myClipPlanes.IsEmpty())
526   {
527     Graphic3d_SequenceOfHClipPlane::Iterator aClippingIter (myClipPlanes);
528     for (; aClippingIter.More(); aClippingIter.Next())
529     {
530       const Handle(Graphic3d_ClipPlane)& aClipPlane = aClippingIter.Value();
531       if (!aClipPlane->IsOn())
532       {
533         continue;
534       }
535
536       if (aUserPlanes.IsNull())
537       {
538         aUserPlanes = new Graphic3d_SequenceOfHClipPlane();
539       }
540
541       aUserPlanes->Append (aClipPlane);
542     }
543   }
544
545   if (!aUserPlanes.IsNull() && !aUserPlanes->IsEmpty())
546   {
547     // add planes at loaded view matrix state
548     aCtx->ChangeClipping().AddWorld (aCtx, *aUserPlanes);
549
550     // Set OCCT state uniform variables
551     if (!aCtx->ShaderManager()->IsEmpty())
552     {
553       aCtx->ShaderManager()->UpdateClippingState();
554     }
555   }
556
557   // Render groups
558   bool hasClosedPrims = false;
559   renderGeometry (theWorkspace, hasClosedPrims);
560
561   // Reset correction for mirror transform
562   if (myIsMirrored)
563   {
564     aCtx->core11fwd->glFrontFace (GL_CCW);
565   }
566
567   // Render capping for structure groups
568   if (hasClosedPrims
569   && !aCtx->Clipping().Planes().IsEmpty())
570   {
571     OpenGl_CappingAlgo::RenderCapping (theWorkspace, *this);
572   }
573
574   // Revert structure clippings
575   if (!aUserPlanes.IsNull() && !aUserPlanes->IsEmpty())
576   {
577     aCtx->ChangeClipping().Remove (aCtx, *aUserPlanes);
578
579     // Set OCCT state uniform variables
580     if (!aCtx->ShaderManager()->IsEmpty())
581     {
582       aCtx->ShaderManager()->RevertClippingState();
583     }
584   }
585
586   // Restore local transformation
587   aCtx->ModelWorldState.Pop();
588   aCtx->SetGlNormalizeEnabled (anOldGlNormalize);
589   if (TransformPersistence.Flags)
590   {
591     aCtx->ProjectionState.Pop();
592     aCtx->WorldViewState.Pop();
593     aCtx->ApplyProjectionMatrix();
594   }
595
596   // Restore highlight color
597   theWorkspace->HighlightColor = aHighlightColor;
598
599   // Restore aspects
600   theWorkspace->SetAspectLine (anAspectLine);
601   theWorkspace->SetAspectFace (anAspectFace);
602   theWorkspace->SetAspectMarker (anAspectMarker);
603   theWorkspace->SetAspectText (anAspectText);
604
605   // Apply highlight box
606   if (!myHighlightBox.IsNull())
607   {
608     myHighlightBox->Render (theWorkspace);
609   }
610
611   // Restore named status
612   theWorkspace->NamedStatus = aNamedStatus;
613 }
614
615 // =======================================================================
616 // function : Release
617 // purpose  :
618 // =======================================================================
619 void OpenGl_Structure::Release (const Handle(OpenGl_Context)& theGlCtx)
620 {
621   // Release groups
622   Clear (theGlCtx);
623   clearHighlightColor (theGlCtx);
624 }
625
626 // =======================================================================
627 // function : ReleaseGlResources
628 // purpose  :
629 // =======================================================================
630 void OpenGl_Structure::ReleaseGlResources (const Handle(OpenGl_Context)& theGlCtx)
631 {
632   for (OpenGl_Structure::GroupIterator aGroupIter (myGroups); aGroupIter.More(); aGroupIter.Next())
633   {
634     aGroupIter.ChangeValue()->Release (theGlCtx);
635   }
636   if (!myHighlightBox.IsNull())
637   {
638     myHighlightBox->Release (theGlCtx.operator->());
639   }
640 }
641
642 //=======================================================================
643 //function : ShadowLink
644 //purpose  :
645 //=======================================================================
646 Handle(Graphic3d_CStructure) OpenGl_Structure::ShadowLink (const Handle(Graphic3d_StructureManager)& theManager) const
647 {
648   return new OpenGl_StructureShadow (theManager, this);
649 }