0027317: Some visualisation tests failed because of exceptions generated by FP signals.
[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 <OSD_Timer.hxx>
17 #include <OSD_Parallel.hxx>
18 #include <Standard_Assert.hxx>
19 #include <OpenGl_ArbTexBindless.hxx>
20 #include <OpenGl_PrimitiveArray.hxx>
21 #include <OpenGl_SceneGeometry.hxx>
22 #include <OpenGl_Structure.hxx>
23 #include <Graphic3d_GraphicDriver.hxx>
24
25 //! Use this macro to output BVH profiling info
26 // #define RAY_TRACE_PRINT_INFO
27
28 namespace
29 {
30   //! Useful constant for null floating-point 4D vector.
31   static const BVH_Vec4f ZERO_VEC_4F;
32 }
33
34 // =======================================================================
35 // function : OpenGl_RaytraceMaterial
36 // purpose  : Creates new default material
37 // =======================================================================
38 OpenGl_RaytraceMaterial::OpenGl_RaytraceMaterial()
39 : Ambient      (ZERO_VEC_4F),
40   Diffuse      (ZERO_VEC_4F),
41   Specular     (ZERO_VEC_4F),
42   Emission     (ZERO_VEC_4F),
43   Reflection   (ZERO_VEC_4F),
44   Refraction   (ZERO_VEC_4F),
45   Transparency (ZERO_VEC_4F)
46 { }
47
48 // =======================================================================
49 // function : OpenGl_RaytraceMaterial
50 // purpose  : Creates new material with specified properties
51 // =======================================================================
52 OpenGl_RaytraceMaterial::OpenGl_RaytraceMaterial (const BVH_Vec4f& theAmbient,
53                                                   const BVH_Vec4f& theDiffuse,
54                                                   const BVH_Vec4f& theSpecular)
55 : Ambient      (theAmbient),
56   Diffuse      (theDiffuse),
57   Specular     (theSpecular),
58   Emission     (ZERO_VEC_4F),
59   Reflection   (ZERO_VEC_4F),
60   Refraction   (ZERO_VEC_4F),
61   Transparency (ZERO_VEC_4F)
62 {
63   //
64 }
65
66 // =======================================================================
67 // function : OpenGl_RaytraceMaterial
68 // purpose  : Creates new material with specified properties
69 // =======================================================================
70 OpenGl_RaytraceMaterial::OpenGl_RaytraceMaterial (const BVH_Vec4f& theAmbient,
71                                                   const BVH_Vec4f& theDiffuse,
72                                                   const BVH_Vec4f& theSpecular,
73                                                   const BVH_Vec4f& theEmission,
74                                                   const BVH_Vec4f& theTranspar)
75 : Ambient      (theAmbient),
76   Diffuse      (theDiffuse),
77   Specular     (theSpecular),
78   Emission     (theEmission),
79   Reflection   (ZERO_VEC_4F),
80   Refraction   (ZERO_VEC_4F),
81   Transparency (theTranspar)
82 {
83   //
84 }
85
86 // =======================================================================
87 // function : OpenGl_RaytraceMaterial
88 // purpose  : Creates new material with specified properties
89 // =======================================================================
90 OpenGl_RaytraceMaterial::OpenGl_RaytraceMaterial (const BVH_Vec4f& theAmbient,
91                                                   const BVH_Vec4f& theDiffuse,
92                                                   const BVH_Vec4f& theSpecular,
93                                                   const BVH_Vec4f& theEmission,
94                                                   const BVH_Vec4f& theTranspar,
95                                                   const BVH_Vec4f& theReflection,
96                                                   const BVH_Vec4f& theRefraction)
97 : Ambient      (theAmbient),
98   Diffuse      (theDiffuse),
99   Specular     (theSpecular),
100   Emission     (theEmission),
101   Reflection   (theReflection),
102   Refraction   (theRefraction),
103   Transparency (theTranspar)
104 {
105   //
106 }
107
108 // =======================================================================
109 // function : OpenGl_LightSource
110 // purpose  : Creates new light source
111 // =======================================================================
112 OpenGl_RaytraceLight::OpenGl_RaytraceLight (const BVH_Vec4f& theDiffuse,
113                                             const BVH_Vec4f& thePosition)
114 : Diffuse (theDiffuse),
115   Position (thePosition)
116 {
117   //
118 }
119
120 // =======================================================================
121 // function : Center
122 // purpose  : Returns centroid position along the given axis
123 // =======================================================================
124 Standard_ShortReal OpenGl_TriangleSet::Center (
125   const Standard_Integer theIndex, const Standard_Integer theAxis) const
126 {
127   // Note: Experiments show that the use of the box centroid (instead
128   // of the triangle centroid) increases render performance up to 12%
129
130   const BVH_Vec4i& aTriangle = Elements[theIndex];
131
132   const Standard_ShortReal aVertex0 =
133     BVH::VecComp<Standard_ShortReal, 3>::Get (Vertices[aTriangle.x()], theAxis);
134   const Standard_ShortReal aVertex1 =
135     BVH::VecComp<Standard_ShortReal, 3>::Get (Vertices[aTriangle.y()], theAxis);
136   const Standard_ShortReal aVertex2 =
137     BVH::VecComp<Standard_ShortReal, 3>::Get (Vertices[aTriangle.z()], theAxis);
138
139   return (Min (Min (aVertex0, aVertex1), aVertex2) +
140           Max (Max (aVertex0, aVertex1), aVertex2)) * 0.5f;
141 }
142
143 // =======================================================================
144 // function : Box
145 // purpose  : Returns AABB of primitive set
146 // =======================================================================
147 OpenGl_TriangleSet::BVH_BoxNt OpenGl_TriangleSet::Box() const
148 {
149   const BVH_Transform<Standard_ShortReal, 4>* aTransform =
150     dynamic_cast<const BVH_Transform<Standard_ShortReal, 4>* > (Properties().operator->());
151
152   BVH_BoxNt aBox = BVH_PrimitiveSet<Standard_ShortReal, 3>::Box();
153
154   if (aTransform != NULL)
155   {
156     BVH_BoxNt aTransformedBox;
157
158     for (Standard_Integer aX = 0; aX <= 1; ++aX)
159     {
160       for (Standard_Integer aY = 0; aY <= 1; ++aY)
161       {
162         for (Standard_Integer aZ = 0; aZ <= 1; ++aZ)
163         {
164           BVH_Vec4f aCorner = aTransform->Transform() * BVH_Vec4f (
165             aX == 0 ? aBox.CornerMin().x() : aBox.CornerMax().x(),
166             aY == 0 ? aBox.CornerMin().y() : aBox.CornerMax().y(),
167             aZ == 0 ? aBox.CornerMin().z() : aBox.CornerMax().z(),
168             1.f);
169
170           aTransformedBox.Add (aCorner.xyz());
171         }
172       }
173     }
174
175     return aTransformedBox;
176   }
177
178   return aBox;
179 }
180
181 // =======================================================================
182 // function : OpenGl_TriangleSet
183 // purpose  : Creates new OpenGL element triangulation
184 // =======================================================================
185 OpenGl_TriangleSet::OpenGl_TriangleSet (const Standard_Size theArrayID)
186 : BVH_Triangulation<Standard_ShortReal, 3>(),
187   myArrayID (theArrayID)
188 {
189   myBuilder = new BVH_BinnedBuilder<Standard_ShortReal, 3 /* dim */, 48 /* bins */>
190     (5 /* leaf size */, 32 /* max height */, Standard_False, OSD_Parallel::NbLogicalProcessors() + 1 /* threads */);
191 }
192
193 // =======================================================================
194 // function : Clear
195 // purpose  : Clears ray-tracing geometry
196 // =======================================================================
197 void OpenGl_RaytraceGeometry::Clear()
198 {
199   BVH_Geometry<Standard_ShortReal, 3>::BVH_Geometry::Clear();
200
201   std::vector<OpenGl_RaytraceLight,
202     NCollection_StdAllocator<OpenGl_RaytraceLight> > anEmptySources;
203
204   Sources.swap (anEmptySources);
205
206   std::vector<OpenGl_RaytraceMaterial,
207     NCollection_StdAllocator<OpenGl_RaytraceMaterial> > anEmptyMaterials;
208
209   Materials.swap (anEmptyMaterials);
210 }
211
212 struct OpenGL_BVHParallelBuilder
213 {
214   BVH_ObjectSet<Standard_ShortReal, 3>* Set;
215
216   OpenGL_BVHParallelBuilder (BVH_ObjectSet<Standard_ShortReal, 3>* theSet)
217   : Set (theSet)
218   {
219     //
220   }
221
222   void operator() (const Standard_Integer theObjectIdx) const
223   {
224     OpenGl_TriangleSet* aTriangleSet = dynamic_cast<OpenGl_TriangleSet*> (
225       Set->Objects().ChangeValue (static_cast<Standard_Integer> (theObjectIdx)).operator->());
226
227     if (aTriangleSet != NULL)
228       aTriangleSet->BVH();
229   }
230 };
231
232 // =======================================================================
233 // function : ProcessAcceleration
234 // purpose  : Performs post-processing of high-level BVH
235 // =======================================================================
236 Standard_Boolean OpenGl_RaytraceGeometry::ProcessAcceleration()
237 {
238 #ifdef RAY_TRACE_PRINT_INFO
239   OSD_Timer aTimer;
240 #endif
241
242   MarkDirty(); // force BVH rebuilding
243
244 #ifdef RAY_TRACE_PRINT_INFO
245   aTimer.Reset();
246   aTimer.Start();
247 #endif
248
249   OSD_Parallel::For(0, Size(), OpenGL_BVHParallelBuilder(this));
250
251   myBottomLevelTreeDepth = 0;
252
253   for (Standard_Integer anObjectIdx = 0; anObjectIdx < Size(); ++anObjectIdx)
254   {
255     OpenGl_TriangleSet* aTriangleSet = dynamic_cast<OpenGl_TriangleSet*> (
256       myObjects.ChangeValue (anObjectIdx).operator->());
257
258     Standard_ASSERT_RETURN (aTriangleSet != NULL,
259       "Error! Failed to get triangulation of OpenGL element", Standard_False);
260
261     Standard_ASSERT_RETURN (!aTriangleSet->BVH().IsNull(),
262       "Error! Failed to update bottom-level BVH of OpenGL element", Standard_False);
263
264     NCollection_Handle<BVH_Tree<Standard_ShortReal, 3> > aBVH = aTriangleSet->BVH();
265
266     // correct data array of bottom-level BVH to set special flag for outer
267     // nodes in order to distinguish them from outer nodes of top-level BVH
268     for (Standard_Integer aNodeIdx = 0; aNodeIdx < aBVH->Length(); ++aNodeIdx)
269     {
270       if (aBVH->IsOuter (aNodeIdx))
271       {
272         aBVH->NodeInfoBuffer()[aNodeIdx].x() = -1;
273       }
274     }
275
276     myBottomLevelTreeDepth = Max (myBottomLevelTreeDepth, aTriangleSet->BVH()->Depth());
277   }
278
279 #ifdef RAY_TRACE_PRINT_INFO
280   aTimer.Stop();
281
282   std::cout << "Updating bottom-level BVHs (sec): " <<
283     aTimer.ElapsedTime() << std::endl;
284 #endif
285
286 #ifdef RAY_TRACE_PRINT_INFO
287   aTimer.Reset();
288   aTimer.Start();
289 #endif
290
291   NCollection_Handle<BVH_Tree<Standard_ShortReal, 3> > aBVH = BVH();
292
293 #ifdef RAY_TRACE_PRINT_INFO
294   aTimer.Stop();
295
296   std::cout << "Updating high-level BVH (sec): " <<
297     aTimer.ElapsedTime() << std::endl;
298 #endif
299
300   Standard_ASSERT_RETURN (!aBVH.IsNull(),
301     "Error! Failed to update high-level BVH of ray-tracing scene", Standard_False);
302
303   myHighLevelTreeDepth = aBVH->Depth();
304
305   Standard_Integer aVerticesOffset = 0;
306   Standard_Integer aElementsOffset = 0;
307   Standard_Integer aBVHNodesOffset = BVH()->Length();
308
309   for (Standard_Integer aNodeIdx = 0; aNodeIdx < aBVH->Length(); ++aNodeIdx)
310   {
311     if (!aBVH->IsOuter (aNodeIdx))
312       continue;
313
314     Standard_ASSERT_RETURN (aBVH->BegPrimitive (aNodeIdx) == aBVH->EndPrimitive (aNodeIdx),
315       "Error! Invalid leaf node in high-level BVH (contains several objects)", Standard_False);
316
317     Standard_Integer anObjectIdx = aBVH->BegPrimitive (aNodeIdx);
318
319     Standard_ASSERT_RETURN (anObjectIdx < myObjects.Size(),
320       "Error! Invalid leaf node in high-level BVH (contains out-of-range object)", Standard_False);
321
322     OpenGl_TriangleSet* aTriangleSet = dynamic_cast<OpenGl_TriangleSet*> (
323       myObjects.ChangeValue (anObjectIdx).operator->());
324
325     // Note: We overwrite node info record to store parameters
326     // of bottom-level BVH and triangulation of OpenGL element
327
328     aBVH->NodeInfoBuffer().at (aNodeIdx) = BVH_Vec4i (
329       anObjectIdx + 1 /* to keep leaf flag */, aBVHNodesOffset, aVerticesOffset, aElementsOffset);
330
331     aVerticesOffset += (int)aTriangleSet->Vertices.size();
332     aElementsOffset += (int)aTriangleSet->Elements.size();
333     aBVHNodesOffset += aTriangleSet->BVH()->Length();
334   }
335
336   return Standard_True;
337 }
338
339 // =======================================================================
340 // function : AccelerationOffset
341 // purpose  : Returns offset of bottom-level BVH for given leaf node
342 // =======================================================================
343 Standard_Integer OpenGl_RaytraceGeometry::AccelerationOffset (Standard_Integer theNodeIdx)
344 {
345   const NCollection_Handle<BVH_Tree<Standard_ShortReal, 3> >& aBVH = BVH();
346
347   if (theNodeIdx >= aBVH->Length() || !aBVH->IsOuter (theNodeIdx))
348     return INVALID_OFFSET;
349
350   return aBVH->NodeInfoBuffer().at (theNodeIdx).y();
351 }
352
353 // =======================================================================
354 // function : VerticesOffset
355 // purpose  : Returns offset of triangulation vertices for given leaf node
356 // =======================================================================
357 Standard_Integer OpenGl_RaytraceGeometry::VerticesOffset (Standard_Integer theNodeIdx)
358 {
359   const NCollection_Handle<BVH_Tree<Standard_ShortReal, 3> >& aBVH = BVH();
360
361   if (theNodeIdx >= aBVH->Length() || !aBVH->IsOuter (theNodeIdx))
362     return INVALID_OFFSET;
363
364   return aBVH->NodeInfoBuffer().at (theNodeIdx).z();
365 }
366
367 // =======================================================================
368 // function : ElementsOffset
369 // purpose  : Returns offset of triangulation elements for given leaf node
370 // =======================================================================
371 Standard_Integer OpenGl_RaytraceGeometry::ElementsOffset (Standard_Integer theNodeIdx)
372 {
373   const NCollection_Handle<BVH_Tree<Standard_ShortReal, 3> >& aBVH = BVH();
374
375   if (theNodeIdx >= aBVH->Length() || !aBVH->IsOuter (theNodeIdx))
376     return INVALID_OFFSET;
377
378   return aBVH->NodeInfoBuffer().at (theNodeIdx).w();
379 }
380
381 // =======================================================================
382 // function : TriangleSet
383 // purpose  : Returns triangulation data for given leaf node
384 // =======================================================================
385 OpenGl_TriangleSet* OpenGl_RaytraceGeometry::TriangleSet (Standard_Integer theNodeIdx)
386 {
387   const NCollection_Handle<BVH_Tree<Standard_ShortReal, 3> >& aBVH = BVH();
388
389   if (theNodeIdx >= aBVH->Length() || !aBVH->IsOuter (theNodeIdx))
390     return NULL;
391
392   if (aBVH->NodeInfoBuffer().at (theNodeIdx).x() > myObjects.Size())
393     return NULL;
394
395   return dynamic_cast<OpenGl_TriangleSet*> (myObjects.ChangeValue (
396     aBVH->NodeInfoBuffer().at (theNodeIdx).x() - 1).operator->());
397 }
398
399 // =======================================================================
400 // function : AcquireTextures
401 // purpose  : Makes the OpenGL texture handles resident
402 // =======================================================================
403 Standard_Boolean OpenGl_RaytraceGeometry::AcquireTextures (const Handle(OpenGl_Context)& theContext) const
404 {
405   if (theContext->arbTexBindless == NULL)
406   {
407     return Standard_True;
408   }
409
410 #if !defined(GL_ES_VERSION_2_0)
411   for (Standard_Integer anIdx = 0; anIdx < myTextures.Size(); ++anIdx)
412   {
413     theContext->arbTexBindless->glMakeTextureHandleResidentARB (myTextureHandles[anIdx]);
414
415     if (glGetError() != GL_NO_ERROR)
416     {
417 #ifdef RAY_TRACE_PRINT_INFO
418       std::cout << "Error: Failed to make OpenGL texture resident" << std::endl;
419 #endif
420       return Standard_False;
421     }
422   }
423 #endif
424
425   return Standard_True;
426 }
427
428 // =======================================================================
429 // function : ReleaseTextures
430 // purpose  : Makes the OpenGL texture handles non-resident
431 // =======================================================================
432 Standard_Boolean OpenGl_RaytraceGeometry::ReleaseTextures (const Handle(OpenGl_Context)& theContext) const
433 {
434   if (theContext->arbTexBindless == NULL)
435   {
436     return Standard_True;
437   }
438
439 #if !defined(GL_ES_VERSION_2_0)
440   for (Standard_Integer anIdx = 0; anIdx < myTextures.Size(); ++anIdx)
441   {
442     theContext->arbTexBindless->glMakeTextureHandleNonResidentARB (myTextureHandles[anIdx]);
443
444     if (glGetError() != GL_NO_ERROR)
445     {
446 #ifdef RAY_TRACE_PRINT_INFO
447       std::cout << "Error: Failed to make OpenGL texture non-resident" << std::endl;
448 #endif
449       return Standard_False;
450     }
451   }
452 #endif
453
454   return Standard_True;
455 }
456
457 // =======================================================================
458 // function : AddTexture
459 // purpose  : Adds new OpenGL texture to the scene and returns its index
460 // =======================================================================
461 Standard_Integer OpenGl_RaytraceGeometry::AddTexture (const Handle(OpenGl_Texture)& theTexture)
462 {
463   NCollection_Vector<Handle (OpenGl_Texture)>::iterator anIter =
464     std::find (myTextures.begin(), myTextures.end(), theTexture);
465
466   if (anIter == myTextures.end())
467   {
468     if (myTextures.Size() >= MAX_TEX_NUMBER)
469     {
470       return -1;
471     }
472
473     myTextures.Append (theTexture);
474   }
475
476   return static_cast<Standard_Integer> (anIter - myTextures.begin());
477 }
478
479 // =======================================================================
480 // function : UpdateTextureHandles
481 // purpose  : Updates unique 64-bit texture handles to use in shaders
482 // =======================================================================
483 Standard_Boolean OpenGl_RaytraceGeometry::UpdateTextureHandles (const Handle(OpenGl_Context)& theContext)
484 {
485   if (theContext->arbTexBindless == NULL)
486   {
487     return Standard_False;
488   }
489
490   if (myTextureSampler.IsNull())
491   {
492     myTextureSampler = new OpenGl_Sampler();
493     myTextureSampler->Init (*theContext.operator->());
494     myTextureSampler->SetParameter (*theContext.operator->(), GL_TEXTURE_MIN_FILTER, GL_LINEAR);
495     myTextureSampler->SetParameter (*theContext.operator->(), GL_TEXTURE_MAG_FILTER, GL_LINEAR);
496     myTextureSampler->SetParameter (*theContext.operator->(), GL_TEXTURE_WRAP_S,     GL_REPEAT);
497     myTextureSampler->SetParameter (*theContext.operator->(), GL_TEXTURE_WRAP_T,     GL_REPEAT);
498   }
499
500   myTextureHandles.clear();
501
502 #if !defined(GL_ES_VERSION_2_0)
503   for (Standard_Integer anIdx = 0; anIdx < myTextures.Size(); ++anIdx)
504   {
505     const GLuint64 aHandle = theContext->arbTexBindless->glGetTextureSamplerHandleARB (
506       myTextures.Value (anIdx)->TextureId(), myTextureSampler->SamplerID());
507
508     if (glGetError() != GL_NO_ERROR)
509     {
510 #ifdef RAY_TRACE_PRINT_INFO
511       std::cout << "Error: Failed to get 64-bit handle of OpenGL texture" << std::endl;
512 #endif
513       return Standard_False;
514     }
515
516     myTextureHandles.push_back (aHandle);
517   }
518 #endif
519
520   return Standard_True;
521 }
522
523 namespace OpenGl_Raytrace
524 {
525   // =======================================================================
526   // function : IsRaytracedElement
527   // purpose  : Checks to see if the element contains ray-trace geometry
528   // =======================================================================
529   Standard_Boolean IsRaytracedElement (const OpenGl_ElementNode* theNode)
530   {
531     OpenGl_PrimitiveArray* anArray = dynamic_cast<OpenGl_PrimitiveArray*> (theNode->elem);
532     return anArray != NULL
533         && anArray->DrawMode() >= GL_TRIANGLES;
534   }
535
536   // =======================================================================
537   // function : IsRaytracedElement
538   // purpose  : Checks to see if the element contains ray-trace geometry
539   // =======================================================================
540   Standard_Boolean IsRaytracedElement (const OpenGl_Element* theElement)
541   {
542     const OpenGl_PrimitiveArray* anArray = dynamic_cast<const OpenGl_PrimitiveArray*> (theElement);
543     return anArray != NULL
544         && anArray->DrawMode() >= GL_TRIANGLES;
545   }
546
547   // =======================================================================
548   // function : IsRaytracedGroup
549   // purpose  : Checks to see if the group contains ray-trace geometry
550   // =======================================================================
551   Standard_Boolean IsRaytracedGroup (const OpenGl_Group* theGroup)
552   {
553     for (const OpenGl_ElementNode* aNode = theGroup->FirstNode(); aNode != NULL; aNode = aNode->next)
554     {
555       if (IsRaytracedElement (aNode))
556       {
557         return Standard_True;
558       }
559     }
560     return Standard_False;
561   }
562
563   // =======================================================================
564   // function : IsRaytracedStructure
565   // purpose  : Checks to see if the structure contains ray-trace geometry
566   // =======================================================================
567   Standard_Boolean IsRaytracedStructure (const OpenGl_Structure* theStructure)
568   {
569     for (OpenGl_Structure::GroupIterator anIter (theStructure->DrawGroups()); anIter.More(); anIter.Next())
570     {
571       if (anIter.Value()->IsRaytracable())
572       {
573         return Standard_True;
574       }
575     }
576     return Standard_False;
577   }
578 }