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