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