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