0026601: Visualization, Ray Tracing - make Path Tracing results reproducible for...
[occt.git] / src / OpenGl / OpenGl_View_Raytrace.cxx
1 // Created on: 2015-02-20
2 // Created by: Denis BOGOLEPOV
3 // Copyright (c) 2015 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 <Graphic3d_TextureParams.hxx>
17
18 #include <OpenGl_FrameBuffer.hxx>
19 #include <OpenGl_PrimitiveArray.hxx>
20 #include <OpenGl_VertexBuffer.hxx>
21 #include <OpenGl_View.hxx>
22 #include <Graphic3d_GraphicDriver.hxx>
23
24 #include <OSD_Protection.hxx>
25 #include <OSD_File.hxx>
26
27 using namespace OpenGl_Raytrace;
28
29 //! Use this macro to output ray-tracing debug info
30 // #define RAY_TRACE_PRINT_INFO
31
32 #ifdef RAY_TRACE_PRINT_INFO
33   #include <OSD_Timer.hxx>
34 #endif
35
36 // =======================================================================
37 // function : updateRaytraceGeometry
38 // purpose  : Updates 3D scene geometry for ray-tracing
39 // =======================================================================
40 Standard_Boolean OpenGl_View::updateRaytraceGeometry (const RaytraceUpdateMode      theMode,
41                                                       const Standard_Integer        theViewId,
42                                                       const Handle(OpenGl_Context)& theGlContext)
43 {
44   // In 'check' mode (OpenGl_GUM_CHECK) the scene geometry is analyzed for
45   // modifications. This is light-weight procedure performed on each frame
46   if (theMode == OpenGl_GUM_CHECK)
47   {
48     if (myLayerListState != myZLayers.ModificationState())
49     {
50       return updateRaytraceGeometry (OpenGl_GUM_PREPARE, theViewId, theGlContext);
51     }
52   }
53   else if (theMode == OpenGl_GUM_PREPARE)
54   {
55     myRaytraceGeometry.ClearMaterials();
56
57     myArrayToTrianglesMap.clear();
58
59     myIsRaytraceDataValid = Standard_False;
60   }
61
62   // The set of processed structures (reflected to ray-tracing)
63   // This set is used to remove out-of-date records from the
64   // hash map of structures
65   std::set<const OpenGl_Structure*> anElements;
66
67   // Set to store all currently visible OpenGL primitive arrays
68   // applicable for ray-tracing
69   std::set<Standard_Size> anArrayIDs;
70
71   // Set to store all non-raytracable elements allowing tracking
72   // of changes in OpenGL scene (only for path tracing)
73   std::set<Standard_Integer> aNonRaytraceIDs;
74
75   const OpenGl_Layer& aLayer = myZLayers.Layer (Graphic3d_ZLayerId_Default);
76
77   if (aLayer.NbStructures() != 0)
78   {
79     const OpenGl_ArrayOfIndexedMapOfStructure& aStructArray = aLayer.ArrayOfStructures();
80
81     for (Standard_Integer anIndex = 0; anIndex < aStructArray.Length(); ++anIndex)
82     {
83       for (OpenGl_IndexedMapOfStructure::Iterator aStructIt (aStructArray (anIndex)); aStructIt.More(); aStructIt.Next())
84       {
85         const OpenGl_Structure* aStructure = aStructIt.Value();
86
87         if (theMode == OpenGl_GUM_CHECK)
88         {
89           if (toUpdateStructure (aStructure))
90           {
91             return updateRaytraceGeometry (OpenGl_GUM_PREPARE, theViewId, theGlContext);
92           }
93           else if (aStructure->IsVisible() && myRaytraceParameters.GlobalIllumination)
94           {
95             aNonRaytraceIDs.insert (aStructure->highlight ? aStructure->Id : -aStructure->Id);
96           }
97         }
98         else if (theMode == OpenGl_GUM_PREPARE)
99         {
100           if (!aStructure->IsRaytracable() || !aStructure->IsVisible())
101           {
102             continue;
103           }
104           else if (!aStructure->ViewAffinity.IsNull() && !aStructure->ViewAffinity->IsVisible (theViewId))
105           {
106             continue;
107           }
108
109           for (OpenGl_Structure::GroupIterator aGroupIter (aStructure->DrawGroups()); aGroupIter.More(); aGroupIter.Next())
110           {
111             // Extract OpenGL elements from the group (primitives arrays)
112             for (const OpenGl_ElementNode* aNode = aGroupIter.Value()->FirstNode(); aNode != NULL; aNode = aNode->next)
113             {
114               OpenGl_PrimitiveArray* aPrimArray = dynamic_cast<OpenGl_PrimitiveArray*> (aNode->elem);
115
116               if (aPrimArray != NULL)
117               {
118                 anArrayIDs.insert (aPrimArray->GetUID());
119               }
120             }
121           }
122         }
123         else if (theMode == OpenGl_GUM_REBUILD)
124         {
125           if (!aStructure->IsRaytracable())
126           {
127             continue;
128           }
129           else if (addRaytraceStructure (aStructure, theGlContext))
130           {
131             anElements.insert (aStructure); // structure was processed
132           }
133         }
134       }
135     }
136   }
137
138   if (theMode == OpenGl_GUM_PREPARE)
139   {
140     BVH_ObjectSet<Standard_ShortReal, 3>::BVH_ObjectList anUnchangedObjects;
141
142     // Filter out unchanged objects so only their transformations and materials
143     // will be updated (and newly added objects will be processed from scratch)
144     for (Standard_Integer anObjIdx = 0; anObjIdx < myRaytraceGeometry.Size(); ++anObjIdx)
145     {
146       OpenGl_TriangleSet* aTriangleSet = dynamic_cast<OpenGl_TriangleSet*> (
147         myRaytraceGeometry.Objects().ChangeValue (anObjIdx).operator->());
148
149       if (aTriangleSet == NULL)
150       {
151         continue;
152       }
153
154       if (anArrayIDs.find (aTriangleSet->AssociatedPArrayID()) != anArrayIDs.end())
155       {
156         anUnchangedObjects.Append (myRaytraceGeometry.Objects().Value (anObjIdx));
157
158         myArrayToTrianglesMap[aTriangleSet->AssociatedPArrayID()] = aTriangleSet;
159       }
160     }
161
162     myRaytraceGeometry.Objects() = anUnchangedObjects;
163
164     return updateRaytraceGeometry (OpenGl_GUM_REBUILD, theViewId, theGlContext);
165   }
166   else if (theMode == OpenGl_GUM_REBUILD)
167   {
168     // Actualize the hash map of structures - remove out-of-date records
169     std::map<const OpenGl_Structure*, StructState>::iterator anIter = myStructureStates.begin();
170
171     while (anIter != myStructureStates.end())
172     {
173       if (anElements.find (anIter->first) == anElements.end())
174       {
175         myStructureStates.erase (anIter++);
176       }
177       else
178       {
179         ++anIter;
180       }
181     }
182
183     // Actualize OpenGL layer list state
184     myLayerListState = myZLayers.ModificationState();
185
186     // Rebuild two-level acceleration structure
187     myRaytraceGeometry.ProcessAcceleration();
188
189     myRaytraceSceneRadius = 2.f /* scale factor */ * std::max (
190       myRaytraceGeometry.Box().CornerMin().cwiseAbs().maxComp(),
191       myRaytraceGeometry.Box().CornerMax().cwiseAbs().maxComp());
192
193     const BVH_Vec3f aSize = myRaytraceGeometry.Box().Size();
194
195     myRaytraceSceneEpsilon = Max (1.0e-6f, 1.0e-4f * aSize.Modulus());
196
197     return uploadRaytraceData (theGlContext);
198   }
199
200   if (myRaytraceParameters.GlobalIllumination)
201   {
202     Standard_Boolean toRestart =
203       aNonRaytraceIDs.size() != myNonRaytraceStructureIDs.size();
204
205     for (std::set<Standard_Integer>::iterator anID = aNonRaytraceIDs.begin(); anID != aNonRaytraceIDs.end() && !toRestart; ++anID)
206     {
207       if (myNonRaytraceStructureIDs.find (*anID) == myNonRaytraceStructureIDs.end())
208       {
209         toRestart = Standard_True;
210       }
211     }
212
213     if (toRestart)
214       myAccumFrames = 0;
215
216     myNonRaytraceStructureIDs = aNonRaytraceIDs;
217   }
218
219   return Standard_True;
220 }
221
222 // =======================================================================
223 // function : toUpdateStructure
224 // purpose  : Checks to see if the structure is modified
225 // =======================================================================
226 Standard_Boolean OpenGl_View::toUpdateStructure (const OpenGl_Structure* theStructure)
227 {
228   if (!theStructure->IsRaytracable())
229   {
230     if (theStructure->ModificationState() > 0)
231     {
232       theStructure->ResetModificationState();
233
234       return Standard_True; // ray-trace element was removed - need to rebuild
235     }
236
237     return Standard_False; // did not contain ray-trace elements
238   }
239
240   std::map<const OpenGl_Structure*, StructState>::iterator aStructState = myStructureStates.find (theStructure);
241
242   if (aStructState == myStructureStates.end() || aStructState->second.StructureState != theStructure->ModificationState())
243   {
244     return Standard_True;
245   }
246   else if (theStructure->InstancedStructure() != NULL)
247   {
248     return aStructState->second.InstancedState != theStructure->InstancedStructure()->ModificationState();
249   }
250
251   return Standard_False;
252 }
253
254 // =======================================================================
255 // function : buildTextureTransform
256 // purpose  : Constructs texture transformation matrix
257 // =======================================================================
258 void buildTextureTransform (const Handle(Graphic3d_TextureParams)& theParams, BVH_Mat4f& theMatrix)
259 {
260   theMatrix.InitIdentity();
261
262   // Apply scaling
263   const Graphic3d_Vec2& aScale = theParams->Scale();
264
265   theMatrix.ChangeValue (0, 0) *= aScale.x();
266   theMatrix.ChangeValue (1, 0) *= aScale.x();
267   theMatrix.ChangeValue (2, 0) *= aScale.x();
268   theMatrix.ChangeValue (3, 0) *= aScale.x();
269
270   theMatrix.ChangeValue (0, 1) *= aScale.y();
271   theMatrix.ChangeValue (1, 1) *= aScale.y();
272   theMatrix.ChangeValue (2, 1) *= aScale.y();
273   theMatrix.ChangeValue (3, 1) *= aScale.y();
274
275   // Apply translation
276   const Graphic3d_Vec2 aTrans = -theParams->Translation();
277
278   theMatrix.ChangeValue (0, 3) = theMatrix.GetValue (0, 0) * aTrans.x() +
279                                  theMatrix.GetValue (0, 1) * aTrans.y();
280
281   theMatrix.ChangeValue (1, 3) = theMatrix.GetValue (1, 0) * aTrans.x() +
282                                  theMatrix.GetValue (1, 1) * aTrans.y();
283
284   theMatrix.ChangeValue (2, 3) = theMatrix.GetValue (2, 0) * aTrans.x() +
285                                  theMatrix.GetValue (2, 1) * aTrans.y();
286
287   // Apply rotation
288   const Standard_ShortReal aSin = std::sin (
289     -theParams->Rotation() * static_cast<Standard_ShortReal> (M_PI / 180.0));
290   const Standard_ShortReal aCos = std::cos (
291     -theParams->Rotation() * static_cast<Standard_ShortReal> (M_PI / 180.0));
292
293   BVH_Mat4f aRotationMat;
294   aRotationMat.SetValue (0, 0,  aCos);
295   aRotationMat.SetValue (1, 1,  aCos);
296   aRotationMat.SetValue (0, 1, -aSin);
297   aRotationMat.SetValue (1, 0,  aSin);
298
299   theMatrix = theMatrix * aRotationMat;
300 }
301
302 // =======================================================================
303 // function : convertMaterial
304 // purpose  : Creates ray-tracing material properties
305 // =======================================================================
306 OpenGl_RaytraceMaterial OpenGl_View::convertMaterial (const OpenGl_AspectFace*      theAspect,
307                                                       const Handle(OpenGl_Context)& theGlContext)
308 {
309   OpenGl_RaytraceMaterial theMaterial;
310
311   const OPENGL_SURF_PROP& aProperties = theAspect->IntFront();
312
313   theMaterial.Ambient = BVH_Vec4f (
314     (aProperties.isphysic ? aProperties.ambcol.rgb[0] : aProperties.matcol.rgb[0]) * aProperties.amb,
315     (aProperties.isphysic ? aProperties.ambcol.rgb[1] : aProperties.matcol.rgb[1]) * aProperties.amb,
316     (aProperties.isphysic ? aProperties.ambcol.rgb[2] : aProperties.matcol.rgb[2]) * aProperties.amb,
317     1.f);
318
319   theMaterial.Diffuse = BVH_Vec4f (
320     (aProperties.isphysic ? aProperties.difcol.rgb[0] : aProperties.matcol.rgb[0]) * aProperties.diff,
321     (aProperties.isphysic ? aProperties.difcol.rgb[1] : aProperties.matcol.rgb[1]) * aProperties.diff,
322     (aProperties.isphysic ? aProperties.difcol.rgb[2] : aProperties.matcol.rgb[2]) * aProperties.diff,
323     -1.f /* no texture */);
324
325   theMaterial.Specular = BVH_Vec4f (
326     (aProperties.isphysic ? aProperties.speccol.rgb[0] : 1.f) * aProperties.spec,
327     (aProperties.isphysic ? aProperties.speccol.rgb[1] : 1.f) * aProperties.spec,
328     (aProperties.isphysic ? aProperties.speccol.rgb[2] : 1.f) * aProperties.spec,
329     aProperties.shine);
330
331   theMaterial.Emission = BVH_Vec4f (
332     (aProperties.isphysic ? aProperties.emscol.rgb[0] : aProperties.matcol.rgb[0]) * aProperties.emsv,
333     (aProperties.isphysic ? aProperties.emscol.rgb[1] : aProperties.matcol.rgb[1]) * aProperties.emsv,
334     (aProperties.isphysic ? aProperties.emscol.rgb[2] : aProperties.matcol.rgb[2]) * aProperties.emsv,
335     1.f);
336
337   theMaterial.Transparency = BVH_Vec4f (aProperties.trans,
338                                         1.f - aProperties.trans,
339                                         aProperties.index == 0 ? 1.f : aProperties.index,
340                                         aProperties.index == 0 ? 1.f : 1.f / aProperties.index);
341
342   const Standard_ShortReal aMaxRefl = Max (theMaterial.Diffuse.x() + theMaterial.Specular.x(),
343                                       Max (theMaterial.Diffuse.y() + theMaterial.Specular.y(),
344                                            theMaterial.Diffuse.z() + theMaterial.Specular.z()));
345
346   const Standard_ShortReal aReflectionScale = 0.75f / aMaxRefl;
347
348   theMaterial.Reflection = BVH_Vec4f (
349     aProperties.speccol.rgb[0] * aProperties.spec * aReflectionScale,
350     aProperties.speccol.rgb[1] * aProperties.spec * aReflectionScale,
351     aProperties.speccol.rgb[2] * aProperties.spec * aReflectionScale,
352     0.f);
353
354   // Serialize physically-based material properties
355   const Graphic3d_BSDF& aBSDF = aProperties.BSDF;
356
357   theMaterial.BSDF.Le = BVH_Vec4f (aBSDF.Le,               0.f);
358   theMaterial.BSDF.Kd = BVH_Vec4f (aBSDF.Kd, -1.f /* no tex */);
359   theMaterial.BSDF.Kr = BVH_Vec4f (aBSDF.Kr,               0.f);
360   theMaterial.BSDF.Kt = BVH_Vec4f (aBSDF.Kt,               0.f);
361   theMaterial.BSDF.Ks = BVH_Vec4f (aBSDF.Ks,   aBSDF.Roughness);
362
363   theMaterial.BSDF.Fresnel = aBSDF.Fresnel.Serialize();
364
365   theMaterial.BSDF.Absorption = BVH_Vec4f (aBSDF.AbsorptionColor,
366                                            aBSDF.AbsorptionCoeff);
367
368   // Handle material textures
369   if (theAspect->DoTextureMap())
370   {
371     if (theGlContext->arbTexBindless != NULL)
372     {
373       buildTextureTransform (theAspect->TextureParams(), theMaterial.TextureTransform);
374
375       // write texture ID to diffuse w-component
376       theMaterial.Diffuse.w() = theMaterial.BSDF.Kd.w() =
377         static_cast<Standard_ShortReal> (myRaytraceGeometry.AddTexture (theAspect->TextureRes (theGlContext)));
378     }
379     else if (!myIsRaytraceWarnTextures)
380     {
381       const TCollection_ExtendedString aWarnMessage =
382         "Warning: texturing in Ray-Trace requires GL_ARB_bindless_texture extension which is missing. "
383         "Please try to update graphics card driver. At the moment textures will be ignored.";
384
385       theGlContext->PushMessage (GL_DEBUG_SOURCE_APPLICATION_ARB,
386         GL_DEBUG_TYPE_PORTABILITY_ARB, 0, GL_DEBUG_SEVERITY_HIGH_ARB, aWarnMessage);
387
388       myIsRaytraceWarnTextures = Standard_True;
389     }
390   }
391
392   return theMaterial;
393 }
394
395 // =======================================================================
396 // function : addRaytraceStructure
397 // purpose  : Adds OpenGL structure to ray-traced scene geometry
398 // =======================================================================
399 Standard_Boolean OpenGl_View::addRaytraceStructure (const OpenGl_Structure*       theStructure,
400                                                     const Handle(OpenGl_Context)& theGlContext)
401 {
402   if (!theStructure->IsVisible())
403   {
404     myStructureStates[theStructure] = StructState (theStructure);
405
406     return Standard_True;
407   }
408
409   // Get structure material
410   OpenGl_RaytraceMaterial aStructMaterial;
411
412   if (theStructure->AspectFace() != NULL)
413   {
414     aStructMaterial = convertMaterial (theStructure->AspectFace(), theGlContext);
415   }
416
417   Standard_ShortReal aStructTransform[16];
418
419   if (theStructure->Transformation()->mat != NULL)
420   {
421     for (Standard_Integer i = 0; i < 4; ++i)
422     {
423       for (Standard_Integer j = 0; j < 4; ++j)
424       {
425         aStructTransform[j * 4 + i] = theStructure->Transformation()->mat[i][j];
426       }
427     }
428   }
429
430   Standard_Boolean aResult = addRaytraceGroups (theStructure, aStructMaterial,
431     theStructure->Transformation()->mat ? aStructTransform : NULL, theGlContext);
432
433   // Process all connected OpenGL structures
434   const OpenGl_Structure* anInstanced = theStructure->InstancedStructure();
435
436   if (anInstanced != NULL && anInstanced->IsRaytracable())
437   {
438     aResult &= addRaytraceGroups (anInstanced, aStructMaterial,
439       theStructure->Transformation()->mat ? aStructTransform : NULL, theGlContext);
440   }
441
442   myStructureStates[theStructure] = StructState (theStructure);
443
444   return aResult;
445 }
446
447 // =======================================================================
448 // function : addRaytraceGroups
449 // purpose  : Adds OpenGL groups to ray-traced scene geometry
450 // =======================================================================
451 Standard_Boolean OpenGl_View::addRaytraceGroups (const OpenGl_Structure*        theStructure,
452                                                  const OpenGl_RaytraceMaterial& theStructMat,
453                                                  const Standard_ShortReal*      theTransform,
454                                                  const Handle(OpenGl_Context)&  theGlContext)
455 {
456   for (OpenGl_Structure::GroupIterator aGroupIter (theStructure->DrawGroups()); aGroupIter.More(); aGroupIter.Next())
457   {
458     // Get group material
459     OpenGl_RaytraceMaterial aGroupMaterial;
460     if (aGroupIter.Value()->AspectFace() != NULL)
461     {
462       aGroupMaterial = convertMaterial (
463         aGroupIter.Value()->AspectFace(), theGlContext);
464     }
465
466     Standard_Integer aMatID = static_cast<Standard_Integer> (myRaytraceGeometry.Materials.size());
467
468     // Use group material if available, otherwise use structure material
469     myRaytraceGeometry.Materials.push_back (
470       aGroupIter.Value()->AspectFace() != NULL ? aGroupMaterial : theStructMat);
471
472     // Add OpenGL elements from group (extract primitives arrays and aspects)
473     for (const OpenGl_ElementNode* aNode = aGroupIter.Value()->FirstNode(); aNode != NULL; aNode = aNode->next)
474     {
475       OpenGl_AspectFace* anAspect = dynamic_cast<OpenGl_AspectFace*> (aNode->elem);
476
477       if (anAspect != NULL)
478       {
479         aMatID = static_cast<Standard_Integer> (myRaytraceGeometry.Materials.size());
480
481         OpenGl_RaytraceMaterial aMaterial = convertMaterial (anAspect, theGlContext);
482
483         myRaytraceGeometry.Materials.push_back (aMaterial);
484       }
485       else
486       {
487         OpenGl_PrimitiveArray* aPrimArray = dynamic_cast<OpenGl_PrimitiveArray*> (aNode->elem);
488
489         if (aPrimArray != NULL)
490         {
491           std::map<Standard_Size, OpenGl_TriangleSet*>::iterator aSetIter = myArrayToTrianglesMap.find (aPrimArray->GetUID());
492
493           if (aSetIter != myArrayToTrianglesMap.end())
494           {
495             OpenGl_TriangleSet* aSet = aSetIter->second;
496
497             BVH_Transform<Standard_ShortReal, 4>* aTransform = new BVH_Transform<Standard_ShortReal, 4>();
498
499             if (theTransform != NULL)
500             {
501               aTransform->SetTransform (*(reinterpret_cast<const BVH_Mat4f*> (theTransform)));
502             }
503
504             aSet->SetProperties (aTransform);
505
506             if (aSet->MaterialIndex() != OpenGl_TriangleSet::INVALID_MATERIAL && aSet->MaterialIndex() != aMatID)
507             {
508               aSet->SetMaterialIndex (aMatID);
509             }
510           }
511           else
512           {
513             NCollection_Handle<BVH_Object<Standard_ShortReal, 3> > aSet =
514               addRaytracePrimitiveArray (aPrimArray, aMatID, 0);
515
516             if (!aSet.IsNull())
517             {
518               BVH_Transform<Standard_ShortReal, 4>* aTransform = new BVH_Transform<Standard_ShortReal, 4>;
519
520               if (theTransform != NULL)
521               {
522                 aTransform->SetTransform (*(reinterpret_cast<const BVH_Mat4f*> (theTransform)));
523               }
524
525               aSet->SetProperties (aTransform);
526
527               myRaytraceGeometry.Objects().Append (aSet);
528             }
529           }
530         }
531       }
532     }
533   }
534
535   return Standard_True;
536 }
537
538 // =======================================================================
539 // function : addRaytracePrimitiveArray
540 // purpose  : Adds OpenGL primitive array to ray-traced scene geometry
541 // =======================================================================
542 OpenGl_TriangleSet* OpenGl_View::addRaytracePrimitiveArray (const OpenGl_PrimitiveArray* theArray,
543                                                             const Standard_Integer       theMaterial,
544                                                             const OpenGl_Mat4*           theTransform)
545 {
546   const Handle(Graphic3d_BoundBuffer)& aBounds   = theArray->Bounds();
547   const Handle(Graphic3d_IndexBuffer)& anIndices = theArray->Indices();
548   const Handle(Graphic3d_Buffer)&      anAttribs = theArray->Attributes();
549
550   if (theArray->DrawMode() < GL_TRIANGLES
551   #ifndef GL_ES_VERSION_2_0
552    || theArray->DrawMode() > GL_POLYGON
553   #else
554    || theArray->DrawMode() > GL_TRIANGLE_FAN
555   #endif
556    || anAttribs.IsNull())
557   {
558     return NULL;
559   }
560
561   OpenGl_Mat4 aNormalMatrix;
562
563   if (theTransform != NULL)
564   {
565     Standard_ASSERT_RETURN (theTransform->Inverted (aNormalMatrix),
566       "Error: Failed to compute normal transformation matrix", NULL);
567
568     aNormalMatrix.Transpose();
569   }
570
571   OpenGl_TriangleSet* aSet = new OpenGl_TriangleSet (theArray->GetUID());
572   {
573     aSet->Vertices.reserve (anAttribs->NbElements);
574     aSet->Normals.reserve  (anAttribs->NbElements);
575     aSet->TexCrds.reserve  (anAttribs->NbElements);
576
577     const size_t aVertFrom = aSet->Vertices.size();
578
579     for (Standard_Integer anAttribIter = 0; anAttribIter < anAttribs->NbAttributes; ++anAttribIter)
580     {
581       const Graphic3d_Attribute& anAttrib = anAttribs->Attribute       (anAttribIter);
582       const size_t               anOffset = anAttribs->AttributeOffset (anAttribIter);
583       if (anAttrib.Id == Graphic3d_TOA_POS)
584       {
585         if (anAttrib.DataType == Graphic3d_TOD_VEC3
586          || anAttrib.DataType == Graphic3d_TOD_VEC4)
587         {
588           for (Standard_Integer aVertIter = 0; aVertIter < anAttribs->NbElements; ++aVertIter)
589           {
590             aSet->Vertices.push_back (
591               *reinterpret_cast<const Graphic3d_Vec3*> (anAttribs->value (aVertIter) + anOffset));
592           }
593         }
594         else if (anAttrib.DataType == Graphic3d_TOD_VEC2)
595         {
596           for (Standard_Integer aVertIter = 0; aVertIter < anAttribs->NbElements; ++aVertIter)
597           {
598             const Standard_ShortReal* aCoords =
599               reinterpret_cast<const Standard_ShortReal*> (anAttribs->value (aVertIter) + anOffset);
600
601             aSet->Vertices.push_back (BVH_Vec3f (aCoords[0], aCoords[1], 0.0f));
602           }
603         }
604       }
605       else if (anAttrib.Id == Graphic3d_TOA_NORM)
606       {
607         if (anAttrib.DataType == Graphic3d_TOD_VEC3
608          || anAttrib.DataType == Graphic3d_TOD_VEC4)
609         {
610           for (Standard_Integer aVertIter = 0; aVertIter < anAttribs->NbElements; ++aVertIter)
611           {
612             aSet->Normals.push_back (
613               *reinterpret_cast<const Graphic3d_Vec3*> (anAttribs->value (aVertIter) + anOffset));
614           }
615         }
616       }
617       else if (anAttrib.Id == Graphic3d_TOA_UV)
618       {
619         if (anAttrib.DataType == Graphic3d_TOD_VEC2)
620         {
621           for (Standard_Integer aVertIter = 0; aVertIter < anAttribs->NbElements; ++aVertIter)
622           {
623             aSet->TexCrds.push_back (
624               *reinterpret_cast<const Graphic3d_Vec2*> (anAttribs->value (aVertIter) + anOffset));
625           }
626         }
627       }
628     }
629
630     if (aSet->Normals.size() != aSet->Vertices.size())
631     {
632       for (Standard_Integer aVertIter = 0; aVertIter < anAttribs->NbElements; ++aVertIter)
633       {
634         aSet->Normals.push_back (BVH_Vec3f());
635       }
636     }
637
638     if (aSet->TexCrds.size() != aSet->Vertices.size())
639     {
640       for (Standard_Integer aVertIter = 0; aVertIter < anAttribs->NbElements; ++aVertIter)
641       {
642         aSet->TexCrds.push_back (BVH_Vec2f());
643       }
644     }
645
646     if (theTransform != NULL)
647     {
648       for (size_t aVertIter = aVertFrom; aVertIter < aSet->Vertices.size(); ++aVertIter)
649       {
650         BVH_Vec3f& aVertex = aSet->Vertices[aVertIter];
651
652         BVH_Vec4f aTransVertex = *theTransform *
653           BVH_Vec4f (aVertex.x(), aVertex.y(), aVertex.z(), 1.f);
654
655         aVertex = BVH_Vec3f (aTransVertex.x(), aTransVertex.y(), aTransVertex.z());
656       }
657       for (size_t aVertIter = aVertFrom; aVertIter < aSet->Normals.size(); ++aVertIter)
658       {
659         BVH_Vec3f& aNormal = aSet->Normals[aVertIter];
660
661         BVH_Vec4f aTransNormal = aNormalMatrix *
662           BVH_Vec4f (aNormal.x(), aNormal.y(), aNormal.z(), 0.f);
663
664         aNormal = BVH_Vec3f (aTransNormal.x(), aTransNormal.y(), aTransNormal.z());
665       }
666     }
667
668     if (!aBounds.IsNull())
669     {
670       for (Standard_Integer aBound = 0, aBoundStart = 0; aBound < aBounds->NbBounds; ++aBound)
671       {
672         const Standard_Integer aVertNum = aBounds->Bounds[aBound];
673
674         if (!addRaytraceVertexIndices (*aSet, theMaterial, aVertNum, aBoundStart, *theArray))
675         {
676           delete aSet;
677           return NULL;
678         }
679
680         aBoundStart += aVertNum;
681       }
682     }
683     else
684     {
685       const Standard_Integer aVertNum = !anIndices.IsNull() ? anIndices->NbElements : anAttribs->NbElements;
686
687       if (!addRaytraceVertexIndices (*aSet, theMaterial, aVertNum, 0, *theArray))
688       {
689         delete aSet;
690         return NULL;
691       }
692     }
693   }
694
695   if (aSet->Size() != 0)
696   {
697     aSet->MarkDirty();
698   }
699
700   return aSet;
701 }
702
703 // =======================================================================
704 // function : addRaytraceVertexIndices
705 // purpose  : Adds vertex indices to ray-traced scene geometry
706 // =======================================================================
707 Standard_Boolean OpenGl_View::addRaytraceVertexIndices (OpenGl_TriangleSet&                  theSet,
708                                                         const Standard_Integer               theMatID,
709                                                         const Standard_Integer               theCount,
710                                                         const Standard_Integer               theOffset,
711                                                         const OpenGl_PrimitiveArray&         theArray)
712 {
713   switch (theArray.DrawMode())
714   {
715     case GL_TRIANGLES:      return addRaytraceTriangleArray        (theSet, theMatID, theCount, theOffset, theArray.Indices());
716     case GL_TRIANGLE_FAN:   return addRaytraceTriangleFanArray     (theSet, theMatID, theCount, theOffset, theArray.Indices());
717     case GL_TRIANGLE_STRIP: return addRaytraceTriangleStripArray   (theSet, theMatID, theCount, theOffset, theArray.Indices());
718   #if !defined(GL_ES_VERSION_2_0)
719     case GL_QUAD_STRIP:     return addRaytraceQuadrangleStripArray (theSet, theMatID, theCount, theOffset, theArray.Indices());
720     case GL_QUADS:          return addRaytraceQuadrangleArray      (theSet, theMatID, theCount, theOffset, theArray.Indices());
721     case GL_POLYGON:        return addRaytracePolygonArray         (theSet, theMatID, theCount, theOffset, theArray.Indices());
722   #endif
723   }
724
725   return Standard_False;
726 }
727
728 // =======================================================================
729 // function : addRaytraceTriangleArray
730 // purpose  : Adds OpenGL triangle array to ray-traced scene geometry
731 // =======================================================================
732 Standard_Boolean OpenGl_View::addRaytraceTriangleArray (OpenGl_TriangleSet&                  theSet,
733                                                         const Standard_Integer               theMatID,
734                                                         const Standard_Integer               theCount,
735                                                         const Standard_Integer               theOffset,
736                                                         const Handle(Graphic3d_IndexBuffer)& theIndices)
737 {
738   if (theCount < 3)
739   {
740     return Standard_True;
741   }
742
743   theSet.Elements.reserve (theSet.Elements.size() + theCount / 3);
744
745   if (!theIndices.IsNull())
746   {
747     for (Standard_Integer aVert = theOffset; aVert < theOffset + theCount - 2; aVert += 3)
748     {
749       theSet.Elements.push_back (BVH_Vec4i (theIndices->Index (aVert + 0),
750                                             theIndices->Index (aVert + 1),
751                                             theIndices->Index (aVert + 2),
752                                             theMatID));
753     }
754   }
755   else
756   {
757     for (Standard_Integer aVert = theOffset; aVert < theOffset + theCount - 2; aVert += 3)
758     {
759       theSet.Elements.push_back (BVH_Vec4i (aVert + 0, aVert + 1, aVert + 2, theMatID));
760     }
761   }
762
763   return Standard_True;
764 }
765
766 // =======================================================================
767 // function : addRaytraceTriangleFanArray
768 // purpose  : Adds OpenGL triangle fan array to ray-traced scene geometry
769 // =======================================================================
770 Standard_Boolean OpenGl_View::addRaytraceTriangleFanArray (OpenGl_TriangleSet&                  theSet,
771                                                            const Standard_Integer               theMatID,
772                                                            const Standard_Integer               theCount,
773                                                            const Standard_Integer               theOffset,
774                                                            const Handle(Graphic3d_IndexBuffer)& theIndices)
775 {
776   if (theCount < 3)
777   {
778     return Standard_True;
779   }
780
781   theSet.Elements.reserve (theSet.Elements.size() + theCount - 2);
782
783   if (!theIndices.IsNull())
784   {
785     for (Standard_Integer aVert = theOffset; aVert < theOffset + theCount - 2; ++aVert)
786     {
787       theSet.Elements.push_back (BVH_Vec4i (theIndices->Index (theOffset),
788                                             theIndices->Index (aVert + 1),
789                                             theIndices->Index (aVert + 2),
790                                             theMatID));
791     }
792   }
793   else
794   {
795     for (Standard_Integer aVert = theOffset; aVert < theOffset + theCount - 2; ++aVert)
796     {
797       theSet.Elements.push_back (BVH_Vec4i (theOffset,
798                                             aVert + 1,
799                                             aVert + 2,
800                                             theMatID));
801     }
802   }
803
804   return Standard_True;
805 }
806
807 // =======================================================================
808 // function : addRaytraceTriangleStripArray
809 // purpose  : Adds OpenGL triangle strip array to ray-traced scene geometry
810 // =======================================================================
811 Standard_Boolean OpenGl_View::addRaytraceTriangleStripArray (OpenGl_TriangleSet&                  theSet,
812                                                              const Standard_Integer               theMatID,
813                                                              const Standard_Integer               theCount,
814                                                              const Standard_Integer               theOffset,
815                                                              const Handle(Graphic3d_IndexBuffer)& theIndices)
816 {
817   if (theCount < 3)
818   {
819     return Standard_True;
820   }
821
822   theSet.Elements.reserve (theSet.Elements.size() + theCount - 2);
823
824   if (!theIndices.IsNull())
825   {
826     for (Standard_Integer aVert = theOffset, aCW = 0; aVert < theOffset + theCount - 2; ++aVert, aCW = (aCW + 1) % 2)
827     {
828       theSet.Elements.push_back (BVH_Vec4i (theIndices->Index (aVert + aCW ? 1 : 0),
829                                             theIndices->Index (aVert + aCW ? 0 : 1),
830                                             theIndices->Index (aVert + 2),
831                                             theMatID));
832     }
833   }
834   else
835   {
836     for (Standard_Integer aVert = theOffset, aCW = 0; aVert < theOffset + theCount - 2; ++aVert, aCW = (aCW + 1) % 2)
837     {
838       theSet.Elements.push_back (BVH_Vec4i (aVert + aCW ? 1 : 0,
839                                             aVert + aCW ? 0 : 1,
840                                             aVert + 2,
841                                             theMatID));
842     }
843   }
844
845   return Standard_True;
846 }
847
848 // =======================================================================
849 // function : addRaytraceQuadrangleArray
850 // purpose  : Adds OpenGL quad array to ray-traced scene geometry
851 // =======================================================================
852 Standard_Boolean OpenGl_View::addRaytraceQuadrangleArray (OpenGl_TriangleSet&                  theSet,
853                                                           const Standard_Integer               theMatID,
854                                                           const Standard_Integer               theCount,
855                                                           const Standard_Integer               theOffset,
856                                                           const Handle(Graphic3d_IndexBuffer)& theIndices)
857 {
858   if (theCount < 4)
859   {
860     return Standard_True;
861   }
862
863   theSet.Elements.reserve (theSet.Elements.size() + theCount / 2);
864
865   if (!theIndices.IsNull())
866   {
867     for (Standard_Integer aVert = theOffset; aVert < theOffset + theCount - 3; aVert += 4)
868     {
869       theSet.Elements.push_back (BVH_Vec4i (theIndices->Index (aVert + 0),
870                                             theIndices->Index (aVert + 1),
871                                             theIndices->Index (aVert + 2),
872                                             theMatID));
873       theSet.Elements.push_back (BVH_Vec4i (theIndices->Index (aVert + 0),
874                                             theIndices->Index (aVert + 2),
875                                             theIndices->Index (aVert + 3),
876                                             theMatID));
877     }
878   }
879   else
880   {
881     for (Standard_Integer aVert = theOffset; aVert < theOffset + theCount - 3; aVert += 4)
882     {
883       theSet.Elements.push_back (BVH_Vec4i (aVert + 0, aVert + 1, aVert + 2,
884                                             theMatID));
885       theSet.Elements.push_back (BVH_Vec4i (aVert + 0, aVert + 2, aVert + 3,
886                                             theMatID));
887     }
888   }
889
890   return Standard_True;
891 }
892
893 // =======================================================================
894 // function : addRaytraceQuadrangleStripArray
895 // purpose  : Adds OpenGL quad strip array to ray-traced scene geometry
896 // =======================================================================
897 Standard_Boolean OpenGl_View::addRaytraceQuadrangleStripArray (OpenGl_TriangleSet&                  theSet,
898                                                                const Standard_Integer               theMatID,
899                                                                const Standard_Integer               theCount,
900                                                                const Standard_Integer               theOffset,
901                                                                const Handle(Graphic3d_IndexBuffer)& theIndices)
902 {
903   if (theCount < 4)
904   {
905     return Standard_True;
906   }
907
908   theSet.Elements.reserve (theSet.Elements.size() + 2 * theCount - 6);
909
910   if (!theIndices.IsNull())
911   {
912     for (Standard_Integer aVert = theOffset; aVert < theOffset + theCount - 3; aVert += 2)
913     {
914       theSet.Elements.push_back (BVH_Vec4i (theIndices->Index (aVert + 0),
915                                             theIndices->Index (aVert + 1),
916                                             theIndices->Index (aVert + 2),
917                                             theMatID));
918
919       theSet.Elements.push_back (BVH_Vec4i (theIndices->Index (aVert + 1),
920                                             theIndices->Index (aVert + 3),
921                                             theIndices->Index (aVert + 2),
922                                             theMatID));
923     }
924   }
925   else
926   {
927     for (Standard_Integer aVert = theOffset; aVert < theOffset + theCount - 3; aVert += 2)
928     {
929       theSet.Elements.push_back (BVH_Vec4i (aVert + 0,
930                                             aVert + 1,
931                                             aVert + 2,
932                                             theMatID));
933
934       theSet.Elements.push_back (BVH_Vec4i (aVert + 1,
935                                             aVert + 3,
936                                             aVert + 2,
937                                             theMatID));
938     }
939   }
940
941   return Standard_True;
942 }
943
944 // =======================================================================
945 // function : addRaytracePolygonArray
946 // purpose  : Adds OpenGL polygon array to ray-traced scene geometry
947 // =======================================================================
948 Standard_Boolean OpenGl_View::addRaytracePolygonArray (OpenGl_TriangleSet&                  theSet,
949                                                        const Standard_Integer               theMatID,
950                                                        const Standard_Integer               theCount,
951                                                        const Standard_Integer               theOffset,
952                                                        const Handle(Graphic3d_IndexBuffer)& theIndices)
953 {
954   if (theCount < 3)
955   {
956     return Standard_True;
957   }
958
959   theSet.Elements.reserve (theSet.Elements.size() + theCount - 2);
960
961   if (!theIndices.IsNull())
962   {
963     for (Standard_Integer aVert = theOffset; aVert < theOffset + theCount - 2; ++aVert)
964     {
965       theSet.Elements.push_back (BVH_Vec4i (theIndices->Index (theOffset),
966                                             theIndices->Index (aVert + 1),
967                                             theIndices->Index (aVert + 2),
968                                             theMatID));
969     }
970   }
971   else
972   {
973     for (Standard_Integer aVert = theOffset; aVert < theOffset + theCount - 2; ++aVert)
974     {
975       theSet.Elements.push_back (BVH_Vec4i (theOffset,
976                                             aVert + 1,
977                                             aVert + 2,
978                                             theMatID));
979     }
980   }
981
982   return Standard_True;
983 }
984
985 const TCollection_AsciiString OpenGl_View::ShaderSource::EMPTY_PREFIX;
986
987 // =======================================================================
988 // function : Source
989 // purpose  : Returns shader source combined with prefix
990 // =======================================================================
991 TCollection_AsciiString OpenGl_View::ShaderSource::Source() const
992 {
993   const TCollection_AsciiString aVersion = "#version 140";
994
995   if (myPrefix.IsEmpty())
996   {
997     return aVersion + "\n" + mySource;
998   }
999
1000   return aVersion + "\n" + myPrefix + "\n" + mySource;
1001 }
1002
1003 // =======================================================================
1004 // function : Load
1005 // purpose  : Loads shader source from specified files
1006 // =======================================================================
1007 Standard_Boolean OpenGl_View::ShaderSource::Load (const TCollection_AsciiString* theFileNames,
1008                                                   const TCollection_AsciiString& thePrefix)
1009 {
1010   myError.Clear();
1011   mySource.Clear();
1012   TCollection_AsciiString aMissingFiles;
1013   for (Standard_Integer anIndex = 0; !theFileNames[anIndex].IsEmpty(); ++anIndex)
1014   {
1015     OSD_File aFile (theFileNames[anIndex]);
1016     if (aFile.Exists())
1017     {
1018       aFile.Open (OSD_ReadOnly, OSD_Protection());
1019     }
1020     if (!aFile.IsOpen())
1021     {
1022       if (!aMissingFiles.IsEmpty())
1023       {
1024         aMissingFiles += ", ";
1025       }
1026       aMissingFiles += TCollection_AsciiString("'") + theFileNames[anIndex] + "'";
1027       continue;
1028     }
1029     else if (!aMissingFiles.IsEmpty())
1030     {
1031       aFile.Close();
1032       continue;
1033     }
1034
1035     TCollection_AsciiString aSource;
1036     aFile.Read (aSource, (Standard_Integer) aFile.Size());
1037     if (!aSource.IsEmpty())
1038     {
1039       mySource += TCollection_AsciiString ("\n") + aSource;
1040     }
1041     aFile.Close();
1042   }
1043
1044   myPrefix = thePrefix;
1045   if (!aMissingFiles.IsEmpty())
1046   {
1047     myError = TCollection_AsciiString("Shader files ") + aMissingFiles + " are missing or inaccessible";
1048     return Standard_False;
1049   }
1050   return Standard_True;
1051 }
1052
1053 // =======================================================================
1054 // function : generateShaderPrefix
1055 // purpose  : Generates shader prefix based on current ray-tracing options
1056 // =======================================================================
1057 TCollection_AsciiString OpenGl_View::generateShaderPrefix (const Handle(OpenGl_Context)& theGlContext) const
1058 {
1059   TCollection_AsciiString aPrefixString =
1060     TCollection_AsciiString ("#define STACK_SIZE ") + TCollection_AsciiString (myRaytraceParameters.StackSize) + "\n" +
1061     TCollection_AsciiString ("#define NB_BOUNCES ") + TCollection_AsciiString (myRaytraceParameters.NbBounces);
1062
1063   if (myRaytraceParameters.TransparentShadows)
1064   {
1065     aPrefixString += TCollection_AsciiString ("\n#define TRANSPARENT_SHADOWS");
1066   }
1067
1068   // If OpenGL driver supports bindless textures and texturing
1069   // is actually used, activate texturing in ray-tracing mode
1070   if (myRaytraceParameters.UseBindlessTextures && theGlContext->arbTexBindless != NULL)
1071   {
1072     aPrefixString += TCollection_AsciiString ("\n#define USE_TEXTURES") +
1073       TCollection_AsciiString ("\n#define MAX_TEX_NUMBER ") + TCollection_AsciiString (OpenGl_RaytraceGeometry::MAX_TEX_NUMBER);
1074   }
1075
1076   if (myRaytraceParameters.GlobalIllumination)
1077   {
1078     aPrefixString += TCollection_AsciiString ("\n#define PATH_TRACING");
1079   }
1080
1081   return aPrefixString;
1082 }
1083
1084 // =======================================================================
1085 // function : safeFailBack
1086 // purpose  : Performs safe exit when shaders initialization fails
1087 // =======================================================================
1088 Standard_Boolean OpenGl_View::safeFailBack (const TCollection_ExtendedString& theMessage,
1089                                             const Handle(OpenGl_Context)&     theGlContext)
1090 {
1091   theGlContext->PushMessage (GL_DEBUG_SOURCE_APPLICATION_ARB,
1092     GL_DEBUG_TYPE_ERROR_ARB, 0, GL_DEBUG_SEVERITY_HIGH_ARB, theMessage);
1093
1094   myRaytraceInitStatus = OpenGl_RT_FAIL;
1095
1096   releaseRaytraceResources (theGlContext);
1097
1098   return Standard_False;
1099 }
1100
1101 // =======================================================================
1102 // function : initShader
1103 // purpose  : Creates new shader object with specified source
1104 // =======================================================================
1105 Handle(OpenGl_ShaderObject) OpenGl_View::initShader (const GLenum                  theType,
1106                                                      const ShaderSource&           theSource,
1107                                                      const Handle(OpenGl_Context)& theGlContext)
1108 {
1109   Handle(OpenGl_ShaderObject) aShader = new OpenGl_ShaderObject (theType);
1110
1111   if (!aShader->Create (theGlContext))
1112   {
1113     const TCollection_ExtendedString aMessage = TCollection_ExtendedString ("Error: Failed to create ") +
1114       (theType == GL_VERTEX_SHADER ? "vertex" : "fragment") + " shader object";
1115
1116     theGlContext->PushMessage (GL_DEBUG_SOURCE_APPLICATION_ARB,
1117       GL_DEBUG_TYPE_ERROR_ARB, 0, GL_DEBUG_SEVERITY_HIGH_ARB, aMessage);
1118
1119     aShader->Release (theGlContext.operator->());
1120
1121     return Handle(OpenGl_ShaderObject)();
1122   }
1123
1124   if (!aShader->LoadSource (theGlContext, theSource.Source()))
1125   {
1126     const TCollection_ExtendedString aMessage = TCollection_ExtendedString ("Error: Failed to set ") +
1127       (theType == GL_VERTEX_SHADER ? "vertex" : "fragment") + " shader source";
1128
1129     theGlContext->PushMessage (GL_DEBUG_SOURCE_APPLICATION_ARB,
1130       GL_DEBUG_TYPE_ERROR_ARB, 0, GL_DEBUG_SEVERITY_HIGH_ARB, aMessage);
1131
1132     aShader->Release (theGlContext.operator->());
1133
1134     return Handle(OpenGl_ShaderObject)();
1135   }
1136
1137   TCollection_AsciiString aBuildLog;
1138
1139   if (!aShader->Compile (theGlContext))
1140   {
1141     aShader->FetchInfoLog (theGlContext, aBuildLog);
1142
1143     const TCollection_ExtendedString aMessage = TCollection_ExtendedString ("Error: Failed to compile ") +
1144       (theType == GL_VERTEX_SHADER ? "vertex" : "fragment") + " shader object:\n" + aBuildLog;
1145
1146     theGlContext->PushMessage (GL_DEBUG_SOURCE_APPLICATION_ARB,
1147       GL_DEBUG_TYPE_ERROR_ARB, 0, GL_DEBUG_SEVERITY_HIGH_ARB, aMessage);
1148
1149     aShader->Release (theGlContext.operator->());
1150
1151     return Handle(OpenGl_ShaderObject)();
1152   }
1153   else if (theGlContext->caps->glslWarnings)
1154   {
1155     aShader->FetchInfoLog (theGlContext, aBuildLog);
1156
1157     if (!aBuildLog.IsEmpty() && !aBuildLog.IsEqual ("No errors.\n"))
1158     {
1159       const TCollection_ExtendedString aMessage = TCollection_ExtendedString (theType == GL_VERTEX_SHADER ?
1160         "Vertex" : "Fragment") + " shader was compiled with following warnings:\n" + aBuildLog;
1161
1162       theGlContext->PushMessage (GL_DEBUG_SOURCE_APPLICATION_ARB,
1163         GL_DEBUG_TYPE_PORTABILITY_ARB, 0, GL_DEBUG_SEVERITY_LOW_ARB, aMessage);
1164     }
1165   }
1166
1167   return aShader;
1168 }
1169
1170 // =======================================================================
1171 // function : initProgram
1172 // purpose  : Creates GLSL program from the given shader objects
1173 // =======================================================================
1174 Handle(OpenGl_ShaderProgram) OpenGl_View::initProgram (const Handle(OpenGl_Context)&      theGlContext,
1175                                                        const Handle(OpenGl_ShaderObject)& theVertShader,
1176                                                        const Handle(OpenGl_ShaderObject)& theFragShader)
1177 {
1178   Handle(OpenGl_ShaderProgram) aProgram = new OpenGl_ShaderProgram;
1179
1180   if (!aProgram->Create (theGlContext))
1181   {
1182     theVertShader->Release (theGlContext.operator->());
1183
1184     theGlContext->PushMessage (GL_DEBUG_SOURCE_APPLICATION_ARB,
1185       GL_DEBUG_TYPE_ERROR_ARB, 0, GL_DEBUG_SEVERITY_HIGH_ARB, "Failed to create shader program");
1186
1187     return Handle(OpenGl_ShaderProgram)();
1188   }
1189
1190   if (!aProgram->AttachShader (theGlContext, theVertShader)
1191    || !aProgram->AttachShader (theGlContext, theFragShader))
1192   {
1193     theVertShader->Release (theGlContext.operator->());
1194
1195     theGlContext->PushMessage (GL_DEBUG_SOURCE_APPLICATION_ARB,
1196       GL_DEBUG_TYPE_ERROR_ARB, 0, GL_DEBUG_SEVERITY_HIGH_ARB, "Failed to attach shader objects");
1197
1198     return Handle(OpenGl_ShaderProgram)();
1199   }
1200
1201   aProgram->SetAttributeName (theGlContext, Graphic3d_TOA_POS, "occVertex");
1202
1203   TCollection_AsciiString aLinkLog;
1204
1205   if (!aProgram->Link (theGlContext))
1206   {
1207     aProgram->FetchInfoLog (theGlContext, aLinkLog);
1208
1209     const TCollection_ExtendedString aMessage = TCollection_ExtendedString (
1210       "Failed to link shader program:\n") + aLinkLog;
1211
1212     theGlContext->PushMessage (GL_DEBUG_SOURCE_APPLICATION_ARB,
1213       GL_DEBUG_TYPE_ERROR_ARB, 0, GL_DEBUG_SEVERITY_HIGH_ARB, aMessage);
1214
1215     return Handle(OpenGl_ShaderProgram)();
1216   }
1217   else if (theGlContext->caps->glslWarnings)
1218   {
1219     myRaytraceProgram->FetchInfoLog (theGlContext, aLinkLog);
1220
1221     if (!aLinkLog.IsEmpty() && !aLinkLog.IsEqual ("No errors.\n"))
1222     {
1223       const TCollection_ExtendedString aMessage = TCollection_ExtendedString (
1224         "Shader program was linked with following warnings:\n") + aLinkLog;
1225
1226       theGlContext->PushMessage (GL_DEBUG_SOURCE_APPLICATION_ARB,
1227         GL_DEBUG_TYPE_PORTABILITY_ARB, 0, GL_DEBUG_SEVERITY_LOW_ARB, aMessage);
1228     }
1229   }
1230
1231   return aProgram;
1232 }
1233
1234 // =======================================================================
1235 // function : initRaytraceResources
1236 // purpose  : Initializes OpenGL/GLSL shader programs
1237 // =======================================================================
1238 Standard_Boolean OpenGl_View::initRaytraceResources (const Graphic3d_CView& theCView, const Handle(OpenGl_Context)& theGlContext)
1239 {
1240   if (myRaytraceInitStatus == OpenGl_RT_FAIL)
1241   {
1242     return Standard_False;
1243   }
1244
1245   Standard_Boolean aToRebuildShaders = Standard_False;
1246
1247   if (myRaytraceInitStatus == OpenGl_RT_INIT)
1248   {
1249     if (!myIsRaytraceDataValid)
1250       return Standard_True;
1251
1252     const Standard_Integer aRequiredStackSize =
1253       myRaytraceGeometry.HighLevelTreeDepth() + myRaytraceGeometry.BottomLevelTreeDepth();
1254
1255     if (myRaytraceParameters.StackSize < aRequiredStackSize)
1256     {
1257       myRaytraceParameters.StackSize = Max (aRequiredStackSize, THE_DEFAULT_STACK_SIZE);
1258
1259       aToRebuildShaders = Standard_True;
1260     }
1261     else
1262     {
1263       if (aRequiredStackSize < myRaytraceParameters.StackSize)
1264       {
1265         if (myRaytraceParameters.StackSize > THE_DEFAULT_STACK_SIZE)
1266         {
1267           myRaytraceParameters.StackSize = Max (aRequiredStackSize, THE_DEFAULT_STACK_SIZE);
1268           aToRebuildShaders = Standard_True;
1269         }
1270       }
1271     }
1272
1273     if (theCView.RenderParams.RaytracingDepth != myRaytraceParameters.NbBounces)
1274     {
1275       myRaytraceParameters.NbBounces = theCView.RenderParams.RaytracingDepth;
1276       aToRebuildShaders = Standard_True;
1277     }
1278
1279     if (myRaytraceGeometry.HasTextures() != myRaytraceParameters.UseBindlessTextures)
1280     {
1281       myRaytraceParameters.UseBindlessTextures = myRaytraceGeometry.HasTextures();
1282       aToRebuildShaders = Standard_True;
1283     }
1284
1285     if (theCView.RenderParams.IsTransparentShadowEnabled != myRaytraceParameters.TransparentShadows)
1286     {
1287       myRaytraceParameters.TransparentShadows = theCView.RenderParams.IsTransparentShadowEnabled;
1288       aToRebuildShaders = Standard_True;
1289     }
1290
1291     if (theCView.RenderParams.IsGlobalIlluminationEnabled != myRaytraceParameters.GlobalIllumination)
1292     {
1293       myRaytraceParameters.GlobalIllumination = theCView.RenderParams.IsGlobalIlluminationEnabled;
1294       aToRebuildShaders = Standard_True;
1295     }
1296
1297     if (aToRebuildShaders)
1298     {
1299       // Reject accumulated frames
1300       myAccumFrames = 0;
1301
1302       // We need to update environment texture
1303       myToUpdateEnvironmentMap = Standard_True;
1304
1305       TCollection_AsciiString aPrefixString = generateShaderPrefix (theGlContext);
1306
1307 #ifdef RAY_TRACE_PRINT_INFO
1308       std::cout << "GLSL prefix string:" << std::endl << aPrefixString << std::endl;
1309 #endif
1310
1311       myRaytraceShaderSource.SetPrefix (aPrefixString);
1312       myPostFSAAShaderSource.SetPrefix (aPrefixString);
1313
1314       if (!myRaytraceShader->LoadSource (theGlContext, myRaytraceShaderSource.Source())
1315        || !myPostFSAAShader->LoadSource (theGlContext, myPostFSAAShaderSource.Source()))
1316       {
1317         return safeFailBack ("Failed to load source into ray-tracing fragment shaders", theGlContext);
1318       }
1319
1320       if (!myRaytraceShader->Compile (theGlContext)
1321        || !myPostFSAAShader->Compile (theGlContext))
1322       {
1323         return safeFailBack ("Failed to compile ray-tracing fragment shaders", theGlContext);
1324       }
1325
1326       myRaytraceProgram->SetAttributeName (theGlContext, Graphic3d_TOA_POS, "occVertex");
1327       myPostFSAAProgram->SetAttributeName (theGlContext, Graphic3d_TOA_POS, "occVertex");
1328       if (!myRaytraceProgram->Link (theGlContext)
1329        || !myPostFSAAProgram->Link (theGlContext))
1330       {
1331         return safeFailBack ("Failed to initialize vertex attributes for ray-tracing program", theGlContext);
1332       }
1333     }
1334   }
1335
1336   if (myRaytraceInitStatus == OpenGl_RT_NONE)
1337   {
1338     if (!theGlContext->IsGlGreaterEqual (3, 1))
1339     {
1340       return safeFailBack ("Ray-tracing requires OpenGL 3.1 and higher", theGlContext);
1341     }
1342     else if (!theGlContext->arbTboRGB32)
1343     {
1344       return safeFailBack ("Ray-tracing requires OpenGL 4.0+ or GL_ARB_texture_buffer_object_rgb32 extension", theGlContext);
1345     }
1346     else if (!theGlContext->arbFBOBlit)
1347     {
1348       return safeFailBack ("Ray-tracing requires EXT_framebuffer_blit extension", theGlContext);
1349     }
1350
1351     myRaytraceParameters.NbBounces = theCView.RenderParams.RaytracingDepth;
1352
1353     TCollection_AsciiString aFolder = Graphic3d_ShaderProgram::ShadersFolder();
1354
1355     if (aFolder.IsEmpty())
1356     {
1357       return safeFailBack ("Failed to locate shaders directory", theGlContext);
1358     }
1359
1360     if (myIsRaytraceDataValid)
1361     {
1362       myRaytraceParameters.StackSize = Max (THE_DEFAULT_STACK_SIZE,
1363         myRaytraceGeometry.HighLevelTreeDepth() + myRaytraceGeometry.BottomLevelTreeDepth());
1364     }
1365
1366     TCollection_AsciiString aPrefixString  = generateShaderPrefix (theGlContext);
1367
1368 #ifdef RAY_TRACE_PRINT_INFO
1369     std::cout << "GLSL prefix string:" << std::endl << aPrefixString << std::endl;
1370 #endif
1371
1372     ShaderSource aBasicVertShaderSrc;
1373     {
1374       TCollection_AsciiString aFiles[] = { aFolder + "/RaytraceBase.vs", "" };
1375       if (!aBasicVertShaderSrc.Load (aFiles))
1376       {
1377         return safeFailBack (aBasicVertShaderSrc.ErrorDescription(), theGlContext);
1378       }
1379     }
1380
1381     {
1382       TCollection_AsciiString aFiles[] = { aFolder + "/RaytraceBase.fs",
1383                                            aFolder + "/PathtraceBase.fs",
1384                                            aFolder + "/RaytraceRender.fs",
1385                                            "" };
1386       if (!myRaytraceShaderSource.Load (aFiles, aPrefixString))
1387       {
1388         return safeFailBack (myRaytraceShaderSource.ErrorDescription(), theGlContext);
1389       }
1390
1391       Handle(OpenGl_ShaderObject) aBasicVertShader = initShader (GL_VERTEX_SHADER, aBasicVertShaderSrc, theGlContext);
1392       if (aBasicVertShader.IsNull())
1393       {
1394         return safeFailBack ("Failed to initialize ray-trace vertex shader", theGlContext);
1395       }
1396
1397       myRaytraceShader = initShader (GL_FRAGMENT_SHADER, myRaytraceShaderSource, theGlContext);
1398       if (myRaytraceShader.IsNull())
1399       {
1400         aBasicVertShader->Release (theGlContext.operator->());
1401         return safeFailBack ("Failed to initialize ray-trace fragment shader", theGlContext);
1402       }
1403
1404       myRaytraceProgram = initProgram (theGlContext, aBasicVertShader, myRaytraceShader);
1405       if (myRaytraceProgram.IsNull())
1406       {
1407         return safeFailBack ("Failed to initialize ray-trace shader program", theGlContext);
1408       }
1409     }
1410
1411     {
1412       TCollection_AsciiString aFiles[] = { aFolder + "/RaytraceBase.fs",
1413                                            aFolder + "/RaytraceSmooth.fs",
1414                                            "" };
1415       if (!myPostFSAAShaderSource.Load (aFiles, aPrefixString))
1416       {
1417         return safeFailBack (myPostFSAAShaderSource.ErrorDescription(), theGlContext);
1418       }
1419
1420       Handle(OpenGl_ShaderObject) aBasicVertShader = initShader (GL_VERTEX_SHADER, aBasicVertShaderSrc, theGlContext);
1421       if (aBasicVertShader.IsNull())
1422       {
1423         return safeFailBack ("Failed to initialize FSAA vertex shader", theGlContext);
1424       }
1425
1426       myPostFSAAShader = initShader (GL_FRAGMENT_SHADER, myPostFSAAShaderSource, theGlContext);
1427       if (myPostFSAAShader.IsNull())
1428       {
1429         aBasicVertShader->Release (theGlContext.operator->());
1430         return safeFailBack ("Failed to initialize FSAA fragment shader", theGlContext);
1431       }
1432
1433       myPostFSAAProgram = initProgram (theGlContext, aBasicVertShader, myPostFSAAShader);
1434       if (myPostFSAAProgram.IsNull())
1435       {
1436         return safeFailBack ("Failed to initialize FSAA shader program", theGlContext);
1437       }
1438     }
1439
1440     {
1441       ShaderSource aDispShaderSrc;
1442       TCollection_AsciiString aFiles[] = { aFolder + "/Display.fs", "" };
1443       if (!aDispShaderSrc.Load (aFiles, aPrefixString))
1444       {
1445         return safeFailBack (aDispShaderSrc.ErrorDescription(), theGlContext);
1446       }
1447
1448       Handle(OpenGl_ShaderObject) aBasicVertShader = initShader (GL_VERTEX_SHADER, aBasicVertShaderSrc, theGlContext);
1449       if (aBasicVertShader.IsNull())
1450       {
1451         return safeFailBack ("Failed to set vertex shader source", theGlContext);
1452       }
1453
1454       Handle(OpenGl_ShaderObject) aDisplayShader = initShader (GL_FRAGMENT_SHADER, aDispShaderSrc, theGlContext);
1455       if (aDisplayShader.IsNull())
1456       {
1457         aBasicVertShader->Release (theGlContext.operator->());
1458         return safeFailBack ("Failed to set display fragment shader source", theGlContext);
1459       }
1460
1461       myOutImageProgram = initProgram (theGlContext, aBasicVertShader, aDisplayShader);
1462       if (myOutImageProgram.IsNull())
1463       {
1464         return safeFailBack ("Failed to initialize output shader program", theGlContext);
1465       }
1466     }
1467   }
1468
1469   if (myRaytraceInitStatus == OpenGl_RT_NONE || aToRebuildShaders)
1470   {
1471     for (Standard_Integer anIndex = 0; anIndex < 2; ++anIndex)
1472     {
1473       Handle(OpenGl_ShaderProgram)& aShaderProgram =
1474         (anIndex == 0) ? myRaytraceProgram : myPostFSAAProgram;
1475
1476       theGlContext->BindProgram (aShaderProgram);
1477
1478       aShaderProgram->SetSampler (theGlContext,
1479         "uSceneMinPointTexture", OpenGl_RT_SceneMinPointTexture);
1480       aShaderProgram->SetSampler (theGlContext,
1481         "uSceneMaxPointTexture", OpenGl_RT_SceneMaxPointTexture);
1482       aShaderProgram->SetSampler (theGlContext,
1483         "uSceneNodeInfoTexture", OpenGl_RT_SceneNodeInfoTexture);
1484       aShaderProgram->SetSampler (theGlContext,
1485         "uGeometryVertexTexture", OpenGl_RT_GeometryVertexTexture);
1486       aShaderProgram->SetSampler (theGlContext,
1487         "uGeometryNormalTexture", OpenGl_RT_GeometryNormalTexture);
1488       aShaderProgram->SetSampler (theGlContext,
1489         "uGeometryTexCrdTexture", OpenGl_RT_GeometryTexCrdTexture);
1490       aShaderProgram->SetSampler (theGlContext,
1491         "uGeometryTriangTexture", OpenGl_RT_GeometryTriangTexture);
1492       aShaderProgram->SetSampler (theGlContext, 
1493         "uSceneTransformTexture", OpenGl_RT_SceneTransformTexture);
1494       aShaderProgram->SetSampler (theGlContext,
1495         "uEnvironmentMapTexture", OpenGl_RT_EnvironmentMapTexture);
1496       aShaderProgram->SetSampler (theGlContext,
1497         "uRaytraceMaterialTexture", OpenGl_RT_RaytraceMaterialTexture);
1498       aShaderProgram->SetSampler (theGlContext,
1499         "uRaytraceLightSrcTexture", OpenGl_RT_RaytraceLightSrcTexture);
1500
1501       aShaderProgram->SetSampler (theGlContext,
1502         "uOpenGlColorTexture", OpenGl_RT_OpenGlColorTexture);
1503       aShaderProgram->SetSampler (theGlContext,
1504         "uOpenGlDepthTexture", OpenGl_RT_OpenGlDepthTexture);
1505
1506       if (anIndex == 1)
1507       {
1508         aShaderProgram->SetSampler (theGlContext,
1509           "uFSAAInputTexture", OpenGl_RT_FsaaInputTexture);
1510       }
1511       else
1512       {
1513         aShaderProgram->SetSampler (theGlContext,
1514           "uAccumTexture", OpenGl_RT_PrevAccumTexture);
1515       }
1516
1517       myUniformLocations[anIndex][OpenGl_RT_aPosition] =
1518         aShaderProgram->GetAttributeLocation (theGlContext, "occVertex");
1519
1520       myUniformLocations[anIndex][OpenGl_RT_uOriginLB] =
1521         aShaderProgram->GetUniformLocation (theGlContext, "uOriginLB");
1522       myUniformLocations[anIndex][OpenGl_RT_uOriginRB] =
1523         aShaderProgram->GetUniformLocation (theGlContext, "uOriginRB");
1524       myUniformLocations[anIndex][OpenGl_RT_uOriginLT] =
1525         aShaderProgram->GetUniformLocation (theGlContext, "uOriginLT");
1526       myUniformLocations[anIndex][OpenGl_RT_uOriginRT] =
1527         aShaderProgram->GetUniformLocation (theGlContext, "uOriginRT");
1528       myUniformLocations[anIndex][OpenGl_RT_uDirectLB] =
1529         aShaderProgram->GetUniformLocation (theGlContext, "uDirectLB");
1530       myUniformLocations[anIndex][OpenGl_RT_uDirectRB] =
1531         aShaderProgram->GetUniformLocation (theGlContext, "uDirectRB");
1532       myUniformLocations[anIndex][OpenGl_RT_uDirectLT] =
1533         aShaderProgram->GetUniformLocation (theGlContext, "uDirectLT");
1534       myUniformLocations[anIndex][OpenGl_RT_uDirectRT] =
1535         aShaderProgram->GetUniformLocation (theGlContext, "uDirectRT");
1536       myUniformLocations[anIndex][OpenGl_RT_uUnviewMat] =
1537         aShaderProgram->GetUniformLocation (theGlContext, "uUnviewMat");
1538
1539       myUniformLocations[anIndex][OpenGl_RT_uSceneRad] =
1540         aShaderProgram->GetUniformLocation (theGlContext, "uSceneRadius");
1541       myUniformLocations[anIndex][OpenGl_RT_uSceneEps] =
1542         aShaderProgram->GetUniformLocation (theGlContext, "uSceneEpsilon");
1543       myUniformLocations[anIndex][OpenGl_RT_uLightCount] =
1544         aShaderProgram->GetUniformLocation (theGlContext, "uLightCount");
1545       myUniformLocations[anIndex][OpenGl_RT_uLightAmbnt] =
1546         aShaderProgram->GetUniformLocation (theGlContext, "uGlobalAmbient");
1547
1548       myUniformLocations[anIndex][OpenGl_RT_uOffsetX] =
1549         aShaderProgram->GetUniformLocation (theGlContext, "uOffsetX");
1550       myUniformLocations[anIndex][OpenGl_RT_uOffsetY] =
1551         aShaderProgram->GetUniformLocation (theGlContext, "uOffsetY");
1552       myUniformLocations[anIndex][OpenGl_RT_uSamples] =
1553         aShaderProgram->GetUniformLocation (theGlContext, "uSamples");
1554
1555       myUniformLocations[anIndex][OpenGl_RT_uTexSamplersArray] =
1556         aShaderProgram->GetUniformLocation (theGlContext, "uTextureSamplers");
1557
1558       myUniformLocations[anIndex][OpenGl_RT_uShadowsEnabled] =
1559         aShaderProgram->GetUniformLocation (theGlContext, "uShadowsEnabled");
1560       myUniformLocations[anIndex][OpenGl_RT_uReflectEnabled] =
1561         aShaderProgram->GetUniformLocation (theGlContext, "uReflectEnabled");
1562       myUniformLocations[anIndex][OpenGl_RT_uSphereMapEnabled] =
1563         aShaderProgram->GetUniformLocation (theGlContext, "uSphereMapEnabled");
1564       myUniformLocations[anIndex][OpenGl_RT_uSphereMapForBack] =
1565         aShaderProgram->GetUniformLocation (theGlContext, "uSphereMapForBack");
1566       myUniformLocations[anIndex][OpenGl_RT_uBlockedRngEnabled] =
1567         aShaderProgram->GetUniformLocation (theGlContext, "uBlockedRngEnabled");
1568
1569       myUniformLocations[anIndex][OpenGl_RT_uSampleWeight] =
1570         aShaderProgram->GetUniformLocation (theGlContext, "uSampleWeight");
1571       myUniformLocations[anIndex][OpenGl_RT_uFrameRndSeed] =
1572         aShaderProgram->GetUniformLocation (theGlContext, "uFrameRndSeed");
1573
1574       myUniformLocations[anIndex][OpenGl_RT_uBackColorTop] =
1575         aShaderProgram->GetUniformLocation (theGlContext, "uBackColorTop");
1576       myUniformLocations[anIndex][OpenGl_RT_uBackColorBot] =
1577         aShaderProgram->GetUniformLocation (theGlContext, "uBackColorBot");
1578     }
1579
1580     theGlContext->BindProgram (myOutImageProgram);
1581
1582     myOutImageProgram->SetSampler (theGlContext,
1583       "uInputTexture", OpenGl_RT_PrevAccumTexture);
1584
1585     theGlContext->BindProgram (NULL);
1586   }
1587
1588   if (myRaytraceInitStatus != OpenGl_RT_NONE)
1589   {
1590     return myRaytraceInitStatus == OpenGl_RT_INIT;
1591   }
1592
1593   if (myRaytraceFBO1.IsNull())
1594   {
1595     myRaytraceFBO1 = new OpenGl_FrameBuffer (GL_RGBA32F);
1596   }
1597
1598   if (myRaytraceFBO2.IsNull())
1599   {
1600     myRaytraceFBO2 = new OpenGl_FrameBuffer (GL_RGBA32F);
1601   }
1602
1603   const GLfloat aVertices[] = { -1.f, -1.f,  0.f,
1604                                 -1.f,  1.f,  0.f,
1605                                  1.f,  1.f,  0.f,
1606                                  1.f,  1.f,  0.f,
1607                                  1.f, -1.f,  0.f,
1608                                 -1.f, -1.f,  0.f };
1609
1610   myRaytraceScreenQuad.Init (theGlContext, 3, 6, aVertices);
1611
1612   myRaytraceInitStatus = OpenGl_RT_INIT; // initialized in normal way
1613
1614   return Standard_True;
1615 }
1616
1617 // =======================================================================
1618 // function : nullifyResource
1619 // purpose  :
1620 // =======================================================================
1621 inline void nullifyResource (const Handle(OpenGl_Context)& theGlContext,
1622                              Handle(OpenGl_Resource)&      theResource)
1623 {
1624   if (!theResource.IsNull())
1625   {
1626     theResource->Release (theGlContext.operator->());
1627     theResource.Nullify();
1628   }
1629 }
1630
1631 // =======================================================================
1632 // function : releaseRaytraceResources
1633 // purpose  : Releases OpenGL/GLSL shader programs
1634 // =======================================================================
1635 void OpenGl_View::releaseRaytraceResources (const Handle(OpenGl_Context)& theGlContext)
1636 {
1637   nullifyResource (theGlContext, myOpenGlFBO);
1638   nullifyResource (theGlContext, myRaytraceFBO1);
1639   nullifyResource (theGlContext, myRaytraceFBO2);
1640
1641   nullifyResource (theGlContext, myRaytraceShader);
1642   nullifyResource (theGlContext, myPostFSAAShader);
1643
1644   nullifyResource (theGlContext, myRaytraceProgram);
1645   nullifyResource (theGlContext, myPostFSAAProgram);
1646   nullifyResource (theGlContext, myOutImageProgram);
1647
1648   nullifyResource (theGlContext, mySceneNodeInfoTexture);
1649   nullifyResource (theGlContext, mySceneMinPointTexture);
1650   nullifyResource (theGlContext, mySceneMaxPointTexture);
1651
1652   nullifyResource (theGlContext, myGeometryVertexTexture);
1653   nullifyResource (theGlContext, myGeometryNormalTexture);
1654   nullifyResource (theGlContext, myGeometryTexCrdTexture);
1655   nullifyResource (theGlContext, myGeometryTriangTexture);
1656   nullifyResource (theGlContext, mySceneTransformTexture);
1657
1658   nullifyResource (theGlContext, myRaytraceLightSrcTexture);
1659   nullifyResource (theGlContext, myRaytraceMaterialTexture);
1660
1661   if (myRaytraceScreenQuad.IsValid())
1662     myRaytraceScreenQuad.Release (theGlContext.operator->());
1663 }
1664
1665 // =======================================================================
1666 // function : resizeRaytraceBuffers
1667 // purpose  : Resizes OpenGL frame buffers
1668 // =======================================================================
1669 Standard_Boolean OpenGl_View::resizeRaytraceBuffers (const Standard_Integer        theSizeX,
1670                                                      const Standard_Integer        theSizeY,
1671                                                      const Handle(OpenGl_Context)& theGlContext)
1672 {
1673   if (myRaytraceFBO1->GetVPSizeX() != theSizeX
1674    || myRaytraceFBO1->GetVPSizeY() != theSizeY)
1675   {
1676     myRaytraceFBO1->Init (theGlContext, theSizeX, theSizeY);
1677     myRaytraceFBO2->Init (theGlContext, theSizeX, theSizeY);
1678   }
1679
1680   return Standard_True;
1681 }
1682
1683 // =======================================================================
1684 // function : updateCamera
1685 // purpose  : Generates viewing rays for corners of screen quad
1686 // =======================================================================
1687 void OpenGl_View::updateCamera (const OpenGl_Mat4& theOrientation,
1688                                 const OpenGl_Mat4& theViewMapping,
1689                                 OpenGl_Vec3*       theOrigins,
1690                                 OpenGl_Vec3*       theDirects,
1691                                 OpenGl_Mat4&       theUnview)
1692 {
1693   // compute inverse model-view-projection matrix
1694   (theViewMapping * theOrientation).Inverted (theUnview);
1695
1696   Standard_Integer aOriginIndex = 0;
1697   Standard_Integer aDirectIndex = 0;
1698
1699   for (Standard_Integer aY = -1; aY <= 1; aY += 2)
1700   {
1701     for (Standard_Integer aX = -1; aX <= 1; aX += 2)
1702     {
1703       OpenGl_Vec4 aOrigin (GLfloat(aX),
1704                            GLfloat(aY),
1705                           -1.0f,
1706                            1.0f);
1707
1708       aOrigin = theUnview * aOrigin;
1709
1710       aOrigin.x() = aOrigin.x() / aOrigin.w();
1711       aOrigin.y() = aOrigin.y() / aOrigin.w();
1712       aOrigin.z() = aOrigin.z() / aOrigin.w();
1713
1714       OpenGl_Vec4 aDirect (GLfloat(aX),
1715                            GLfloat(aY),
1716                            1.0f,
1717                            1.0f);
1718
1719       aDirect = theUnview * aDirect;
1720
1721       aDirect.x() = aDirect.x() / aDirect.w();
1722       aDirect.y() = aDirect.y() / aDirect.w();
1723       aDirect.z() = aDirect.z() / aDirect.w();
1724
1725       aDirect = aDirect - aOrigin;
1726
1727       GLdouble aInvLen = 1.0 / sqrt (aDirect.x() * aDirect.x() +
1728                                      aDirect.y() * aDirect.y() +
1729                                      aDirect.z() * aDirect.z());
1730
1731       theOrigins[aOriginIndex++] = OpenGl_Vec3 (static_cast<GLfloat> (aOrigin.x()),
1732                                                 static_cast<GLfloat> (aOrigin.y()),
1733                                                 static_cast<GLfloat> (aOrigin.z()));
1734
1735       theDirects[aDirectIndex++] = OpenGl_Vec3 (static_cast<GLfloat> (aDirect.x() * aInvLen),
1736                                                 static_cast<GLfloat> (aDirect.y() * aInvLen),
1737                                                 static_cast<GLfloat> (aDirect.z() * aInvLen));
1738     }
1739   }
1740 }
1741
1742 // =======================================================================
1743 // function : uploadRaytraceData
1744 // purpose  : Uploads ray-trace data to the GPU
1745 // =======================================================================
1746 Standard_Boolean OpenGl_View::uploadRaytraceData (const Handle(OpenGl_Context)& theGlContext)
1747 {
1748   if (!theGlContext->IsGlGreaterEqual (3, 1))
1749   {
1750 #ifdef RAY_TRACE_PRINT_INFO
1751     std::cout << "Error: OpenGL version is less than 3.1" << std::endl;
1752 #endif
1753     return Standard_False;
1754   }
1755
1756   myAccumFrames = 0; // accumulation should be restarted
1757
1758   /////////////////////////////////////////////////////////////////////////////
1759   // Prepare OpenGL textures
1760
1761   if (theGlContext->arbTexBindless != NULL)
1762   {
1763     // If OpenGL driver supports bindless textures we need
1764     // to get unique 64- bit handles for using on the GPU
1765     if (!myRaytraceGeometry.UpdateTextureHandles (theGlContext))
1766     {
1767 #ifdef RAY_TRACE_PRINT_INFO
1768       std::cout << "Error: Failed to get OpenGL texture handles" << std::endl;
1769 #endif
1770       return Standard_False;
1771     }
1772   }
1773
1774   /////////////////////////////////////////////////////////////////////////////
1775   // Create OpenGL BVH buffers
1776
1777   if (mySceneNodeInfoTexture.IsNull())  // create scene BVH buffers
1778   {
1779     mySceneNodeInfoTexture  = new OpenGl_TextureBufferArb;
1780     mySceneMinPointTexture  = new OpenGl_TextureBufferArb;
1781     mySceneMaxPointTexture  = new OpenGl_TextureBufferArb;
1782     mySceneTransformTexture = new OpenGl_TextureBufferArb;
1783
1784     if (!mySceneNodeInfoTexture->Create  (theGlContext)
1785      || !mySceneMinPointTexture->Create  (theGlContext)
1786      || !mySceneMaxPointTexture->Create  (theGlContext)
1787      || !mySceneTransformTexture->Create (theGlContext))
1788     {
1789 #ifdef RAY_TRACE_PRINT_INFO
1790       std::cout << "Error: Failed to create scene BVH buffers" << std::endl;
1791 #endif
1792       return Standard_False;
1793     }
1794   }
1795
1796   if  (myGeometryVertexTexture.IsNull())  // create geometry buffers
1797   {
1798     myGeometryVertexTexture = new OpenGl_TextureBufferArb;
1799     myGeometryNormalTexture = new OpenGl_TextureBufferArb;
1800     myGeometryTexCrdTexture = new OpenGl_TextureBufferArb;
1801     myGeometryTriangTexture = new OpenGl_TextureBufferArb;
1802
1803     if (!myGeometryVertexTexture->Create (theGlContext)
1804      || !myGeometryNormalTexture->Create (theGlContext)
1805      || !myGeometryTexCrdTexture->Create (theGlContext)
1806      || !myGeometryTriangTexture->Create (theGlContext))
1807     {
1808 #ifdef RAY_TRACE_PRINT_INFO
1809       std::cout << "Error: Failed to create buffers for triangulation data" << std::endl;
1810 #endif
1811       return Standard_False;
1812     }
1813   }
1814
1815   if (myRaytraceMaterialTexture.IsNull()) // create material buffer
1816   {
1817     myRaytraceMaterialTexture = new OpenGl_TextureBufferArb;
1818
1819     if (!myRaytraceMaterialTexture->Create (theGlContext))
1820     {
1821 #ifdef RAY_TRACE_PRINT_INFO
1822       std::cout << "Error: Failed to create buffers for material data" << std::endl;
1823 #endif
1824       return Standard_False;
1825     }
1826   }
1827   
1828   /////////////////////////////////////////////////////////////////////////////
1829   // Write transform buffer
1830
1831   BVH_Mat4f* aNodeTransforms = new BVH_Mat4f[myRaytraceGeometry.Size()];
1832
1833   bool aResult = true;
1834
1835   for (Standard_Integer anElemIndex = 0; anElemIndex < myRaytraceGeometry.Size(); ++anElemIndex)
1836   {
1837     OpenGl_TriangleSet* aTriangleSet = dynamic_cast<OpenGl_TriangleSet*> (
1838       myRaytraceGeometry.Objects().ChangeValue (anElemIndex).operator->());
1839
1840     const BVH_Transform<Standard_ShortReal, 4>* aTransform = 
1841       dynamic_cast<const BVH_Transform<Standard_ShortReal, 4>* > (aTriangleSet->Properties().operator->());
1842
1843     Standard_ASSERT_RETURN (aTransform != NULL,
1844       "OpenGl_TriangleSet does not contain transform", Standard_False);
1845
1846     aNodeTransforms[anElemIndex] = aTransform->Inversed();
1847   }
1848
1849   aResult &= mySceneTransformTexture->Init (theGlContext, 4,
1850     myRaytraceGeometry.Size() * 4, reinterpret_cast<const GLfloat*> (aNodeTransforms));
1851
1852   delete [] aNodeTransforms;
1853
1854   /////////////////////////////////////////////////////////////////////////////
1855   // Write geometry and bottom-level BVH buffers
1856
1857   Standard_Size aTotalVerticesNb = 0;
1858   Standard_Size aTotalElementsNb = 0;
1859   Standard_Size aTotalBVHNodesNb = 0;
1860
1861   for (Standard_Integer anElemIndex = 0; anElemIndex < myRaytraceGeometry.Size(); ++anElemIndex)
1862   {
1863     OpenGl_TriangleSet* aTriangleSet = dynamic_cast<OpenGl_TriangleSet*> (
1864       myRaytraceGeometry.Objects().ChangeValue (anElemIndex).operator->());
1865
1866     Standard_ASSERT_RETURN (aTriangleSet != NULL,
1867       "Error: Failed to get triangulation of OpenGL element", Standard_False);
1868
1869     aTotalVerticesNb += aTriangleSet->Vertices.size();
1870     aTotalElementsNb += aTriangleSet->Elements.size();
1871
1872     Standard_ASSERT_RETURN (!aTriangleSet->BVH().IsNull(),
1873       "Error: Failed to get bottom-level BVH of OpenGL element", Standard_False);
1874
1875     aTotalBVHNodesNb += aTriangleSet->BVH()->NodeInfoBuffer().size();
1876   }
1877
1878   aTotalBVHNodesNb += myRaytraceGeometry.BVH()->NodeInfoBuffer().size();
1879
1880   if (aTotalBVHNodesNb != 0)
1881   {
1882     aResult &= mySceneNodeInfoTexture->Init (
1883       theGlContext, 4, GLsizei (aTotalBVHNodesNb), static_cast<const GLuint*>  (NULL));
1884     aResult &= mySceneMinPointTexture->Init (
1885       theGlContext, 3, GLsizei (aTotalBVHNodesNb), static_cast<const GLfloat*> (NULL));
1886     aResult &= mySceneMaxPointTexture->Init (
1887       theGlContext, 3, GLsizei (aTotalBVHNodesNb), static_cast<const GLfloat*> (NULL));
1888   }
1889
1890   if (!aResult)
1891   {
1892 #ifdef RAY_TRACE_PRINT_INFO
1893     std::cout << "Error: Failed to upload buffers for bottom-level scene BVH" << std::endl;
1894 #endif
1895     return Standard_False;
1896   }
1897
1898   if (aTotalElementsNb != 0)
1899   {
1900     aResult &= myGeometryTriangTexture->Init (
1901       theGlContext, 4, GLsizei (aTotalElementsNb), static_cast<const GLuint*> (NULL));
1902   }
1903
1904   if (aTotalVerticesNb != 0)
1905   {
1906     aResult &= myGeometryVertexTexture->Init (
1907       theGlContext, 3, GLsizei (aTotalVerticesNb), static_cast<const GLfloat*> (NULL));
1908     aResult &= myGeometryNormalTexture->Init (
1909       theGlContext, 3, GLsizei (aTotalVerticesNb), static_cast<const GLfloat*> (NULL));
1910     aResult &= myGeometryTexCrdTexture->Init (
1911       theGlContext, 2, GLsizei (aTotalVerticesNb), static_cast<const GLfloat*> (NULL));
1912   }
1913
1914   if (!aResult)
1915   {
1916 #ifdef RAY_TRACE_PRINT_INFO
1917     std::cout << "Error: Failed to upload buffers for scene geometry" << std::endl;
1918 #endif
1919     return Standard_False;
1920   }
1921
1922   const NCollection_Handle<BVH_Tree<Standard_ShortReal, 3> >& aBVH = myRaytraceGeometry.BVH();
1923
1924   if (aBVH->Length() > 0)
1925   {
1926     aResult &= mySceneNodeInfoTexture->SubData (theGlContext, 0, aBVH->Length(),
1927       reinterpret_cast<const GLuint*> (&aBVH->NodeInfoBuffer().front()));
1928     aResult &= mySceneMinPointTexture->SubData (theGlContext, 0, aBVH->Length(),
1929       reinterpret_cast<const GLfloat*> (&aBVH->MinPointBuffer().front()));
1930     aResult &= mySceneMaxPointTexture->SubData (theGlContext, 0, aBVH->Length(),
1931       reinterpret_cast<const GLfloat*> (&aBVH->MaxPointBuffer().front()));
1932   }
1933
1934   for (Standard_Integer aNodeIdx = 0; aNodeIdx < aBVH->Length(); ++aNodeIdx)
1935   {
1936     if (!aBVH->IsOuter (aNodeIdx))
1937       continue;
1938
1939     OpenGl_TriangleSet* aTriangleSet = myRaytraceGeometry.TriangleSet (aNodeIdx);
1940
1941     Standard_ASSERT_RETURN (aTriangleSet != NULL,
1942       "Error: Failed to get triangulation of OpenGL element", Standard_False);
1943
1944     Standard_Integer aBVHOffset = myRaytraceGeometry.AccelerationOffset (aNodeIdx);
1945
1946     Standard_ASSERT_RETURN (aBVHOffset != OpenGl_RaytraceGeometry::INVALID_OFFSET,
1947       "Error: Failed to get offset for bottom-level BVH", Standard_False);
1948
1949     const Standard_Integer aBvhBuffersSize = aTriangleSet->BVH()->Length();
1950
1951     if (aBvhBuffersSize != 0)
1952     {
1953       aResult &= mySceneNodeInfoTexture->SubData (theGlContext, aBVHOffset, aBvhBuffersSize,
1954         reinterpret_cast<const GLuint*> (&aTriangleSet->BVH()->NodeInfoBuffer().front()));
1955       aResult &= mySceneMinPointTexture->SubData (theGlContext, aBVHOffset, aBvhBuffersSize,
1956         reinterpret_cast<const GLfloat*> (&aTriangleSet->BVH()->MinPointBuffer().front()));
1957       aResult &= mySceneMaxPointTexture->SubData (theGlContext, aBVHOffset, aBvhBuffersSize,
1958         reinterpret_cast<const GLfloat*> (&aTriangleSet->BVH()->MaxPointBuffer().front()));
1959
1960       if (!aResult)
1961       {
1962 #ifdef RAY_TRACE_PRINT_INFO
1963         std::cout << "Error: Failed to upload buffers for bottom-level scene BVHs" << std::endl;
1964 #endif
1965         return Standard_False;
1966       }
1967     }
1968
1969     const Standard_Integer aVerticesOffset = myRaytraceGeometry.VerticesOffset (aNodeIdx);
1970
1971     Standard_ASSERT_RETURN (aVerticesOffset != OpenGl_RaytraceGeometry::INVALID_OFFSET,
1972       "Error: Failed to get offset for triangulation vertices of OpenGL element", Standard_False);
1973
1974     if (!aTriangleSet->Vertices.empty())
1975     {
1976       aResult &= myGeometryNormalTexture->SubData (theGlContext, aVerticesOffset,
1977         GLsizei (aTriangleSet->Normals.size()), reinterpret_cast<const GLfloat*> (&aTriangleSet->Normals.front()));
1978       aResult &= myGeometryTexCrdTexture->SubData (theGlContext, aVerticesOffset,
1979         GLsizei (aTriangleSet->TexCrds.size()), reinterpret_cast<const GLfloat*> (&aTriangleSet->TexCrds.front()));
1980       aResult &= myGeometryVertexTexture->SubData (theGlContext, aVerticesOffset,
1981         GLsizei (aTriangleSet->Vertices.size()), reinterpret_cast<const GLfloat*> (&aTriangleSet->Vertices.front()));
1982     }
1983
1984     const Standard_Integer anElementsOffset = myRaytraceGeometry.ElementsOffset (aNodeIdx);
1985
1986     Standard_ASSERT_RETURN (anElementsOffset != OpenGl_RaytraceGeometry::INVALID_OFFSET,
1987       "Error: Failed to get offset for triangulation elements of OpenGL element", Standard_False);
1988
1989     if (!aTriangleSet->Elements.empty())
1990     {
1991       aResult &= myGeometryTriangTexture->SubData (theGlContext, anElementsOffset, GLsizei (aTriangleSet->Elements.size()),
1992                                                    reinterpret_cast<const GLuint*> (&aTriangleSet->Elements.front()));
1993     }
1994
1995     if (!aResult)
1996     {
1997 #ifdef RAY_TRACE_PRINT_INFO
1998       std::cout << "Error: Failed to upload triangulation buffers for OpenGL element" << std::endl;
1999 #endif
2000       return Standard_False;
2001     }
2002   }
2003
2004   /////////////////////////////////////////////////////////////////////////////
2005   // Write material buffer
2006
2007   if (myRaytraceGeometry.Materials.size() != 0)
2008   {
2009     aResult &= myRaytraceMaterialTexture->Init (theGlContext, 4,
2010       GLsizei (myRaytraceGeometry.Materials.size() * 18), myRaytraceGeometry.Materials.front().Packed());
2011
2012     if (!aResult)
2013     {
2014 #ifdef RAY_TRACE_PRINT_INFO
2015       std::cout << "Error: Failed to upload material buffer" << std::endl;
2016 #endif
2017       return Standard_False;
2018     }
2019   }
2020
2021   myIsRaytraceDataValid = myRaytraceGeometry.Objects().Size() != 0;
2022
2023 #ifdef RAY_TRACE_PRINT_INFO
2024
2025   Standard_ShortReal aMemUsed = 0.f;
2026
2027   for (Standard_Integer anElemIdx = 0; anElemIdx < myRaytraceGeometry.Size(); ++anElemIdx)
2028   {
2029     OpenGl_TriangleSet* aTriangleSet = dynamic_cast<OpenGl_TriangleSet*> (
2030       myRaytraceGeometry.Objects().ChangeValue (anElemIdx).operator->());
2031
2032     aMemUsed += static_cast<Standard_ShortReal> (
2033       aTriangleSet->Vertices.size() * sizeof (BVH_Vec3f));
2034     aMemUsed += static_cast<Standard_ShortReal> (
2035       aTriangleSet->Normals.size() * sizeof (BVH_Vec3f));
2036     aMemUsed += static_cast<Standard_ShortReal> (
2037       aTriangleSet->TexCrds.size() * sizeof (BVH_Vec2f));
2038     aMemUsed += static_cast<Standard_ShortReal> (
2039       aTriangleSet->Elements.size() * sizeof (BVH_Vec4i));
2040
2041     aMemUsed += static_cast<Standard_ShortReal> (
2042       aTriangleSet->BVH()->NodeInfoBuffer().size() * sizeof (BVH_Vec4i));
2043     aMemUsed += static_cast<Standard_ShortReal> (
2044       aTriangleSet->BVH()->MinPointBuffer().size() * sizeof (BVH_Vec3f));
2045     aMemUsed += static_cast<Standard_ShortReal> (
2046       aTriangleSet->BVH()->MaxPointBuffer().size() * sizeof (BVH_Vec3f));
2047   }
2048
2049   aMemUsed += static_cast<Standard_ShortReal> (
2050     myRaytraceGeometry.BVH()->NodeInfoBuffer().size() * sizeof (BVH_Vec4i));
2051   aMemUsed += static_cast<Standard_ShortReal> (
2052     myRaytraceGeometry.BVH()->MinPointBuffer().size() * sizeof (BVH_Vec3f));
2053   aMemUsed += static_cast<Standard_ShortReal> (
2054     myRaytraceGeometry.BVH()->MaxPointBuffer().size() * sizeof (BVH_Vec3f));
2055
2056   std::cout << "GPU Memory Used (MB): ~" << aMemUsed / 1048576 << std::endl;
2057
2058 #endif
2059
2060   return aResult;
2061 }
2062
2063 // =======================================================================
2064 // function : updateRaytraceLightSources
2065 // purpose  : Updates 3D scene light sources for ray-tracing
2066 // =======================================================================
2067 Standard_Boolean OpenGl_View::updateRaytraceLightSources (const OpenGl_Mat4& theInvModelView, const Handle(OpenGl_Context)& theGlContext)
2068 {
2069   myRaytraceGeometry.Sources.clear();
2070
2071   myRaytraceGeometry.Ambient = BVH_Vec4f (0.0f, 0.0f, 0.0f, 0.0f);
2072
2073   for (OpenGl_ListOfLight::Iterator aLightIter (myLights); aLightIter.More(); aLightIter.Next())
2074   {
2075     const OpenGl_Light& aLight = aLightIter.Value();
2076
2077     if (aLight.Type == Visual3d_TOLS_AMBIENT)
2078     {
2079       myRaytraceGeometry.Ambient += BVH_Vec4f (aLight.Color.r() * aLight.Intensity,
2080                                                aLight.Color.g() * aLight.Intensity,
2081                                                aLight.Color.b() * aLight.Intensity,
2082                                                0.0f);
2083       continue;
2084     }
2085
2086     BVH_Vec4f aDiffuse  (aLight.Color.r() * aLight.Intensity,
2087                          aLight.Color.g() * aLight.Intensity,
2088                          aLight.Color.b() * aLight.Intensity,
2089                          1.0f);
2090
2091     BVH_Vec4f aPosition (-aLight.Direction.x(),
2092                          -aLight.Direction.y(),
2093                          -aLight.Direction.z(),
2094                          0.0f);
2095
2096     if (aLight.Type != Visual3d_TOLS_DIRECTIONAL)
2097     {
2098       aPosition = BVH_Vec4f (aLight.Position.x(),
2099                              aLight.Position.y(),
2100                              aLight.Position.z(),
2101                              1.0f);
2102
2103       // store smoothing radius in w-component
2104       aDiffuse.w() = Max (aLight.Smoothness, 0.f);
2105     }
2106     else
2107     {
2108       // store cosine of smoothing angle in w-component
2109       aDiffuse.w() = cosf (Min (Max (aLight.Smoothness, 0.f), static_cast<Standard_ShortReal> (M_PI / 2.0)));
2110     }
2111
2112     if (aLight.IsHeadlight)
2113     {
2114       aPosition = theInvModelView * aPosition;
2115     }
2116
2117     myRaytraceGeometry.Sources.push_back (OpenGl_RaytraceLight (aDiffuse, aPosition));
2118   }
2119
2120   if (myRaytraceLightSrcTexture.IsNull())  // create light source buffer
2121   {
2122     myRaytraceLightSrcTexture = new OpenGl_TextureBufferArb;
2123
2124     if (!myRaytraceLightSrcTexture->Create (theGlContext))
2125     {
2126 #ifdef RAY_TRACE_PRINT_INFO
2127       std::cout << "Error: Failed to create light source buffer" << std::endl;
2128 #endif
2129       return Standard_False;
2130     }
2131   }
2132
2133   if (myRaytraceGeometry.Sources.size() != 0)
2134   {
2135     const GLfloat* aDataPtr = myRaytraceGeometry.Sources.front().Packed();
2136     if (!myRaytraceLightSrcTexture->Init (theGlContext, 4, GLsizei (myRaytraceGeometry.Sources.size() * 2), aDataPtr))
2137     {
2138 #ifdef RAY_TRACE_PRINT_INFO
2139       std::cout << "Error: Failed to upload light source buffer" << std::endl;
2140 #endif
2141       return Standard_False;
2142     }
2143   }
2144
2145   return Standard_True;
2146 }
2147
2148 // =======================================================================
2149 // function : updateRaytraceEnvironmentMap
2150 // purpose  : Updates environment map for ray-tracing
2151 // =======================================================================
2152 Standard_Boolean OpenGl_View::updateRaytraceEnvironmentMap (const Handle(OpenGl_Context)& theGlContext)
2153 {
2154   Standard_Boolean aResult = Standard_True;
2155
2156   if (!myToUpdateEnvironmentMap)
2157   {
2158     return aResult;
2159   }
2160
2161   for (Standard_Integer anIdx = 0; anIdx < 2; ++anIdx)
2162   {
2163     const Handle(OpenGl_ShaderProgram)& aProgram =
2164       anIdx == 0 ? myRaytraceProgram : myPostFSAAProgram;
2165
2166     if (!aProgram.IsNull())
2167     {
2168       aResult &= theGlContext->BindProgram (aProgram);
2169
2170       if (!myTextureEnv.IsNull() && mySurfaceDetail != Visual3d_TOD_NONE)
2171       {
2172         myTextureEnv->Bind (theGlContext,
2173           GL_TEXTURE0 + OpenGl_RT_EnvironmentMapTexture);
2174
2175         aResult &= aProgram->SetUniform (theGlContext,
2176           myUniformLocations[anIdx][OpenGl_RT_uSphereMapEnabled], 1);
2177       }
2178       else
2179       {
2180         aResult &= aProgram->SetUniform (theGlContext,
2181           myUniformLocations[anIdx][OpenGl_RT_uSphereMapEnabled], 0);
2182       }
2183     }
2184   }
2185
2186   myToUpdateEnvironmentMap = Standard_False;
2187
2188   theGlContext->BindProgram (NULL);
2189
2190   return aResult;
2191 }
2192
2193 // =======================================================================
2194 // function : setUniformState
2195 // purpose  : Sets uniform state for the given ray-tracing shader program
2196 // =======================================================================
2197 Standard_Boolean OpenGl_View::setUniformState (const Graphic3d_CView&        theCView,
2198                                                const OpenGl_Vec3*            theOrigins,
2199                                                const OpenGl_Vec3*            theDirects,
2200                                                const OpenGl_Mat4&            theUnviewMat,
2201                                                const Standard_Integer        theProgramId,
2202                                                const Handle(OpenGl_Context)& theGlContext)
2203 {
2204   Handle(OpenGl_ShaderProgram)& theProgram =
2205     theProgramId == 0 ? myRaytraceProgram : myPostFSAAProgram;
2206
2207   if (theProgram.IsNull())
2208   {
2209     return Standard_False;
2210   }
2211
2212   const Standard_Integer aLightSourceBufferSize =
2213     static_cast<Standard_Integer> (myRaytraceGeometry.Sources.size());
2214
2215   // Set camera state
2216   theProgram->SetUniform (theGlContext,
2217     myUniformLocations[theProgramId][OpenGl_RT_uOriginLB], theOrigins[0]);
2218   theProgram->SetUniform (theGlContext,
2219     myUniformLocations[theProgramId][OpenGl_RT_uOriginRB], theOrigins[1]);
2220   theProgram->SetUniform (theGlContext,
2221     myUniformLocations[theProgramId][OpenGl_RT_uOriginLT], theOrigins[2]);
2222   theProgram->SetUniform (theGlContext,
2223     myUniformLocations[theProgramId][OpenGl_RT_uOriginRT], theOrigins[3]);
2224   theProgram->SetUniform (theGlContext,
2225     myUniformLocations[theProgramId][OpenGl_RT_uDirectLB], theDirects[0]);
2226   theProgram->SetUniform (theGlContext,
2227     myUniformLocations[theProgramId][OpenGl_RT_uDirectRB], theDirects[1]);
2228   theProgram->SetUniform (theGlContext,
2229     myUniformLocations[theProgramId][OpenGl_RT_uDirectLT], theDirects[2]);
2230   theProgram->SetUniform (theGlContext,
2231     myUniformLocations[theProgramId][OpenGl_RT_uDirectRT], theDirects[3]);
2232   theProgram->SetUniform (theGlContext,
2233     myUniformLocations[theProgramId][OpenGl_RT_uUnviewMat], theUnviewMat);
2234
2235   // Set scene parameters
2236   theProgram->SetUniform (theGlContext,
2237     myUniformLocations[theProgramId][OpenGl_RT_uSceneRad], myRaytraceSceneRadius);
2238   theProgram->SetUniform (theGlContext,
2239     myUniformLocations[theProgramId][OpenGl_RT_uSceneEps], myRaytraceSceneEpsilon);
2240   theProgram->SetUniform (theGlContext,
2241     myUniformLocations[theProgramId][OpenGl_RT_uLightCount], aLightSourceBufferSize);
2242   theProgram->SetUniform (theGlContext,
2243     myUniformLocations[theProgramId][OpenGl_RT_uLightAmbnt], myRaytraceGeometry.Ambient);
2244
2245   // Set run-time rendering options
2246   theProgram->SetUniform (theGlContext,
2247     myUniformLocations[theProgramId][OpenGl_RT_uShadowsEnabled], theCView.RenderParams.IsShadowEnabled ?  1 : 0);
2248   theProgram->SetUniform (theGlContext,
2249     myUniformLocations[theProgramId][OpenGl_RT_uReflectEnabled], theCView.RenderParams.IsReflectionEnabled ?  1 : 0);
2250
2251   if (theCView.RenderParams.IsGlobalIlluminationEnabled)
2252   {
2253     theProgram->SetUniform (theGlContext,
2254       myUniformLocations[theProgramId][OpenGl_RT_uBlockedRngEnabled], theCView.RenderParams.CoherentPathTracingMode ?  1 : 0);
2255   }
2256
2257   // Set array of 64-bit texture handles
2258   if (theGlContext->arbTexBindless != NULL && myRaytraceGeometry.HasTextures())
2259   {
2260     theProgram->SetUniform (theGlContext, myUniformLocations[theProgramId][OpenGl_RT_uTexSamplersArray],
2261       static_cast<GLsizei> (myRaytraceGeometry.TextureHandles().size()), &myRaytraceGeometry.TextureHandles()[0]);
2262   }
2263
2264   // Set background colors (only gradient background supported)
2265   if (myBgGradientArray != NULL
2266    && myBgGradientArray->IsDefined())
2267   {
2268     theProgram->SetUniform (theGlContext,
2269       myUniformLocations[theProgramId][OpenGl_RT_uBackColorTop], myBgGradientArray->GradientColor (0));
2270     theProgram->SetUniform (theGlContext,
2271       myUniformLocations[theProgramId][OpenGl_RT_uBackColorBot], myBgGradientArray->GradientColor (1));
2272   }
2273   else
2274   {
2275     const OpenGl_Vec4 aBackColor (theCView.DefWindow.Background.r,
2276                                   theCView.DefWindow.Background.g,
2277                                   theCView.DefWindow.Background.b,
2278                                   1.0f);
2279     theProgram->SetUniform (theGlContext,
2280       myUniformLocations[theProgramId][OpenGl_RT_uBackColorTop], aBackColor);
2281     theProgram->SetUniform (theGlContext,
2282       myUniformLocations[theProgramId][OpenGl_RT_uBackColorBot], aBackColor);
2283   }
2284
2285   theProgram->SetUniform (theGlContext,
2286     myUniformLocations[theProgramId][OpenGl_RT_uSphereMapForBack], theCView.RenderParams.UseEnvironmentMapBackground ?  1 : 0);
2287
2288   return Standard_True;
2289 }
2290
2291 // =======================================================================
2292 // function : bindRaytraceTextures
2293 // purpose  : Binds ray-trace textures to corresponding texture units
2294 // =======================================================================
2295 void OpenGl_View::bindRaytraceTextures (const Handle(OpenGl_Context)& theGlContext)
2296 {
2297   mySceneMinPointTexture->BindTexture    (theGlContext, GL_TEXTURE0 + OpenGl_RT_SceneMinPointTexture);
2298   mySceneMaxPointTexture->BindTexture    (theGlContext, GL_TEXTURE0 + OpenGl_RT_SceneMaxPointTexture);
2299   mySceneNodeInfoTexture->BindTexture    (theGlContext, GL_TEXTURE0 + OpenGl_RT_SceneNodeInfoTexture);
2300   myGeometryVertexTexture->BindTexture   (theGlContext, GL_TEXTURE0 + OpenGl_RT_GeometryVertexTexture);
2301   myGeometryNormalTexture->BindTexture   (theGlContext, GL_TEXTURE0 + OpenGl_RT_GeometryNormalTexture);
2302   myGeometryTexCrdTexture->BindTexture   (theGlContext, GL_TEXTURE0 + OpenGl_RT_GeometryTexCrdTexture);
2303   myGeometryTriangTexture->BindTexture   (theGlContext, GL_TEXTURE0 + OpenGl_RT_GeometryTriangTexture);
2304   mySceneTransformTexture->BindTexture   (theGlContext, GL_TEXTURE0 + OpenGl_RT_SceneTransformTexture);
2305   myRaytraceMaterialTexture->BindTexture (theGlContext, GL_TEXTURE0 + OpenGl_RT_RaytraceMaterialTexture);
2306   myRaytraceLightSrcTexture->BindTexture (theGlContext, GL_TEXTURE0 + OpenGl_RT_RaytraceLightSrcTexture);
2307
2308   if (!myOpenGlFBO.IsNull())
2309   {
2310     myOpenGlFBO->ColorTexture()->Bind        (theGlContext, GL_TEXTURE0 + OpenGl_RT_OpenGlColorTexture);
2311     myOpenGlFBO->DepthStencilTexture()->Bind (theGlContext, GL_TEXTURE0 + OpenGl_RT_OpenGlDepthTexture);
2312   }
2313 }
2314
2315 // =======================================================================
2316 // function : unbindRaytraceTextures
2317 // purpose  : Unbinds ray-trace textures from corresponding texture units
2318 // =======================================================================
2319 void OpenGl_View::unbindRaytraceTextures (const Handle(OpenGl_Context)& theGlContext)
2320 {
2321   mySceneMinPointTexture->UnbindTexture    (theGlContext, GL_TEXTURE0 + OpenGl_RT_SceneMinPointTexture);
2322   mySceneMaxPointTexture->UnbindTexture    (theGlContext, GL_TEXTURE0 + OpenGl_RT_SceneMaxPointTexture);
2323   mySceneNodeInfoTexture->UnbindTexture    (theGlContext, GL_TEXTURE0 + OpenGl_RT_SceneNodeInfoTexture);
2324   myGeometryVertexTexture->UnbindTexture   (theGlContext, GL_TEXTURE0 + OpenGl_RT_GeometryVertexTexture);
2325   myGeometryNormalTexture->UnbindTexture   (theGlContext, GL_TEXTURE0 + OpenGl_RT_GeometryNormalTexture);
2326   myGeometryTexCrdTexture->UnbindTexture   (theGlContext, GL_TEXTURE0 + OpenGl_RT_GeometryTexCrdTexture);
2327   myGeometryTriangTexture->UnbindTexture   (theGlContext, GL_TEXTURE0 + OpenGl_RT_GeometryTriangTexture);
2328   mySceneTransformTexture->UnbindTexture   (theGlContext, GL_TEXTURE0 + OpenGl_RT_SceneTransformTexture);
2329   myRaytraceMaterialTexture->UnbindTexture (theGlContext, GL_TEXTURE0 + OpenGl_RT_RaytraceMaterialTexture);
2330   myRaytraceLightSrcTexture->UnbindTexture (theGlContext, GL_TEXTURE0 + OpenGl_RT_RaytraceLightSrcTexture);
2331
2332   if (!myOpenGlFBO.IsNull())
2333   {
2334     myOpenGlFBO->ColorTexture()->Unbind        (theGlContext, GL_TEXTURE0 + OpenGl_RT_OpenGlColorTexture);
2335     myOpenGlFBO->DepthStencilTexture()->Unbind (theGlContext, GL_TEXTURE0 + OpenGl_RT_OpenGlDepthTexture);
2336   }
2337
2338   theGlContext->core15fwd->glActiveTexture (GL_TEXTURE0);
2339 }
2340
2341 // =======================================================================
2342 // function : runRaytraceShaders
2343 // purpose  : Runs ray-tracing shader programs
2344 // =======================================================================
2345 Standard_Boolean OpenGl_View::runRaytraceShaders (const Graphic3d_CView&        theCView,
2346                                                   const Standard_Integer        theSizeX,
2347                                                   const Standard_Integer        theSizeY,
2348                                                   const OpenGl_Vec3*            theOrigins,
2349                                                   const OpenGl_Vec3*            theDirects,
2350                                                   const OpenGl_Mat4&            theUnviewMat,
2351                                                   OpenGl_FrameBuffer*           theReadDrawFbo,
2352                                                   const Handle(OpenGl_Context)& theGlContext)
2353 {
2354   bindRaytraceTextures (theGlContext);
2355
2356   Handle(OpenGl_FrameBuffer) aRenderFramebuffer;
2357   Handle(OpenGl_FrameBuffer) anAccumFramebuffer;
2358
2359   if (myRaytraceParameters.GlobalIllumination) // if path-tracing is used
2360   {
2361     for (int anIdx = 0; anIdx < 3; ++anIdx)
2362     {
2363       if  (fabsf (theOrigins[anIdx].x() - myPreviousOrigins[anIdx].x()) > std::numeric_limits<Standard_ShortReal>::epsilon()
2364         || fabsf (theOrigins[anIdx].y() - myPreviousOrigins[anIdx].y()) > std::numeric_limits<Standard_ShortReal>::epsilon()
2365         || fabsf (theOrigins[anIdx].z() - myPreviousOrigins[anIdx].z()) > std::numeric_limits<Standard_ShortReal>::epsilon())
2366       {
2367         myAccumFrames = 0; // camera has been moved
2368       }
2369
2370       myPreviousOrigins[anIdx] = theOrigins[anIdx];
2371     }
2372
2373     aRenderFramebuffer = myAccumFrames % 2 ? myRaytraceFBO1 : myRaytraceFBO2;
2374     anAccumFramebuffer = myAccumFrames % 2 ? myRaytraceFBO2 : myRaytraceFBO1;
2375
2376     anAccumFramebuffer->ColorTexture()->Bind (
2377       theGlContext, GL_TEXTURE0 + OpenGl_RT_PrevAccumTexture);
2378
2379     aRenderFramebuffer->BindBuffer (theGlContext);
2380   }
2381   else if (theCView.RenderParams.IsAntialiasingEnabled) // if 2-pass ray-tracing is used
2382   {
2383     myRaytraceFBO1->BindBuffer (theGlContext);
2384
2385     glDisable (GL_BLEND);
2386   }
2387
2388   Standard_Boolean aResult = theGlContext->BindProgram (myRaytraceProgram);
2389
2390   aResult &= setUniformState (theCView,
2391                               theOrigins,
2392                               theDirects,
2393                               theUnviewMat,
2394                               0, // ID of RT program
2395                               theGlContext);
2396
2397   if (myRaytraceParameters.GlobalIllumination)
2398   {
2399     if (myAccumFrames == 0)
2400     {
2401       myRNG.SetSeed();
2402     }
2403
2404     // Set frame accumulation weight
2405     myRaytraceProgram->SetUniform (theGlContext,
2406       myUniformLocations[0][OpenGl_RT_uSampleWeight], 1.f / (myAccumFrames + 1));
2407
2408     // Set random number generator seed
2409     myRaytraceProgram->SetUniform (theGlContext,
2410       myUniformLocations[0][OpenGl_RT_uFrameRndSeed], static_cast<Standard_Integer> (myRNG.NextInt() >> 2));
2411   }
2412
2413   theGlContext->core20fwd->glDrawArrays (GL_TRIANGLES, 0, 6);
2414
2415   if (myRaytraceParameters.GlobalIllumination)
2416   {
2417     // Output accumulated image
2418     glDisable (GL_BLEND);
2419
2420     theGlContext->BindProgram (myOutImageProgram);
2421
2422     if (theReadDrawFbo != NULL)
2423     {
2424       theReadDrawFbo->BindBuffer (theGlContext);
2425     }
2426     else
2427     {
2428       aRenderFramebuffer->UnbindBuffer (theGlContext);
2429     }
2430
2431     aRenderFramebuffer->ColorTexture()->Bind (
2432       theGlContext, GL_TEXTURE0 + OpenGl_RT_PrevAccumTexture);
2433
2434     theGlContext->core20fwd->glDrawArrays (GL_TRIANGLES, 0, 6);
2435
2436     ++myAccumFrames;
2437   }
2438   else if (theCView.RenderParams.IsAntialiasingEnabled)
2439   {
2440     myRaytraceFBO1->ColorTexture()->Bind (theGlContext, GL_TEXTURE0 + OpenGl_RT_FsaaInputTexture);
2441
2442     aResult &= theGlContext->BindProgram (myPostFSAAProgram);
2443
2444     aResult &= setUniformState (theCView,
2445                                 theOrigins,
2446                                 theDirects,
2447                                 theUnviewMat,
2448                                 1, // ID of FSAA program
2449                                 theGlContext);
2450
2451     // Perform multi-pass adaptive FSAA using ping-pong technique.
2452     // We use 'FLIPTRI' sampling pattern changing for every pixel
2453     // (3 additional samples per pixel, the 1st sample is already
2454     // available from initial ray-traced image).
2455     for (Standard_Integer anIt = 1; anIt < 4; ++anIt)
2456     {
2457       GLfloat aOffsetX = 1.f / theSizeX;
2458       GLfloat aOffsetY = 1.f / theSizeY;
2459
2460       if (anIt == 1)
2461       {
2462         aOffsetX *= -0.55f;
2463         aOffsetY *=  0.55f;
2464       }
2465       else if (anIt == 2)
2466       {
2467         aOffsetX *=  0.00f;
2468         aOffsetY *= -0.55f;
2469       }
2470       else if (anIt == 3)
2471       {
2472         aOffsetX *= 0.55f;
2473         aOffsetY *= 0.00f;
2474       }
2475
2476       aResult &= myPostFSAAProgram->SetUniform (theGlContext,
2477         myUniformLocations[1][OpenGl_RT_uSamples], anIt + 1);
2478       aResult &= myPostFSAAProgram->SetUniform (theGlContext,
2479         myUniformLocations[1][OpenGl_RT_uOffsetX], aOffsetX);
2480       aResult &= myPostFSAAProgram->SetUniform (theGlContext,
2481         myUniformLocations[1][OpenGl_RT_uOffsetY], aOffsetY);
2482
2483       Handle(OpenGl_FrameBuffer)& aFramebuffer = anIt % 2 ? myRaytraceFBO2 : myRaytraceFBO1;
2484
2485       if (anIt == 3) // disable FBO on last iteration
2486       {
2487         if (theReadDrawFbo != NULL)
2488         {
2489           theReadDrawFbo->BindBuffer (theGlContext);
2490         }
2491         else
2492         {
2493           aFramebuffer->UnbindBuffer (theGlContext);
2494         }
2495       }
2496       else
2497       {
2498         aFramebuffer->BindBuffer (theGlContext);
2499       }
2500
2501       theGlContext->core20fwd->glDrawArrays (GL_TRIANGLES, 0, 6);
2502
2503       if (anIt != 3) // set input for the next pass
2504       {
2505         aFramebuffer->ColorTexture()->Bind (theGlContext, GL_TEXTURE0 + OpenGl_RT_FsaaInputTexture);
2506       }
2507     }
2508   }
2509
2510   unbindRaytraceTextures (theGlContext);
2511
2512   theGlContext->BindProgram (NULL);
2513
2514   return aResult;
2515 }
2516
2517 // =======================================================================
2518 // function : raytrace
2519 // purpose  : Redraws the window using OpenGL/GLSL ray-tracing
2520 // =======================================================================
2521 Standard_Boolean OpenGl_View::raytrace (const Graphic3d_CView&        theCView,
2522                                         const Standard_Integer        theSizeX,
2523                                         const Standard_Integer        theSizeY,
2524                                         OpenGl_FrameBuffer*           theReadDrawFbo,
2525                                         const Handle(OpenGl_Context)& theGlContext)
2526 {
2527   if (!initRaytraceResources (theCView, theGlContext))
2528   {
2529     return Standard_False;
2530   }
2531
2532   if (!resizeRaytraceBuffers (theSizeX, theSizeY, theGlContext))
2533   {
2534     return Standard_False;
2535   }
2536
2537   if (!updateRaytraceEnvironmentMap (theGlContext))
2538   {
2539     return Standard_False;
2540   }
2541
2542   // Get model-view and projection matrices
2543   OpenGl_Mat4 aOrientationMatrix = myCamera->OrientationMatrixF();
2544   OpenGl_Mat4 aViewMappingMatrix = theGlContext->ProjectionState.Current();
2545
2546   OpenGl_Mat4 aInverOrientMatrix;
2547   aOrientationMatrix.Inverted (aInverOrientMatrix);
2548   if (!updateRaytraceLightSources (aInverOrientMatrix, theGlContext))
2549   {
2550     return Standard_False;
2551   }
2552
2553   OpenGl_Vec3 aOrigins[4];
2554   OpenGl_Vec3 aDirects[4];
2555   OpenGl_Mat4 anUnviewMat;
2556
2557   updateCamera (aOrientationMatrix,
2558                 aViewMappingMatrix,
2559                 aOrigins,
2560                 aDirects,
2561                 anUnviewMat);
2562
2563   glDisable (GL_BLEND);
2564   glDisable (GL_DEPTH_TEST);
2565
2566   if (theReadDrawFbo != NULL)
2567   {
2568     theReadDrawFbo->BindBuffer (theGlContext);
2569   }
2570
2571   // Generate ray-traced image
2572   if (myIsRaytraceDataValid)
2573   {
2574     myRaytraceScreenQuad.BindVertexAttrib (theGlContext, Graphic3d_TOA_POS);
2575
2576     if (!myRaytraceGeometry.AcquireTextures (theGlContext))
2577     {
2578       theGlContext->PushMessage (GL_DEBUG_SOURCE_APPLICATION_ARB, GL_DEBUG_TYPE_ERROR_ARB,
2579         0, GL_DEBUG_SEVERITY_MEDIUM_ARB, "Error: Failed to acquire OpenGL image textures");
2580     }
2581
2582     Standard_Boolean aResult = runRaytraceShaders (theCView,
2583                                                    theSizeX,
2584                                                    theSizeY,
2585                                                    aOrigins,
2586                                                    aDirects,
2587                                                    anUnviewMat,
2588                                                    theReadDrawFbo,
2589                                                    theGlContext);
2590
2591     if (!aResult)
2592     {
2593       theGlContext->PushMessage (GL_DEBUG_SOURCE_APPLICATION_ARB, GL_DEBUG_TYPE_ERROR_ARB,
2594         0, GL_DEBUG_SEVERITY_MEDIUM_ARB, "Error: Failed to execute ray-tracing shaders");
2595     }
2596
2597     if (!myRaytraceGeometry.ReleaseTextures (theGlContext))
2598     {
2599       theGlContext->PushMessage (GL_DEBUG_SOURCE_APPLICATION_ARB, GL_DEBUG_TYPE_ERROR_ARB,
2600         0, GL_DEBUG_SEVERITY_MEDIUM_ARB, "Error: Failed to release OpenGL image textures");
2601     }
2602
2603     myRaytraceScreenQuad.UnbindVertexAttrib (theGlContext, Graphic3d_TOA_POS);
2604   }
2605
2606   glDisable (GL_BLEND);
2607   glEnable (GL_DEPTH_TEST);
2608
2609   return Standard_True;
2610 }