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