b0bd4ab93de0e68511a08176e5fc91cf767d72d7
[occt.git] / src / OpenGl / OpenGl_SceneGeometry.cxx
1 // Created on: 2013-08-27
2 // Created by: Denis BOGOLEPOV
3 // Copyright (c) 2013 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 #ifdef HAVE_CONFIG_H
17   #include <config.h>
18 #endif
19
20 #ifdef HAVE_OPENCL
21
22 #include <Standard_Assert.hxx>
23
24 #ifdef HAVE_TBB
25   // On Windows, function TryEnterCriticalSection has appeared in Windows NT
26   // and is surrounded by #ifdef in MS VC++ 7.1 headers.
27   // Thus to use it we need to define appropriate macro saying that we wil
28   // run on Windows NT 4.0 at least
29   #if ((defined(_WIN32) || defined(__WIN32__)) && !defined(_WIN32_WINNT))
30     #define _WIN32_WINNT 0x0501
31   #endif
32
33   #include <tbb/tbb.h>
34 #endif
35
36 #include <OpenGl_SceneGeometry.hxx>
37
38 //! Use this macro to output BVH profiling info
39 //#define BVH_PRINT_INFO
40
41 #ifdef BVH_PRINT_INFO
42   #include <OSD_Timer.hxx>
43 #endif
44
45 namespace
46 {
47   //! Useful constant for null floating-point 4D vector.
48   static const BVH_Vec4f ZERO_VEC_4F;
49 };
50
51 // =======================================================================
52 // function : OpenGl_RaytraceMaterial
53 // purpose  : Creates new default material
54 // =======================================================================
55 OpenGl_RaytraceMaterial::OpenGl_RaytraceMaterial()
56 : Ambient      (ZERO_VEC_4F),
57   Diffuse      (ZERO_VEC_4F),
58   Specular     (ZERO_VEC_4F),
59   Emission     (ZERO_VEC_4F),
60   Reflection   (ZERO_VEC_4F),
61   Refraction   (ZERO_VEC_4F),
62   Transparency (ZERO_VEC_4F)
63 { }
64
65 // =======================================================================
66 // function : OpenGl_RaytraceMaterial
67 // purpose  : Creates new material with specified properties
68 // =======================================================================
69 OpenGl_RaytraceMaterial::OpenGl_RaytraceMaterial (const BVH_Vec4f& theAmbient,
70                                                   const BVH_Vec4f& theDiffuse,
71                                                   const BVH_Vec4f& theSpecular)
72 : Ambient      (theAmbient),
73   Diffuse      (theDiffuse),
74   Specular     (theSpecular),
75   Emission     (ZERO_VEC_4F),
76   Reflection   (ZERO_VEC_4F),
77   Refraction   (ZERO_VEC_4F),
78   Transparency (ZERO_VEC_4F)
79 {
80   //
81 }
82
83 // =======================================================================
84 // function : OpenGl_RaytraceMaterial
85 // purpose  : Creates new material with specified properties
86 // =======================================================================
87 OpenGl_RaytraceMaterial::OpenGl_RaytraceMaterial (const BVH_Vec4f& theAmbient,
88                                                   const BVH_Vec4f& theDiffuse,
89                                                   const BVH_Vec4f& theSpecular,
90                                                   const BVH_Vec4f& theEmission,
91                                                   const BVH_Vec4f& theTranspar)
92 : Ambient      (theAmbient),
93   Diffuse      (theDiffuse),
94   Specular     (theSpecular),
95   Emission     (theEmission),
96   Reflection   (ZERO_VEC_4F),
97   Refraction   (ZERO_VEC_4F),
98   Transparency (theTranspar)
99 {
100   //
101 }
102
103 // =======================================================================
104 // function : OpenGl_RaytraceMaterial
105 // purpose  : Creates new material with specified properties
106 // =======================================================================
107 OpenGl_RaytraceMaterial::OpenGl_RaytraceMaterial (const BVH_Vec4f& theAmbient,
108                                                   const BVH_Vec4f& theDiffuse,
109                                                   const BVH_Vec4f& theSpecular,
110                                                   const BVH_Vec4f& theEmission,
111                                                   const BVH_Vec4f& theTranspar,
112                                                   const BVH_Vec4f& theReflection,
113                                                   const BVH_Vec4f& theRefraction)
114 : Ambient      (theAmbient),
115   Diffuse      (theDiffuse),
116   Specular     (theSpecular),
117   Emission     (theEmission),
118   Reflection   (theReflection),
119   Refraction   (theRefraction),
120   Transparency (theTranspar)
121 {
122   //
123 }
124
125 // =======================================================================
126 // function : OpenGl_LightSource
127 // purpose  : Creates new light source
128 // =======================================================================
129 OpenGl_RaytraceLight::OpenGl_RaytraceLight (const BVH_Vec4f& theDiffuse,
130                                             const BVH_Vec4f& thePosition)
131 : Diffuse (theDiffuse),
132   Position (thePosition)
133 {
134   //
135 }
136
137 // =======================================================================
138 // function : Clear
139 // purpose  : Clears ray-tracing geometry
140 // =======================================================================
141 void OpenGl_RaytraceGeometry::Clear()
142 {
143   BVH_Geometry<Standard_ShortReal, 4>::BVH_Geometry::Clear();
144
145   std::vector<OpenGl_RaytraceLight,
146     NCollection_StdAllocator<OpenGl_RaytraceLight> > anEmptySources;
147
148   Sources.swap (anEmptySources);
149
150   std::vector<OpenGl_RaytraceMaterial,
151     NCollection_StdAllocator<OpenGl_RaytraceMaterial> > anEmptyMaterials;
152
153   Materials.swap (anEmptyMaterials);
154 }
155
156 #ifdef HAVE_TBB
157
158 struct OpenGL_BVHParallelBuilder
159 {
160   BVH_ObjectSet<Standard_ShortReal, 4>* Set;
161
162   OpenGL_BVHParallelBuilder (BVH_ObjectSet<Standard_ShortReal, 4>* theSet)
163     : Set (theSet)
164   {
165     //
166   }
167
168   void operator() (const tbb::blocked_range<size_t>& theRange) const
169   {
170     for (size_t anObjectIdx = theRange.begin(); anObjectIdx != theRange.end(); ++anObjectIdx)
171     {
172       OpenGl_TriangleSet* aTriangleSet = dynamic_cast<OpenGl_TriangleSet*> (
173         Set->Objects().ChangeValue (static_cast<Standard_Integer> (anObjectIdx)).operator->());
174
175       if (aTriangleSet != NULL)
176       {
177         aTriangleSet->BVH();
178       }
179     }
180   }
181 };
182
183 #endif
184
185 // =======================================================================
186 // function : ProcessAcceleration
187 // purpose  : Performs post-processing of high-level BVH
188 // =======================================================================
189 Standard_Boolean OpenGl_RaytraceGeometry::ProcessAcceleration()
190 {
191 #ifdef BVH_PRINT_INFO
192     OSD_Timer aTimer;
193 #endif
194
195   MarkDirty(); // force BVH rebuilding
196
197 #ifdef BVH_PRINT_INFO
198   aTimer.Reset();
199   aTimer.Start();
200 #endif
201
202 #ifdef HAVE_TBB
203   // If Intel TBB is available, perform the preliminary
204   // construction of bottom-level scene BVHs
205   tbb::parallel_for (tbb::blocked_range<size_t> (0, Size()),
206     OpenGL_BVHParallelBuilder (this));
207 #endif
208
209   for (Standard_Integer anObjectIdx = 0; anObjectIdx < Size(); ++anObjectIdx)
210   {
211     OpenGl_TriangleSet* aTriangleSet = dynamic_cast<OpenGl_TriangleSet*> (
212       myObjects.ChangeValue (anObjectIdx).operator->());
213
214     Standard_ASSERT_RETURN (aTriangleSet != NULL,
215       "Error! Failed to get triangulation of OpenGL element", Standard_False);
216
217     Standard_ASSERT_RETURN (!aTriangleSet->BVH().IsNull(),
218       "Error! Failed to update bottom-level BVH of OpenGL element", Standard_False);
219   }
220
221 #ifdef BVH_PRINT_INFO
222   aTimer.Stop();
223
224   std::cout << "Updating bottom-level BVHs (sec): " <<
225     aTimer.ElapsedTime() << std::endl;
226 #endif
227
228 #ifdef BVH_PRINT_INFO
229   aTimer.Reset();
230   aTimer.Start();
231 #endif
232
233   NCollection_Handle<BVH_Tree<Standard_ShortReal, 4> > aBVH = BVH();
234
235 #ifdef BVH_PRINT_INFO
236   aTimer.Stop();
237
238   std::cout << "Updating high-level BVH (sec): " <<
239     aTimer.ElapsedTime() << std::endl;
240 #endif
241
242   Standard_ASSERT_RETURN (!aBVH.IsNull(),
243     "Error! Failed to update high-level BVH of ray-tracing scene", Standard_False);
244
245   Standard_Integer aVerticesOffset = 0;
246   Standard_Integer aElementsOffset = 0;
247   Standard_Integer aBVHNodesOffset = 0;
248
249   for (Standard_Integer aNodeIdx = 0; aNodeIdx < aBVH->Length(); ++aNodeIdx)
250   {
251     if (!aBVH->IsOuter (aNodeIdx))
252       continue;
253
254     Standard_ASSERT_RETURN (aBVH->BegPrimitive (aNodeIdx) == aBVH->EndPrimitive (aNodeIdx),
255       "Error! Invalid leaf node in high-level BVH (contains several objects)", Standard_False);
256
257     Standard_Integer anObjectIdx = aBVH->BegPrimitive (aNodeIdx);
258
259     Standard_ASSERT_RETURN (anObjectIdx < myObjects.Size(),
260       "Error! Invalid leaf node in high-level BVH (contains out-of-range object)", Standard_False);
261
262     OpenGl_TriangleSet* aTriangleSet = dynamic_cast<OpenGl_TriangleSet*> (
263       myObjects.ChangeValue (anObjectIdx).operator->());
264
265     // Note: We overwrite node info record to store parameters
266     // of bottom-level BVH and triangulation of OpenGL element
267
268     aBVH->NodeInfoBuffer().at (aNodeIdx) = BVH_Vec4i (
269       anObjectIdx + 1 /* to keep leaf flag */, aBVHNodesOffset, aVerticesOffset, aElementsOffset);
270
271     aVerticesOffset += (int)aTriangleSet->Vertices.size();
272     aElementsOffset += (int)aTriangleSet->Elements.size();
273     aBVHNodesOffset += aTriangleSet->BVH()->Length();
274   }
275
276   return Standard_True;
277 }
278
279 // =======================================================================
280 // function : AccelerationOffset
281 // purpose  : Returns offset of bottom-level BVH for given leaf node
282 // =======================================================================
283 Standard_Integer OpenGl_RaytraceGeometry::AccelerationOffset (Standard_Integer theNodeIdx)
284 {
285   const NCollection_Handle<BVH_Tree<Standard_ShortReal, 4> >& aBVH = BVH();
286
287   if (theNodeIdx >= aBVH->Length() || !aBVH->IsOuter (theNodeIdx))
288     return INVALID_OFFSET;
289
290   return aBVH->NodeInfoBuffer().at (theNodeIdx).y();
291 }
292
293 // =======================================================================
294 // function : VerticesOffset
295 // purpose  : Returns offset of triangulation vertices for given leaf node
296 // =======================================================================
297 Standard_Integer OpenGl_RaytraceGeometry::VerticesOffset (Standard_Integer theNodeIdx)
298 {
299   const NCollection_Handle<BVH_Tree<Standard_ShortReal, 4> >& aBVH = BVH();
300
301   if (theNodeIdx >= aBVH->Length() || !aBVH->IsOuter (theNodeIdx))
302     return INVALID_OFFSET;
303
304   return aBVH->NodeInfoBuffer().at (theNodeIdx).z();
305 }
306
307 // =======================================================================
308 // function : ElementsOffset
309 // purpose  : Returns offset of triangulation elements for given leaf node
310 // =======================================================================
311 Standard_Integer OpenGl_RaytraceGeometry::ElementsOffset (Standard_Integer theNodeIdx)
312 {
313   const NCollection_Handle<BVH_Tree<Standard_ShortReal, 4> >& aBVH = BVH();
314
315   if (theNodeIdx >= aBVH->Length() || !aBVH->IsOuter (theNodeIdx))
316     return INVALID_OFFSET;
317
318   return aBVH->NodeInfoBuffer().at (theNodeIdx).w();
319 }
320
321 // =======================================================================
322 // function : TriangleSet
323 // purpose  : Returns triangulation data for given leaf node
324 // =======================================================================
325 OpenGl_TriangleSet* OpenGl_RaytraceGeometry::TriangleSet (Standard_Integer theNodeIdx)
326 {
327   const NCollection_Handle<BVH_Tree<Standard_ShortReal, 4> >& aBVH = BVH();
328
329   if (theNodeIdx >= aBVH->Length() || !aBVH->IsOuter (theNodeIdx))
330     return NULL;
331
332   if (aBVH->NodeInfoBuffer().at (theNodeIdx).x() > myObjects.Size())
333     return NULL;
334
335   return dynamic_cast<OpenGl_TriangleSet*> (myObjects.ChangeValue (
336     aBVH->NodeInfoBuffer().at (theNodeIdx).x() - 1).operator->());
337 }
338
339 namespace OpenGl_Raytrace
340 {
341   // =======================================================================
342   // function : IsRaytracedElement
343   // purpose  : Checks to see if the element contains ray-trace geometry
344   // =======================================================================
345   Standard_Boolean IsRaytracedElement (const OpenGl_ElementNode* theNode)
346   {
347     OpenGl_PrimitiveArray* anArray = dynamic_cast< OpenGl_PrimitiveArray* > (theNode->elem);
348     return anArray != NULL
349         && anArray->PArray()->type >= TelPolygonsArrayType;
350   }
351
352   // =======================================================================
353   // function : IsRaytracedGroup
354   // purpose  : Checks to see if the group contains ray-trace geometry
355   // =======================================================================
356   Standard_Boolean IsRaytracedGroup (const OpenGl_Group *theGroup)
357   {
358     const OpenGl_ElementNode* aNode;
359     for (aNode = theGroup->FirstNode(); aNode != NULL; aNode = aNode->next)
360     {
361       if (IsRaytracedElement (aNode))
362       {
363         return Standard_True;
364       }
365     }
366     return Standard_False;
367   }
368
369   // =======================================================================
370   // function : IsRaytracedStructure
371   // purpose  : Checks to see if the structure contains ray-trace geometry
372   // =======================================================================
373   Standard_Boolean IsRaytracedStructure (const OpenGl_Structure* theStructure)
374   {
375     for (OpenGl_Structure::GroupIterator aGroupIter (theStructure->DrawGroups());
376          aGroupIter.More(); aGroupIter.Next())
377     {
378       if (aGroupIter.Value()->IsRaytracable())
379         return Standard_True;
380     }
381     for (OpenGl_ListOfStructure::Iterator anIts (theStructure->ConnectedStructures());
382          anIts.More(); anIts.Next())
383     {
384       if (IsRaytracedStructure (anIts.Value()))
385         return Standard_True;
386     }
387     return Standard_False;
388   }
389 }
390
391 #endif