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