ff1624362bf55c5520d1cfbe3f8520ecbf1cf8d1
[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         ++aHead;
211         aStack[aHead] = myBVHIsLeftChildQueuedFirst ? aRightChildIdx : aLeftChildIdx;
212         myBVHIsLeftChildQueuedFirst = !myBVHIsLeftChildQueuedFirst;
213       }
214       else if (isLeftChildIn
215             || isRightChildIn)
216       {
217         aNode = isLeftChildIn ? aLeftChildIdx : aRightChildIdx;
218       }
219       else
220       {
221         if (aHead < 0)
222         {
223           return;
224         }
225
226         aNode = aStack[aHead];
227         --aHead;
228       }
229     }
230     else
231     {
232       if (theSelector.Intersect (aBVHTree->MinPoint (aNode),
233                                  aBVHTree->MaxPoint (aNode)))
234       {
235         Standard_Integer aIdx = aBVHTree->BegPrimitive (aNode);
236         myBVHPrimitives.GetStructureById (aIdx)->MarkAsNotCulled();
237         if (aHead < 0)
238         {
239           return;
240         }
241
242         aNode = aStack[aHead];
243         --aHead;
244       }
245     }
246   }
247 }
248
249 // =======================================================================
250 // function : Append
251 // purpose  :
252 // =======================================================================
253 Standard_Boolean OpenGl_Layer::Append (const OpenGl_Layer& theOther)
254 {
255   // the source priority list shouldn't have more priorities
256   const Standard_Integer aNbPriorities = theOther.NbPriorities();
257   if (aNbPriorities > NbPriorities())
258   {
259     return Standard_False;
260   }
261
262   // add all structures to destination priority list
263   for (Standard_Integer aPriorityIter = 0; aPriorityIter < aNbPriorities; ++aPriorityIter)
264   {
265     for (OpenGl_SequenceOfStructure::Iterator aStructIter (theOther.myArray (aPriorityIter)); aStructIter.More(); aStructIter.Next())
266     {
267       Add (aStructIter.Value(), aPriorityIter);
268     }
269   }
270
271   return Standard_True;
272 }
273
274 //=======================================================================
275 //function : Render
276 //purpose  :
277 //=======================================================================
278 void OpenGl_Layer::Render (const Handle(OpenGl_Workspace)&   theWorkspace,
279                            const OpenGl_GlobalLayerSettings& theDefaultSettings) const
280 {
281   TEL_POFFSET_PARAM anAppliedOffsetParams = theWorkspace->AppliedPolygonOffset();
282
283   // separate depth buffers
284   if (IsSettingEnabled (Graphic3d_ZLayerDepthClear))
285   {
286     glClear (GL_DEPTH_BUFFER_BIT);
287   }
288  
289   // handle depth test
290   if (IsSettingEnabled (Graphic3d_ZLayerDepthTest))
291   {
292     // assuming depth test is enabled by default
293     glDepthFunc (theDefaultSettings.DepthFunc);
294   }
295   else
296   {
297     glDepthFunc (GL_ALWAYS);
298   }
299   
300   // handle depth offset
301   if (IsSettingEnabled (Graphic3d_ZLayerDepthOffset))
302   {
303     theWorkspace->SetPolygonOffset (Aspect_POM_Fill,
304                                     myLayerSettings.DepthOffsetFactor,
305                                     myLayerSettings.DepthOffsetUnits);
306   }
307   else
308   {
309     theWorkspace->SetPolygonOffset (anAppliedOffsetParams.mode,
310                                     anAppliedOffsetParams.factor,
311                                     anAppliedOffsetParams.units);
312   }
313
314   // handle depth write
315   glDepthMask (IsSettingEnabled (Graphic3d_ZLayerDepthWrite) ? GL_TRUE : GL_FALSE);
316
317   // render priority list
318   theWorkspace->IsCullingEnabled() ? renderTraverse (theWorkspace) : renderAll (theWorkspace);
319
320   // always restore polygon offset between layers rendering
321   theWorkspace->SetPolygonOffset (anAppliedOffsetParams.mode,
322                                   anAppliedOffsetParams.factor,
323                                   anAppliedOffsetParams.units);
324 }