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