0029331: Visualization, TKOpenGl - make OpenGl_PrimitiveArray::IsFillDrawMode() as...
[occt.git] / src / OpenGl / OpenGl_LayerList.cxx
1 // Created on: 2012-02-02
2 // Created by: Anton POLETAEV
3 // Copyright (c) 2012-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_GlCore15.hxx>
17
18 #include <BVH_LinearBuilder.hxx>
19 #include <OpenGl_FrameBuffer.hxx>
20 #include <OpenGl_LayerList.hxx>
21 #include <OpenGl_ShaderManager.hxx>
22 #include <OpenGl_Structure.hxx>
23 #include <OpenGl_VertexBuffer.hxx>
24 #include <OpenGl_View.hxx>
25 #include <OpenGl_Workspace.hxx>
26
27 #include <Graphic3d_GraphicDriver.hxx>
28
29 namespace
30 {
31   //! Auxiliary class extending sequence iterator with index.
32   class OpenGl_IndexedLayerIterator : public OpenGl_SequenceOfLayers::Iterator
33   {
34   public:
35     //! Main constructor.
36     OpenGl_IndexedLayerIterator (const OpenGl_SequenceOfLayers& theSeq)
37     : OpenGl_SequenceOfLayers::Iterator (theSeq),
38       myIndex (theSeq.Lower()) {}
39
40     //! Return index of current position.
41     Standard_Integer Index() const { return myIndex; }
42
43     //! Move to the next position.
44     void Next()
45     {
46       OpenGl_SequenceOfLayers::Iterator::Next();
47       ++myIndex;
48     }
49
50   private:
51     Standard_Integer myIndex;
52   };
53
54   //! Iterator through layers with filter.
55   class OpenGl_FilteredIndexedLayerIterator
56   {
57   public:
58     //! Main constructor.
59     OpenGl_FilteredIndexedLayerIterator (const OpenGl_SequenceOfLayers& theSeq,
60                                          Standard_Integer theDefaultLayerIndex,
61                                          Standard_Boolean theToDrawImmediate,
62                                          OpenGl_LayerFilter theLayersToProcess)
63     : myIter (theSeq),
64       myDefaultLayerIndex (theDefaultLayerIndex),
65       myLayersToProcess (theLayersToProcess),
66       myToDrawImmediate (theToDrawImmediate)
67     {
68       next();
69     }
70
71     //! Return true if iterator points to the valid value.
72     bool More() const { return myIter.More(); }
73
74     //! Return layer at current position.
75     const OpenGl_Layer& Value() const { return *myIter.Value(); }
76
77     //! Return index of current position.
78     Standard_Integer Index() const { return myIter.Index(); }
79
80     //! Go to the next item.
81     void Next()
82     {
83       myIter.Next();
84       next();
85     }
86
87   private:
88     //! Look for the nearest item passing filters.
89     void next()
90     {
91       for (; myIter.More(); myIter.Next())
92       {
93         if (myIter.Value()->IsImmediate() != myToDrawImmediate)
94         {
95           continue;
96         }
97
98         switch (myLayersToProcess)
99         {
100           case OpenGl_LF_All:
101           {
102             break;
103           }
104           case OpenGl_LF_Upper:
105           {
106             if (myIter.Index() <= myDefaultLayerIndex)
107             {
108               continue;
109             }
110             break;
111           }
112           case OpenGl_LF_Bottom:
113           {
114             if (myIter.Index() >= myDefaultLayerIndex)
115             {
116               continue;
117             }
118             break;
119           }
120           case OpenGl_LF_Default:
121           {
122             if (myIter.Index() != myDefaultLayerIndex)
123             {
124               continue;
125             }
126             break;
127           }
128         }
129         return;
130       }
131     }
132   private:
133     OpenGl_IndexedLayerIterator myIter;
134     Standard_Integer            myDefaultLayerIndex;
135     OpenGl_LayerFilter          myLayersToProcess;
136     Standard_Boolean            myToDrawImmediate;
137   };
138 }
139
140 //=======================================================================
141 //function : OpenGl_LayerList
142 //purpose  : Constructor
143 //=======================================================================
144
145 OpenGl_LayerList::OpenGl_LayerList (const Standard_Integer theNbPriorities)
146 : myBVHBuilder (new BVH_LinearBuilder<Standard_Real, 3> (BVH_Constants_LeafNodeSizeSingle, BVH_Constants_MaxTreeDepth)),
147   myDefaultLayerIndex (0),
148   myNbPriorities (theNbPriorities),
149   myNbStructures (0),
150   myImmediateNbStructures (0),
151   myModifStateOfRaytraceable (0),
152   myRenderOpaqueFilter (new OpenGl_OpaqueFilter()),
153   myRenderTranspFilter (new OpenGl_TransparentFilter())
154 {
155   // insert default priority layers
156   myLayers.Append (new OpenGl_Layer (myNbPriorities, myBVHBuilder));
157   myLayerIds.Bind (Graphic3d_ZLayerId_BotOSD,  myLayers.Upper());
158
159   myLayers.Append (new OpenGl_Layer (myNbPriorities, myBVHBuilder));
160   myLayerIds.Bind (Graphic3d_ZLayerId_Default, myLayers.Upper());
161
162   myLayers.Append (new OpenGl_Layer (myNbPriorities, myBVHBuilder));
163   myLayerIds.Bind (Graphic3d_ZLayerId_Top,     myLayers.Upper());
164
165   myLayers.Append (new OpenGl_Layer (myNbPriorities, myBVHBuilder));
166   myLayerIds.Bind (Graphic3d_ZLayerId_Topmost, myLayers.Upper());
167
168   myLayers.Append (new OpenGl_Layer (myNbPriorities, myBVHBuilder));
169   myLayerIds.Bind (Graphic3d_ZLayerId_TopOSD,  myLayers.Upper());
170
171   myDefaultLayerIndex = myLayerIds.Find (Graphic3d_ZLayerId_Default);
172
173   myTransparentToProcess.Allocate (myLayers.Length());
174 }
175
176 //=======================================================================
177 //function : ~OpenGl_LayerList
178 //purpose  : Destructor
179 //=======================================================================
180
181 OpenGl_LayerList::~OpenGl_LayerList()
182 {
183 }
184
185 //=======================================================================
186 //function : SetFrustumCullingBVHBuilder
187 //purpose  :
188 //=======================================================================
189 void OpenGl_LayerList::SetFrustumCullingBVHBuilder (const Handle(Select3D_BVHBuilder3d)& theBuilder)
190 {
191   myBVHBuilder = theBuilder;
192   for (OpenGl_SequenceOfLayers::Iterator anIts (myLayers); anIts.More(); anIts.Next())
193   {
194     anIts.ChangeValue()->SetFrustumCullingBVHBuilder (theBuilder);
195   }
196 }
197
198 //=======================================================================
199 //function : AddLayer
200 //purpose  : 
201 //=======================================================================
202
203 void OpenGl_LayerList::AddLayer (const Graphic3d_ZLayerId theLayerId)
204 {
205   if (myLayerIds.IsBound (theLayerId))
206   {
207     return;
208   }
209
210   // add the new layer
211   myLayers.Append (new OpenGl_Layer (myNbPriorities, myBVHBuilder));
212   myLayerIds.Bind (theLayerId, myLayers.Length());
213
214   myTransparentToProcess.Allocate (myLayers.Length());
215 }
216
217 //=======================================================================
218 //function : Layer
219 //purpose  : 
220 //=======================================================================
221 OpenGl_Layer& OpenGl_LayerList::Layer (const Graphic3d_ZLayerId theLayerId)
222 {
223   return *myLayers.ChangeValue (myLayerIds.Find (theLayerId));
224 }
225
226 //=======================================================================
227 //function : Layer
228 //purpose  : 
229 //=======================================================================
230 const OpenGl_Layer& OpenGl_LayerList::Layer (const Graphic3d_ZLayerId theLayerId) const
231 {
232   return *myLayers.Value (myLayerIds.Find (theLayerId));
233 }
234
235 //=======================================================================
236 //function : RemoveLayer
237 //purpose  :
238 //=======================================================================
239
240 void OpenGl_LayerList::RemoveLayer (const Graphic3d_ZLayerId theLayerId)
241 {
242   if (!myLayerIds.IsBound (theLayerId)
243     || theLayerId <= 0)
244   {
245     return;
246   }
247
248   const Standard_Integer aRemovePos = myLayerIds.Find (theLayerId);
249   
250   // move all displayed structures to first layer
251   {
252     const OpenGl_Layer& aLayerToMove = *myLayers.Value (aRemovePos);
253     myLayers.ChangeFirst()->Append (aLayerToMove);
254   }
255
256   // remove layer
257   myLayers.Remove (aRemovePos);
258   myLayerIds.UnBind (theLayerId);
259
260   // updated sequence indexes in map
261   for (OpenGl_LayerSeqIds::Iterator aMapIt (myLayerIds); aMapIt.More(); aMapIt.Next())
262   {
263     Standard_Integer& aSeqIdx = aMapIt.ChangeValue();
264     if (aSeqIdx > aRemovePos)
265       aSeqIdx--;
266   }
267
268   myDefaultLayerIndex = myLayerIds.Find (Graphic3d_ZLayerId_Default);
269
270   myTransparentToProcess.Allocate (myLayers.Length());
271 }
272
273 //=======================================================================
274 //function : AddStructure
275 //purpose  :
276 //=======================================================================
277
278 void OpenGl_LayerList::AddStructure (const OpenGl_Structure*  theStruct,
279                                      const Graphic3d_ZLayerId theLayerId,
280                                      const Standard_Integer   thePriority,
281                                      Standard_Boolean         isForChangePriority)
282 {
283   // add structure to associated layer,
284   // if layer doesn't exists, display structure in default layer
285   Standard_Integer aSeqPos = myLayers.Lower();
286   myLayerIds.Find (theLayerId, aSeqPos);
287
288   OpenGl_Layer& aLayer = *myLayers.ChangeValue (aSeqPos);
289   aLayer.Add (theStruct, thePriority, isForChangePriority);
290   ++myNbStructures;
291   if (aLayer.IsImmediate())
292   {
293     ++myImmediateNbStructures;
294   }
295
296   // Note: In ray-tracing mode we don't modify modification
297   // state here. It is redundant, because the possible changes
298   // will be handled in the loop for structures
299 }
300
301 //=======================================================================
302 //function : RemoveStructure
303 //purpose  :
304 //=======================================================================
305
306 void OpenGl_LayerList::RemoveStructure (const OpenGl_Structure* theStructure)
307 {
308   const Graphic3d_ZLayerId aLayerId = theStructure->ZLayer();
309
310   Standard_Integer aSeqPos = myLayers.Lower();
311   myLayerIds.Find (aLayerId, aSeqPos);
312
313   OpenGl_Layer&    aLayer    = *myLayers.ChangeValue (aSeqPos);
314   Standard_Integer aPriority = -1;
315
316   // remove structure from associated list
317   // if the structure is not found there,
318   // scan through layers and remove it
319   if (aLayer.Remove (theStructure, aPriority))
320   {
321     --myNbStructures;
322     if (aLayer.IsImmediate())
323     {
324       --myImmediateNbStructures;
325     }
326
327     if (aLayerId == Graphic3d_ZLayerId_Default
328      && theStructure->IsRaytracable())
329     {
330       ++myModifStateOfRaytraceable;
331     }
332
333     return;
334   }
335
336   // scan through layers and remove it
337   for (OpenGl_IndexedLayerIterator anIts (myLayers); anIts.More(); anIts.Next())
338   {
339     OpenGl_Layer& aLayerEx = *anIts.ChangeValue();
340     if (aSeqPos == anIts.Index())
341     {
342       continue;
343     }
344
345     if (aLayerEx.Remove (theStructure, aPriority))
346     {
347       --myNbStructures;
348       if (aLayerEx.IsImmediate())
349       {
350         --myImmediateNbStructures;
351       }
352
353       if (anIts.Index() == myDefaultLayerIndex
354        && theStructure->IsRaytracable())
355       {
356         ++myModifStateOfRaytraceable;
357       }
358       return;
359     }
360   }
361 }
362
363 //=======================================================================
364 //function : InvalidateBVHData
365 //purpose  :
366 //=======================================================================
367 void OpenGl_LayerList::InvalidateBVHData (const Graphic3d_ZLayerId theLayerId)
368 {
369   Standard_Integer aSeqPos = myLayers.Lower();
370   myLayerIds.Find (theLayerId, aSeqPos);
371   OpenGl_Layer& aLayer = *myLayers.ChangeValue (aSeqPos);
372   aLayer.InvalidateBVHData();
373 }
374
375 //=======================================================================
376 //function : ChangeLayer
377 //purpose  :
378 //=======================================================================
379
380 void OpenGl_LayerList::ChangeLayer (const OpenGl_Structure*  theStructure,
381                                     const Graphic3d_ZLayerId theOldLayerId,
382                                     const Graphic3d_ZLayerId theNewLayerId)
383 {
384   Standard_Integer aSeqPos = myLayers.Lower();
385   myLayerIds.Find (theOldLayerId, aSeqPos);
386   OpenGl_Layer&    aLayer    = *myLayers.ChangeValue (aSeqPos);
387   Standard_Integer aPriority = -1;
388
389   // take priority and remove structure from list found by <theOldLayerId>
390   // if the structure is not found there, scan through all other layers
391   if (aLayer.Remove (theStructure, aPriority, Standard_False))
392   {
393     if (theOldLayerId == Graphic3d_ZLayerId_Default
394      && theStructure->IsRaytracable())
395     {
396       ++myModifStateOfRaytraceable;
397     }
398
399     --myNbStructures;
400     if (aLayer.IsImmediate())
401     {
402       --myImmediateNbStructures;
403     }
404
405     // isForChangePriority should be Standard_False below, because we want
406     // the BVH tree in the target layer to be updated with theStructure
407     AddStructure (theStructure, theNewLayerId, aPriority);
408     return;
409   }
410
411   // scan through layers and remove it
412   for (OpenGl_IndexedLayerIterator anIts (myLayers); anIts.More(); anIts.Next())
413   {
414     if (aSeqPos == anIts.Index())
415     {
416       continue;
417     }
418   
419     // try to remove structure and get priority value from this layer
420     OpenGl_Layer& aLayerEx = *anIts.ChangeValue();
421     if (aLayerEx.Remove (theStructure, aPriority, Standard_True))
422     {
423       if (anIts.Index() == myDefaultLayerIndex
424        && theStructure->IsRaytracable())
425       {
426         ++myModifStateOfRaytraceable;
427       }
428
429       --myNbStructures;
430       if (aLayerEx.IsImmediate())
431       {
432         --myImmediateNbStructures;
433       }
434
435       // isForChangePriority should be Standard_False below, because we want
436       // the BVH tree in the target layer to be updated with theStructure
437       AddStructure (theStructure, theNewLayerId, aPriority);
438       return;
439     }
440   }
441 }
442
443 //=======================================================================
444 //function : ChangePriority
445 //purpose  :
446 //=======================================================================
447 void OpenGl_LayerList::ChangePriority (const OpenGl_Structure*  theStructure,
448                                        const Graphic3d_ZLayerId theLayerId,
449                                        const Standard_Integer   theNewPriority)
450 {
451   Standard_Integer aSeqPos = myLayers.Lower();
452   myLayerIds.Find (theLayerId, aSeqPos);
453   OpenGl_Layer&    aLayer        = *myLayers.ChangeValue (aSeqPos);
454   Standard_Integer anOldPriority = -1;
455
456   if (aLayer.Remove (theStructure, anOldPriority, Standard_True))
457   {
458     --myNbStructures;
459     if (aLayer.IsImmediate())
460     {
461       --myImmediateNbStructures;
462     }
463
464     AddStructure (theStructure, theLayerId, theNewPriority, Standard_True);
465     return;
466   }
467
468   for (OpenGl_IndexedLayerIterator anIts (myLayers); anIts.More(); anIts.Next())
469   {
470     if (aSeqPos == anIts.Index())
471     {
472       continue;
473     }
474
475     OpenGl_Layer& aLayerEx = *anIts.ChangeValue();
476     if (aLayerEx.Remove (theStructure, anOldPriority, Standard_True))
477     {
478       --myNbStructures;
479       if (aLayerEx.IsImmediate())
480       {
481         --myImmediateNbStructures;
482       }
483
484       AddStructure (theStructure, theLayerId, theNewPriority, Standard_True);
485       return;
486     }
487   }
488 }
489
490 //=======================================================================
491 //function : SetLayerSettings
492 //purpose  :
493 //=======================================================================
494 void OpenGl_LayerList::SetLayerSettings (const Graphic3d_ZLayerId        theLayerId,
495                                          const Graphic3d_ZLayerSettings& theSettings)
496 {
497   OpenGl_Layer& aLayer = Layer (theLayerId);
498   if (aLayer.LayerSettings().IsImmediate() != theSettings.IsImmediate())
499   {
500     if (theSettings.IsImmediate())
501     {
502       myImmediateNbStructures += aLayer.NbStructures();
503     }
504     else
505     {
506       myImmediateNbStructures -= aLayer.NbStructures();
507     }
508   }
509   aLayer.SetLayerSettings (theSettings);
510 }
511
512 //=======================================================================
513 //function : UpdateCulling
514 //purpose  :
515 //=======================================================================
516 void OpenGl_LayerList::UpdateCulling (const Handle(OpenGl_Workspace)& theWorkspace,
517                                       const Standard_Boolean theToDrawImmediate)
518 {
519   const OpenGl_BVHTreeSelector& aSelector = theWorkspace->View()->BVHTreeSelector();
520   for (OpenGl_IndexedLayerIterator anIts (myLayers); anIts.More(); anIts.Next())
521   {
522     OpenGl_Layer& aLayer = *anIts.ChangeValue();
523     if (aLayer.IsImmediate() != theToDrawImmediate)
524     {
525       continue;
526     }
527
528     aLayer.UpdateCulling (aSelector, theWorkspace->IsCullingEnabled());
529   }
530 }
531
532 //=======================================================================
533 //function : Render
534 //purpose  :
535 //=======================================================================
536 void OpenGl_LayerList::Render (const Handle(OpenGl_Workspace)& theWorkspace,
537                                const Standard_Boolean          theToDrawImmediate,
538                                const OpenGl_LayerFilter        theLayersToProcess,
539                                OpenGl_FrameBuffer*             theReadDrawFbo,
540                                OpenGl_FrameBuffer*             theOitAccumFbo) const
541 {
542   // Remember global settings for glDepth function and write mask.
543   OpenGl_GlobalLayerSettings aPrevSettings;
544
545   const Handle(OpenGl_Context)& aCtx = theWorkspace->GetGlContext();
546   aCtx->core11fwd->glGetIntegerv (GL_DEPTH_FUNC,      &aPrevSettings.DepthFunc);
547   aCtx->core11fwd->glGetBooleanv (GL_DEPTH_WRITEMASK, &aPrevSettings.DepthMask);
548   OpenGl_GlobalLayerSettings aDefaultSettings = aPrevSettings;
549
550   // Two render filters are used to support transparency draw. Opaque filter accepts
551   // only non-transparent OpenGl elements of a layer and counts number of skipped
552   // transparent ones. If the counter has positive value the layer is added into
553   // transparency post-processing stack. At the end of drawing or once the depth
554   // buffer is to be cleared the layers in the stack should be drawn using
555   // blending and depth mask settings and another transparency filter which accepts
556   // only transparent OpenGl elements of a layer. The stack <myTransparentToProcess>
557   // was preallocated before going into this method and has enough space to keep
558   // maximum number of references to layers, therefore it will not increase memory
559   // fragmentation during regular rendering.
560   const Handle(OpenGl_RenderFilter) aPrevFilter = theWorkspace->GetRenderFilter();
561   myRenderOpaqueFilter->SetPreviousFilter (aPrevFilter);
562   myRenderTranspFilter->SetPreviousFilter (aPrevFilter);
563   theWorkspace->SetRenderFilter (myRenderOpaqueFilter);
564
565   myTransparentToProcess.Clear();
566
567   OpenGl_LayerStack::iterator aStackIter (myTransparentToProcess.Origin());
568   Standard_Integer aClearDepthLayerPrev = -1, aClearDepthLayer = -1;
569   const bool toPerformDepthPrepass = theWorkspace->View()->RenderingParams().ToEnableDepthPrepass
570                                   && aPrevSettings.DepthMask == GL_TRUE;
571   for (OpenGl_FilteredIndexedLayerIterator aLayerIterStart (myLayers, myDefaultLayerIndex, theToDrawImmediate, theLayersToProcess); aLayerIterStart.More();)
572   {
573     bool hasSkippedDepthLayers = false;
574     for (int aPassIter = toPerformDepthPrepass ? 0 : 2; aPassIter < 3; ++aPassIter)
575     {
576       if (aPassIter == 0)
577       {
578         aCtx->SetColorMask (false);
579         aDefaultSettings.DepthFunc = aPrevSettings.DepthFunc;
580         aDefaultSettings.DepthMask = GL_TRUE;
581       }
582       else if (aPassIter == 1)
583       {
584         if (!hasSkippedDepthLayers)
585         {
586           continue;
587         }
588         aCtx->SetColorMask (true);
589         aDefaultSettings = aPrevSettings;
590       }
591       else if (aPassIter == 2)
592       {
593         aCtx->SetColorMask (true);
594         if (toPerformDepthPrepass)
595         {
596           aDefaultSettings.DepthFunc = GL_EQUAL;
597           aDefaultSettings.DepthMask = GL_FALSE;
598         }
599       }
600
601       OpenGl_FilteredIndexedLayerIterator aLayerIter (aLayerIterStart);
602       for (; aLayerIter.More(); aLayerIter.Next())
603       {
604         const OpenGl_Layer& aLayer = aLayerIter.Value();
605
606         // make sure to clear depth of previous layers even if layer has no structures
607         if (aLayer.LayerSettings().ToClearDepth())
608         {
609           aClearDepthLayer = aLayerIter.Index();
610         }
611         if (aLayer.IsCulled())
612         {
613           continue;
614         }
615         else if (aClearDepthLayer > aClearDepthLayerPrev)
616         {
617           // At this point the depth buffer may be set to clear by previous configuration of layers or configuration of the current layer.
618           // Additional rendering pass to handle transparent elements of recently drawn layers require use of current depth
619           // buffer so we put remaining layers for processing as one bunch before erasing the depth buffer.
620           if (aPassIter == 2)
621           {
622             aLayerIterStart = aLayerIter;
623           }
624           else
625           {
626             aClearDepthLayer = -1;
627           }
628           break;
629         }
630         else if (aPassIter == 0
631              && !aLayer.LayerSettings().ToRenderInDepthPrepass())
632         {
633           hasSkippedDepthLayers = true;
634           continue;
635         }
636         else if (aPassIter == 1
637               && aLayer.LayerSettings().ToRenderInDepthPrepass())
638         {
639           continue;
640         }
641
642         // Render opaque OpenGl elements of a layer and count the number of skipped.
643         // If a layer has skipped (e.g. transparent) elements it should be added into
644         // the transparency post-processing stack.
645         myRenderOpaqueFilter->SetSkippedCounter (0);
646
647         aLayer.Render (theWorkspace, aDefaultSettings);
648
649         if (aPassIter != 0
650          && myRenderOpaqueFilter->NbSkipped() > 0)
651         {
652           myTransparentToProcess.Push (&aLayer);
653         }
654       }
655       if (aPassIter == 2
656       && !aLayerIter.More())
657       {
658         aLayerIterStart = aLayerIter;
659       }
660     }
661
662     if (!myTransparentToProcess.IsEmpty())
663     {
664       renderTransparent (theWorkspace, aStackIter, aPrevSettings, theReadDrawFbo, theOitAccumFbo);
665     }
666     if (aClearDepthLayer > aClearDepthLayerPrev)
667     {
668       aClearDepthLayerPrev = aClearDepthLayer;
669       glDepthMask (GL_TRUE);
670       glClear (GL_DEPTH_BUFFER_BIT);
671     }
672   }
673
674   aCtx->core11fwd->glDepthMask (aPrevSettings.DepthMask);
675   aCtx->core11fwd->glDepthFunc (aPrevSettings.DepthFunc);
676
677   theWorkspace->SetRenderFilter (aPrevFilter);
678 }
679
680 //=======================================================================
681 //function : renderTransparent
682 //purpose  : Render transparent objects using blending operator.
683 //=======================================================================
684 void OpenGl_LayerList::renderTransparent (const Handle(OpenGl_Workspace)&   theWorkspace,
685                                           OpenGl_LayerStack::iterator&      theLayerIter,
686                                           const OpenGl_GlobalLayerSettings& theGlobalSettings,
687                                           OpenGl_FrameBuffer*               theReadDrawFbo,
688                                           OpenGl_FrameBuffer*               theOitAccumFbo) const
689 {
690   // Blended order-independent transparency algorithm require several preconditions
691   // to be enabled. It should be requested by user, at least two outputs from
692   // fragment shader should be supported by GPU, so is the given framebuffer
693   // should contain two additional color buffers to handle accumulated color channels,
694   // blended alpha channel and weight factors - these accumulation buffers are required
695   // to implement commuting blend operator (at least OpenGl 2.0 should be available).
696   const bool isEnabledOit = theOitAccumFbo != NULL
697                          && theOitAccumFbo->NbColorBuffers() >= 2
698                          && theOitAccumFbo->ColorTexture (0)->IsValid()
699                          && theOitAccumFbo->ColorTexture (1)->IsValid();
700
701   // Check if current iterator has already reached the end of the stack.
702   // This should happen if no additional layers has been added to
703   // the processing stack after last transparency pass.
704   if (theLayerIter == myTransparentToProcess.Back())
705   {
706     return;
707   }
708
709   const Handle(OpenGl_Context) aCtx            = theWorkspace->GetGlContext();
710   const Handle(OpenGl_ShaderManager)& aManager = aCtx->ShaderManager();
711   OpenGl_View* aView = theWorkspace->View();
712   const float aDepthFactor =  aView != NULL ? aView->RenderingParams().OitDepthFactor : 0.0f;
713
714   theWorkspace->SetRenderFilter (myRenderTranspFilter);
715
716   aCtx->core11fwd->glEnable (GL_BLEND);
717
718   if (isEnabledOit)
719   {
720     aManager->SetOitState (true, aDepthFactor);
721
722     theOitAccumFbo->BindBuffer (aCtx);
723
724     static const Standard_Integer aDrawBuffers[] = { GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT0 + 1 };
725     aCtx->SetDrawBuffers (2, aDrawBuffers);
726     aCtx->core11fwd->glClearColor (0.0f, 0.0f, 0.0f, 1.0f);
727     aCtx->core11fwd->glClear (GL_COLOR_BUFFER_BIT);
728     aCtx->core15fwd->glBlendFuncSeparate (GL_ONE, GL_ONE, GL_ZERO, GL_ONE_MINUS_SRC_ALPHA);
729   }
730   else
731   {
732     aCtx->core11fwd->glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
733   }
734
735   // During blended order-independent transparency pass the depth test
736   // should be enabled to discard fragments covered by opaque geometry
737   // and depth writing should be disabled, because transparent fragments
738   // overal each other with non unitary coverage factor.
739   OpenGl_GlobalLayerSettings aGlobalSettings = theGlobalSettings;
740   aGlobalSettings.DepthMask   = GL_FALSE;
741   aCtx->core11fwd->glDepthMask (GL_FALSE);
742
743   for (; theLayerIter != myTransparentToProcess.Back(); ++theLayerIter)
744   {
745     (*theLayerIter)->Render (theWorkspace, aGlobalSettings);
746   }
747
748   // Revert state of rendering.
749   if (isEnabledOit)
750   {
751     aManager->SetOitState (false, aDepthFactor);
752     theOitAccumFbo->UnbindBuffer (aCtx);
753     if (theReadDrawFbo)
754     {
755       theReadDrawFbo->BindBuffer (aCtx);
756     }
757
758     static const Standard_Integer aDrawBuffers[] = { GL_COLOR_ATTACHMENT0 };
759     aCtx->SetDrawBuffers (1, aDrawBuffers);
760   }
761
762   theWorkspace->SetRenderFilter (myRenderOpaqueFilter);
763   if (isEnabledOit)
764   {
765     const Standard_Boolean isMSAA = theReadDrawFbo && theReadDrawFbo->NbSamples() > 0;
766     OpenGl_VertexBuffer*   aVerts = theWorkspace->View()->initBlitQuad (Standard_False);
767     if (aVerts->IsValid() && aManager->BindOitCompositingProgram (isMSAA))
768     {
769       aCtx->core11fwd->glDepthFunc (GL_ALWAYS);
770       aCtx->core11fwd->glDepthMask (GL_FALSE);
771
772       // Bind full screen quad buffer and framebuffer resources.
773       aVerts->BindVertexAttrib (aCtx, Graphic3d_TOA_POS);
774
775       const Handle(OpenGl_TextureSet) aTextureBack = aCtx->BindTextures (Handle(OpenGl_TextureSet)());
776
777       theOitAccumFbo->ColorTexture (0)->Bind (aCtx, Graphic3d_TextureUnit_0);
778       theOitAccumFbo->ColorTexture (1)->Bind (aCtx, Graphic3d_TextureUnit_1);
779
780       // Draw full screen quad with special shader to compose the buffers.
781       aCtx->core11fwd->glBlendFunc (GL_ONE_MINUS_SRC_ALPHA, GL_SRC_ALPHA);
782       aCtx->core11fwd->glDrawArrays (GL_TRIANGLE_STRIP, 0, 4);
783
784       // Unbind OpenGL texture objects and shader program.
785       aVerts->UnbindVertexAttrib (aCtx, Graphic3d_TOA_POS);
786       theOitAccumFbo->ColorTexture (0)->Unbind (aCtx, Graphic3d_TextureUnit_0);
787       theOitAccumFbo->ColorTexture (1)->Unbind (aCtx, Graphic3d_TextureUnit_1);
788       aCtx->BindProgram (NULL);
789
790       if (!aTextureBack.IsNull())
791       {
792         aCtx->BindTextures (aTextureBack);
793       }
794     }
795     else
796     {
797       aCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH,
798                          "Initialization of OIT compositing pass has failed.\n"
799                          "  Blended order-independent transparency will not be available.\n");
800       if (aView != NULL)
801       {
802         Standard_Boolean& aOITFlag = isMSAA ? aView->myToDisableOITMSAA : aView->myToDisableOIT;
803         aOITFlag = Standard_True;
804       }
805     }
806   }
807
808   aCtx->core11fwd->glDisable (GL_BLEND);
809   aCtx->core11fwd->glBlendFunc (GL_ONE, GL_ZERO);
810   aCtx->core11fwd->glDepthMask (theGlobalSettings.DepthMask);
811   aCtx->core11fwd->glDepthFunc (theGlobalSettings.DepthFunc);
812 }
813
814 //=======================================================================
815 //class    : OpenGl_OpaqueFilter
816 //function : ShouldRender
817 //purpose  : Checks whether the element should be rendered or skipped.
818 //=======================================================================
819 Standard_Boolean OpenGl_LayerList::OpenGl_OpaqueFilter::ShouldRender (const Handle(OpenGl_Workspace)& theWorkspace,
820                                                                       const OpenGl_Element*           theGlElement)
821 {
822   if (!myFilter.IsNull()
823    && !myFilter->ShouldRender (theWorkspace, theGlElement))
824   {
825     return Standard_False;
826   }
827
828   if (!theGlElement->IsFillDrawMode())
829   {
830     return Standard_True;
831   }
832
833   if (OpenGl_Context::CheckIsTransparent (theWorkspace->AspectFace(),
834                                           theWorkspace->HighlightStyle()))
835   {
836     ++mySkippedCounter;
837     return Standard_False;
838   }
839
840   return Standard_True;
841 }
842
843 //=======================================================================
844 //class    : OpenGl_TransparentFilter
845 //function : ShouldRender
846 //purpose  : Checks whether the element should be rendered or skipped.
847 //=======================================================================
848 Standard_Boolean OpenGl_LayerList::OpenGl_TransparentFilter::ShouldRender (const Handle(OpenGl_Workspace)& theWorkspace,
849                                                                            const OpenGl_Element*           theGlElement)
850 {
851   if (!myFilter.IsNull()
852    && !myFilter->ShouldRender (theWorkspace, theGlElement))
853   {
854     return Standard_False;
855   }
856
857   if (!theGlElement->IsFillDrawMode())
858   {
859     return dynamic_cast<const OpenGl_AspectFace*> (theGlElement) != NULL;
860   }
861
862   return OpenGl_Context::CheckIsTransparent (theWorkspace->AspectFace(),
863                                              theWorkspace->HighlightStyle());
864 }