0027751: Visualization, Graphic3d_ClipPlane - add option to inherit material from...
[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 (TransformPersistence.Flags)
475   {
476     OpenGl_Mat4 aProjection = aCtx->ProjectionState.Current();
477     OpenGl_Mat4 aWorldView  = aCtx->WorldViewState.Current();
478     TransformPersistence.Apply (aProjection, aWorldView, theWorkspace->Width(), theWorkspace->Height());
479
480     aCtx->ProjectionState.Push();
481     aCtx->WorldViewState.Push();
482     aCtx->ProjectionState.SetCurrent (aProjection);
483     aCtx->WorldViewState.SetCurrent (aWorldView);
484     aCtx->ApplyProjectionMatrix();
485
486   #if !defined(GL_ES_VERSION_2_0)
487     if (!aCtx->IsGlNormalizeEnabled()
488       && aCtx->core11 != NULL)
489     {
490       const Standard_Real aScale = Graphic3d_TransformUtils::ScaleFactor<Standard_ShortReal> (aWorldView);
491       if (Abs (aScale - 1.0f) > Precision::Confusion())
492       {
493         aCtx->SetGlNormalizeEnabled (Standard_True);
494       }
495     }
496   #endif
497   }
498
499   // Take into account transform persistence
500   aCtx->ApplyModelViewMatrix();
501
502   // remember aspects
503   const OpenGl_AspectLine*   aPrevAspectLine   = theWorkspace->AspectLine();
504   const OpenGl_AspectFace*   aPrevAspectFace   = theWorkspace->AspectFace();
505   const OpenGl_AspectMarker* aPrevAspectMarker = theWorkspace->AspectMarker();
506   const OpenGl_AspectText*   aPrevAspectText   = theWorkspace->AspectText();
507
508   // Apply correction for mirror transform
509   if (myIsMirrored)
510   {
511     aCtx->core11fwd->glFrontFace (GL_CW);
512   }
513
514   // Apply highlight color
515   const OpenGl_Vec4* aHighlightColor = theWorkspace->HighlightColor;
516   if (myHighlightColor)
517     theWorkspace->HighlightColor = myHighlightColor;
518
519   // Set up plane equations for non-structure transformed global model-view matrix
520   // List of planes to be applied to context state
521   NCollection_Handle<Graphic3d_SequenceOfHClipPlane> aUserPlanes;
522
523   // Collect clipping planes of structure scope
524   if (!myClipPlanes.IsEmpty())
525   {
526     Graphic3d_SequenceOfHClipPlane::Iterator aClippingIter (myClipPlanes);
527     for (; aClippingIter.More(); aClippingIter.Next())
528     {
529       const Handle(Graphic3d_ClipPlane)& aClipPlane = aClippingIter.Value();
530       if (!aClipPlane->IsOn())
531       {
532         continue;
533       }
534
535       if (aUserPlanes.IsNull())
536       {
537         aUserPlanes = new Graphic3d_SequenceOfHClipPlane();
538       }
539
540       aUserPlanes->Append (aClipPlane);
541     }
542   }
543
544   if (!aUserPlanes.IsNull() && !aUserPlanes->IsEmpty())
545   {
546     // add planes at loaded view matrix state
547     aCtx->ChangeClipping().AddWorld (aCtx, *aUserPlanes);
548
549     // Set OCCT state uniform variables
550     aCtx->ShaderManager()->UpdateClippingState();
551   }
552
553   // Render groups
554   bool hasClosedPrims = false;
555   renderGeometry (theWorkspace, hasClosedPrims);
556
557   // Reset correction for mirror transform
558   if (myIsMirrored)
559   {
560     aCtx->core11fwd->glFrontFace (GL_CCW);
561   }
562
563   // Render capping for structure groups
564   if (hasClosedPrims
565   && !aCtx->Clipping().Planes().IsEmpty())
566   {
567     OpenGl_CappingAlgo::RenderCapping (theWorkspace, *this);
568   }
569
570   // Revert structure clippings
571   if (!aUserPlanes.IsNull() && !aUserPlanes->IsEmpty())
572   {
573     aCtx->ChangeClipping().Remove (aCtx, *aUserPlanes);
574
575     // Set OCCT state uniform variables
576     aCtx->ShaderManager()->RevertClippingState();
577   }
578
579   // Restore local transformation
580   aCtx->ModelWorldState.Pop();
581   aCtx->SetGlNormalizeEnabled (anOldGlNormalize);
582   if (TransformPersistence.Flags)
583   {
584     aCtx->ProjectionState.Pop();
585     aCtx->WorldViewState.Pop();
586     aCtx->ApplyProjectionMatrix();
587   }
588
589   // Restore highlight color
590   theWorkspace->HighlightColor = aHighlightColor;
591
592   // Restore aspects
593   theWorkspace->SetAspectLine   (aPrevAspectLine);
594   theWorkspace->SetAspectFace   (aPrevAspectFace);
595   theWorkspace->SetAspectMarker (aPrevAspectMarker);
596   theWorkspace->SetAspectText   (aPrevAspectText);
597
598   // Apply highlight box
599   if (!myHighlightBox.IsNull())
600   {
601     myHighlightBox->Render (theWorkspace);
602   }
603
604   // Restore named status
605   theWorkspace->SetHighlight (false);
606 }
607
608 // =======================================================================
609 // function : Release
610 // purpose  :
611 // =======================================================================
612 void OpenGl_Structure::Release (const Handle(OpenGl_Context)& theGlCtx)
613 {
614   // Release groups
615   Clear (theGlCtx);
616   clearHighlightColor (theGlCtx);
617 }
618
619 // =======================================================================
620 // function : ReleaseGlResources
621 // purpose  :
622 // =======================================================================
623 void OpenGl_Structure::ReleaseGlResources (const Handle(OpenGl_Context)& theGlCtx)
624 {
625   for (OpenGl_Structure::GroupIterator aGroupIter (myGroups); aGroupIter.More(); aGroupIter.Next())
626   {
627     aGroupIter.ChangeValue()->Release (theGlCtx);
628   }
629   if (!myHighlightBox.IsNull())
630   {
631     myHighlightBox->Release (theGlCtx.operator->());
632   }
633 }
634
635 //=======================================================================
636 //function : ShadowLink
637 //purpose  :
638 //=======================================================================
639 Handle(Graphic3d_CStructure) OpenGl_Structure::ShadowLink (const Handle(Graphic3d_StructureManager)& theManager) const
640 {
641   return new OpenGl_StructureShadow (theManager, this);
642 }