0026344: Visualization - provide a support of zoom persistent selection
[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_Layer
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     if (!theStruct->TransformPersistence.Flags)
68     {
69       myBVHPrimitives.Add (theStruct);
70     }
71     else
72     {
73       myBVHPrimitivesTrsfPers.Add (theStruct);
74     }
75   }
76   ++myNbStructures;
77 }
78
79 // =======================================================================
80 // function : Remove
81 // purpose  :
82 // =======================================================================
83 bool OpenGl_Layer::Remove (const OpenGl_Structure* theStruct,
84                            Standard_Integer&       thePriority,
85                            Standard_Boolean        isForChangePriority)
86 {
87   if (theStruct == NULL)
88   {
89     thePriority = -1;
90     return false;
91   }
92
93   const Standard_Integer aNbPriorities = myArray.Length();
94   for (Standard_Integer aPriorityIter = 0; aPriorityIter < aNbPriorities; ++aPriorityIter)
95   {
96     OpenGl_IndexedMapOfStructure& aStructures = myArray (aPriorityIter);
97
98     const Standard_Integer anIndex = aStructures.FindIndex (theStruct);
99     if (anIndex != 0)
100     {
101       aStructures.Swap (anIndex, aStructures.Size());
102       aStructures.RemoveLast();
103
104       if (!theStruct->IsAlwaysRendered()
105        && !isForChangePriority)
106       {
107         if (!myBVHPrimitives.Remove (theStruct))
108         {
109           myBVHPrimitivesTrsfPers.Remove (theStruct);
110         }
111       }
112       --myNbStructures;
113       thePriority = aPriorityIter;
114       return true;
115     }
116   }
117
118   thePriority = -1;
119   return false;
120 }
121
122 // =======================================================================
123 // function : InvalidateBVHData
124 // purpose  :
125 // =======================================================================
126 void OpenGl_Layer::InvalidateBVHData()
127 {
128   myIsBVHPrimitivesNeedsReset = Standard_True;
129 }
130
131 // =======================================================================
132 // function : renderAll
133 // purpose  :
134 // =======================================================================
135 void OpenGl_Layer::renderAll (const Handle(OpenGl_Workspace)& theWorkspace) const
136 {
137   const Standard_Integer aNbPriorities = myArray.Length();
138   const Standard_Integer aViewId       = theWorkspace->ActiveViewId();
139   for (Standard_Integer aPriorityIter = 0; aPriorityIter < aNbPriorities; ++aPriorityIter)
140   {
141     const OpenGl_IndexedMapOfStructure& aStructures = myArray (aPriorityIter);
142     for (Standard_Integer aStructIdx = 1; aStructIdx <= aStructures.Size(); ++aStructIdx)
143     {
144       const OpenGl_Structure* aStruct = aStructures.FindKey (aStructIdx);
145       if (!aStruct->IsVisible())
146       {
147         continue;
148       }
149       else if (!aStruct->ViewAffinity.IsNull()
150             && !aStruct->ViewAffinity->IsVisible (aViewId))
151       {
152         continue;
153       }
154
155       aStruct->Render (theWorkspace);
156     }
157   }
158 }
159
160 // =======================================================================
161 // function : renderTraverse
162 // purpose  :
163 // =======================================================================
164 void OpenGl_Layer::renderTraverse (const Handle(OpenGl_Workspace)& theWorkspace) const
165 {
166   if (myIsBVHPrimitivesNeedsReset)
167   {
168     myBVHPrimitives.Clear();
169     myBVHPrimitivesTrsfPers.Clear();
170     myIsBVHPrimitivesNeedsReset = Standard_False;
171     for (Standard_Integer aPriorityIdx = 0, aNbPriorities = myArray.Length(); aPriorityIdx < aNbPriorities; ++aPriorityIdx)
172     {
173       for (OpenGl_IndexedMapOfStructure::Iterator aStructIter (myArray (aPriorityIdx)); aStructIter.More(); aStructIter.Next())
174       {
175         const OpenGl_Structure* aStruct = aStructIter.Value();
176
177         if (aStruct->IsAlwaysRendered())
178           continue;
179
180         if (!aStruct->TransformPersistence.Flags)
181         {
182           myBVHPrimitives.Add (aStruct);
183         }
184         else
185         {
186           myBVHPrimitivesTrsfPers.Add (aStruct);
187         }
188       }
189     }
190   }
191
192   OpenGl_BVHTreeSelector& aSelector = theWorkspace->ActiveView()->BVHTreeSelector();
193   traverse (aSelector);
194
195   const Standard_Integer aNbPriorities = myArray.Length();
196   const Standard_Integer aViewId       = theWorkspace->ActiveViewId();
197   for (Standard_Integer aPriorityIter = 0; aPriorityIter < aNbPriorities; ++aPriorityIter)
198   {
199     const OpenGl_IndexedMapOfStructure& aStructures = myArray (aPriorityIter);
200     for (Standard_Integer aStructIdx = 1; aStructIdx <= aStructures.Size(); ++aStructIdx)
201     {
202       const OpenGl_Structure* aStruct = aStructures.FindKey (aStructIdx);
203       if (!aStruct->IsVisible()
204         || aStruct->IsCulled())
205       {
206         continue;
207       }
208       else if (!aStruct->ViewAffinity.IsNull()
209             && !aStruct->ViewAffinity->IsVisible (aViewId))
210       {
211         continue;
212       }
213
214       aStruct->Render (theWorkspace);
215       aStruct->ResetCullingStatus();
216     }
217   }
218 }
219
220 // =======================================================================
221 // function : traverse
222 // purpose  :
223 // =======================================================================
224 void OpenGl_Layer::traverse (OpenGl_BVHTreeSelector& theSelector) const
225 {
226   // handle a case when all objects are infinite
227   if (myBVHPrimitives.Size() == 0 && myBVHPrimitivesTrsfPers.Size() == 0)
228     return;
229
230   theSelector.CacheClipPtsProjections();
231
232   NCollection_Handle<BVH_Tree<Standard_ShortReal, 4> > aBVHTree;
233
234   for (Standard_Integer aBVHTreeIdx = 0; aBVHTreeIdx < 2; ++aBVHTreeIdx)
235   {
236     const Standard_Boolean isTrsfPers = aBVHTreeIdx == 1;
237     if (isTrsfPers)
238     {
239       if (myBVHPrimitivesTrsfPers.Size() == 0)
240       {
241         continue;
242       }
243       const OpenGl_Mat4& aProjection = theSelector.ProjectionMatrix();
244       const OpenGl_Mat4& aWorldView  = theSelector.WorldViewMatrix();
245       const Graphic3d_WorldViewProjState& aWVPState = theSelector.WorldViewProjState();
246       aBVHTree = myBVHPrimitivesTrsfPers.BVH (aProjection, aWorldView, aWVPState);
247     }
248     else
249     {
250       if (myBVHPrimitives.Size() == 0)
251       {
252         continue;
253       }
254       aBVHTree = myBVHPrimitives.BVH();
255     }
256
257     Standard_Integer aNode = 0; // a root node
258
259     if (!theSelector.Intersect (aBVHTree->MinPoint (0),
260                                 aBVHTree->MaxPoint (0)))
261     {
262       continue;
263     }
264
265     Standard_Integer aStack[32];
266     Standard_Integer aHead = -1;
267     for (;;)
268     {
269       if (!aBVHTree->IsOuter (aNode))
270       {
271         const Standard_Integer aLeftChildIdx  = aBVHTree->LeftChild  (aNode);
272         const Standard_Integer aRightChildIdx = aBVHTree->RightChild (aNode);
273         const Standard_Boolean isLeftChildIn  = theSelector.Intersect (aBVHTree->MinPoint (aLeftChildIdx),
274                                                                        aBVHTree->MaxPoint (aLeftChildIdx));
275         const Standard_Boolean isRightChildIn = theSelector.Intersect (aBVHTree->MinPoint (aRightChildIdx),
276                                                                        aBVHTree->MaxPoint (aRightChildIdx));
277         if (isLeftChildIn
278          && isRightChildIn)
279         {
280           aNode = myBVHIsLeftChildQueuedFirst ? aLeftChildIdx : aRightChildIdx;
281           aStack[++aHead] = myBVHIsLeftChildQueuedFirst ? aRightChildIdx : aLeftChildIdx;
282           myBVHIsLeftChildQueuedFirst = !myBVHIsLeftChildQueuedFirst;
283         }
284         else if (isLeftChildIn
285               || isRightChildIn)
286         {
287           aNode = isLeftChildIn ? aLeftChildIdx : aRightChildIdx;
288         }
289         else
290         {
291           if (aHead < 0)
292           {
293             break;
294           }
295
296           aNode = aStack[aHead--];
297         }
298       }
299       else
300       {
301         Standard_Integer aIdx = aBVHTree->BegPrimitive (aNode);
302         const OpenGl_Structure* aStruct =
303           isTrsfPers ? myBVHPrimitivesTrsfPers.GetStructureById (aIdx)
304                      : myBVHPrimitives.GetStructureById (aIdx);
305         aStruct->MarkAsNotCulled();
306         if (aHead < 0)
307         {
308           break;
309         }
310
311         aNode = aStack[aHead--];
312       }
313     }
314   }
315 }
316
317 // =======================================================================
318 // function : Append
319 // purpose  :
320 // =======================================================================
321 Standard_Boolean OpenGl_Layer::Append (const OpenGl_Layer& theOther)
322 {
323   // the source priority list shouldn't have more priorities
324   const Standard_Integer aNbPriorities = theOther.NbPriorities();
325   if (aNbPriorities > NbPriorities())
326   {
327     return Standard_False;
328   }
329
330   // add all structures to destination priority list
331   for (Standard_Integer aPriorityIter = 0; aPriorityIter < aNbPriorities; ++aPriorityIter)
332   {
333     const OpenGl_IndexedMapOfStructure& aStructures = theOther.myArray (aPriorityIter);
334     for (Standard_Integer aStructIdx = 1; aStructIdx <= aStructures.Size(); ++aStructIdx)
335     {
336       Add (aStructures.FindKey (aStructIdx), aPriorityIter);
337     }
338   }
339
340   return Standard_True;
341 }
342
343 //=======================================================================
344 //function : Render
345 //purpose  :
346 //=======================================================================
347 void OpenGl_Layer::Render (const Handle(OpenGl_Workspace)&   theWorkspace,
348                            const OpenGl_GlobalLayerSettings& theDefaultSettings) const
349 {
350   TEL_POFFSET_PARAM anAppliedOffsetParams = theWorkspace->AppliedPolygonOffset();
351
352   // separate depth buffers
353   if (IsSettingEnabled (Graphic3d_ZLayerDepthClear))
354   {
355     glClear (GL_DEPTH_BUFFER_BIT);
356   }
357
358   // handle depth test
359   if (IsSettingEnabled (Graphic3d_ZLayerDepthTest))
360   {
361     // assuming depth test is enabled by default
362     glDepthFunc (theDefaultSettings.DepthFunc);
363   }
364   else
365   {
366     glDepthFunc (GL_ALWAYS);
367   }
368
369   // handle depth offset
370   if (IsSettingEnabled (Graphic3d_ZLayerDepthOffset))
371   {
372     theWorkspace->SetPolygonOffset (Aspect_POM_Fill,
373                                     myLayerSettings.DepthOffsetFactor,
374                                     myLayerSettings.DepthOffsetUnits);
375   }
376   else
377   {
378     theWorkspace->SetPolygonOffset (anAppliedOffsetParams.mode,
379                                     anAppliedOffsetParams.factor,
380                                     anAppliedOffsetParams.units);
381   }
382
383   // handle depth write
384   theWorkspace->UseDepthWrite() = IsSettingEnabled (Graphic3d_ZLayerDepthWrite);
385   glDepthMask (theWorkspace->UseDepthWrite() ? GL_TRUE : GL_FALSE);
386
387   // render priority list
388   theWorkspace->IsCullingEnabled() ? renderTraverse (theWorkspace) : renderAll (theWorkspace);
389
390   // always restore polygon offset between layers rendering
391   theWorkspace->SetPolygonOffset (anAppliedOffsetParams.mode,
392                                   anAppliedOffsetParams.factor,
393                                   anAppliedOffsetParams.units);
394 }