0024739: TKOpenGl - port ray-tracing from OpenCL to GLSL for better integration and...
[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 #include <Standard_Assert.hxx>
17
18 #ifdef HAVE_TBB
19   // On Windows, function TryEnterCriticalSection has appeared in Windows NT
20   // and is surrounded by #ifdef in MS VC++ 7.1 headers.
21   // Thus to use it we need to define appropriate macro saying that we wil
22   // run on Windows NT 4.0 at least
23   #if ((defined(_WIN32) || defined(__WIN32__)) && !defined(_WIN32_WINNT))
24     #define _WIN32_WINNT 0x0501
25   #endif
26
27   #include <tbb/tbb.h>
28 #endif
29
30 #include <OpenGl_SceneGeometry.hxx>
31
32 //! Use this macro to output BVH profiling info
33 //#define BVH_PRINT_INFO
34
35 #ifdef BVH_PRINT_INFO
36   #include <OSD_Timer.hxx>
37 #endif
38
39 namespace
40 {
41   //! Useful constant for null floating-point 4D vector.
42   static const BVH_Vec4f ZERO_VEC_4F;
43 };
44
45 // =======================================================================
46 // function : OpenGl_RaytraceMaterial
47 // purpose  : Creates new default material
48 // =======================================================================
49 OpenGl_RaytraceMaterial::OpenGl_RaytraceMaterial()
50 : Ambient      (ZERO_VEC_4F),
51   Diffuse      (ZERO_VEC_4F),
52   Specular     (ZERO_VEC_4F),
53   Emission     (ZERO_VEC_4F),
54   Reflection   (ZERO_VEC_4F),
55   Refraction   (ZERO_VEC_4F),
56   Transparency (ZERO_VEC_4F)
57 { }
58
59 // =======================================================================
60 // function : OpenGl_RaytraceMaterial
61 // purpose  : Creates new material with specified properties
62 // =======================================================================
63 OpenGl_RaytraceMaterial::OpenGl_RaytraceMaterial (const BVH_Vec4f& theAmbient,
64                                                   const BVH_Vec4f& theDiffuse,
65                                                   const BVH_Vec4f& theSpecular)
66 : Ambient      (theAmbient),
67   Diffuse      (theDiffuse),
68   Specular     (theSpecular),
69   Emission     (ZERO_VEC_4F),
70   Reflection   (ZERO_VEC_4F),
71   Refraction   (ZERO_VEC_4F),
72   Transparency (ZERO_VEC_4F)
73 {
74   //
75 }
76
77 // =======================================================================
78 // function : OpenGl_RaytraceMaterial
79 // purpose  : Creates new material with specified properties
80 // =======================================================================
81 OpenGl_RaytraceMaterial::OpenGl_RaytraceMaterial (const BVH_Vec4f& theAmbient,
82                                                   const BVH_Vec4f& theDiffuse,
83                                                   const BVH_Vec4f& theSpecular,
84                                                   const BVH_Vec4f& theEmission,
85                                                   const BVH_Vec4f& theTranspar)
86 : Ambient      (theAmbient),
87   Diffuse      (theDiffuse),
88   Specular     (theSpecular),
89   Emission     (theEmission),
90   Reflection   (ZERO_VEC_4F),
91   Refraction   (ZERO_VEC_4F),
92   Transparency (theTranspar)
93 {
94   //
95 }
96
97 // =======================================================================
98 // function : OpenGl_RaytraceMaterial
99 // purpose  : Creates new material with specified properties
100 // =======================================================================
101 OpenGl_RaytraceMaterial::OpenGl_RaytraceMaterial (const BVH_Vec4f& theAmbient,
102                                                   const BVH_Vec4f& theDiffuse,
103                                                   const BVH_Vec4f& theSpecular,
104                                                   const BVH_Vec4f& theEmission,
105                                                   const BVH_Vec4f& theTranspar,
106                                                   const BVH_Vec4f& theReflection,
107                                                   const BVH_Vec4f& theRefraction)
108 : Ambient      (theAmbient),
109   Diffuse      (theDiffuse),
110   Specular     (theSpecular),
111   Emission     (theEmission),
112   Reflection   (theReflection),
113   Refraction   (theRefraction),
114   Transparency (theTranspar)
115 {
116   //
117 }
118
119 // =======================================================================
120 // function : OpenGl_LightSource
121 // purpose  : Creates new light source
122 // =======================================================================
123 OpenGl_RaytraceLight::OpenGl_RaytraceLight (const BVH_Vec4f& theDiffuse,
124                                             const BVH_Vec4f& thePosition)
125 : Diffuse (theDiffuse),
126   Position (thePosition)
127 {
128   //
129 }
130
131 // =======================================================================
132 // function : Clear
133 // purpose  : Clears ray-tracing geometry
134 // =======================================================================
135 void OpenGl_RaytraceGeometry::Clear()
136 {
137   BVH_Geometry<Standard_ShortReal, 4>::BVH_Geometry::Clear();
138
139   std::vector<OpenGl_RaytraceLight,
140     NCollection_StdAllocator<OpenGl_RaytraceLight> > anEmptySources;
141
142   Sources.swap (anEmptySources);
143
144   std::vector<OpenGl_RaytraceMaterial,
145     NCollection_StdAllocator<OpenGl_RaytraceMaterial> > anEmptyMaterials;
146
147   Materials.swap (anEmptyMaterials);
148 }
149
150 #ifdef HAVE_TBB
151
152 struct OpenGL_BVHParallelBuilder
153 {
154   BVH_ObjectSet<Standard_ShortReal, 4>* Set;
155
156   OpenGL_BVHParallelBuilder (BVH_ObjectSet<Standard_ShortReal, 4>* theSet)
157     : Set (theSet)
158   {
159     //
160   }
161
162   void operator() (const tbb::blocked_range<size_t>& theRange) const
163   {
164     for (size_t anObjectIdx = theRange.begin(); anObjectIdx != theRange.end(); ++anObjectIdx)
165     {
166       OpenGl_TriangleSet* aTriangleSet = dynamic_cast<OpenGl_TriangleSet*> (
167         Set->Objects().ChangeValue (static_cast<Standard_Integer> (anObjectIdx)).operator->());
168
169       if (aTriangleSet != NULL)
170       {
171         aTriangleSet->BVH();
172       }
173     }
174   }
175 };
176
177 #endif
178
179 // =======================================================================
180 // function : ProcessAcceleration
181 // purpose  : Performs post-processing of high-level BVH
182 // =======================================================================
183 Standard_Boolean OpenGl_RaytraceGeometry::ProcessAcceleration()
184 {
185 #ifdef BVH_PRINT_INFO
186     OSD_Timer aTimer;
187 #endif
188
189   MarkDirty(); // force BVH rebuilding
190
191 #ifdef BVH_PRINT_INFO
192   aTimer.Reset();
193   aTimer.Start();
194 #endif
195
196 #ifdef HAVE_TBB
197   // If Intel TBB is available, perform the preliminary
198   // construction of bottom-level scene BVHs
199   tbb::parallel_for (tbb::blocked_range<size_t> (0, Size()),
200     OpenGL_BVHParallelBuilder (this));
201 #endif
202
203   myBottomLevelTreeDepth = 0;
204
205   for (Standard_Integer anObjectIdx = 0; anObjectIdx < Size(); ++anObjectIdx)
206   {
207     OpenGl_TriangleSet* aTriangleSet = dynamic_cast<OpenGl_TriangleSet*> (
208       myObjects.ChangeValue (anObjectIdx).operator->());
209
210     Standard_ASSERT_RETURN (aTriangleSet != NULL,
211       "Error! Failed to get triangulation of OpenGL element", Standard_False);
212
213     Standard_ASSERT_RETURN (!aTriangleSet->BVH().IsNull(),
214       "Error! Failed to update bottom-level BVH of OpenGL element", Standard_False);
215
216     myBottomLevelTreeDepth = Max (myBottomLevelTreeDepth, aTriangleSet->BVH()->Depth());
217   }
218
219 #ifdef BVH_PRINT_INFO
220   aTimer.Stop();
221
222   std::cout << "Updating bottom-level BVHs (sec): " <<
223     aTimer.ElapsedTime() << std::endl;
224 #endif
225
226 #ifdef BVH_PRINT_INFO
227   aTimer.Reset();
228   aTimer.Start();
229 #endif
230
231   NCollection_Handle<BVH_Tree<Standard_ShortReal, 4> > aBVH = BVH();
232
233 #ifdef BVH_PRINT_INFO
234   aTimer.Stop();
235
236   std::cout << "Updating high-level BVH (sec): " <<
237     aTimer.ElapsedTime() << std::endl;
238 #endif
239
240   Standard_ASSERT_RETURN (!aBVH.IsNull(),
241     "Error! Failed to update high-level BVH of ray-tracing scene", Standard_False);
242
243   myHighLevelTreeDepth = aBVH->Depth();
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 }