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