0026434: Visualization - Textured objects should have priority over the environment...
[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 == Graphic3d_TMF_None)
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->View()->Identification();
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 == Graphic3d_TMF_None)
181         {
182           myBVHPrimitives.Add (aStruct);
183         }
184         else
185         {
186           myBVHPrimitivesTrsfPers.Add (aStruct);
187         }
188       }
189     }
190   }
191
192   OpenGl_BVHTreeSelector& aSelector = theWorkspace->View()->BVHTreeSelector();
193   traverse (aSelector);
194
195   const Standard_Integer aNbPriorities = myArray.Length();
196   const Standard_Integer aViewId       = theWorkspace->View()->Identification();
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
228    && myBVHPrimitivesTrsfPers.Size() == 0)
229     return;
230
231   theSelector.CacheClipPtsProjections();
232
233   NCollection_Handle<BVH_Tree<Standard_ShortReal, 4> > aBVHTree;
234
235   for (Standard_Integer aBVHTreeIdx = 0; aBVHTreeIdx < 2; ++aBVHTreeIdx)
236   {
237     const Standard_Boolean isTrsfPers = aBVHTreeIdx == 1;
238     if (isTrsfPers)
239     {
240       if (myBVHPrimitivesTrsfPers.Size() == 0)
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         continue;
252
253       aBVHTree = myBVHPrimitives.BVH();
254     }
255
256     Standard_Integer aNode = 0; // a root node
257
258     if (!theSelector.Intersect (aBVHTree->MinPoint (0),
259                                 aBVHTree->MaxPoint (0)))
260     {
261       continue;
262     }
263
264     Standard_Integer aStack[32];
265     Standard_Integer aHead = -1;
266     for (;;)
267     {
268       if (!aBVHTree->IsOuter (aNode))
269       {
270         const Standard_Integer aLeftChildIdx  = aBVHTree->LeftChild  (aNode);
271         const Standard_Integer aRightChildIdx = aBVHTree->RightChild (aNode);
272         const Standard_Boolean isLeftChildIn  = theSelector.Intersect (aBVHTree->MinPoint (aLeftChildIdx),
273                                                                        aBVHTree->MaxPoint (aLeftChildIdx));
274         const Standard_Boolean isRightChildIn = theSelector.Intersect (aBVHTree->MinPoint (aRightChildIdx),
275                                                                        aBVHTree->MaxPoint (aRightChildIdx));
276         if (isLeftChildIn
277          && isRightChildIn)
278         {
279           aNode = myBVHIsLeftChildQueuedFirst ? aLeftChildIdx : aRightChildIdx;
280           aStack[++aHead] = myBVHIsLeftChildQueuedFirst ? aRightChildIdx : aLeftChildIdx;
281           myBVHIsLeftChildQueuedFirst = !myBVHIsLeftChildQueuedFirst;
282         }
283         else if (isLeftChildIn
284               || isRightChildIn)
285         {
286           aNode = isLeftChildIn ? aLeftChildIdx : aRightChildIdx;
287         }
288         else
289         {
290           if (aHead < 0)
291           {
292             break;
293           }
294
295           aNode = aStack[aHead--];
296         }
297       }
298       else
299       {
300         Standard_Integer aIdx = aBVHTree->BegPrimitive (aNode);
301         const OpenGl_Structure* aStruct =
302           isTrsfPers ? myBVHPrimitivesTrsfPers.GetStructureById (aIdx)
303                      : myBVHPrimitives.GetStructureById (aIdx);
304         aStruct->MarkAsNotCulled();
305         if (aHead < 0)
306         {
307           break;
308         }
309
310         aNode = aStack[aHead--];
311       }
312     }
313   }
314 }
315
316 // =======================================================================
317 // function : Append
318 // purpose  :
319 // =======================================================================
320 Standard_Boolean OpenGl_Layer::Append (const OpenGl_Layer& theOther)
321 {
322   // the source priority list shouldn't have more priorities
323   const Standard_Integer aNbPriorities = theOther.NbPriorities();
324   if (aNbPriorities > NbPriorities())
325   {
326     return Standard_False;
327   }
328
329   // add all structures to destination priority list
330   for (Standard_Integer aPriorityIter = 0; aPriorityIter < aNbPriorities; ++aPriorityIter)
331   {
332     const OpenGl_IndexedMapOfStructure& aStructures = theOther.myArray (aPriorityIter);
333     for (Standard_Integer aStructIdx = 1; aStructIdx <= aStructures.Size(); ++aStructIdx)
334     {
335       Add (aStructures.FindKey (aStructIdx), aPriorityIter);
336     }
337   }
338
339   return Standard_True;
340 }
341
342 //=======================================================================
343 //function : Render
344 //purpose  :
345 //=======================================================================
346 void OpenGl_Layer::Render (const Handle(OpenGl_Workspace)&   theWorkspace,
347                            const OpenGl_GlobalLayerSettings& theDefaultSettings) const
348 {
349   TEL_POFFSET_PARAM anAppliedOffsetParams = theWorkspace->AppliedPolygonOffset();
350
351   // separate depth buffers
352   if (IsSettingEnabled (Graphic3d_ZLayerDepthClear))
353   {
354     glClear (GL_DEPTH_BUFFER_BIT);
355   }
356
357   // handle depth test
358   if (IsSettingEnabled (Graphic3d_ZLayerDepthTest))
359   {
360     // assuming depth test is enabled by default
361     glDepthFunc (theDefaultSettings.DepthFunc);
362   }
363   else
364   {
365     glDepthFunc (GL_ALWAYS);
366   }
367
368   // save environment texture
369   Handle(OpenGl_Texture) anEnvironmentTexture = theWorkspace->EnvironmentTexture();
370   if (!myLayerSettings.UseEnvironmentTexture)
371   {
372     theWorkspace->SetEnvironmentTexture (Handle(OpenGl_Texture)());
373   }
374
375   // handle depth offset
376   if (IsSettingEnabled (Graphic3d_ZLayerDepthOffset))
377   {
378     theWorkspace->SetPolygonOffset (Aspect_POM_Fill,
379                                     myLayerSettings.DepthOffsetFactor,
380                                     myLayerSettings.DepthOffsetUnits);
381   }
382   else
383   {
384     theWorkspace->SetPolygonOffset (anAppliedOffsetParams.mode,
385                                     anAppliedOffsetParams.factor,
386                                     anAppliedOffsetParams.units);
387   }
388
389   // handle depth write
390   theWorkspace->UseDepthWrite() = IsSettingEnabled (Graphic3d_ZLayerDepthWrite);
391   glDepthMask (theWorkspace->UseDepthWrite() ? GL_TRUE : GL_FALSE);
392
393   // render priority list
394   theWorkspace->IsCullingEnabled() ? renderTraverse (theWorkspace) : renderAll (theWorkspace);
395
396   // always restore polygon offset between layers rendering
397   theWorkspace->SetPolygonOffset (anAppliedOffsetParams.mode,
398                                   anAppliedOffsetParams.factor,
399                                   anAppliedOffsetParams.units);
400
401   // restore environment texture
402   if (!myLayerSettings.UseEnvironmentTexture)
403   {
404     theWorkspace->SetEnvironmentTexture (anEnvironmentTexture);
405   }
406 }