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