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