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