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