0024023: Revamp the OCCT Handle -- general
[occt.git] / src / OpenGl / OpenGl_Layer.cxx
1 // Created on: 2014-03-31
2 // Created by: Danila ULYANOV
3 // Copyright (c) 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_Layer.hxx>
17
18 #include <OpenGl_BVHTreeSelector.hxx>
19 #include <OpenGl_Structure.hxx>
20 #include <OpenGl_View.hxx>
21 #include <OpenGl_Workspace.hxx>
22 #include <Graphic3d_GraphicDriver.hxx>
23
24 // =======================================================================
25 // function : OpenGl_PriorityList
26 // purpose  :
27 // =======================================================================
28 OpenGl_Layer::OpenGl_Layer (const Standard_Integer theNbPriorities)
29 : myArray (0, theNbPriorities - 1),
30   myNbStructures (0),
31   myBVHIsLeftChildQueuedFirst (Standard_True),
32   myIsBVHPrimitivesNeedsReset (Standard_False)
33 {
34   //
35 }
36
37 // =======================================================================
38 // function : ~OpenGl_Layer
39 // purpose  :
40 // =======================================================================
41 OpenGl_Layer::~OpenGl_Layer()
42 {
43   //
44 }
45
46 // =======================================================================
47 // function : Add
48 // purpose  :
49 // =======================================================================
50 void OpenGl_Layer::Add (const OpenGl_Structure* theStruct,
51                         const Standard_Integer  thePriority,
52                         Standard_Boolean        isForChangePriority)
53 {
54   const Standard_Integer anIndex = Min (Max (thePriority, 0), myArray.Length() - 1);
55   if (theStruct == NULL)
56   {
57     return;
58   }
59
60   myArray (anIndex).Add (theStruct);
61   if (theStruct->IsAlwaysRendered())
62   {
63     theStruct->MarkAsNotCulled();
64   }
65   else if (!isForChangePriority)
66   {
67     myBVHPrimitives.Add (theStruct);
68   }
69   ++myNbStructures;
70 }
71
72 // =======================================================================
73 // function : Remove
74 // purpose  :
75 // =======================================================================
76 bool OpenGl_Layer::Remove (const OpenGl_Structure* theStruct,
77                            Standard_Integer&       thePriority,
78                            Standard_Boolean        isForChangePriority)
79 {
80   if (theStruct == NULL)
81   {
82     thePriority = -1;
83     return false;
84   }
85
86   const Standard_Integer aNbPriorities = myArray.Length();
87   for (Standard_Integer aPriorityIter = 0; aPriorityIter < aNbPriorities; ++aPriorityIter)
88   {
89     OpenGl_IndexedMapOfStructure& aStructures = myArray (aPriorityIter);
90
91     const Standard_Integer anIndex = aStructures.FindIndex (theStruct);
92     if (anIndex != 0)
93     {
94       aStructures.Swap (anIndex, aStructures.Size());
95       aStructures.RemoveLast();
96
97       if (!theStruct->IsAlwaysRendered()
98        && !isForChangePriority)
99       {
100         myBVHPrimitives.Remove (theStruct);
101       }
102       --myNbStructures;
103       thePriority = aPriorityIter;
104       return true;
105     }
106   }
107
108   thePriority = -1;
109   return false;
110 }
111
112 // =======================================================================
113 // function : InvalidateBVHData
114 // purpose  :
115 // =======================================================================
116 void OpenGl_Layer::InvalidateBVHData()
117 {
118   myIsBVHPrimitivesNeedsReset = Standard_True;
119 }
120
121 // =======================================================================
122 // function : renderAll
123 // purpose  :
124 // =======================================================================
125 void OpenGl_Layer::renderAll (const Handle(OpenGl_Workspace)& theWorkspace) const
126 {
127   const Standard_Integer aNbPriorities = myArray.Length();
128   const Standard_Integer aViewId       = theWorkspace->ActiveViewId();
129   for (Standard_Integer aPriorityIter = 0; aPriorityIter < aNbPriorities; ++aPriorityIter)
130   {
131     const OpenGl_IndexedMapOfStructure& aStructures = myArray (aPriorityIter);
132     for (Standard_Integer aStructIdx = 1; aStructIdx <= aStructures.Size(); ++aStructIdx)
133     {
134       const OpenGl_Structure* aStruct = aStructures.FindKey (aStructIdx);
135       if (!aStruct->IsVisible())
136       {
137         continue;
138       }
139       else if (!aStruct->ViewAffinity.IsNull()
140             && !aStruct->ViewAffinity->IsVisible (aViewId))
141       {
142         continue;
143       }
144
145       aStruct->Render (theWorkspace);
146     }
147   }
148 }
149
150 // =======================================================================
151 // function : renderTraverse
152 // purpose  :
153 // =======================================================================
154 void OpenGl_Layer::renderTraverse (const Handle(OpenGl_Workspace)& theWorkspace) const
155 {
156   if (myIsBVHPrimitivesNeedsReset)
157   {
158     myBVHPrimitives.Assign (myArray);
159     myIsBVHPrimitivesNeedsReset = Standard_False;
160   }
161
162   OpenGl_BVHTreeSelector& aSelector = theWorkspace->ActiveView()->BVHTreeSelector();
163   traverse (aSelector);
164
165   const Standard_Integer aNbPriorities = myArray.Length();
166   const Standard_Integer aViewId       = theWorkspace->ActiveViewId();
167   for (Standard_Integer aPriorityIter = 0; aPriorityIter < aNbPriorities; ++aPriorityIter)
168   {
169     const OpenGl_IndexedMapOfStructure& aStructures = myArray (aPriorityIter);
170     for (Standard_Integer aStructIdx = 1; aStructIdx <= aStructures.Size(); ++aStructIdx)
171     {
172       const OpenGl_Structure* aStruct = aStructures.FindKey (aStructIdx);
173       if (!aStruct->IsVisible()
174         || aStruct->IsCulled())
175       {
176         continue;
177       }
178       else if (!aStruct->ViewAffinity.IsNull()
179             && !aStruct->ViewAffinity->IsVisible (aViewId))
180       {
181         continue;
182       }
183
184       aStruct->Render (theWorkspace);
185       aStruct->ResetCullingStatus();
186     }
187   }
188 }
189
190 // =======================================================================
191 // function : traverse
192 // purpose  :
193 // =======================================================================
194 void OpenGl_Layer::traverse (OpenGl_BVHTreeSelector& theSelector) const
195 {
196   // handle a case when all objects are infinite
197   if (myBVHPrimitives.Size() == 0)
198     return;
199
200   const NCollection_Handle<BVH_Tree<Standard_ShortReal, 4> >& aBVHTree = myBVHPrimitives.BVH();
201
202   Standard_Integer aNode = 0; // a root node
203   theSelector.CacheClipPtsProjections();
204   if (!theSelector.Intersect (aBVHTree->MinPoint (0),
205                               aBVHTree->MaxPoint (0)))
206   {
207     return;
208   }
209
210   Standard_Integer aStack[32];
211   Standard_Integer aHead = -1;
212   for (;;)
213   {
214     if (!aBVHTree->IsOuter (aNode))
215     {
216       const Standard_Integer aLeftChildIdx  = aBVHTree->LeftChild  (aNode);
217       const Standard_Integer aRightChildIdx = aBVHTree->RightChild (aNode);
218       const Standard_Boolean isLeftChildIn  = theSelector.Intersect (aBVHTree->MinPoint (aLeftChildIdx),
219                                                                      aBVHTree->MaxPoint (aLeftChildIdx));
220       const Standard_Boolean isRightChildIn = theSelector.Intersect (aBVHTree->MinPoint (aRightChildIdx),
221                                                                      aBVHTree->MaxPoint (aRightChildIdx));
222       if (isLeftChildIn
223        && isRightChildIn)
224       {
225         aNode = myBVHIsLeftChildQueuedFirst ? aLeftChildIdx : aRightChildIdx;
226         aStack[++aHead] = myBVHIsLeftChildQueuedFirst ? aRightChildIdx : aLeftChildIdx;
227         myBVHIsLeftChildQueuedFirst = !myBVHIsLeftChildQueuedFirst;
228       }
229       else if (isLeftChildIn
230             || isRightChildIn)
231       {
232         aNode = isLeftChildIn ? aLeftChildIdx : aRightChildIdx;
233       }
234       else
235       {
236         if (aHead < 0)
237         {
238           return;
239         }
240
241         aNode = aStack[aHead--];
242       }
243     }
244     else
245     {
246       Standard_Integer aIdx = aBVHTree->BegPrimitive (aNode);
247       myBVHPrimitives.GetStructureById (aIdx)->MarkAsNotCulled();
248       if (aHead < 0)
249       {
250         return;
251       }
252
253       aNode = aStack[aHead--];
254     }
255   }
256 }
257
258 // =======================================================================
259 // function : Append
260 // purpose  :
261 // =======================================================================
262 Standard_Boolean OpenGl_Layer::Append (const OpenGl_Layer& theOther)
263 {
264   // the source priority list shouldn't have more priorities
265   const Standard_Integer aNbPriorities = theOther.NbPriorities();
266   if (aNbPriorities > NbPriorities())
267   {
268     return Standard_False;
269   }
270
271   // add all structures to destination priority list
272   for (Standard_Integer aPriorityIter = 0; aPriorityIter < aNbPriorities; ++aPriorityIter)
273   {
274     const OpenGl_IndexedMapOfStructure& aStructures = theOther.myArray (aPriorityIter);
275     for (Standard_Integer aStructIdx = 1; aStructIdx <= aStructures.Size(); ++aStructIdx)
276     {
277       Add (aStructures.FindKey (aStructIdx), aPriorityIter);
278     }
279   }
280
281   return Standard_True;
282 }
283
284 //=======================================================================
285 //function : Render
286 //purpose  :
287 //=======================================================================
288 void OpenGl_Layer::Render (const Handle(OpenGl_Workspace)&   theWorkspace,
289                            const OpenGl_GlobalLayerSettings& theDefaultSettings) const
290 {
291   TEL_POFFSET_PARAM anAppliedOffsetParams = theWorkspace->AppliedPolygonOffset();
292
293   // separate depth buffers
294   if (IsSettingEnabled (Graphic3d_ZLayerDepthClear))
295   {
296     glClear (GL_DEPTH_BUFFER_BIT);
297   }
298
299   // handle depth test
300   if (IsSettingEnabled (Graphic3d_ZLayerDepthTest))
301   {
302     // assuming depth test is enabled by default
303     glDepthFunc (theDefaultSettings.DepthFunc);
304   }
305   else
306   {
307     glDepthFunc (GL_ALWAYS);
308   }
309
310   // handle depth offset
311   if (IsSettingEnabled (Graphic3d_ZLayerDepthOffset))
312   {
313     theWorkspace->SetPolygonOffset (Aspect_POM_Fill,
314                                     myLayerSettings.DepthOffsetFactor,
315                                     myLayerSettings.DepthOffsetUnits);
316   }
317   else
318   {
319     theWorkspace->SetPolygonOffset (anAppliedOffsetParams.mode,
320                                     anAppliedOffsetParams.factor,
321                                     anAppliedOffsetParams.units);
322   }
323
324   // handle depth write
325   theWorkspace->UseDepthWrite() = IsSettingEnabled (Graphic3d_ZLayerDepthWrite);
326   glDepthMask (theWorkspace->UseDepthWrite() ? GL_TRUE : GL_FALSE);
327
328   // render priority list
329   theWorkspace->IsCullingEnabled() ? renderTraverse (theWorkspace) : renderAll (theWorkspace);
330
331   // always restore polygon offset between layers rendering
332   theWorkspace->SetPolygonOffset (anAppliedOffsetParams.mode,
333                                   anAppliedOffsetParams.factor,
334                                   anAppliedOffsetParams.units);
335 }