0024023: Revamp the OCCT Handle -- general
[occt.git] / src / OpenGl / OpenGl_Workspace.cxx
1 // Created on: 2011-09-20
2 // Created by: Sergey ZERCHANINOV
3 // Copyright (c) 2011-2014 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_GlCore15.hxx>
17 #include <OpenGl_ArbFBO.hxx>
18
19 #include <InterfaceGraphic.hxx>
20
21 #include <OpenGl_AspectLine.hxx>
22 #include <OpenGl_AspectFace.hxx>
23 #include <OpenGl_AspectMarker.hxx>
24 #include <OpenGl_AspectText.hxx>
25 #include <OpenGl_Context.hxx>
26 #include <OpenGl_Element.hxx>
27 #include <OpenGl_FrameBuffer.hxx>
28 #include <OpenGl_Structure.hxx>
29 #include <OpenGl_Sampler.hxx>
30 #include <OpenGl_ShaderManager.hxx>
31 #include <OpenGl_Texture.hxx>
32 #include <OpenGl_Utils.hxx>
33 #include <OpenGl_View.hxx>
34 #include <OpenGl_Workspace.hxx>
35
36 #include <Graphic3d_TextureParams.hxx>
37 #include <Graphic3d_GraphicDriver.hxx>
38
39 #if defined(_WIN32) && defined(HAVE_VIDEOCAPTURE)
40   #include <OpenGl_AVIWriter.hxx>
41 #endif
42
43
44 namespace
45 {
46   static const TEL_COLOUR  THE_WHITE_COLOR = { { 1.0f, 1.0f, 1.0f, 1.0f } };
47   static const OpenGl_Vec4 THE_BLACK_COLOR      (0.0f, 0.0f, 0.0f, 1.0f);
48
49   static const OpenGl_AspectLine myDefaultAspectLine;
50   static const OpenGl_AspectFace myDefaultAspectFace;
51   static const OpenGl_AspectMarker myDefaultAspectMarker;
52   static const OpenGl_AspectText myDefaultAspectText;
53
54   static const OpenGl_TextParam myDefaultTextParam =
55   {
56     16, Graphic3d_HTA_LEFT, Graphic3d_VTA_BOTTOM
57   };
58
59   static const OpenGl_Matrix myDefaultMatrix =
60   {
61     {{ 1.0F, 0.0F, 0.0F, 0.0F },
62      { 0.0F, 1.0F, 0.0F, 0.0F },
63      { 0.0F, 0.0F, 1.0F, 0.0F },
64      { 0.0F, 0.0F, 0.0F, 1.0F }}
65   };
66
67 };
68
69 // =======================================================================
70 // function : Init
71 // purpose  :
72 // =======================================================================
73 void OpenGl_Material::Init (const OPENGL_SURF_PROP& theProp)
74 {
75   // ambient component
76   if (theProp.color_mask & OPENGL_AMBIENT_MASK)
77   {
78     const float* aSrcAmb = theProp.isphysic ? theProp.ambcol.rgb : theProp.matcol.rgb;
79     Ambient = OpenGl_Vec4 (aSrcAmb[0] * theProp.amb,
80                            aSrcAmb[1] * theProp.amb,
81                            aSrcAmb[2] * theProp.amb,
82                            1.0f);
83   }
84   else
85   {
86     Ambient = THE_BLACK_COLOR;
87   }
88
89   // diffusion component
90   if (theProp.color_mask & OPENGL_DIFFUSE_MASK)
91   {
92     const float* aSrcDif = theProp.isphysic ? theProp.difcol.rgb : theProp.matcol.rgb;
93     Diffuse = OpenGl_Vec4 (aSrcDif[0] * theProp.diff,
94                            aSrcDif[1] * theProp.diff,
95                            aSrcDif[2] * theProp.diff,
96                            1.0f);
97   }
98   else
99   {
100     Diffuse = THE_BLACK_COLOR;
101   }
102
103   // specular component
104   if (theProp.color_mask & OPENGL_SPECULAR_MASK)
105   {
106     const float* aSrcSpe = theProp.isphysic ? theProp.speccol.rgb : THE_WHITE_COLOR.rgb;
107     Specular = OpenGl_Vec4 (aSrcSpe[0] * theProp.spec,
108                             aSrcSpe[1] * theProp.spec,
109                             aSrcSpe[2] * theProp.spec,
110                             1.0f);
111   }
112   else
113   {
114     Specular = THE_BLACK_COLOR;
115   }
116
117   // emission component
118   if (theProp.color_mask & OPENGL_EMISSIVE_MASK)
119   {
120     const float* aSrcEms = theProp.isphysic ? theProp.emscol.rgb : theProp.matcol.rgb;
121     Emission = OpenGl_Vec4 (aSrcEms[0] * theProp.emsv,
122                             aSrcEms[1] * theProp.emsv,
123                             aSrcEms[2] * theProp.emsv,
124                             1.0f);
125   }
126   else
127   {
128     Emission = THE_BLACK_COLOR;
129   }
130
131   ChangeShine()        = theProp.shine;
132   ChangeTransparency() = theProp.trans;
133 }
134
135 // =======================================================================
136 // function : OpenGl_Workspace
137 // purpose  :
138 // =======================================================================
139 OpenGl_Workspace::OpenGl_Workspace (const Handle(OpenGl_GraphicDriver)& theDriver,
140                                     const CALL_DEF_WINDOW&        theCWindow,
141                                     Aspect_RenderingContext       theGContext,
142                                     const Handle(OpenGl_Caps)&    theCaps,
143                                     const Handle(OpenGl_Context)& theShareCtx)
144 : OpenGl_Window (theDriver, theCWindow, theGContext, theCaps, theShareCtx),
145   NamedStatus (0),
146   HighlightColor (&THE_WHITE_COLOR),
147   //
148   myHasFboBlit (Standard_True),
149   //
150   myViewId               (-1),
151   myAntiAliasingMode     (3),
152   myTransientDrawToFront (Standard_True),
153   myBackBufferRestored   (Standard_False),
154   myIsImmediateDrawn     (Standard_False),
155   myUseZBuffer    (Standard_True),
156   myUseDepthWrite (Standard_True),
157   myUseGLLight (Standard_True),
158   myIsCullingEnabled (Standard_False),
159   myFrameCounter (0),
160   //
161   AspectLine_set (&myDefaultAspectLine),
162   AspectLine_applied (NULL),
163   AspectFace_set (&myDefaultAspectFace),
164   AspectFace_applied (NULL),
165   AspectMarker_set (&myDefaultAspectMarker),
166   AspectMarker_applied (NULL),
167   AspectText_set (&myDefaultAspectText),
168   AspectText_applied (NULL),
169   TextParam_set (&myDefaultTextParam),
170   TextParam_applied (NULL),
171   ViewMatrix_applied (&myDefaultMatrix),
172   StructureMatrix_applied (&myDefaultMatrix),
173   myCullingMode (TelCullUndefined),
174   myModelViewMatrix (myDefaultMatrix),
175   PolygonOffset_applied (THE_DEFAULT_POFFSET)
176 {
177   myGlContext->core11fwd->glPixelStorei (GL_UNPACK_ALIGNMENT, 1);
178   myMainSceneFbos[0]      = new OpenGl_FrameBuffer();
179   myMainSceneFbos[1]      = new OpenGl_FrameBuffer();
180   myImmediateSceneFbos[0] = new OpenGl_FrameBuffer();
181   myImmediateSceneFbos[1] = new OpenGl_FrameBuffer();
182
183   if (!myGlContext->GetResource ("OpenGl_LineAttributes", myLineAttribs))
184   {
185     // share and register for release once the resource is no longer used
186     myLineAttribs = new OpenGl_LineAttributes();
187     myGlContext->ShareResource ("OpenGl_LineAttributes", myLineAttribs);
188     myLineAttribs->Init (myGlContext);
189   }
190
191   // General initialization of the context
192
193 #if !defined(GL_ES_VERSION_2_0)
194   if (myGlContext->core11 != NULL)
195   {
196     // Eviter d'avoir les faces mal orientees en noir.
197     // Pourrait etre utiliser pour detecter les problemes d'orientation
198     glLightModeli ((GLenum )GL_LIGHT_MODEL_TWO_SIDE, GL_TRUE);
199
200     // Optimisation pour le Fog et l'antialiasing
201     glHint (GL_FOG_HINT,            GL_FASTEST);
202     glHint (GL_POINT_SMOOTH_HINT,   GL_FASTEST);
203   }
204
205   glHint (GL_LINE_SMOOTH_HINT,    GL_FASTEST);
206   glHint (GL_POLYGON_SMOOTH_HINT, GL_FASTEST);
207 #endif
208
209   // AA mode
210   const char* anAaEnv = ::getenv ("CALL_OPENGL_ANTIALIASING_MODE");
211   if (anAaEnv != NULL)
212   {
213     int v;
214     if (sscanf (anAaEnv, "%d", &v) > 0) myAntiAliasingMode = v;
215   }
216
217   myDefaultCappingAlgoFilter         = new OpenGl_CappingAlgoFilter();
218   myNoneCulling.ChangeCullingMode()  = TelCullNone;
219   myNoneCulling.ChangeEdge()         = 0;
220   myFrontCulling.ChangeCullingMode() = TelCullBack;
221   myFrontCulling.ChangeEdge()        = 0;
222 }
223
224 // =======================================================================
225 // function : SetImmediateModeDrawToFront
226 // purpose  :
227 // =======================================================================
228 Standard_Boolean OpenGl_Workspace::SetImmediateModeDrawToFront (const Standard_Boolean theDrawToFrontBuffer)
229 {
230   const Standard_Boolean aPrevMode = myTransientDrawToFront;
231   myTransientDrawToFront = theDrawToFrontBuffer;
232   return aPrevMode;
233 }
234
235 inline void nullifyGlResource (Handle(OpenGl_Resource)&      theResource,
236                                const Handle(OpenGl_Context)& theCtx)
237 {
238   if (!theResource.IsNull())
239   {
240     theResource->Release (theCtx.operator->());
241     theResource.Nullify();
242   }
243 }
244
245 // =======================================================================
246 // function : ~OpenGl_Workspace
247 // purpose  :
248 // =======================================================================
249 OpenGl_Workspace::~OpenGl_Workspace()
250 {
251   if (!myLineAttribs.IsNull())
252   {
253     myLineAttribs.Nullify();
254     myGlContext->ReleaseResource ("OpenGl_LineAttributes", Standard_True);
255   }
256
257   nullifyGlResource (myMainSceneFbos[0],      myGlContext);
258   nullifyGlResource (myMainSceneFbos[1],      myGlContext);
259   nullifyGlResource (myImmediateSceneFbos[0], myGlContext);
260   nullifyGlResource (myImmediateSceneFbos[1], myGlContext);
261
262   myFullScreenQuad.Release (myGlContext.operator->());
263 }
264
265 // =======================================================================
266 // function : Activate
267 // purpose  :
268 // =======================================================================
269 Standard_Boolean OpenGl_Workspace::Activate()
270 {
271   if (!OpenGl_Window::Activate())
272     return Standard_False;
273
274   ViewMatrix_applied      = &myDefaultMatrix;
275   StructureMatrix_applied = &myDefaultMatrix;
276
277   ResetAppliedAspect();
278
279   return Standard_True;
280 }
281
282 //=======================================================================
283 //function : ResetAppliedAspect
284 //purpose  : Sets default values of GL parameters in accordance with default aspects
285 //=======================================================================
286 void OpenGl_Workspace::ResetAppliedAspect()
287 {
288   myGlContext->BindDefaultVao();
289
290   NamedStatus           = !myTextureBound.IsNull() ? OPENGL_NS_TEXTURE : 0;
291   HighlightColor        = &THE_WHITE_COLOR;
292   AspectLine_set        = &myDefaultAspectLine;
293   AspectLine_applied    = NULL;
294   AspectFace_set        = &myDefaultAspectFace;
295   AspectFace_applied    = NULL;
296   AspectMarker_set      = &myDefaultAspectMarker;
297   AspectMarker_applied  = NULL;
298   AspectText_set        = &myDefaultAspectText;
299   AspectText_applied    = NULL;
300   TextParam_set         = &myDefaultTextParam;
301   TextParam_applied     = NULL;
302   PolygonOffset_applied = THE_DEFAULT_POFFSET;
303   myCullingMode         = TelCullUndefined;
304
305   AspectLine(Standard_True);
306   AspectFace(Standard_True);
307   AspectMarker(Standard_True);
308   AspectText(Standard_True);
309
310   myGlContext->SetTypeOfLine (myDefaultAspectLine.Type());
311   myGlContext->SetLineWidth  (myDefaultAspectLine.Width());
312 }
313
314 // =======================================================================
315 // function : DisableTexture
316 // purpose  :
317 // =======================================================================
318 Handle(OpenGl_Texture) OpenGl_Workspace::DisableTexture()
319 {
320   if (myTextureBound.IsNull())
321   {
322     return myTextureBound;
323   }
324
325   const Handle(OpenGl_Sampler)& aSampler = myGlContext->TextureSampler();
326   if (!aSampler.IsNull())
327   {
328     aSampler->Unbind (*myGlContext);
329   }
330
331 #if !defined(GL_ES_VERSION_2_0)
332   // reset texture matrix because some code may expect it is identity
333   if (myGlContext->core11 != NULL)
334   {
335     GLint aMatrixMode = GL_TEXTURE;
336     glGetIntegerv (GL_MATRIX_MODE, &aMatrixMode);
337     glMatrixMode (GL_TEXTURE);
338     glLoadIdentity();
339     glMatrixMode (aMatrixMode);
340   }
341 #endif
342
343   myTextureBound->Unbind (myGlContext);
344   switch (myTextureBound->GetTarget())
345   {
346   #if !defined(GL_ES_VERSION_2_0)
347     case GL_TEXTURE_1D:
348     {
349       if (myGlContext->core11 != NULL)
350       {
351         if (myTextureBound->GetParams()->GenMode() != GL_NONE)
352         {
353           glDisable (GL_TEXTURE_GEN_S);
354         }
355         glDisable (GL_TEXTURE_1D);
356       }
357       break;
358     }
359   #endif
360     case GL_TEXTURE_2D:
361     {
362     #if !defined(GL_ES_VERSION_2_0)
363       if (myGlContext->core11 != NULL)
364       {
365         if (myTextureBound->GetParams()->GenMode() != GL_NONE)
366         {
367           glDisable (GL_TEXTURE_GEN_S);
368           glDisable (GL_TEXTURE_GEN_T);
369           if (myTextureBound->GetParams()->GenMode() == Graphic3d_TOTM_SPRITE)
370           {
371             glDisable (GL_POINT_SPRITE);
372           }
373         }
374         glDisable (GL_TEXTURE_2D);
375       }
376     #endif
377       break;
378     }
379     default: break;
380   }
381
382   Handle(OpenGl_Texture) aPrevTexture = myTextureBound;
383   myTextureBound.Nullify();
384   return aPrevTexture;
385 }
386
387 // =======================================================================
388 // function : setTextureParams
389 // purpose  :
390 // =======================================================================
391 void OpenGl_Workspace::setTextureParams (Handle(OpenGl_Texture)&                theTexture,
392                                          const Handle(Graphic3d_TextureParams)& theParams)
393 {
394   const Handle(Graphic3d_TextureParams)& aParams = theParams.IsNull() ? theTexture->GetParams() : theParams;
395   if (aParams.IsNull())
396   {
397     return;
398   }
399
400 #if !defined(GL_ES_VERSION_2_0)
401   GLint aMatrixMode = GL_TEXTURE;
402   if (myGlContext->core11 != NULL)
403   {
404     glGetIntegerv (GL_MATRIX_MODE, &aMatrixMode);
405
406     // setup texture matrix
407     glMatrixMode (GL_TEXTURE);
408     OpenGl_Mat4 aTextureMat;
409     const Graphic3d_Vec2& aScale = aParams->Scale();
410     const Graphic3d_Vec2& aTrans = aParams->Translation();
411     OpenGl_Utils::Scale     (aTextureMat,  aScale.x(),  aScale.y(), 1.0f);
412     OpenGl_Utils::Translate (aTextureMat, -aTrans.x(), -aTrans.y(), 0.0f);
413     OpenGl_Utils::Rotate    (aTextureMat, -aParams->Rotation(), 0.0f, 0.0f, 1.0f);
414     glLoadMatrixf (aTextureMat);
415
416     GLint anEnvMode = GL_MODULATE; // lighting mode
417     if (!aParams->IsModulate())
418     {
419       anEnvMode = GL_DECAL;
420       if (theTexture->GetFormat() == GL_ALPHA
421        || theTexture->GetFormat() == GL_LUMINANCE)
422       {
423         anEnvMode = GL_REPLACE;
424       }
425     }
426
427     // setup generation of texture coordinates
428     switch (aParams->GenMode())
429     {
430       case Graphic3d_TOTM_OBJECT:
431       {
432         glTexGeni  (GL_S, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);
433         glTexGenfv (GL_S, GL_OBJECT_PLANE,     aParams->GenPlaneS().GetData());
434         if (theTexture->GetTarget() != GL_TEXTURE_1D)
435         {
436           glTexGeni  (GL_T, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);
437           glTexGenfv (GL_T, GL_OBJECT_PLANE,     aParams->GenPlaneT().GetData());
438         }
439         break;
440       }
441       case Graphic3d_TOTM_SPHERE:
442       {
443         glTexGeni (GL_S, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP);
444         if (theTexture->GetTarget() != GL_TEXTURE_1D)
445         {
446           glTexGeni (GL_T, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP);
447         }
448         break;
449       }
450       case Graphic3d_TOTM_EYE:
451       {
452         myGlContext->WorldViewState.Push();
453
454         myGlContext->WorldViewState.SetIdentity();
455         myGlContext->ApplyWorldViewMatrix();
456
457         glTexGeni  (GL_S, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
458         glTexGenfv (GL_S, GL_EYE_PLANE,        aParams->GenPlaneS().GetData());
459
460         if (theTexture->GetTarget() != GL_TEXTURE_1D)
461         {
462           glTexGeni  (GL_T, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
463           glTexGenfv (GL_T, GL_EYE_PLANE,        aParams->GenPlaneT().GetData());
464         }
465
466         myGlContext->WorldViewState.Pop();
467
468         break;
469       }
470       case Graphic3d_TOTM_SPRITE:
471       {
472         if (GetGlContext()->core20fwd != NULL)
473         {
474           glEnable  (GL_POINT_SPRITE);
475           glTexEnvi (GL_POINT_SPRITE, GL_COORD_REPLACE, GL_TRUE);
476           anEnvMode = GL_REPLACE;
477           GetGlContext()->core15->glPointParameteri (GL_POINT_SPRITE_COORD_ORIGIN, GL_LOWER_LEFT);
478         }
479         break;
480       }
481       case Graphic3d_TOTM_MANUAL:
482       default: break;
483     }
484
485     // setup lighting
486     glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, anEnvMode);
487   }
488 #endif
489
490   // get active sampler object to override default texture parameters
491   const Handle(OpenGl_Sampler)& aSampler = myGlContext->TextureSampler();
492
493   // setup texture filtering and wrapping
494   //if (theTexture->GetParams() != theParams)
495   const GLenum aFilter   = (aParams->Filter() == Graphic3d_TOTF_NEAREST) ? GL_NEAREST : GL_LINEAR;
496   const GLenum aWrapMode = aParams->IsRepeat() ? GL_REPEAT : myGlContext->TextureWrapClamp();
497   switch (theTexture->GetTarget())
498   {
499   #if !defined(GL_ES_VERSION_2_0)
500     case GL_TEXTURE_1D:
501     {
502       if (aSampler.IsNull() || !aSampler->IsValid())
503       {
504         glTexParameteri (GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, aFilter);
505         glTexParameteri (GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, aFilter);
506         glTexParameteri (GL_TEXTURE_1D, GL_TEXTURE_WRAP_S,     aWrapMode);
507       }
508       else
509       {
510         aSampler->SetParameter (*myGlContext, GL_TEXTURE_MAG_FILTER, aFilter);
511         aSampler->SetParameter (*myGlContext, GL_TEXTURE_MIN_FILTER, aFilter);
512         aSampler->SetParameter (*myGlContext, GL_TEXTURE_WRAP_S,     aWrapMode);
513       }
514
515       break;
516     }
517   #endif
518     case GL_TEXTURE_2D:
519     {
520       GLenum aFilterMin = aFilter;
521       if (theTexture->HasMipmaps())
522       {
523         aFilterMin = GL_NEAREST_MIPMAP_NEAREST;
524         if (aParams->Filter() == Graphic3d_TOTF_BILINEAR)
525         {
526           aFilterMin = GL_LINEAR_MIPMAP_NEAREST;
527         }
528         else if (aParams->Filter() == Graphic3d_TOTF_TRILINEAR)
529         {
530           aFilterMin = GL_LINEAR_MIPMAP_LINEAR;
531         }
532
533         if (myGlContext->extAnis)
534         {
535           // setup degree of anisotropy filter
536           const GLint aMaxDegree = myGlContext->MaxDegreeOfAnisotropy();
537           GLint aDegree;
538           switch (aParams->AnisoFilter())
539           {
540             case Graphic3d_LOTA_QUALITY:
541             {
542               aDegree = aMaxDegree;
543               break;
544             }
545             case Graphic3d_LOTA_MIDDLE:
546             {
547               aDegree = (aMaxDegree <= 4) ? 2 : (aMaxDegree / 2);
548               break;
549             }
550             case Graphic3d_LOTA_FAST:
551             {
552               aDegree = 2;
553               break;
554             }
555             case Graphic3d_LOTA_OFF:
556             default:
557             {
558               aDegree = 1;
559               break;
560             }
561           }
562
563           if (aSampler.IsNull() || !aSampler->IsValid())
564           {
565             glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, aDegree);
566           }
567           else
568           {
569             aSampler->SetParameter (*myGlContext, GL_TEXTURE_MAX_ANISOTROPY_EXT, aDegree);
570           }
571         }
572       }
573
574       if (aSampler.IsNull() || !aSampler->IsValid())
575       {
576         glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, aFilterMin);
577         glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, aFilter);
578         glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S,     aWrapMode);
579         glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T,     aWrapMode);
580       }
581       else
582       {
583         aSampler->SetParameter (*myGlContext, GL_TEXTURE_MIN_FILTER, aFilterMin);
584         aSampler->SetParameter (*myGlContext, GL_TEXTURE_MAG_FILTER, aFilter);
585         aSampler->SetParameter (*myGlContext, GL_TEXTURE_WRAP_S,     aWrapMode);
586         aSampler->SetParameter (*myGlContext, GL_TEXTURE_WRAP_T,     aWrapMode);
587       }
588
589       break;
590     }
591     default: break;
592   }
593
594   switch (theTexture->GetTarget())
595   {
596   #if !defined(GL_ES_VERSION_2_0)
597     case GL_TEXTURE_1D:
598     {
599       if (myGlContext->core11 != NULL)
600       {
601         if (aParams->GenMode() != Graphic3d_TOTM_MANUAL)
602         {
603           glEnable (GL_TEXTURE_GEN_S);
604         }
605         glEnable (GL_TEXTURE_1D);
606       }
607       break;
608     }
609   #endif
610     case GL_TEXTURE_2D:
611     {
612     #if !defined(GL_ES_VERSION_2_0)
613       if (myGlContext->core11 != NULL)
614       {
615         if (aParams->GenMode() != Graphic3d_TOTM_MANUAL)
616         {
617           glEnable (GL_TEXTURE_GEN_S);
618           glEnable (GL_TEXTURE_GEN_T);
619         }
620         glEnable (GL_TEXTURE_2D);
621       }
622     #endif
623       break;
624     }
625     default: break;
626   }
627
628 #if !defined(GL_ES_VERSION_2_0)
629   if (myGlContext->core11 != NULL)
630   {
631     glMatrixMode (aMatrixMode); // turn back active matrix
632   }
633 #endif
634   theTexture->SetParams (aParams);
635 }
636
637 // =======================================================================
638 // function : EnableTexture
639 // purpose  :
640 // =======================================================================
641 Handle(OpenGl_Texture) OpenGl_Workspace::EnableTexture (const Handle(OpenGl_Texture)&          theTexture,
642                                                         const Handle(Graphic3d_TextureParams)& theParams)
643 {
644   if (theTexture.IsNull() || !theTexture->IsValid())
645   {
646     return DisableTexture();
647   }
648
649   if (myTextureBound == theTexture
650    && (theParams.IsNull() || theParams == theTexture->GetParams()))
651   {
652     // already bound
653     return myTextureBound;
654   }
655
656   Handle(OpenGl_Texture) aPrevTexture = DisableTexture();
657   myTextureBound = theTexture;
658   myTextureBound->Bind (myGlContext);
659   setTextureParams (myTextureBound, theParams);
660
661   // If custom sampler object is available it will be
662   // used for overriding default texture parameters
663   const Handle(OpenGl_Sampler)& aSampler = myGlContext->TextureSampler();
664
665   if (!aSampler.IsNull() && aSampler->IsValid())
666   {
667     aSampler->Bind (*myGlContext);
668   }
669
670   return aPrevTexture;
671 }
672
673 // =======================================================================
674 // function : bindDefaultFbo
675 // purpose  :
676 // =======================================================================
677 void OpenGl_Workspace::bindDefaultFbo (OpenGl_FrameBuffer* theCustomFbo)
678 {
679   OpenGl_FrameBuffer* anFbo = (theCustomFbo != NULL && theCustomFbo->IsValid())
680                             ?  theCustomFbo
681                             : (!myGlContext->DefaultFrameBuffer().IsNull()
682                              && myGlContext->DefaultFrameBuffer()->IsValid()
683                               ? myGlContext->DefaultFrameBuffer().operator->()
684                               : NULL);
685   if (anFbo != NULL)
686   {
687     anFbo->BindBuffer (myGlContext);
688   }
689   else
690   {
691   #if !defined(GL_ES_VERSION_2_0)
692     myGlContext->SetReadDrawBuffer (GL_BACK);
693   #else
694     if (myGlContext->arbFBO != NULL)
695     {
696       myGlContext->arbFBO->glBindFramebuffer (GL_FRAMEBUFFER, OpenGl_FrameBuffer::NO_FRAMEBUFFER);
697     }
698   #endif
699   }
700   myGlContext->core11fwd->glViewport (0, 0, myWidth, myHeight);
701 }
702
703 // =======================================================================
704 // function : blitBuffers
705 // purpose  :
706 // =======================================================================
707 bool OpenGl_Workspace::blitBuffers (OpenGl_FrameBuffer* theReadFbo,
708                                     OpenGl_FrameBuffer* theDrawFbo)
709 {
710   if (theReadFbo == NULL)
711   {
712     return false;
713   }
714   else if (theReadFbo == theDrawFbo)
715   {
716     return true;
717   }
718
719   // clear destination before blitting
720   if (theDrawFbo != NULL
721   &&  theDrawFbo->IsValid())
722   {
723     theDrawFbo->BindBuffer (myGlContext);
724   }
725   else
726   {
727     myGlContext->arbFBO->glBindFramebuffer (GL_FRAMEBUFFER, OpenGl_FrameBuffer::NO_FRAMEBUFFER);
728   }
729 #if !defined(GL_ES_VERSION_2_0)
730   myGlContext->core20fwd->glClearDepth  (1.0);
731 #else
732   myGlContext->core20fwd->glClearDepthf (1.0f);
733 #endif
734   myGlContext->core20fwd->glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
735
736 /*#if !defined(GL_ES_VERSION_2_0)
737   if (myGlContext->arbFBOBlit != NULL)
738   {
739     theReadFbo->BindReadBuffer (myGlContext);
740     if (theDrawFbo != NULL
741      && theDrawFbo->IsValid())
742     {
743       theDrawFbo->BindDrawBuffer (myGlContext);
744     }
745     else
746     {
747       myGlContext->arbFBO->glBindFramebuffer (GL_DRAW_FRAMEBUFFER, OpenGl_FrameBuffer::NO_FRAMEBUFFER);
748     }
749     // we don't copy stencil buffer here... does it matter for performance?
750     myGlContext->arbFBOBlit->glBlitFramebuffer (0, 0, theReadFbo->GetVPSizeX(), theReadFbo->GetVPSizeY(),
751                                                 0, 0, theReadFbo->GetVPSizeX(), theReadFbo->GetVPSizeY(),
752                                                 GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT, GL_NEAREST);
753
754     if (theDrawFbo != NULL
755       && theDrawFbo->IsValid())
756     {
757       theDrawFbo->BindBuffer (myGlContext);
758     }
759     else
760     {
761       myGlContext->arbFBO->glBindFramebuffer (GL_FRAMEBUFFER, OpenGl_FrameBuffer::NO_FRAMEBUFFER);
762     }
763   }
764   else
765 #endif*/
766   {
767     myGlContext->core20fwd->glDepthFunc (GL_ALWAYS);
768     myGlContext->core20fwd->glDepthMask (GL_TRUE);
769     myGlContext->core20fwd->glEnable (GL_DEPTH_TEST);
770
771     DisableTexture();
772     if (!myFullScreenQuad.IsValid())
773     {
774       OpenGl_Vec4 aQuad[4] =
775       {
776         OpenGl_Vec4( 1.0f, -1.0f, 1.0f, 0.0f),
777         OpenGl_Vec4( 1.0f,  1.0f, 1.0f, 1.0f),
778         OpenGl_Vec4(-1.0f, -1.0f, 0.0f, 0.0f),
779         OpenGl_Vec4(-1.0f,  1.0f, 0.0f, 1.0f)
780       };
781       myFullScreenQuad.Init (myGlContext, 4, 4, aQuad[0].GetData());
782     }
783
784     const Handle(OpenGl_ShaderManager)& aManager = myGlContext->ShaderManager();
785     if (myFullScreenQuad.IsValid()
786      && aManager->BindFboBlitProgram())
787     {
788       theReadFbo->ColorTexture()       ->Bind   (myGlContext, GL_TEXTURE0 + 0);
789       theReadFbo->DepthStencilTexture()->Bind   (myGlContext, GL_TEXTURE0 + 1);
790       myFullScreenQuad.BindVertexAttrib (myGlContext, Graphic3d_TOA_POS);
791
792       myGlContext->core20fwd->glDrawArrays (GL_TRIANGLE_STRIP, 0, 4);
793
794       myFullScreenQuad.UnbindVertexAttrib (myGlContext, Graphic3d_TOA_POS);
795       theReadFbo->DepthStencilTexture()->Unbind (myGlContext, GL_TEXTURE0 + 1);
796       theReadFbo->ColorTexture()       ->Unbind (myGlContext, GL_TEXTURE0 + 0);
797     }
798     else
799     {
800       TCollection_ExtendedString aMsg = TCollection_ExtendedString()
801         + "Error! FBO blitting has failed";
802       myGlContext->PushMessage (GL_DEBUG_SOURCE_APPLICATION_ARB,
803                                 GL_DEBUG_TYPE_ERROR_ARB,
804                                 0,
805                                 GL_DEBUG_SEVERITY_HIGH_ARB,
806                                 aMsg);
807       myHasFboBlit = Standard_False;
808       theReadFbo->Release (myGlContext.operator->());
809       return true;
810     }
811   }
812   return true;
813 }
814
815 // =======================================================================
816 // function : drawStereoPair
817 // purpose  :
818 // =======================================================================
819 void OpenGl_Workspace::drawStereoPair (const Graphic3d_CView& theCView)
820 {
821   OpenGl_FrameBuffer* aPair[2] =
822   {
823     myImmediateSceneFbos[0]->IsValid() ? myImmediateSceneFbos[0].operator->() : NULL,
824     myImmediateSceneFbos[1]->IsValid() ? myImmediateSceneFbos[1].operator->() : NULL
825   };
826   if (aPair[0] == NULL
827   ||  aPair[1] == NULL
828   || !myTransientDrawToFront)
829   {
830     aPair[0] = myMainSceneFbos[0]->IsValid() ? myMainSceneFbos[0].operator->() : NULL;
831     aPair[1] = myMainSceneFbos[1]->IsValid() ? myMainSceneFbos[1].operator->() : NULL;
832   }
833
834   if (aPair[0] == NULL
835    || aPair[1] == NULL)
836   {
837     return;
838   }
839
840   Standard_Boolean toReverse = theCView.RenderParams.ToReverseStereo;
841   const Standard_Boolean isOddY = (theCView.DefWindow.top + theCView.DefWindow.dy) % 2 == 1;
842   const Standard_Boolean isOddX =  theCView.DefWindow.left % 2 == 1;
843   if (isOddY
844    && (theCView.RenderParams.StereoMode == Graphic3d_StereoMode_RowInterlaced
845     || theCView.RenderParams.StereoMode == Graphic3d_StereoMode_ChessBoard))
846   {
847     toReverse = !toReverse;
848   }
849   if (isOddX
850    && (theCView.RenderParams.StereoMode == Graphic3d_StereoMode_ColumnInterlaced
851     || theCView.RenderParams.StereoMode == Graphic3d_StereoMode_ChessBoard))
852   {
853     toReverse = !toReverse;
854   }
855
856   if (toReverse)
857   {
858     std::swap (aPair[0], aPair[1]);
859   }
860
861   myGlContext->core20fwd->glDepthFunc (GL_ALWAYS);
862   myGlContext->core20fwd->glDepthMask (GL_TRUE);
863   myGlContext->core20fwd->glEnable (GL_DEPTH_TEST);
864
865   DisableTexture();
866   if (!myFullScreenQuad.IsValid())
867   {
868     OpenGl_Vec4 aQuad[4] =
869     {
870       OpenGl_Vec4( 1.0f, -1.0f, 1.0f, 0.0f),
871       OpenGl_Vec4( 1.0f,  1.0f, 1.0f, 1.0f),
872       OpenGl_Vec4(-1.0f, -1.0f, 0.0f, 0.0f),
873       OpenGl_Vec4(-1.0f,  1.0f, 0.0f, 1.0f)
874     };
875     myFullScreenQuad.Init (myGlContext, 4, 4, aQuad[0].GetData());
876   }
877
878   const Handle(OpenGl_ShaderManager)& aManager = myGlContext->ShaderManager();
879   if (myFullScreenQuad.IsValid()
880    && aManager->BindStereoProgram (theCView.RenderParams.StereoMode))
881   {
882     if (theCView.RenderParams.StereoMode == Graphic3d_StereoMode_Anaglyph)
883     {
884       OpenGl_Mat4 aFilterL, aFilterR;
885       aFilterL.SetDiagonal (Graphic3d_Vec4 (0.0f, 0.0f, 0.0f, 0.0f));
886       aFilterR.SetDiagonal (Graphic3d_Vec4 (0.0f, 0.0f, 0.0f, 0.0f));
887       switch (theCView.RenderParams.AnaglyphFilter)
888       {
889         case Graphic3d_RenderingParams::Anaglyph_RedCyan_Simple:
890         {
891           aFilterL.SetRow (0, Graphic3d_Vec4 (1.0f, 0.0f, 0.0f, 0.0f));
892           aFilterR.SetRow (1, Graphic3d_Vec4 (0.0f, 1.0f, 0.0f, 0.0f));
893           aFilterR.SetRow (2, Graphic3d_Vec4 (0.0f, 0.0f, 1.0f, 0.0f));
894           break;
895         }
896         case Graphic3d_RenderingParams::Anaglyph_RedCyan_Optimized:
897         {
898           aFilterL.SetRow (0, Graphic3d_Vec4 ( 0.4154f,      0.4710f,      0.16666667f, 0.0f));
899           aFilterL.SetRow (1, Graphic3d_Vec4 (-0.0458f,     -0.0484f,     -0.0257f,     0.0f));
900           aFilterL.SetRow (2, Graphic3d_Vec4 (-0.0547f,     -0.0615f,      0.0128f,     0.0f));
901           aFilterL.SetRow (3, Graphic3d_Vec4 ( 0.0f,         0.0f,         0.0f,        0.0f));
902           aFilterR.SetRow (0, Graphic3d_Vec4 (-0.01090909f, -0.03636364f, -0.00606061f, 0.0f));
903           aFilterR.SetRow (1, Graphic3d_Vec4 ( 0.37560000f,  0.73333333f,  0.01111111f, 0.0f));
904           aFilterR.SetRow (2, Graphic3d_Vec4 (-0.06510000f, -0.12870000f,  1.29710000f, 0.0f));
905           aFilterR.SetRow (3, Graphic3d_Vec4 ( 0.0f,                0.0f,  0.0f,        0.0f));
906           break;
907         }
908         case Graphic3d_RenderingParams::Anaglyph_YellowBlue_Simple:
909         {
910           aFilterL.SetRow (0, Graphic3d_Vec4 (1.0f, 0.0f, 0.0f, 0.0f));
911           aFilterL.SetRow (1, Graphic3d_Vec4 (0.0f, 1.0f, 0.0f, 0.0f));
912           aFilterR.SetRow (2, Graphic3d_Vec4 (0.0f, 0.0f, 1.0f, 0.0f));
913           break;
914         }
915         case Graphic3d_RenderingParams::Anaglyph_YellowBlue_Optimized:
916         {
917           aFilterL.SetRow (0, Graphic3d_Vec4 ( 1.062f, -0.205f,  0.299f, 0.0f));
918           aFilterL.SetRow (1, Graphic3d_Vec4 (-0.026f,  0.908f,  0.068f, 0.0f));
919           aFilterL.SetRow (2, Graphic3d_Vec4 (-0.038f, -0.173f,  0.022f, 0.0f));
920           aFilterL.SetRow (3, Graphic3d_Vec4 ( 0.0f,    0.0f,    0.0f,   0.0f));
921           aFilterR.SetRow (0, Graphic3d_Vec4 (-0.016f, -0.123f, -0.017f, 0.0f));
922           aFilterR.SetRow (1, Graphic3d_Vec4 ( 0.006f,  0.062f, -0.017f, 0.0f));
923           aFilterR.SetRow (2, Graphic3d_Vec4 ( 0.094f,  0.185f,  0.911f, 0.0f));
924           aFilterR.SetRow (3, Graphic3d_Vec4 ( 0.0f,    0.0f,    0.0f,   0.0f));
925           break;
926         }
927         case Graphic3d_RenderingParams::Anaglyph_GreenMagenta_Simple:
928         {
929           aFilterR.SetRow (0, Graphic3d_Vec4 (1.0f, 0.0f, 0.0f, 0.0f));
930           aFilterL.SetRow (1, Graphic3d_Vec4 (0.0f, 1.0f, 0.0f, 0.0f));
931           aFilterR.SetRow (2, Graphic3d_Vec4 (0.0f, 0.0f, 1.0f, 0.0f));
932           break;
933         }
934         case Graphic3d_RenderingParams::Anaglyph_UserDefined:
935         {
936           aFilterL = theCView.RenderParams.AnaglyphLeft;
937           aFilterR = theCView.RenderParams.AnaglyphRight;
938           break;
939         }
940       }
941       myGlContext->ActiveProgram()->SetUniform (myGlContext, "uMultL", aFilterL);
942       myGlContext->ActiveProgram()->SetUniform (myGlContext, "uMultR", aFilterR);
943     }
944
945     aPair[0]->ColorTexture()->Bind (myGlContext, GL_TEXTURE0 + 0);
946     aPair[1]->ColorTexture()->Bind (myGlContext, GL_TEXTURE0 + 1);
947     myFullScreenQuad.BindVertexAttrib (myGlContext, 0);
948
949     myGlContext->core20fwd->glDrawArrays (GL_TRIANGLE_STRIP, 0, 4);
950
951     myFullScreenQuad.UnbindVertexAttrib (myGlContext, 0);
952     aPair[1]->ColorTexture()->Unbind (myGlContext, GL_TEXTURE0 + 1);
953     aPair[0]->ColorTexture()->Unbind (myGlContext, GL_TEXTURE0 + 0);
954   }
955   else
956   {
957     TCollection_ExtendedString aMsg = TCollection_ExtendedString()
958       + "Error! Anaglyph has failed";
959     myGlContext->PushMessage (GL_DEBUG_SOURCE_APPLICATION_ARB,
960                               GL_DEBUG_TYPE_ERROR_ARB,
961                               0,
962                               GL_DEBUG_SEVERITY_HIGH_ARB,
963                               aMsg);
964   }
965 }
966
967 // =======================================================================
968 // function : Redraw
969 // purpose  :
970 // =======================================================================
971 void OpenGl_Workspace::Redraw (const Graphic3d_CView& theCView,
972                                const Aspect_CLayer2d& theCUnderLayer,
973                                const Aspect_CLayer2d& theCOverLayer)
974 {
975   if (!Activate())
976   {
977     return;
978   }
979
980   if (mySwapInterval != myGlContext->caps->swapInterval)
981   {
982     mySwapInterval = myGlContext->caps->swapInterval;
983     myGlContext->SetSwapInterval (mySwapInterval);
984   }
985
986   ++myFrameCounter;
987   myIsCullingEnabled = theCView.IsCullingEnabled;
988   const Graphic3d_StereoMode      aStereoMode  = theCView.RenderParams.StereoMode;
989   const Handle(Graphic3d_Camera)& aCamera      = myView->Camera();
990   Graphic3d_Camera::Projection    aProjectType = aCamera->ProjectionType();
991
992   // release pending GL resources
993   myGlContext->ReleaseDelayed();
994
995   // fetch OpenGl context state
996   myGlContext->FetchState();
997
998   OpenGl_FrameBuffer* aFrameBuffer = (OpenGl_FrameBuffer* )theCView.ptrFBO;
999   bool toSwap = myGlContext->IsRender()
1000             && !myGlContext->caps->buffersNoSwap
1001             &&  aFrameBuffer == NULL;
1002
1003   Standard_Integer aSizeX = aFrameBuffer != NULL ? aFrameBuffer->GetVPSizeX() : myWidth;
1004   Standard_Integer aSizeY = aFrameBuffer != NULL ? aFrameBuffer->GetVPSizeY() : myHeight;
1005
1006   if ( aFrameBuffer == NULL
1007    && !myGlContext->DefaultFrameBuffer().IsNull()
1008    &&  myGlContext->DefaultFrameBuffer()->IsValid())
1009   {
1010     aFrameBuffer = myGlContext->DefaultFrameBuffer().operator->();
1011   }
1012
1013   if (myHasFboBlit
1014    && (myTransientDrawToFront || aProjectType == Graphic3d_Camera::Projection_Stereo))
1015   {
1016     if (myMainSceneFbos[0]->GetVPSizeX() != aSizeX
1017      || myMainSceneFbos[0]->GetVPSizeY() != aSizeY)
1018     {
1019       // prepare FBOs containing main scene
1020       // for further blitting and rendering immediate presentations on top
1021       if (myGlContext->core20fwd != NULL)
1022       {
1023         myMainSceneFbos[0]->Init (myGlContext, aSizeX, aSizeY);
1024       }
1025     }
1026   }
1027   else
1028   {
1029     myMainSceneFbos     [0]->Release (myGlContext.operator->());
1030     myMainSceneFbos     [1]->Release (myGlContext.operator->());
1031     myImmediateSceneFbos[0]->Release (myGlContext.operator->());
1032     myImmediateSceneFbos[1]->Release (myGlContext.operator->());
1033     myMainSceneFbos     [0]->ChangeViewport (0, 0);
1034     myMainSceneFbos     [1]->ChangeViewport (0, 0);
1035     myImmediateSceneFbos[0]->ChangeViewport (0, 0);
1036     myImmediateSceneFbos[1]->ChangeViewport (0, 0);
1037   }
1038
1039   if (aProjectType == Graphic3d_Camera::Projection_Stereo
1040    && myMainSceneFbos[0]->IsValid())
1041   {
1042     myMainSceneFbos[1]->InitLazy (myGlContext, aSizeX, aSizeY);
1043     if (!myMainSceneFbos[1]->IsValid())
1044     {
1045       // no enough memory?
1046       aProjectType = Graphic3d_Camera::Projection_Perspective;
1047     }
1048     else if (!myTransientDrawToFront)
1049     {
1050       //
1051     }
1052     else if (!myGlContext->HasStereoBuffers()
1053            || aStereoMode != Graphic3d_StereoMode_QuadBuffer)
1054     {
1055       myImmediateSceneFbos[0]->InitLazy (myGlContext, aSizeX, aSizeY);
1056       myImmediateSceneFbos[1]->InitLazy (myGlContext, aSizeX, aSizeY);
1057       if (!myImmediateSceneFbos[0]->IsValid()
1058        || !myImmediateSceneFbos[1]->IsValid())
1059       {
1060         aProjectType = Graphic3d_Camera::Projection_Perspective;
1061       }
1062     }
1063   }
1064
1065   if (aProjectType == Graphic3d_Camera::Projection_Stereo)
1066   {
1067     OpenGl_FrameBuffer* aMainFbos[2] =
1068     {
1069       myMainSceneFbos[0]->IsValid() ? myMainSceneFbos[0].operator->() : NULL,
1070       myMainSceneFbos[1]->IsValid() ? myMainSceneFbos[1].operator->() : NULL
1071     };
1072     OpenGl_FrameBuffer* anImmFbos[2] =
1073     {
1074       myImmediateSceneFbos[0]->IsValid() ? myImmediateSceneFbos[0].operator->() : NULL,
1075       myImmediateSceneFbos[1]->IsValid() ? myImmediateSceneFbos[1].operator->() : NULL
1076     };
1077
1078     if (!myTransientDrawToFront)
1079     {
1080       anImmFbos[0] = aMainFbos[0];
1081       anImmFbos[1] = aMainFbos[1];
1082     }
1083     else if (aStereoMode == Graphic3d_StereoMode_SoftPageFlip
1084           || aStereoMode == Graphic3d_StereoMode_QuadBuffer)
1085     {
1086       anImmFbos[0] = NULL;
1087       anImmFbos[1] = NULL;
1088     }
1089
1090   #if !defined(GL_ES_VERSION_2_0)
1091     myGlContext->SetReadDrawBuffer (aStereoMode == Graphic3d_StereoMode_QuadBuffer ? GL_BACK_LEFT : GL_BACK);
1092   #endif
1093     redraw1 (theCView, theCUnderLayer, theCOverLayer,
1094              aMainFbos[0], Graphic3d_Camera::Projection_MonoLeftEye);
1095     myBackBufferRestored = Standard_True;
1096     myIsImmediateDrawn   = Standard_False;
1097   #if !defined(GL_ES_VERSION_2_0)
1098     myGlContext->SetReadDrawBuffer (aStereoMode == Graphic3d_StereoMode_QuadBuffer ? GL_BACK_LEFT : GL_BACK);
1099   #endif
1100     if (!redrawImmediate (theCView, theCOverLayer, theCUnderLayer, aMainFbos[0], aProjectType, anImmFbos[0]))
1101     {
1102       toSwap = false;
1103     }
1104     else if (aStereoMode == Graphic3d_StereoMode_SoftPageFlip
1105           && toSwap)
1106     {
1107       myGlContext->SwapBuffers();
1108     }
1109
1110   #if !defined(GL_ES_VERSION_2_0)
1111     myGlContext->SetReadDrawBuffer (aStereoMode == Graphic3d_StereoMode_QuadBuffer ? GL_BACK_RIGHT : GL_BACK);
1112   #endif
1113     redraw1 (theCView, theCUnderLayer, theCOverLayer,
1114              aMainFbos[1], Graphic3d_Camera::Projection_MonoRightEye);
1115     myBackBufferRestored = Standard_True;
1116     myIsImmediateDrawn   = Standard_False;
1117     if (!redrawImmediate (theCView, theCOverLayer, theCUnderLayer, aMainFbos[1], aProjectType, anImmFbos[1]))
1118     {
1119       toSwap = false;
1120     }
1121
1122     if (anImmFbos[0] != NULL)
1123     {
1124       bindDefaultFbo (aFrameBuffer);
1125       drawStereoPair (theCView);
1126     }
1127   }
1128   else
1129   {
1130     OpenGl_FrameBuffer* aMainFbo = myMainSceneFbos[0]->IsValid() ? myMainSceneFbos[0].operator->() : NULL;
1131   #if !defined(GL_ES_VERSION_2_0)
1132     if (aMainFbo     == NULL
1133      && aFrameBuffer == NULL)
1134     {
1135       myGlContext->SetReadDrawBuffer (GL_BACK);
1136     }
1137   #endif
1138     redraw1 (theCView, theCUnderLayer, theCOverLayer,
1139              aMainFbo != NULL ? aMainFbo : aFrameBuffer, aProjectType);
1140     myBackBufferRestored = Standard_True;
1141     myIsImmediateDrawn   = Standard_False;
1142     if (!redrawImmediate (theCView, theCOverLayer, theCUnderLayer, aMainFbo, aProjectType, aFrameBuffer))
1143     {
1144       toSwap = false;
1145     }
1146   }
1147
1148 #if defined(_WIN32) && defined(HAVE_VIDEOCAPTURE)
1149   if (OpenGl_AVIWriter_AllowWriting (theCView.DefWindow.XWindow))
1150   {
1151     GLint params[4];
1152     glGetIntegerv (GL_VIEWPORT, params);
1153     int nWidth  = params[2] & ~0x7;
1154     int nHeight = params[3] & ~0x7;
1155
1156     const int nBitsPerPixel = 24;
1157     GLubyte* aDumpData = new GLubyte[nWidth * nHeight * nBitsPerPixel / 8];
1158
1159     glPixelStorei (GL_PACK_ALIGNMENT, 1);
1160     glReadPixels (0, 0, nWidth, nHeight, GL_BGR_EXT, GL_UNSIGNED_BYTE, aDumpData);
1161     OpenGl_AVIWriter_AVIWriter (aDumpData, nWidth, nHeight, nBitsPerPixel);
1162     delete[] aDumpData;
1163   }
1164 #endif
1165
1166   // bind default FBO
1167   bindDefaultFbo();
1168
1169   // Swap the buffers
1170   if (toSwap)
1171   {
1172     GetGlContext()->SwapBuffers();
1173     if (!myMainSceneFbos[0]->IsValid())
1174     {
1175       myBackBufferRestored = Standard_False;
1176     }
1177   }
1178   else
1179   {
1180     myGlContext->core11fwd->glFlush();
1181   }
1182
1183   // reset render mode state
1184   myGlContext->FetchState();
1185 }
1186
1187 // =======================================================================
1188 // function : redraw1
1189 // purpose  :
1190 // =======================================================================
1191 void OpenGl_Workspace::redraw1 (const Graphic3d_CView&               theCView,
1192                                 const Aspect_CLayer2d&               theCUnderLayer,
1193                                 const Aspect_CLayer2d&               theCOverLayer,
1194                                 OpenGl_FrameBuffer*                  theReadDrawFbo,
1195                                 const Graphic3d_Camera::Projection   theProjection)
1196 {
1197   if (myView.IsNull())
1198   {
1199     return;
1200   }
1201
1202   if (theReadDrawFbo != NULL)
1203   {
1204     theReadDrawFbo->BindBuffer    (myGlContext);
1205     theReadDrawFbo->SetupViewport (myGlContext);
1206   }
1207   else
1208   {
1209     myGlContext->core11fwd->glViewport (0, 0, myWidth, myHeight);
1210   }
1211
1212   // request reset of material
1213   NamedStatus |= OPENGL_NS_RESMAT;
1214
1215   myUseZBuffer    = Standard_True;
1216   myUseDepthWrite = Standard_True;
1217   GLbitfield toClear = GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT;
1218   glDepthFunc (GL_LEQUAL);
1219   glDepthMask (GL_TRUE);
1220   glEnable (GL_DEPTH_TEST);
1221
1222 #if !defined(GL_ES_VERSION_2_0)
1223   glClearDepth (1.0);
1224 #else
1225   glClearDepthf (1.0f);
1226 #endif
1227
1228   if (NamedStatus & OPENGL_NS_WHITEBACK)
1229   {
1230     // set background to white
1231     glClearColor (1.0f, 1.0f, 1.0f, 1.0f);
1232   }
1233   else
1234   {
1235     glClearColor (myBgColor.rgb[0], myBgColor.rgb[1], myBgColor.rgb[2], 0.0f);
1236   }
1237
1238   glClear (toClear);
1239
1240   Handle(OpenGl_Workspace) aWS (this);
1241   myView->Render (myPrintContext, aWS, theReadDrawFbo, theProjection, theCView, theCUnderLayer, theCOverLayer, Standard_False);
1242 }
1243
1244 // =======================================================================
1245 // function : copyBackToFront
1246 // purpose  :
1247 // =======================================================================
1248 void OpenGl_Workspace::copyBackToFront()
1249 {
1250 #if !defined(GL_ES_VERSION_2_0)
1251
1252   OpenGl_Mat4 aProjectMat;
1253   OpenGl_Utils::Ortho2D<Standard_ShortReal> (aProjectMat,
1254     0.f, static_cast<GLfloat> (myWidth), 0.f, static_cast<GLfloat> (myHeight));
1255
1256   myGlContext->WorldViewState.Push();
1257   myGlContext->ProjectionState.Push();
1258
1259   myGlContext->WorldViewState.SetIdentity();
1260   myGlContext->ProjectionState.SetCurrent (aProjectMat);
1261
1262   myGlContext->ApplyProjectionMatrix();
1263   myGlContext->ApplyWorldViewMatrix();
1264
1265   DisableFeatures();
1266
1267   switch (myGlContext->DrawBuffer())
1268   {
1269     case GL_BACK_LEFT:
1270     {
1271       myGlContext->SetReadBuffer (GL_BACK_LEFT);
1272       myGlContext->SetDrawBuffer (GL_FRONT_LEFT);
1273       break;
1274     }
1275     case GL_BACK_RIGHT:
1276     {
1277       myGlContext->SetReadBuffer (GL_BACK_RIGHT);
1278       myGlContext->SetDrawBuffer (GL_FRONT_RIGHT);
1279       break;
1280     }
1281     default:
1282     {
1283       myGlContext->SetReadBuffer (GL_BACK);
1284       myGlContext->SetDrawBuffer (GL_FRONT);
1285       break;
1286     }
1287   }
1288
1289   glRasterPos2i (0, 0);
1290   glCopyPixels  (0, 0, myWidth + 1, myHeight + 1, GL_COLOR);
1291   //glCopyPixels  (0, 0, myWidth + 1, myHeight + 1, GL_DEPTH);
1292
1293   EnableFeatures();
1294
1295   myGlContext->WorldViewState.Pop();
1296   myGlContext->ProjectionState.Pop();
1297   myGlContext->ApplyProjectionMatrix();
1298
1299   // read/write from front buffer now
1300   myGlContext->SetReadBuffer (myGlContext->DrawBuffer());
1301 #endif
1302   myIsImmediateDrawn = Standard_False;
1303 }
1304
1305 // =======================================================================
1306 // function : DisplayCallback
1307 // purpose  :
1308 // =======================================================================
1309 void OpenGl_Workspace::DisplayCallback (const Graphic3d_CView& theCView,
1310                                         Standard_Integer       theReason)
1311 {
1312   if (theCView.GDisplayCB == NULL)
1313   {
1314     return;
1315   }
1316
1317   Aspect_GraphicCallbackStruct aCallData;
1318   aCallData.reason    = theReason;
1319   aCallData.glContext = myGlContext;
1320   aCallData.wsID      = theCView.WsId;
1321   aCallData.viewID    = theCView.ViewId;
1322   aCallData.IsCoreProfile = (myGlContext->core11 == NULL);
1323   theCView.GDisplayCB (theCView.DefWindow.XWindow, theCView.GClientData, &aCallData);
1324 }
1325
1326 // =======================================================================
1327 // function : RedrawImmediate
1328 // purpose  :
1329 // =======================================================================
1330 void OpenGl_Workspace::RedrawImmediate (const Graphic3d_CView& theCView,
1331                                         const Aspect_CLayer2d& theCUnderLayer,
1332                                         const Aspect_CLayer2d& theCOverLayer)
1333 {
1334   const Handle(Graphic3d_Camera)& aCamera      = myView->Camera();
1335   Graphic3d_Camera::Projection    aProjectType = aCamera->ProjectionType();
1336   OpenGl_FrameBuffer* aFrameBuffer = (OpenGl_FrameBuffer* )theCView.ptrFBO;
1337   if ( aFrameBuffer == NULL
1338    && !myGlContext->DefaultFrameBuffer().IsNull()
1339    &&  myGlContext->DefaultFrameBuffer()->IsValid())
1340   {
1341     aFrameBuffer = myGlContext->DefaultFrameBuffer().operator->();
1342   }
1343
1344   const Graphic3d_StereoMode aStereoMode = theCView.RenderParams.StereoMode;
1345   if (aProjectType == Graphic3d_Camera::Projection_Stereo)
1346   {
1347     if (aFrameBuffer != NULL)
1348     {
1349       // implicitly switch to mono camera for image dump
1350       aProjectType = Graphic3d_Camera::Projection_Perspective;
1351     }
1352     else if (myMainSceneFbos[0]->IsValid()
1353          && !myMainSceneFbos[1]->IsValid())
1354     {
1355       aProjectType = Graphic3d_Camera::Projection_Perspective;
1356     }
1357   }
1358
1359   if (!myTransientDrawToFront
1360    || !myBackBufferRestored
1361    || (myGlContext->caps->buffersNoSwap && !myMainSceneFbos[0]->IsValid()))
1362   {
1363     Redraw (theCView, theCUnderLayer, theCOverLayer);
1364     return;
1365   }
1366   else if (!Activate())
1367   {
1368     return;
1369   }
1370
1371   bool toSwap = false;
1372   if (aProjectType == Graphic3d_Camera::Projection_Stereo)
1373   {
1374     OpenGl_FrameBuffer* aMainFbos[2] =
1375     {
1376       myMainSceneFbos[0]->IsValid() ? myMainSceneFbos[0].operator->() : NULL,
1377       myMainSceneFbos[1]->IsValid() ? myMainSceneFbos[1].operator->() : NULL
1378     };
1379     OpenGl_FrameBuffer* anImmFbos[2] =
1380     {
1381       myImmediateSceneFbos[0]->IsValid() ? myImmediateSceneFbos[0].operator->() : NULL,
1382       myImmediateSceneFbos[1]->IsValid() ? myImmediateSceneFbos[1].operator->() : NULL
1383     };
1384     if (aStereoMode == Graphic3d_StereoMode_SoftPageFlip
1385      || aStereoMode == Graphic3d_StereoMode_QuadBuffer)
1386     {
1387       anImmFbos[0] = NULL;
1388       anImmFbos[1] = NULL;
1389     }
1390
1391     if (myGlContext->arbFBO != NULL)
1392     {
1393       myGlContext->arbFBO->glBindFramebuffer (GL_FRAMEBUFFER, OpenGl_FrameBuffer::NO_FRAMEBUFFER);
1394     }
1395   #if !defined(GL_ES_VERSION_2_0)
1396     if (anImmFbos[0] == NULL)
1397     {
1398       myGlContext->SetReadDrawBuffer (aStereoMode == Graphic3d_StereoMode_QuadBuffer ? GL_BACK_LEFT : GL_BACK);
1399     }
1400   #endif
1401     toSwap = redrawImmediate (theCView, theCUnderLayer, theCOverLayer,
1402                               aMainFbos[0],
1403                               Graphic3d_Camera::Projection_MonoLeftEye,
1404                               anImmFbos[0],
1405                               Standard_True) || toSwap;
1406     if (aStereoMode == Graphic3d_StereoMode_SoftPageFlip
1407     &&  toSwap
1408     && !myGlContext->caps->buffersNoSwap)
1409     {
1410       myGlContext->SwapBuffers();
1411     }
1412
1413     if (myGlContext->arbFBO != NULL)
1414     {
1415       myGlContext->arbFBO->glBindFramebuffer (GL_FRAMEBUFFER, OpenGl_FrameBuffer::NO_FRAMEBUFFER);
1416     }
1417   #if !defined(GL_ES_VERSION_2_0)
1418     if (anImmFbos[1] == NULL)
1419     {
1420       myGlContext->SetReadDrawBuffer (aStereoMode == Graphic3d_StereoMode_QuadBuffer ? GL_BACK_RIGHT : GL_BACK);
1421     }
1422   #endif
1423     toSwap = redrawImmediate (theCView, theCUnderLayer, theCOverLayer,
1424                               aMainFbos[1],
1425                               Graphic3d_Camera::Projection_MonoRightEye,
1426                               anImmFbos[1],
1427                               Standard_True) || toSwap;
1428     if (anImmFbos[0] != NULL)
1429     {
1430       bindDefaultFbo (aFrameBuffer);
1431       drawStereoPair (theCView);
1432     }
1433   }
1434   else
1435   {
1436     OpenGl_FrameBuffer* aMainFbo = myMainSceneFbos[0]->IsValid() ? myMainSceneFbos[0].operator->() : NULL;
1437   #if !defined(GL_ES_VERSION_2_0)
1438     if (aMainFbo == NULL)
1439     {
1440       myGlContext->SetReadDrawBuffer (GL_BACK);
1441     }
1442   #endif
1443     toSwap = redrawImmediate (theCView, theCUnderLayer, theCOverLayer,
1444                               aMainFbo,
1445                               aProjectType,
1446                               aFrameBuffer,
1447                               Standard_True) || toSwap;
1448   }
1449
1450   // bind default FBO
1451   bindDefaultFbo();
1452
1453   if (toSwap
1454   && !myGlContext->caps->buffersNoSwap)
1455   {
1456     myGlContext->SwapBuffers();
1457   }
1458   else
1459   {
1460     myGlContext->core11fwd->glFlush();
1461   }
1462 }
1463
1464 // =======================================================================
1465 // function : redrawImmediate
1466 // purpose  :
1467 // =======================================================================
1468 bool OpenGl_Workspace::redrawImmediate (const Graphic3d_CView& theCView,
1469                                         const Aspect_CLayer2d& theCUnderLayer,
1470                                         const Aspect_CLayer2d& theCOverLayer,
1471                                         OpenGl_FrameBuffer*    theReadFbo,
1472                                         const Graphic3d_Camera::Projection theProjection,
1473                                         OpenGl_FrameBuffer*    theDrawFbo,
1474                                         const Standard_Boolean theIsPartialUpdate)
1475 {
1476   GLboolean toCopyBackToFront = GL_FALSE;
1477   if (!myTransientDrawToFront)
1478   {
1479     myBackBufferRestored = Standard_False;
1480   }
1481   else if (theReadFbo != NULL
1482         && theReadFbo->IsValid()
1483         && myGlContext->IsRender())
1484   {
1485     if (!blitBuffers (theReadFbo, theDrawFbo))
1486     {
1487       return true;
1488     }
1489   }
1490   else if (theDrawFbo == NULL)
1491   {
1492   #if !defined(GL_ES_VERSION_2_0)
1493     myGlContext->core11fwd->glGetBooleanv (GL_DOUBLEBUFFER, &toCopyBackToFront);
1494   #endif
1495     if (toCopyBackToFront)
1496     {
1497       if (!myView->HasImmediateStructures()
1498        && !theIsPartialUpdate)
1499       {
1500         // prefer Swap Buffers within Redraw in compatibility mode (without FBO)
1501         return true;
1502       }
1503       copyBackToFront();
1504     }
1505     else
1506     {
1507       myBackBufferRestored = Standard_False;
1508     }
1509   }
1510   else
1511   {
1512     myBackBufferRestored = Standard_False;
1513   }
1514   myIsImmediateDrawn = Standard_True;
1515
1516   Handle(OpenGl_Workspace) aWS (this);
1517
1518   myUseZBuffer    = Standard_True;
1519   myUseDepthWrite = Standard_True;
1520   glDepthFunc (GL_LEQUAL);
1521   glDepthMask (GL_TRUE);
1522   glEnable (GL_DEPTH_TEST);
1523 #if !defined(GL_ES_VERSION_2_0)
1524   glClearDepth (1.0);
1525 #else
1526   glClearDepthf (1.0f);
1527 #endif
1528
1529   myView->Render (myPrintContext, aWS, theDrawFbo, theProjection,
1530                   theCView, theCUnderLayer, theCOverLayer, Standard_True);
1531   if (!myView->ImmediateStructures().IsEmpty())
1532   {
1533     myUseZBuffer = Standard_False;
1534     glDisable (GL_DEPTH_TEST);
1535   }
1536   for (OpenGl_IndexedMapOfStructure::Iterator anIter (myView->ImmediateStructures()); anIter.More(); anIter.Next())
1537   {
1538     const OpenGl_Structure* aStructure = anIter.Value();
1539     if (!aStructure->IsVisible())
1540     {
1541       continue;
1542     }
1543
1544     aStructure->Render (aWS);
1545   }
1546
1547   return !toCopyBackToFront;
1548 }
1549
1550
1551 // =======================================================================
1552 // function : CanRender
1553 // purpose  :
1554 // =======================================================================
1555 Standard_Boolean OpenGl_RaytraceFilter::CanRender (const OpenGl_Element* theElement)
1556 {
1557   Standard_Boolean aPrevFilterResult = Standard_True;
1558   if (!myPrevRenderFilter.IsNull())
1559   {
1560     aPrevFilterResult = myPrevRenderFilter->CanRender (theElement);
1561   }
1562   return aPrevFilterResult &&
1563     !OpenGl_Raytrace::IsRaytracedElement (theElement);
1564 }