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