57f81419f0bb2d77ed6ea75359423ee9fae5a06e
[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).Append (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_SequenceOfStructure& aSeq = myArray (aPriorityIter);
89     for (OpenGl_SequenceOfStructure::Iterator aStructIter (aSeq); aStructIter.More(); aStructIter.Next())
90     {
91       if (aStructIter.Value() == theStruct)
92       {
93         aSeq.Remove (aStructIter);
94         if (!theStruct->IsAlwaysRendered()
95          && !isForChangePriority)
96         {
97           myBVHPrimitives.Remove (theStruct);
98         }
99         --myNbStructures;
100         thePriority = aPriorityIter;
101         return true;
102       }
103     }
104   }
105
106   thePriority = -1;
107   return false;
108 }
109
110 // =======================================================================
111 // function : InvalidateBVHData
112 // purpose  :
113 // =======================================================================
114 void OpenGl_Layer::InvalidateBVHData()
115 {
116   myIsBVHPrimitivesNeedsReset = Standard_True;
117 }
118
119 // =======================================================================
120 // function : renderAll
121 // purpose  :
122 // =======================================================================
123 void OpenGl_Layer::renderAll (const Handle(OpenGl_Workspace)& theWorkspace) const
124 {
125   const Standard_Integer aNbPriorities = myArray.Length();
126   for (Standard_Integer aPriorityIter = 0; aPriorityIter < aNbPriorities; ++aPriorityIter)
127   {
128     for (OpenGl_SequenceOfStructure::Iterator aStructIter (myArray (aPriorityIter)); aStructIter.More(); aStructIter.Next())
129     {
130       const OpenGl_Structure* aStruct = aStructIter.Value();
131       if (!aStruct->IsVisible())
132       {
133         continue;
134       }
135
136       aStruct->Render (theWorkspace);
137     }
138   }
139 }
140
141 // =======================================================================
142 // function : renderTraverse
143 // purpose  :
144 // =======================================================================
145 void OpenGl_Layer::renderTraverse (const Handle(OpenGl_Workspace)& theWorkspace) const
146 {
147   if (myIsBVHPrimitivesNeedsReset)
148   {
149     myBVHPrimitives.Assign (myArray);
150     myIsBVHPrimitivesNeedsReset = Standard_False;
151   }
152
153   OpenGl_BVHTreeSelector& aSelector = theWorkspace->ActiveView()->BVHTreeSelector();
154   traverse (aSelector);
155
156   const Standard_Integer aNbPriorities = myArray.Length();
157   for (Standard_Integer aPriorityIter = 0; aPriorityIter < aNbPriorities; ++aPriorityIter)
158   {
159     for (OpenGl_SequenceOfStructure::Iterator aStructIter (myArray (aPriorityIter)); aStructIter.More(); aStructIter.Next())
160     {
161       const OpenGl_Structure* aStruct = aStructIter.Value();
162       if (!aStruct->IsVisible()
163         || aStruct->IsCulled())
164       {
165         continue;
166       }
167
168       aStruct->Render (theWorkspace);
169       aStruct->ResetCullingStatus();
170     }
171   }
172 }
173
174 // =======================================================================
175 // function : traverse
176 // purpose  :
177 // =======================================================================
178 void OpenGl_Layer::traverse (OpenGl_BVHTreeSelector& theSelector) const
179 {
180   // handle a case when all objects are infinite
181   if (myBVHPrimitives.Size() == 0)
182     return;
183
184   const NCollection_Handle<BVH_Tree<Standard_ShortReal, 4> >& aBVHTree = myBVHPrimitives.BVH();
185
186   Standard_Integer aNode = 0; // a root node
187   theSelector.CacheClipPtsProjections();
188   if (!theSelector.Intersect (aBVHTree->MinPoint (0),
189                               aBVHTree->MaxPoint (0)))
190   {
191     return;
192   }
193
194   Standard_Integer aStack[32];
195   Standard_Integer aHead = -1;
196   for (;;)
197   {
198     if (!aBVHTree->IsOuter (aNode))
199     {
200       const Standard_Integer aLeftChildIdx  = aBVHTree->LeftChild  (aNode);
201       const Standard_Integer aRightChildIdx = aBVHTree->RightChild (aNode);
202       const Standard_Boolean isLeftChildIn  = theSelector.Intersect (aBVHTree->MinPoint (aLeftChildIdx),
203                                                                      aBVHTree->MaxPoint (aLeftChildIdx));
204       const Standard_Boolean isRightChildIn = theSelector.Intersect (aBVHTree->MinPoint (aRightChildIdx),
205                                                                      aBVHTree->MaxPoint (aRightChildIdx));
206       if (isLeftChildIn
207        && isRightChildIn)
208       {
209         aNode = myBVHIsLeftChildQueuedFirst ? aLeftChildIdx : aRightChildIdx;
210         aStack[++aHead] = myBVHIsLeftChildQueuedFirst ? aRightChildIdx : aLeftChildIdx;
211         myBVHIsLeftChildQueuedFirst = !myBVHIsLeftChildQueuedFirst;
212       }
213       else if (isLeftChildIn
214             || isRightChildIn)
215       {
216         aNode = isLeftChildIn ? aLeftChildIdx : aRightChildIdx;
217       }
218       else
219       {
220         if (aHead < 0)
221         {
222           return;
223         }
224
225         aNode = aStack[aHead--];
226       }
227     }
228     else
229     {
230       Standard_Integer aIdx = aBVHTree->BegPrimitive (aNode);
231       myBVHPrimitives.GetStructureById (aIdx)->MarkAsNotCulled();
232       if (aHead < 0)
233       {
234         return;
235       }
236
237       aNode = aStack[aHead--];
238     }
239   }
240 }
241
242 // =======================================================================
243 // function : Append
244 // purpose  :
245 // =======================================================================
246 Standard_Boolean OpenGl_Layer::Append (const OpenGl_Layer& theOther)
247 {
248   // the source priority list shouldn't have more priorities
249   const Standard_Integer aNbPriorities = theOther.NbPriorities();
250   if (aNbPriorities > NbPriorities())
251   {
252     return Standard_False;
253   }
254
255   // add all structures to destination priority list
256   for (Standard_Integer aPriorityIter = 0; aPriorityIter < aNbPriorities; ++aPriorityIter)
257   {
258     for (OpenGl_SequenceOfStructure::Iterator aStructIter (theOther.myArray (aPriorityIter)); aStructIter.More(); aStructIter.Next())
259     {
260       Add (aStructIter.Value(), aPriorityIter);
261     }
262   }
263
264   return Standard_True;
265 }
266
267 //=======================================================================
268 //function : Render
269 //purpose  :
270 //=======================================================================
271 void OpenGl_Layer::Render (const Handle(OpenGl_Workspace)&   theWorkspace,
272                            const OpenGl_GlobalLayerSettings& theDefaultSettings) const
273 {
274   TEL_POFFSET_PARAM anAppliedOffsetParams = theWorkspace->AppliedPolygonOffset();
275
276   // separate depth buffers
277   if (IsSettingEnabled (Graphic3d_ZLayerDepthClear))
278   {
279     glClear (GL_DEPTH_BUFFER_BIT);
280   }
281  
282   // handle depth test
283   if (IsSettingEnabled (Graphic3d_ZLayerDepthTest))
284   {
285     // assuming depth test is enabled by default
286     glDepthFunc (theDefaultSettings.DepthFunc);
287   }
288   else
289   {
290     glDepthFunc (GL_ALWAYS);
291   }
292   
293   // handle depth offset
294   if (IsSettingEnabled (Graphic3d_ZLayerDepthOffset))
295   {
296     theWorkspace->SetPolygonOffset (Aspect_POM_Fill,
297                                     myLayerSettings.DepthOffsetFactor,
298                                     myLayerSettings.DepthOffsetUnits);
299   }
300   else
301   {
302     theWorkspace->SetPolygonOffset (anAppliedOffsetParams.mode,
303                                     anAppliedOffsetParams.factor,
304                                     anAppliedOffsetParams.units);
305   }
306
307   // handle depth write
308   glDepthMask (IsSettingEnabled (Graphic3d_ZLayerDepthWrite) ? GL_TRUE : GL_FALSE);
309
310   // render priority list
311   theWorkspace->IsCullingEnabled() ? renderTraverse (theWorkspace) : renderAll (theWorkspace);
312
313   // always restore polygon offset between layers rendering
314   theWorkspace->SetPolygonOffset (anAppliedOffsetParams.mode,
315                                   anAppliedOffsetParams.factor,
316                                   anAppliedOffsetParams.units);
317 }