0027961: Visualization - remove unused and no more working OpenGl_AVIWriter
[occt.git] / src / OpenGl / OpenGl_View_Redraw.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 <stdio.h>
17 #include <stdlib.h>
18
19 #include <OpenGl_GlCore11.hxx>
20
21 #include <Graphic3d_GraphicDriver.hxx>
22 #include <Graphic3d_TextureParams.hxx>
23 #include <Graphic3d_Texture2Dmanual.hxx>
24 #include <Graphic3d_TransformUtils.hxx>
25 #include <Image_AlienPixMap.hxx>
26
27 #include <NCollection_Mat4.hxx>
28
29 #include <OpenGl_AspectLine.hxx>
30 #include <OpenGl_Context.hxx>
31 #include <OpenGl_Matrix.hxx>
32 #include <OpenGl_Workspace.hxx>
33 #include <OpenGl_View.hxx>
34 #include <OpenGl_Trihedron.hxx>
35 #include <OpenGl_GraduatedTrihedron.hxx>
36 #include <OpenGl_PrimitiveArray.hxx>
37 #include <OpenGl_ShaderManager.hxx>
38 #include <OpenGl_ShaderProgram.hxx>
39 #include <OpenGl_Structure.hxx>
40 #include <OpenGl_ArbFBO.hxx>
41
42 #define EPSI 0.0001
43
44 namespace
45 {
46   static const GLfloat THE_DEFAULT_AMBIENT[4]    = { 0.0f, 0.0f, 0.0f, 1.0f };
47   static const GLfloat THE_DEFAULT_SPOT_DIR[3]   = { 0.0f, 0.0f, -1.0f };
48   static const GLfloat THE_DEFAULT_SPOT_EXPONENT = 0.0f;
49   static const GLfloat THE_DEFAULT_SPOT_CUTOFF   = 180.0f;
50 }
51
52 extern void InitLayerProp (const int theListId); //szvgl: defined in OpenGl_GraphicDriver_Layer.cxx
53
54 #if !defined(GL_ES_VERSION_2_0)
55
56 //=======================================================================
57 //function : bindLight
58 //purpose  :
59 //=======================================================================
60 static void bindLight (const OpenGl_Light&             theLight,
61                        GLenum&                         theLightGlId,
62                        Graphic3d_Vec4&                 theAmbientColor,
63                        const Handle(OpenGl_Workspace)& theWorkspace)
64 {
65   // Only 8 lights in OpenGL...
66   if (theLightGlId > GL_LIGHT7)
67   {
68     return;
69   }
70
71   if (theLight.Type == Graphic3d_TOLS_AMBIENT)
72   {
73     // add RGBA intensity of the ambient light
74     theAmbientColor += theLight.Color;
75     return;
76   }
77
78   const Handle(OpenGl_Context)& aContext = theWorkspace->GetGlContext();
79
80   // the light is a headlight?
81   if (theLight.IsHeadlight)
82   {
83     aContext->WorldViewState.Push();
84     aContext->WorldViewState.SetIdentity();
85
86     aContext->ApplyWorldViewMatrix();
87   }
88
89   // setup light type
90   switch (theLight.Type)
91   {
92     case Graphic3d_TOLS_AMBIENT    : break; // handled by separate if-clause at beginning of method
93     case Graphic3d_TOLS_DIRECTIONAL:
94     {
95       // if the last parameter of GL_POSITION, is zero, the corresponding light source is a Directional one
96       const OpenGl_Vec4 anInfDir = -theLight.Direction;
97
98       // to create a realistic effect,  set the GL_SPECULAR parameter to the same value as the GL_DIFFUSE.
99       glLightfv (theLightGlId, GL_AMBIENT,               THE_DEFAULT_AMBIENT);
100       glLightfv (theLightGlId, GL_DIFFUSE,               theLight.Color.GetData());
101       glLightfv (theLightGlId, GL_SPECULAR,              theLight.Color.GetData());
102       glLightfv (theLightGlId, GL_POSITION,              anInfDir.GetData());
103       glLightfv (theLightGlId, GL_SPOT_DIRECTION,        THE_DEFAULT_SPOT_DIR);
104       glLightf  (theLightGlId, GL_SPOT_EXPONENT,         THE_DEFAULT_SPOT_EXPONENT);
105       glLightf  (theLightGlId, GL_SPOT_CUTOFF,           THE_DEFAULT_SPOT_CUTOFF);
106       break;
107     }
108     case Graphic3d_TOLS_POSITIONAL:
109     {
110       // to create a realistic effect, set the GL_SPECULAR parameter to the same value as the GL_DIFFUSE
111       glLightfv (theLightGlId, GL_AMBIENT,               THE_DEFAULT_AMBIENT);
112       glLightfv (theLightGlId, GL_DIFFUSE,               theLight.Color.GetData());
113       glLightfv (theLightGlId, GL_SPECULAR,              theLight.Color.GetData());
114       glLightfv (theLightGlId, GL_POSITION,              theLight.Position.GetData());
115       glLightfv (theLightGlId, GL_SPOT_DIRECTION,        THE_DEFAULT_SPOT_DIR);
116       glLightf  (theLightGlId, GL_SPOT_EXPONENT,         THE_DEFAULT_SPOT_EXPONENT);
117       glLightf  (theLightGlId, GL_SPOT_CUTOFF,           THE_DEFAULT_SPOT_CUTOFF);
118       glLightf  (theLightGlId, GL_CONSTANT_ATTENUATION,  theLight.ConstAttenuation());
119       glLightf  (theLightGlId, GL_LINEAR_ATTENUATION,    theLight.LinearAttenuation());
120       glLightf  (theLightGlId, GL_QUADRATIC_ATTENUATION, 0.0);
121       break;
122     }
123     case Graphic3d_TOLS_SPOT:
124     {
125       glLightfv (theLightGlId, GL_AMBIENT,               THE_DEFAULT_AMBIENT);
126       glLightfv (theLightGlId, GL_DIFFUSE,               theLight.Color.GetData());
127       glLightfv (theLightGlId, GL_SPECULAR,              theLight.Color.GetData());
128       glLightfv (theLightGlId, GL_POSITION,              theLight.Position.GetData());
129       glLightfv (theLightGlId, GL_SPOT_DIRECTION,        theLight.Direction.GetData());
130       glLightf  (theLightGlId, GL_SPOT_EXPONENT,         theLight.Concentration() * 128.0f);
131       glLightf  (theLightGlId, GL_SPOT_CUTOFF,          (theLight.Angle() * 180.0f) / GLfloat(M_PI));
132       glLightf  (theLightGlId, GL_CONSTANT_ATTENUATION,  theLight.ConstAttenuation());
133       glLightf  (theLightGlId, GL_LINEAR_ATTENUATION,    theLight.LinearAttenuation());
134       glLightf  (theLightGlId, GL_QUADRATIC_ATTENUATION, 0.0f);
135       break;
136     }
137   }
138
139   // restore matrix in case of headlight
140   if (theLight.IsHeadlight)
141   {
142     aContext->WorldViewState.Pop();
143   }
144
145   glEnable (theLightGlId++);
146 }
147 #endif
148
149 //=======================================================================
150 //function : drawBackground
151 //purpose  :
152 //=======================================================================
153 void OpenGl_View::drawBackground (const Handle(OpenGl_Workspace)& theWorkspace)
154 {
155   const Handle(OpenGl_Context)& aCtx = theWorkspace->GetGlContext();
156
157   if ((theWorkspace->NamedStatus & OPENGL_NS_WHITEBACK) != 0 // no background
158     || (!myBgTextureArray->IsDefined()                       // no texture
159      && !myBgGradientArray->IsDefined()))                    // no gradient
160   {
161     return;
162   }
163
164   const Standard_Boolean wasUsedZBuffer = theWorkspace->SetUseZBuffer (Standard_False);
165   if (wasUsedZBuffer)
166   {
167     aCtx->core11fwd->glDisable (GL_DEPTH_TEST);
168   }
169
170   // Drawing background gradient if:
171   // - gradient fill type is not Aspect_GFM_NONE and
172   // - either background texture is no specified or it is drawn in Aspect_FM_CENTERED mode
173   if (myBgGradientArray->IsDefined()
174     && (!myTextureParams->Aspect()->ToMapTexture()
175       || myBgTextureArray->TextureFillMethod() == Aspect_FM_CENTERED
176       || myBgTextureArray->TextureFillMethod() == Aspect_FM_NONE))
177   {
178   #if !defined(GL_ES_VERSION_2_0)
179     GLint aShadingModelOld = GL_SMOOTH;
180     if (aCtx->core11 != NULL)
181     {
182       aCtx->core11fwd->glDisable (GL_LIGHTING);
183       aCtx->core11fwd->glGetIntegerv (GL_SHADE_MODEL, &aShadingModelOld);
184       aCtx->core11->glShadeModel (GL_SMOOTH);
185     }
186   #endif
187
188     myBgGradientArray->Render (theWorkspace);
189
190   #if !defined(GL_ES_VERSION_2_0)
191     if (aCtx->core11 != NULL)
192     {
193       aCtx->core11->glShadeModel (aShadingModelOld);
194     }
195   #endif
196   }
197
198   // Drawing background image if it is defined
199   // (texture is defined and fill type is not Aspect_FM_NONE)
200   if (myBgTextureArray->IsDefined()
201    && myTextureParams->Aspect()->ToMapTexture())
202   {
203     aCtx->core11fwd->glDisable (GL_BLEND);
204
205     const OpenGl_AspectFace* anOldAspectFace = theWorkspace->SetAspectFace (myTextureParams);
206     myBgTextureArray->Render (theWorkspace);
207     theWorkspace->SetAspectFace (anOldAspectFace);
208   }
209
210   if (wasUsedZBuffer)
211   {
212     theWorkspace->SetUseZBuffer (Standard_True);
213     aCtx->core11fwd->glEnable (GL_DEPTH_TEST);
214   }
215 }
216
217 //=======================================================================
218 //function : Redraw
219 //purpose  :
220 //=======================================================================
221 void OpenGl_View::Redraw()
222 {
223   const Standard_Boolean wasDisabledMSAA = myToDisableMSAA;
224   const Standard_Boolean hadFboBlit      = myHasFboBlit;
225   if (myRenderParams.Method == Graphic3d_RM_RAYTRACING
226   && !myCaps->vboDisable
227   && !myCaps->keepArrayData)
228   {
229     if (myWasRedrawnGL)
230     {
231       myDeviceLostFlag = Standard_True;
232     }
233
234     myCaps->keepArrayData = Standard_True;
235   }
236
237   if (!myWorkspace->Activate())
238   {
239     return;
240   }
241
242   myWindow->SetSwapInterval();
243
244   ++myFrameCounter;
245   const Graphic3d_StereoMode      aStereoMode  = myRenderParams.StereoMode;
246   Graphic3d_Camera::Projection    aProjectType = myCamera->ProjectionType();
247   Handle(OpenGl_Context)          aCtx         = myWorkspace->GetGlContext();
248
249   // release pending GL resources
250   aCtx->ReleaseDelayed();
251
252   // fetch OpenGl context state
253   aCtx->FetchState();
254
255   // set resolution ratio
256   aCtx->SetResolutionRatio (RenderingParams().ResolutionRatio());
257
258   OpenGl_FrameBuffer* aFrameBuffer = myFBO.operator->();
259   bool toSwap = aCtx->IsRender()
260             && !aCtx->caps->buffersNoSwap
261             &&  aFrameBuffer == NULL;
262
263   Standard_Integer aSizeX = aFrameBuffer != NULL ? aFrameBuffer->GetVPSizeX() : myWindow->Width();
264   Standard_Integer aSizeY = aFrameBuffer != NULL ? aFrameBuffer->GetVPSizeY() : myWindow->Height();
265
266   // determine multisampling parameters
267   Standard_Integer aNbSamples = !myToDisableMSAA
268                               ? Max (Min (myRenderParams.NbMsaaSamples, aCtx->MaxMsaaSamples()), 0)
269                               : 0;
270   if (aNbSamples != 0)
271   {
272     aNbSamples = OpenGl_Context::GetPowerOfTwo (aNbSamples, aCtx->MaxMsaaSamples());
273   }
274
275   if ( aFrameBuffer == NULL
276    && !aCtx->DefaultFrameBuffer().IsNull()
277    &&  aCtx->DefaultFrameBuffer()->IsValid())
278   {
279     aFrameBuffer = aCtx->DefaultFrameBuffer().operator->();
280   }
281
282   if (myHasFboBlit
283    && (myTransientDrawToFront
284     || aProjectType == Graphic3d_Camera::Projection_Stereo
285     || aNbSamples != 0))
286   {
287     if (myMainSceneFbos[0]->GetVPSizeX() != aSizeX
288      || myMainSceneFbos[0]->GetVPSizeY() != aSizeY
289      || myMainSceneFbos[0]->NbSamples()  != aNbSamples)
290     {
291       if (!myTransientDrawToFront)
292       {
293         myImmediateSceneFbos[0]->Release (aCtx.operator->());
294         myImmediateSceneFbos[1]->Release (aCtx.operator->());
295         myImmediateSceneFbos[0]->ChangeViewport (0, 0);
296         myImmediateSceneFbos[1]->ChangeViewport (0, 0);
297       }
298
299       // prepare FBOs containing main scene
300       // for further blitting and rendering immediate presentations on top
301       if (aCtx->core20fwd != NULL)
302       {
303         myMainSceneFbos[0]->Init (aCtx, aSizeX, aSizeY, myFboColorFormat, myFboDepthFormat, aNbSamples);
304       }
305       if (myTransientDrawToFront
306        && !aCtx->caps->useSystemBuffer
307        && myMainSceneFbos[0]->IsValid())
308       {
309         myImmediateSceneFbos[0]->InitLazy (aCtx, *myMainSceneFbos[0]);
310       }
311     }
312   }
313   else
314   {
315     myMainSceneFbos     [0]->Release (aCtx.operator->());
316     myMainSceneFbos     [1]->Release (aCtx.operator->());
317     myImmediateSceneFbos[0]->Release (aCtx.operator->());
318     myImmediateSceneFbos[1]->Release (aCtx.operator->());
319     myMainSceneFbos     [0]->ChangeViewport (0, 0);
320     myMainSceneFbos     [1]->ChangeViewport (0, 0);
321     myImmediateSceneFbos[0]->ChangeViewport (0, 0);
322     myImmediateSceneFbos[1]->ChangeViewport (0, 0);
323   }
324
325   if (aProjectType == Graphic3d_Camera::Projection_Stereo
326    && myMainSceneFbos[0]->IsValid())
327   {
328     myMainSceneFbos[1]->InitLazy (aCtx, *myMainSceneFbos[0]);
329     if (!myMainSceneFbos[1]->IsValid())
330     {
331       // no enough memory?
332       aProjectType = Graphic3d_Camera::Projection_Perspective;
333     }
334     else if (!myTransientDrawToFront)
335     {
336       //
337     }
338     else if (!aCtx->HasStereoBuffers() || aStereoMode != Graphic3d_StereoMode_QuadBuffer)
339     {
340       myImmediateSceneFbos[0]->InitLazy (aCtx, *myMainSceneFbos[0]);
341       myImmediateSceneFbos[1]->InitLazy (aCtx, *myMainSceneFbos[0]);
342       if (!myImmediateSceneFbos[0]->IsValid()
343        || !myImmediateSceneFbos[1]->IsValid())
344       {
345         aProjectType = Graphic3d_Camera::Projection_Perspective;
346       }
347     }
348   }
349
350   if (aProjectType == Graphic3d_Camera::Projection_Stereo)
351   {
352     OpenGl_FrameBuffer* aMainFbos[2] =
353     {
354       myMainSceneFbos[0]->IsValid() ? myMainSceneFbos[0].operator->() : NULL,
355       myMainSceneFbos[1]->IsValid() ? myMainSceneFbos[1].operator->() : NULL
356     };
357     OpenGl_FrameBuffer* anImmFbos[2] =
358     {
359       myImmediateSceneFbos[0]->IsValid() ? myImmediateSceneFbos[0].operator->() : NULL,
360       myImmediateSceneFbos[1]->IsValid() ? myImmediateSceneFbos[1].operator->() : NULL
361     };
362
363     if (!myTransientDrawToFront)
364     {
365       anImmFbos[0] = aMainFbos[0];
366       anImmFbos[1] = aMainFbos[1];
367     }
368     else if (aStereoMode == Graphic3d_StereoMode_SoftPageFlip
369           || aStereoMode == Graphic3d_StereoMode_QuadBuffer)
370     {
371       anImmFbos[0] = NULL;
372       anImmFbos[1] = NULL;
373     }
374
375   #if !defined(GL_ES_VERSION_2_0)
376     aCtx->SetReadDrawBuffer (aStereoMode == Graphic3d_StereoMode_QuadBuffer ? GL_BACK_LEFT : GL_BACK);
377   #endif
378     redraw (Graphic3d_Camera::Projection_MonoLeftEye, aMainFbos[0]);
379     myBackBufferRestored = Standard_True;
380     myIsImmediateDrawn   = Standard_False;
381   #if !defined(GL_ES_VERSION_2_0)
382     aCtx->SetReadDrawBuffer (aStereoMode == Graphic3d_StereoMode_QuadBuffer ? GL_BACK_LEFT : GL_BACK);
383   #endif
384     if (!redrawImmediate (Graphic3d_Camera::Projection_MonoLeftEye, aMainFbos[0], anImmFbos[0]))
385     {
386       toSwap = false;
387     }
388     else if (aStereoMode == Graphic3d_StereoMode_SoftPageFlip && toSwap)
389     {
390       aCtx->SwapBuffers();
391     }
392
393   #if !defined(GL_ES_VERSION_2_0)
394     aCtx->SetReadDrawBuffer (aStereoMode == Graphic3d_StereoMode_QuadBuffer ? GL_BACK_RIGHT : GL_BACK);
395   #endif
396     redraw (Graphic3d_Camera::Projection_MonoRightEye, aMainFbos[1]);
397     myBackBufferRestored = Standard_True;
398     myIsImmediateDrawn   = Standard_False;
399     if (!redrawImmediate (Graphic3d_Camera::Projection_MonoRightEye, aMainFbos[1], anImmFbos[1]))
400     {
401       toSwap = false;
402     }
403
404     if (anImmFbos[0] != NULL)
405     {
406       drawStereoPair (aFrameBuffer);
407     }
408   }
409   else
410   {
411     OpenGl_FrameBuffer* aMainFbo = myMainSceneFbos[0]->IsValid() ? myMainSceneFbos[0].operator->() : aFrameBuffer;
412     OpenGl_FrameBuffer* anImmFbo = aFrameBuffer;
413     if (!aCtx->caps->useSystemBuffer && myImmediateSceneFbos[0]->IsValid())
414     {
415       anImmFbo = myImmediateSceneFbos[0].operator->();
416     }
417     if (!myTransientDrawToFront)
418     {
419       anImmFbo = aMainFbo;
420     }
421
422   #if !defined(GL_ES_VERSION_2_0)
423     if (aMainFbo == NULL)
424     {
425       aCtx->SetReadDrawBuffer (GL_BACK);
426     }
427   #endif
428     redraw (aProjectType, aMainFbo);
429     myBackBufferRestored = Standard_True;
430     myIsImmediateDrawn   = Standard_False;
431     if (!redrawImmediate (aProjectType, aMainFbo, anImmFbo))
432     {
433       toSwap = false;
434     }
435
436     if (anImmFbo != NULL
437      && anImmFbo != aFrameBuffer)
438     {
439       blitBuffers (anImmFbo, aFrameBuffer, myToFlipOutput);
440     }
441   }
442
443   if (myRenderParams.Method == Graphic3d_RM_RAYTRACING
444    && myRenderParams.IsGlobalIlluminationEnabled)
445   {
446     myAccumFrames++;
447   }
448
449   // bind default FBO
450   bindDefaultFbo();
451
452   if (wasDisabledMSAA != myToDisableMSAA
453    || hadFboBlit      != myHasFboBlit)
454   {
455     // retry on error
456     Redraw();
457   }
458
459   // Swap the buffers
460   if (toSwap)
461   {
462     aCtx->SwapBuffers();
463     if (!myMainSceneFbos[0]->IsValid())
464     {
465       myBackBufferRestored = Standard_False;
466     }
467   }
468   else
469   {
470     aCtx->core11fwd->glFlush();
471   }
472
473   // reset render mode state
474   aCtx->FetchState();
475
476   myWasRedrawnGL = Standard_True;
477 }
478
479 // =======================================================================
480 // function : RedrawImmediate
481 // purpose  :
482 // =======================================================================
483 void OpenGl_View::RedrawImmediate()
484 {
485   if (!myWorkspace->Activate())
486     return;
487
488   Handle(OpenGl_Context) aCtx = myWorkspace->GetGlContext();
489   if (!myTransientDrawToFront
490    || !myBackBufferRestored
491    || (aCtx->caps->buffersNoSwap && !myMainSceneFbos[0]->IsValid()))
492   {
493     Redraw();
494     return;
495   }
496
497   const Graphic3d_StereoMode   aStereoMode  = myRenderParams.StereoMode;
498   Graphic3d_Camera::Projection aProjectType = myCamera->ProjectionType();
499   OpenGl_FrameBuffer*          aFrameBuffer = myFBO.operator->();
500
501   if ( aFrameBuffer == NULL
502    && !aCtx->DefaultFrameBuffer().IsNull()
503    &&  aCtx->DefaultFrameBuffer()->IsValid())
504   {
505     aFrameBuffer = aCtx->DefaultFrameBuffer().operator->();
506   }
507
508   if (aProjectType == Graphic3d_Camera::Projection_Stereo)
509   {
510     if (myMainSceneFbos[0]->IsValid()
511     && !myMainSceneFbos[1]->IsValid())
512     {
513       aProjectType = Graphic3d_Camera::Projection_Perspective;
514     }
515   }
516
517   bool toSwap = false;
518   if (aProjectType == Graphic3d_Camera::Projection_Stereo)
519   {
520     OpenGl_FrameBuffer* aMainFbos[2] =
521     {
522       myMainSceneFbos[0]->IsValid() ? myMainSceneFbos[0].operator->() : NULL,
523       myMainSceneFbos[1]->IsValid() ? myMainSceneFbos[1].operator->() : NULL
524     };
525     OpenGl_FrameBuffer* anImmFbos[2] =
526     {
527       myImmediateSceneFbos[0]->IsValid() ? myImmediateSceneFbos[0].operator->() : NULL,
528       myImmediateSceneFbos[1]->IsValid() ? myImmediateSceneFbos[1].operator->() : NULL
529     };
530     if (aStereoMode == Graphic3d_StereoMode_SoftPageFlip
531      || aStereoMode == Graphic3d_StereoMode_QuadBuffer)
532     {
533       anImmFbos[0] = NULL;
534       anImmFbos[1] = NULL;
535     }
536
537     if (aCtx->arbFBO != NULL)
538     {
539       aCtx->arbFBO->glBindFramebuffer (GL_FRAMEBUFFER, OpenGl_FrameBuffer::NO_FRAMEBUFFER);
540     }
541   #if !defined(GL_ES_VERSION_2_0)
542     if (anImmFbos[0] == NULL)
543     {
544       aCtx->SetReadDrawBuffer (aStereoMode == Graphic3d_StereoMode_QuadBuffer ? GL_BACK_LEFT : GL_BACK);
545     }
546   #endif
547     toSwap = redrawImmediate (Graphic3d_Camera::Projection_MonoLeftEye,
548                               aMainFbos[0],
549                               anImmFbos[0],
550                               Standard_True) || toSwap;
551     if (aStereoMode == Graphic3d_StereoMode_SoftPageFlip
552     &&  toSwap
553     && !aCtx->caps->buffersNoSwap)
554     {
555       aCtx->SwapBuffers();
556     }
557
558     if (aCtx->arbFBO != NULL)
559     {
560       aCtx->arbFBO->glBindFramebuffer (GL_FRAMEBUFFER, OpenGl_FrameBuffer::NO_FRAMEBUFFER);
561     }
562   #if !defined(GL_ES_VERSION_2_0)
563     if (anImmFbos[1] == NULL)
564     {
565       aCtx->SetReadDrawBuffer (aStereoMode == Graphic3d_StereoMode_QuadBuffer ? GL_BACK_RIGHT : GL_BACK);
566     }
567   #endif
568     toSwap = redrawImmediate (Graphic3d_Camera::Projection_MonoRightEye,
569                               aMainFbos[1],
570                               anImmFbos[1],
571                               Standard_True) || toSwap;
572     if (anImmFbos[0] != NULL)
573     {
574       drawStereoPair (aFrameBuffer);
575     }
576   }
577   else
578   {
579     OpenGl_FrameBuffer* aMainFbo = myMainSceneFbos[0]->IsValid() ? myMainSceneFbos[0].operator->() : NULL;
580     OpenGl_FrameBuffer* anImmFbo = aFrameBuffer;
581     if (!aCtx->caps->useSystemBuffer && myImmediateSceneFbos[0]->IsValid())
582     {
583       anImmFbo = myImmediateSceneFbos[0].operator->();
584     }
585   #if !defined(GL_ES_VERSION_2_0)
586     if (aMainFbo == NULL)
587     {
588       aCtx->SetReadDrawBuffer (GL_BACK);
589     }
590   #endif
591     toSwap = redrawImmediate (aProjectType,
592                               aMainFbo,
593                               anImmFbo,
594                               Standard_True) || toSwap;
595     if (anImmFbo != NULL
596      && anImmFbo != aFrameBuffer)
597     {
598       blitBuffers (anImmFbo, aFrameBuffer, myToFlipOutput);
599     }
600   }
601
602   // bind default FBO
603   bindDefaultFbo();
604
605   if (toSwap && !aCtx->caps->buffersNoSwap)
606   {
607     aCtx->SwapBuffers();
608   }
609   else
610   {
611     aCtx->core11fwd->glFlush();
612   }
613
614   myWasRedrawnGL = Standard_True;
615 }
616
617 // =======================================================================
618 // function : redraw
619 // purpose  :
620 // =======================================================================
621 void OpenGl_View::redraw (const Graphic3d_Camera::Projection theProjection, OpenGl_FrameBuffer* theReadDrawFbo)
622 {
623   Handle(OpenGl_Context) aCtx = myWorkspace->GetGlContext();
624   if (theReadDrawFbo != NULL)
625   {
626     theReadDrawFbo->BindBuffer    (aCtx);
627     theReadDrawFbo->SetupViewport (aCtx);
628   }
629   else
630   {
631     const Standard_Integer aViewport[4] = { 0, 0, myWindow->Width(), myWindow->Height() };
632     aCtx->ResizeViewport (aViewport);
633   }
634
635   // request reset of material
636   myWorkspace->NamedStatus    |= OPENGL_NS_RESMAT;
637   myWorkspace->UseZBuffer()    = Standard_True;
638   myWorkspace->UseDepthWrite() = Standard_True;
639   GLbitfield toClear = GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT;
640   glDepthFunc (GL_LEQUAL);
641   glDepthMask (GL_TRUE);
642   glEnable (GL_DEPTH_TEST);
643
644 #if !defined(GL_ES_VERSION_2_0)
645   glClearDepth (1.0);
646 #else
647   glClearDepthf (1.0f);
648 #endif
649
650   if (myWorkspace->NamedStatus & OPENGL_NS_WHITEBACK)
651   {
652     // set background to white
653     glClearColor (1.0f, 1.0f, 1.0f, 1.0f);
654   }
655   else
656   {
657     const OpenGl_Vec4& aBgColor = myBgColor;
658     glClearColor (aBgColor.r(), aBgColor.g(), aBgColor.b(), 0.0f);
659   }
660
661   glClear (toClear);
662
663   render (theProjection, theReadDrawFbo, Standard_False);
664 }
665
666 // =======================================================================
667 // function : redrawMonoImmediate
668 // purpose  :
669 // =======================================================================
670 bool OpenGl_View::redrawImmediate (const Graphic3d_Camera::Projection theProjection,
671                                    OpenGl_FrameBuffer*    theReadFbo,
672                                    OpenGl_FrameBuffer*    theDrawFbo,
673                                    const Standard_Boolean theIsPartialUpdate)
674 {
675   Handle(OpenGl_Context) aCtx = myWorkspace->GetGlContext();
676   GLboolean toCopyBackToFront = GL_FALSE;
677   if (theDrawFbo == theReadFbo
678    && theDrawFbo != NULL)
679   {
680     myBackBufferRestored = Standard_False;
681   }
682   else if (theReadFbo != NULL
683         && theReadFbo->IsValid()
684         && aCtx->IsRender())
685   {
686     if (!blitBuffers (theReadFbo, theDrawFbo))
687     {
688       return true;
689     }
690   }
691   else if (theDrawFbo == NULL)
692   {
693   #if !defined(GL_ES_VERSION_2_0)
694     aCtx->core11fwd->glGetBooleanv (GL_DOUBLEBUFFER, &toCopyBackToFront);
695   #endif
696     if (toCopyBackToFront)
697     {
698       if (!HasImmediateStructures()
699        && !theIsPartialUpdate)
700       {
701         // prefer Swap Buffers within Redraw in compatibility mode (without FBO)
702         return true;
703       }
704       copyBackToFront();
705     }
706     else
707     {
708       myBackBufferRestored = Standard_False;
709     }
710   }
711   else
712   {
713     myBackBufferRestored = Standard_False;
714   }
715   myIsImmediateDrawn = Standard_True;
716
717   myWorkspace->UseZBuffer()    = Standard_True;
718   myWorkspace->UseDepthWrite() = Standard_True;
719   glDepthFunc (GL_LEQUAL);
720   glDepthMask (GL_TRUE);
721   glEnable (GL_DEPTH_TEST);
722 #if !defined(GL_ES_VERSION_2_0)
723   glClearDepth (1.0);
724 #else
725   glClearDepthf (1.0f);
726 #endif
727
728   render (theProjection, theDrawFbo, Standard_True);
729
730   return !toCopyBackToFront;
731 }
732
733 //=======================================================================
734 //function : Render
735 //purpose  :
736 //=======================================================================
737 void OpenGl_View::render (Graphic3d_Camera::Projection theProjection,
738                           OpenGl_FrameBuffer*          theOutputFBO,
739                           const Standard_Boolean       theToDrawImmediate)
740 {
741   // ==================================
742   //      Step 1: Prepare for render
743   // ==================================
744
745   const Handle(OpenGl_Context)& aContext = myWorkspace->GetGlContext();
746
747 #if !defined(GL_ES_VERSION_2_0)
748   // Disable current clipping planes
749   if (aContext->core11 != NULL)
750   {
751     const Standard_Integer aMaxPlanes = aContext->MaxClipPlanes();
752     for (Standard_Integer aClipPlaneId = GL_CLIP_PLANE0; aClipPlaneId < GL_CLIP_PLANE0 + aMaxPlanes; ++aClipPlaneId)
753     {
754       aContext->core11fwd->glDisable (aClipPlaneId);
755     }
756   }
757 #endif
758
759   // Update states of OpenGl_BVHTreeSelector (frustum culling algorithm).
760   myBVHSelector.SetViewVolume (myCamera);
761   myBVHSelector.SetViewportSize (myWindow->Width(), myWindow->Height());
762
763   const Handle(OpenGl_ShaderManager)& aManager   = aContext->ShaderManager();
764   if (StateInfo (myCurrLightSourceState, aManager->LightSourceState().Index()) != myLastLightSourceState)
765   {
766     aManager->UpdateLightSourceStateTo (myShadingModel == Graphic3d_TOSM_NONE ? &myNoShadingLight : &myLights);
767     myLastLightSourceState = StateInfo (myCurrLightSourceState, aManager->LightSourceState().Index());
768   }
769
770   // Update matrices if camera has changed.
771   Graphic3d_WorldViewProjState aWVPState = myCamera->WorldViewProjState();
772   const Standard_Boolean isCameraChanged = myWorldViewProjState != aWVPState;
773   const Standard_Boolean isSameView      = aManager->IsSameView (this);
774   if (isCameraChanged)
775   {
776     aContext->ProjectionState.SetCurrent (myCamera->ProjectionMatrixF());
777     aContext->WorldViewState .SetCurrent (myCamera->OrientationMatrixF());
778     myAccumFrames = 0;
779   }
780
781   // Apply new matrix state if camera has changed or this view differs from the one
782   // that was previously used for configuring matrices of shader manager
783   // (ApplyProjectionMatrix and ApplyWorldViewMatrix will affect the manager).
784   if (isCameraChanged || !isSameView)
785   {
786     aContext->ApplyProjectionMatrix();
787     aContext->ApplyWorldViewMatrix();
788   }
789
790   if (aManager->ModelWorldState().Index() == 0)
791   {
792     aContext->ShaderManager()->UpdateModelWorldStateTo (OpenGl_Mat4());
793   }
794
795   myWorldViewProjState = aWVPState;
796
797   // ====================================
798   //      Step 2: Redraw background
799   // ====================================
800
801   // Render background
802   if (!theToDrawImmediate)
803   {
804     drawBackground (myWorkspace);
805   }
806
807 #if !defined(GL_ES_VERSION_2_0)
808   // Switch off lighting by default
809   if (aContext->core11 != NULL)
810   {
811     glDisable(GL_LIGHTING);
812   }
813 #endif
814
815   // =================================
816   //      Step 3: Redraw main plane
817   // =================================
818
819   // Setup face culling
820   GLboolean isCullFace = GL_FALSE;
821   if (myBackfacing != Graphic3d_TOBM_AUTOMATIC)
822   {
823     isCullFace = glIsEnabled (GL_CULL_FACE);
824     if (myBackfacing == Graphic3d_TOBM_DISABLE)
825     {
826       glEnable (GL_CULL_FACE);
827       glCullFace (GL_BACK);
828     }
829     else
830       glDisable (GL_CULL_FACE);
831   }
832
833 #if !defined(GL_ES_VERSION_2_0)
834   // if the view is scaled normal vectors are scaled to unit
835   // length for correct displaying of shaded objects
836   const gp_Pnt anAxialScale = myCamera->AxialScale();
837   if (anAxialScale.X() != 1.F ||
838       anAxialScale.Y() != 1.F ||
839       anAxialScale.Z() != 1.F)
840   {
841     aContext->SetGlNormalizeEnabled (Standard_True);
842   }
843   else
844   {
845     aContext->SetGlNormalizeEnabled (Standard_False);
846   }
847
848   // Apply InteriorShadingMethod
849   if (aContext->core11 != NULL)
850   {
851     aContext->core11->glShadeModel (myShadingModel == Graphic3d_TOSM_FACET
852                                  || myShadingModel == Graphic3d_TOSM_NONE ? GL_FLAT : GL_SMOOTH);
853   }
854 #endif
855
856   aManager->SetShadingModel (myShadingModel);
857
858   // Redraw 3d scene
859   if (theProjection == Graphic3d_Camera::Projection_MonoLeftEye)
860   {
861     aContext->ProjectionState.SetCurrent (myCamera->ProjectionStereoLeftF());
862     aContext->ApplyProjectionMatrix();
863   }
864   else if (theProjection == Graphic3d_Camera::Projection_MonoRightEye)
865   {
866     aContext->ProjectionState.SetCurrent (myCamera->ProjectionStereoRightF());
867     aContext->ApplyProjectionMatrix();
868   }
869
870   myWorkspace->SetEnvironmentTexture (myTextureEnv);
871
872   renderScene (theProjection, theOutputFBO, theToDrawImmediate);
873
874   myWorkspace->SetEnvironmentTexture (Handle(OpenGl_Texture)());
875
876   // ===============================
877   //      Step 4: Trihedron
878   // ===============================
879
880   // Resetting GL parameters according to the default aspects
881   // in order to synchronize GL state with the graphic driver state
882   // before drawing auxiliary stuff (trihedrons, overlayer)
883   myWorkspace->ResetAppliedAspect();
884
885
886   // We need to disable (unbind) all shaders programs to ensure
887   // that all objects without specified aspect will be drawn
888   // correctly (such as background)
889   aContext->BindProgram (NULL);
890
891   // Render trihedron
892   if (!theToDrawImmediate)
893   {
894     renderTrihedron (myWorkspace);
895
896     // Restore face culling
897     if (myBackfacing != Graphic3d_TOBM_AUTOMATIC)
898     {
899       if (isCullFace)
900       {
901         glEnable (GL_CULL_FACE);
902         glCullFace (GL_BACK);
903       }
904       else
905         glDisable (GL_CULL_FACE);
906     }
907   }
908
909   // ==============================================================
910   //      Step 6: Keep shader manager informed about last View
911   // ==============================================================
912
913   if (!aManager.IsNull())
914   {
915     aManager->SetLastView (this);
916   }
917 }
918
919 // =======================================================================
920 // function : InvalidateBVHData
921 // purpose  :
922 // =======================================================================
923 void OpenGl_View::InvalidateBVHData (const Graphic3d_ZLayerId theLayerId)
924 {
925   myZLayers.InvalidateBVHData (theLayerId);
926 }
927
928 //=======================================================================
929 //function : renderStructs
930 //purpose  :
931 //=======================================================================
932 void OpenGl_View::renderStructs (Graphic3d_Camera::Projection theProjection,
933                                  OpenGl_FrameBuffer*          theReadDrawFbo,
934                                  const Standard_Boolean       theToDrawImmediate)
935 {
936   if ( myZLayers.NbStructures() <= 0 )
937     return;
938
939   Handle(OpenGl_Context) aCtx = myWorkspace->GetGlContext();
940   Standard_Boolean toRenderGL = theToDrawImmediate ||
941     myRenderParams.Method != Graphic3d_RM_RAYTRACING ||
942     myRaytraceInitStatus == OpenGl_RT_FAIL ||
943     aCtx->IsFeedback();
944
945   if (!toRenderGL)
946   {
947     toRenderGL = !initRaytraceResources (aCtx) ||
948       !updateRaytraceGeometry (OpenGl_GUM_CHECK, myId, aCtx);
949
950     toRenderGL |= !myIsRaytraceDataValid; // if no ray-trace data use OpenGL
951
952     if (!toRenderGL)
953     {
954       const Standard_Integer aSizeX = theReadDrawFbo != NULL ? theReadDrawFbo->GetVPSizeX() : myWindow->Width();
955       const Standard_Integer aSizeY = theReadDrawFbo != NULL ? theReadDrawFbo->GetVPSizeY() : myWindow->Height();
956       myOpenGlFBO ->InitLazy (aCtx, aSizeX, aSizeY, myFboColorFormat, myFboDepthFormat, 0);
957
958       if (myRaytraceFilter.IsNull())
959         myRaytraceFilter = new OpenGl_RaytraceFilter;
960
961       myRaytraceFilter->SetPrevRenderFilter (myWorkspace->GetRenderFilter());
962
963       if (theReadDrawFbo != NULL)
964         theReadDrawFbo->UnbindBuffer (aCtx);
965
966       // Prepare preliminary OpenGL output
967       if (aCtx->arbFBOBlit != NULL)
968       {
969         // Render bottom OSD layer
970         myZLayers.Render (myWorkspace, theToDrawImmediate, OpenGl_LF_Bottom);
971
972         myWorkspace->SetRenderFilter (myRaytraceFilter);
973         {
974           if (theReadDrawFbo != NULL)
975           {
976             theReadDrawFbo->BindDrawBuffer (aCtx);
977           }
978           else
979           {
980             aCtx->arbFBO->glBindFramebuffer (GL_DRAW_FRAMEBUFFER, 0);
981           }
982
983           // Render non-polygonal elements in default layer
984           myZLayers.Render (myWorkspace, theToDrawImmediate, OpenGl_LF_Default);
985         }
986         myWorkspace->SetRenderFilter (myRaytraceFilter->PrevRenderFilter());
987       }
988
989       if (theReadDrawFbo != NULL)
990       {
991         theReadDrawFbo->BindBuffer (aCtx);
992       }
993       else
994       {
995         aCtx->arbFBO->glBindFramebuffer (GL_FRAMEBUFFER, 0);
996       }
997
998       // Reset OpenGl aspects state to default to avoid enabling of
999       // backface culling which is not supported in ray-tracing.
1000       myWorkspace->ResetAppliedAspect();
1001
1002       // Ray-tracing polygonal primitive arrays
1003       raytrace (aSizeX, aSizeY, theProjection, theReadDrawFbo, aCtx);
1004
1005       // Render upper (top and topmost) OpenGL layers
1006       myZLayers.Render (myWorkspace, theToDrawImmediate, OpenGl_LF_Upper);
1007     }
1008   }
1009
1010   // Redraw 3D scene using OpenGL in standard
1011   // mode or in case of ray-tracing failure
1012   if (toRenderGL)
1013   {
1014     myZLayers.Render (myWorkspace, theToDrawImmediate, OpenGl_LF_All);
1015
1016     // Set flag that scene was redrawn by standard pipeline
1017     myWasRedrawnGL = Standard_True;
1018   }
1019 }
1020
1021 //=======================================================================
1022 //function : renderTrihedron
1023 //purpose  :
1024 //=======================================================================
1025 void OpenGl_View::renderTrihedron (const Handle(OpenGl_Workspace) &theWorkspace)
1026 {
1027   // display global trihedron
1028   if (myToShowTrihedron)
1029   {
1030     // disable environment texture
1031     Handle(OpenGl_Texture) anEnvironmentTexture = theWorkspace->EnvironmentTexture();
1032     theWorkspace->SetEnvironmentTexture (Handle(OpenGl_Texture)());
1033
1034     myTrihedron.Render (theWorkspace);
1035
1036     // restore environment texture
1037     theWorkspace->SetEnvironmentTexture (anEnvironmentTexture);
1038   }
1039   if (myToShowGradTrihedron)
1040   {
1041     myGraduatedTrihedron.Render (theWorkspace);
1042   }
1043 }
1044
1045 // =======================================================================
1046 // function : Invalidate
1047 // purpose  :
1048 // =======================================================================
1049 void OpenGl_View::Invalidate()
1050 {
1051   myBackBufferRestored = Standard_False;
1052 }
1053
1054 //=======================================================================
1055 //function : renderScene
1056 //purpose  :
1057 //=======================================================================
1058 void OpenGl_View::renderScene (Graphic3d_Camera::Projection theProjection,
1059                                OpenGl_FrameBuffer*          theReadDrawFbo,
1060                                const Standard_Boolean       theToDrawImmediate)
1061 {
1062   const Handle(OpenGl_Context)& aContext = myWorkspace->GetGlContext();
1063
1064   // Specify clipping planes in view transformation space
1065   aContext->ChangeClipping().Reset (aContext, myClipPlanes);
1066   if (!myClipPlanes.IsNull()
1067    && !myClipPlanes->IsEmpty())
1068   {
1069     aContext->ShaderManager()->UpdateClippingState();
1070   }
1071
1072 #if !defined(GL_ES_VERSION_2_0)
1073   // Apply Lights
1074   if (aContext->core11 != NULL)
1075   {
1076     // setup lights
1077     Graphic3d_Vec4 anAmbientColor (THE_DEFAULT_AMBIENT[0],
1078                                    THE_DEFAULT_AMBIENT[1],
1079                                    THE_DEFAULT_AMBIENT[2],
1080                                    THE_DEFAULT_AMBIENT[3]);
1081     GLenum aLightGlId = GL_LIGHT0;
1082
1083     OpenGl_ListOfLight::Iterator aLightIt (myShadingModel == Graphic3d_TOSM_NONE ? myNoShadingLight : myLights);
1084     for (; aLightIt.More(); aLightIt.Next())
1085     {
1086       bindLight (aLightIt.Value(), aLightGlId, anAmbientColor, myWorkspace);
1087     }
1088
1089     // apply accumulated ambient color
1090     anAmbientColor.a() = 1.0f;
1091     glLightModelfv (GL_LIGHT_MODEL_AMBIENT, anAmbientColor.GetData());
1092
1093     if (aLightGlId != GL_LIGHT0)
1094     {
1095       glEnable (GL_LIGHTING);
1096     }
1097     // switch off unused lights
1098     for (; aLightGlId <= GL_LIGHT7; ++aLightGlId)
1099     {
1100       glDisable (aLightGlId);
1101     }
1102   }
1103 #endif
1104
1105   // Clear status bitfields
1106   myWorkspace->NamedStatus &= ~(OPENGL_NS_2NDPASSNEED | OPENGL_NS_2NDPASSDO);
1107
1108   // First pass
1109   renderStructs (theProjection, theReadDrawFbo, theToDrawImmediate);
1110   myWorkspace->DisableTexture();
1111
1112   // Second pass
1113   if (myWorkspace->NamedStatus & OPENGL_NS_2NDPASSNEED)
1114   {
1115     myWorkspace->NamedStatus |= OPENGL_NS_2NDPASSDO;
1116
1117     // Remember OpenGl properties
1118     GLint aSaveBlendDst = GL_ONE_MINUS_SRC_ALPHA, aSaveBlendSrc = GL_SRC_ALPHA;
1119     GLint aSaveZbuffFunc;
1120     GLboolean aSaveZbuffWrite;
1121     glGetBooleanv (GL_DEPTH_WRITEMASK, &aSaveZbuffWrite);
1122     glGetIntegerv (GL_DEPTH_FUNC, &aSaveZbuffFunc);
1123   #if !defined(GL_ES_VERSION_2_0)
1124     glGetIntegerv (GL_BLEND_DST, &aSaveBlendDst);
1125     glGetIntegerv (GL_BLEND_SRC, &aSaveBlendSrc);
1126   #endif
1127     GLboolean wasZbuffEnabled = glIsEnabled (GL_DEPTH_TEST);
1128     GLboolean wasBlendEnabled = glIsEnabled (GL_BLEND);
1129
1130     // Change the properties for second rendering pass
1131     glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1132     glEnable (GL_BLEND);
1133
1134     glDepthFunc (GL_EQUAL);
1135     glDepthMask (GL_FALSE);
1136     glEnable (GL_DEPTH_TEST);
1137
1138     // Render the view
1139     renderStructs (theProjection, theReadDrawFbo, theToDrawImmediate);
1140     myWorkspace->DisableTexture();
1141
1142     // Restore properties back
1143     glBlendFunc (aSaveBlendSrc, aSaveBlendDst);
1144     if (!wasBlendEnabled)
1145       glDisable (GL_BLEND);
1146
1147     glDepthFunc (aSaveZbuffFunc);
1148     glDepthMask (aSaveZbuffWrite);
1149     if (!wasZbuffEnabled)
1150       glDisable (GL_DEPTH_FUNC);
1151   }
1152
1153   // Apply restored view matrix.
1154   aContext->ApplyWorldViewMatrix();
1155
1156   aContext->ChangeClipping().Reset (aContext, Handle(Graphic3d_SequenceOfHClipPlane)());
1157   if (!myClipPlanes.IsNull()
1158    && !myClipPlanes->IsEmpty())
1159   {
1160     aContext->ShaderManager()->RevertClippingState();
1161   }
1162 }
1163
1164 // =======================================================================
1165 // function : bindDefaultFbo
1166 // purpose  :
1167 // =======================================================================
1168 void OpenGl_View::bindDefaultFbo (OpenGl_FrameBuffer* theCustomFbo)
1169 {
1170   Handle(OpenGl_Context) aCtx = myWorkspace->GetGlContext();
1171   OpenGl_FrameBuffer* anFbo = (theCustomFbo != NULL && theCustomFbo->IsValid())
1172                             ?  theCustomFbo
1173                             : (!aCtx->DefaultFrameBuffer().IsNull()
1174                              && aCtx->DefaultFrameBuffer()->IsValid()
1175                               ? aCtx->DefaultFrameBuffer().operator->()
1176                               : NULL);
1177   if (anFbo != NULL)
1178   {
1179     anFbo->BindBuffer (aCtx);
1180     anFbo->SetupViewport (aCtx);
1181   }
1182   else
1183   {
1184   #if !defined(GL_ES_VERSION_2_0)
1185     aCtx->SetReadDrawBuffer (GL_BACK);
1186   #else
1187     if (aCtx->arbFBO != NULL)
1188     {
1189       aCtx->arbFBO->glBindFramebuffer (GL_FRAMEBUFFER, OpenGl_FrameBuffer::NO_FRAMEBUFFER);
1190     }
1191   #endif
1192     const Standard_Integer aViewport[4] = { 0, 0, myWindow->Width(), myWindow->Height() };
1193     aCtx->ResizeViewport (aViewport);
1194   }
1195 }
1196
1197 // =======================================================================
1198 // function : initBlitQuad
1199 // purpose  :
1200 // =======================================================================
1201 OpenGl_VertexBuffer* OpenGl_View::initBlitQuad (const Standard_Boolean theToFlip)
1202 {
1203   OpenGl_VertexBuffer* aVerts = NULL;
1204   if (!theToFlip)
1205   {
1206     aVerts = &myFullScreenQuad;
1207     if (!aVerts->IsValid())
1208     {
1209       OpenGl_Vec4 aQuad[4] =
1210       {
1211         OpenGl_Vec4( 1.0f, -1.0f, 1.0f, 0.0f),
1212         OpenGl_Vec4( 1.0f,  1.0f, 1.0f, 1.0f),
1213         OpenGl_Vec4(-1.0f, -1.0f, 0.0f, 0.0f),
1214         OpenGl_Vec4(-1.0f,  1.0f, 0.0f, 1.0f)
1215       };
1216       aVerts->Init (myWorkspace->GetGlContext(), 4, 4, aQuad[0].GetData());
1217     }
1218   }
1219   else
1220   {
1221     aVerts = &myFullScreenQuadFlip;
1222     if (!aVerts->IsValid())
1223     {
1224       OpenGl_Vec4 aQuad[4] =
1225       {
1226         OpenGl_Vec4( 1.0f, -1.0f, 1.0f, 1.0f),
1227         OpenGl_Vec4( 1.0f,  1.0f, 1.0f, 0.0f),
1228         OpenGl_Vec4(-1.0f, -1.0f, 0.0f, 1.0f),
1229         OpenGl_Vec4(-1.0f,  1.0f, 0.0f, 0.0f)
1230       };
1231       aVerts->Init (myWorkspace->GetGlContext(), 4, 4, aQuad[0].GetData());
1232     }
1233   }
1234   return aVerts;
1235 }
1236
1237 // =======================================================================
1238 // function : blitBuffers
1239 // purpose  :
1240 // =======================================================================
1241 bool OpenGl_View::blitBuffers (OpenGl_FrameBuffer*    theReadFbo,
1242                                OpenGl_FrameBuffer*    theDrawFbo,
1243                                const Standard_Boolean theToFlip)
1244 {
1245   Handle(OpenGl_Context) aCtx = myWorkspace->GetGlContext();
1246   if (theReadFbo == NULL || aCtx->IsFeedback())
1247   {
1248     return false;
1249   }
1250   else if (theReadFbo == theDrawFbo)
1251   {
1252     return true;
1253   }
1254
1255   // clear destination before blitting
1256   if (theDrawFbo != NULL
1257   &&  theDrawFbo->IsValid())
1258   {
1259     theDrawFbo->BindBuffer (aCtx);
1260   }
1261   else
1262   {
1263     aCtx->arbFBO->glBindFramebuffer (GL_FRAMEBUFFER, OpenGl_FrameBuffer::NO_FRAMEBUFFER);
1264   }
1265 #if !defined(GL_ES_VERSION_2_0)
1266   aCtx->core20fwd->glClearDepth  (1.0);
1267 #else
1268   aCtx->core20fwd->glClearDepthf (1.0f);
1269 #endif
1270   aCtx->core20fwd->glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
1271
1272 #if !defined(GL_ES_VERSION_2_0)
1273   if (aCtx->arbFBOBlit != NULL
1274    && theReadFbo->NbSamples() != 0)
1275   {
1276     GLbitfield aCopyMask = 0;
1277     theReadFbo->BindReadBuffer (aCtx);
1278     if (theDrawFbo != NULL
1279      && theDrawFbo->IsValid())
1280     {
1281       theDrawFbo->BindDrawBuffer (aCtx);
1282       if (theDrawFbo->HasColor()
1283        && theReadFbo->HasColor())
1284       {
1285         aCopyMask |= GL_COLOR_BUFFER_BIT;
1286       }
1287       if (theDrawFbo->HasDepth()
1288        && theReadFbo->HasDepth())
1289       {
1290         aCopyMask |= GL_DEPTH_BUFFER_BIT;
1291       }
1292     }
1293     else
1294     {
1295       if (theReadFbo->HasColor())
1296       {
1297         aCopyMask |= GL_COLOR_BUFFER_BIT;
1298       }
1299       if (theReadFbo->HasDepth())
1300       {
1301         aCopyMask |= GL_DEPTH_BUFFER_BIT;
1302       }
1303       aCtx->arbFBO->glBindFramebuffer (GL_DRAW_FRAMEBUFFER, OpenGl_FrameBuffer::NO_FRAMEBUFFER);
1304     }
1305
1306     // we don't copy stencil buffer here... does it matter for performance?
1307     aCtx->arbFBOBlit->glBlitFramebuffer (0, 0, theReadFbo->GetVPSizeX(), theReadFbo->GetVPSizeY(),
1308                                          0, 0, theReadFbo->GetVPSizeX(), theReadFbo->GetVPSizeY(),
1309                                          aCopyMask, GL_NEAREST);
1310     const int anErr = ::glGetError();
1311     if (anErr != GL_NO_ERROR)
1312     {
1313       // glBlitFramebuffer() might fail in several cases:
1314       // - Both FBOs have MSAA and they are samples number does not match.
1315       //   OCCT checks that this does not happen,
1316       //   however some graphics drivers provide an option for overriding MSAA.
1317       //   In this case window MSAA might be non-zero (and application can not check it)
1318       //   and might not match MSAA of our offscreen FBOs.
1319       // - Pixel formats of FBOs do not match.
1320       //   This also might happen with window has pixel format,
1321       //   e.g. Mesa fails blitting RGBA8 -> RGB8 while other drivers support this conversion.
1322       TCollection_ExtendedString aMsg = TCollection_ExtendedString() + "FBO blitting has failed [Error #" + anErr + "]\n"
1323                                       + "  Please check your graphics driver settings or try updating driver.";
1324       if (theReadFbo->NbSamples() != 0)
1325       {
1326         myToDisableMSAA = true;
1327         aMsg += "\n  MSAA settings should not be overridden by driver!";
1328       }
1329       aCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION,
1330                          GL_DEBUG_TYPE_ERROR,
1331                          0,
1332                          GL_DEBUG_SEVERITY_HIGH,
1333                          aMsg);
1334     }
1335
1336     if (theDrawFbo != NULL
1337      && theDrawFbo->IsValid())
1338     {
1339       theDrawFbo->BindBuffer (aCtx);
1340     }
1341     else
1342     {
1343       aCtx->arbFBO->glBindFramebuffer (GL_FRAMEBUFFER, OpenGl_FrameBuffer::NO_FRAMEBUFFER);
1344     }
1345   }
1346   else
1347 #endif
1348   {
1349     aCtx->core20fwd->glDepthFunc (GL_ALWAYS);
1350     aCtx->core20fwd->glDepthMask (GL_TRUE);
1351     aCtx->core20fwd->glEnable (GL_DEPTH_TEST);
1352   #if defined(GL_ES_VERSION_2_0)
1353     if (!aCtx->IsGlGreaterEqual (3, 0)
1354      && !aCtx->extFragDepth)
1355     {
1356       aCtx->core20fwd->glDisable (GL_DEPTH_TEST);
1357     }
1358   #endif
1359
1360     myWorkspace->DisableTexture();
1361
1362     OpenGl_VertexBuffer* aVerts = initBlitQuad (theToFlip);
1363     const Handle(OpenGl_ShaderManager)& aManager = aCtx->ShaderManager();
1364     if (aVerts->IsValid()
1365      && aManager->BindFboBlitProgram())
1366     {
1367       theReadFbo->ColorTexture()       ->Bind   (aCtx, GL_TEXTURE0 + 0);
1368       theReadFbo->DepthStencilTexture()->Bind   (aCtx, GL_TEXTURE0 + 1);
1369       aVerts->BindVertexAttrib (aCtx, Graphic3d_TOA_POS);
1370
1371       aCtx->core20fwd->glDrawArrays (GL_TRIANGLE_STRIP, 0, 4);
1372
1373       aVerts->UnbindVertexAttrib (aCtx, Graphic3d_TOA_POS);
1374       theReadFbo->DepthStencilTexture()->Unbind (aCtx, GL_TEXTURE0 + 1);
1375       theReadFbo->ColorTexture()       ->Unbind (aCtx, GL_TEXTURE0 + 0);
1376       aCtx->BindProgram (NULL);
1377     }
1378     else
1379     {
1380       TCollection_ExtendedString aMsg = TCollection_ExtendedString()
1381         + "Error! FBO blitting has failed";
1382       aCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION,
1383                          GL_DEBUG_TYPE_ERROR,
1384                          0,
1385                          GL_DEBUG_SEVERITY_HIGH,
1386                          aMsg);
1387       myHasFboBlit = Standard_False;
1388       theReadFbo->Release (aCtx.operator->());
1389       return true;
1390     }
1391   }
1392   return true;
1393 }
1394
1395 // =======================================================================
1396 // function : drawStereoPair
1397 // purpose  :
1398 // =======================================================================
1399 void OpenGl_View::drawStereoPair (OpenGl_FrameBuffer* theDrawFbo)
1400 {
1401   const Handle(OpenGl_Context)& aCtx = myWorkspace->GetGlContext();
1402   bindDefaultFbo (theDrawFbo);
1403   OpenGl_FrameBuffer* aPair[2] =
1404   {
1405     myImmediateSceneFbos[0]->IsValid() ? myImmediateSceneFbos[0].operator->() : NULL,
1406     myImmediateSceneFbos[1]->IsValid() ? myImmediateSceneFbos[1].operator->() : NULL
1407   };
1408   if (aPair[0] == NULL
1409   ||  aPair[1] == NULL
1410   || !myTransientDrawToFront)
1411   {
1412     aPair[0] = myMainSceneFbos[0]->IsValid() ? myMainSceneFbos[0].operator->() : NULL;
1413     aPair[1] = myMainSceneFbos[1]->IsValid() ? myMainSceneFbos[1].operator->() : NULL;
1414   }
1415
1416   if (aPair[0] == NULL
1417    || aPair[1] == NULL)
1418   {
1419     return;
1420   }
1421
1422   if (aPair[0]->NbSamples() != 0)
1423   {
1424     // resolve MSAA buffers before drawing
1425     if (!myOpenGlFBO ->InitLazy (aCtx, aPair[0]->GetVPSizeX(), aPair[0]->GetVPSizeY(), myFboColorFormat, myFboDepthFormat, 0)
1426      || !myOpenGlFBO2->InitLazy (aCtx, aPair[0]->GetVPSizeX(), aPair[0]->GetVPSizeY(), myFboColorFormat, 0, 0))
1427     {
1428       aCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION,
1429                          GL_DEBUG_TYPE_ERROR,
1430                          0,
1431                          GL_DEBUG_SEVERITY_HIGH,
1432                          "Error! Unable to allocate FBO for blitting stereo pair");
1433       bindDefaultFbo (theDrawFbo);
1434       return;
1435     }
1436
1437     if (!blitBuffers (aPair[0], myOpenGlFBO .operator->(), Standard_False)
1438      || !blitBuffers (aPair[1], myOpenGlFBO2.operator->(), Standard_False))
1439     {
1440       bindDefaultFbo (theDrawFbo);
1441       return;
1442     }
1443
1444     aPair[0] = myOpenGlFBO .operator->();
1445     aPair[1] = myOpenGlFBO2.operator->();
1446     bindDefaultFbo (theDrawFbo);
1447   }
1448
1449   struct
1450   {
1451     Standard_Integer left;
1452     Standard_Integer top;
1453     Standard_Integer right;
1454     Standard_Integer bottom;
1455     Standard_Integer dx() { return right  - left; }
1456     Standard_Integer dy() { return bottom - top; }
1457   } aGeom;
1458
1459   myWindow->PlatformWindow()->Position (aGeom.left, aGeom.top, aGeom.right, aGeom.bottom);
1460
1461   Standard_Boolean toReverse = myRenderParams.ToReverseStereo;
1462   const Standard_Boolean isOddY = (aGeom.top + aGeom.dy()) % 2 == 1;
1463   const Standard_Boolean isOddX =  aGeom.left % 2 == 1;
1464   if (isOddY
1465    && (myRenderParams.StereoMode == Graphic3d_StereoMode_RowInterlaced
1466     || myRenderParams.StereoMode == Graphic3d_StereoMode_ChessBoard))
1467   {
1468     toReverse = !toReverse;
1469   }
1470   if (isOddX
1471    && (myRenderParams.StereoMode == Graphic3d_StereoMode_ColumnInterlaced
1472     || myRenderParams.StereoMode == Graphic3d_StereoMode_ChessBoard))
1473   {
1474     toReverse = !toReverse;
1475   }
1476
1477   if (toReverse)
1478   {
1479     std::swap (aPair[0], aPair[1]);
1480   }
1481
1482   aCtx->core20fwd->glDepthFunc (GL_ALWAYS);
1483   aCtx->core20fwd->glDepthMask (GL_TRUE);
1484   aCtx->core20fwd->glEnable (GL_DEPTH_TEST);
1485
1486   myWorkspace->DisableTexture();
1487   OpenGl_VertexBuffer* aVerts = initBlitQuad (myToFlipOutput);
1488
1489   const Handle(OpenGl_ShaderManager)& aManager = aCtx->ShaderManager();
1490   if (aVerts->IsValid()
1491    && aManager->BindStereoProgram (myRenderParams.StereoMode))
1492   {
1493     if (myRenderParams.StereoMode == Graphic3d_StereoMode_Anaglyph)
1494     {
1495       OpenGl_Mat4 aFilterL, aFilterR;
1496       aFilterL.SetDiagonal (Graphic3d_Vec4 (0.0f, 0.0f, 0.0f, 0.0f));
1497       aFilterR.SetDiagonal (Graphic3d_Vec4 (0.0f, 0.0f, 0.0f, 0.0f));
1498       switch (myRenderParams.AnaglyphFilter)
1499       {
1500         case Graphic3d_RenderingParams::Anaglyph_RedCyan_Simple:
1501         {
1502           aFilterL.SetRow (0, Graphic3d_Vec4 (1.0f, 0.0f, 0.0f, 0.0f));
1503           aFilterR.SetRow (1, Graphic3d_Vec4 (0.0f, 1.0f, 0.0f, 0.0f));
1504           aFilterR.SetRow (2, Graphic3d_Vec4 (0.0f, 0.0f, 1.0f, 0.0f));
1505           break;
1506         }
1507         case Graphic3d_RenderingParams::Anaglyph_RedCyan_Optimized:
1508         {
1509           aFilterL.SetRow (0, Graphic3d_Vec4 ( 0.4154f,      0.4710f,      0.16666667f, 0.0f));
1510           aFilterL.SetRow (1, Graphic3d_Vec4 (-0.0458f,     -0.0484f,     -0.0257f,     0.0f));
1511           aFilterL.SetRow (2, Graphic3d_Vec4 (-0.0547f,     -0.0615f,      0.0128f,     0.0f));
1512           aFilterL.SetRow (3, Graphic3d_Vec4 ( 0.0f,         0.0f,         0.0f,        0.0f));
1513           aFilterR.SetRow (0, Graphic3d_Vec4 (-0.01090909f, -0.03636364f, -0.00606061f, 0.0f));
1514           aFilterR.SetRow (1, Graphic3d_Vec4 ( 0.37560000f,  0.73333333f,  0.01111111f, 0.0f));
1515           aFilterR.SetRow (2, Graphic3d_Vec4 (-0.06510000f, -0.12870000f,  1.29710000f, 0.0f));
1516           aFilterR.SetRow (3, Graphic3d_Vec4 ( 0.0f,                0.0f,  0.0f,        0.0f));
1517           break;
1518         }
1519         case Graphic3d_RenderingParams::Anaglyph_YellowBlue_Simple:
1520         {
1521           aFilterL.SetRow (0, Graphic3d_Vec4 (1.0f, 0.0f, 0.0f, 0.0f));
1522           aFilterL.SetRow (1, Graphic3d_Vec4 (0.0f, 1.0f, 0.0f, 0.0f));
1523           aFilterR.SetRow (2, Graphic3d_Vec4 (0.0f, 0.0f, 1.0f, 0.0f));
1524           break;
1525         }
1526         case Graphic3d_RenderingParams::Anaglyph_YellowBlue_Optimized:
1527         {
1528           aFilterL.SetRow (0, Graphic3d_Vec4 ( 1.062f, -0.205f,  0.299f, 0.0f));
1529           aFilterL.SetRow (1, Graphic3d_Vec4 (-0.026f,  0.908f,  0.068f, 0.0f));
1530           aFilterL.SetRow (2, Graphic3d_Vec4 (-0.038f, -0.173f,  0.022f, 0.0f));
1531           aFilterL.SetRow (3, Graphic3d_Vec4 ( 0.0f,    0.0f,    0.0f,   0.0f));
1532           aFilterR.SetRow (0, Graphic3d_Vec4 (-0.016f, -0.123f, -0.017f, 0.0f));
1533           aFilterR.SetRow (1, Graphic3d_Vec4 ( 0.006f,  0.062f, -0.017f, 0.0f));
1534           aFilterR.SetRow (2, Graphic3d_Vec4 ( 0.094f,  0.185f,  0.911f, 0.0f));
1535           aFilterR.SetRow (3, Graphic3d_Vec4 ( 0.0f,    0.0f,    0.0f,   0.0f));
1536           break;
1537         }
1538         case Graphic3d_RenderingParams::Anaglyph_GreenMagenta_Simple:
1539         {
1540           aFilterR.SetRow (0, Graphic3d_Vec4 (1.0f, 0.0f, 0.0f, 0.0f));
1541           aFilterL.SetRow (1, Graphic3d_Vec4 (0.0f, 1.0f, 0.0f, 0.0f));
1542           aFilterR.SetRow (2, Graphic3d_Vec4 (0.0f, 0.0f, 1.0f, 0.0f));
1543           break;
1544         }
1545         case Graphic3d_RenderingParams::Anaglyph_UserDefined:
1546         {
1547           aFilterL = myRenderParams.AnaglyphLeft;
1548           aFilterR = myRenderParams.AnaglyphRight;
1549           break;
1550         }
1551       }
1552       aCtx->ActiveProgram()->SetUniform (aCtx, "uMultL", aFilterL);
1553       aCtx->ActiveProgram()->SetUniform (aCtx, "uMultR", aFilterR);
1554     }
1555
1556     aPair[0]->ColorTexture()->Bind (aCtx, GL_TEXTURE0 + 0);
1557     aPair[1]->ColorTexture()->Bind (aCtx, GL_TEXTURE0 + 1);
1558     aVerts->BindVertexAttrib (aCtx, 0);
1559
1560     aCtx->core20fwd->glDrawArrays (GL_TRIANGLE_STRIP, 0, 4);
1561
1562     aVerts->UnbindVertexAttrib (aCtx, 0);
1563     aPair[1]->ColorTexture()->Unbind (aCtx, GL_TEXTURE0 + 1);
1564     aPair[0]->ColorTexture()->Unbind (aCtx, GL_TEXTURE0 + 0);
1565   }
1566   else
1567   {
1568     TCollection_ExtendedString aMsg = TCollection_ExtendedString()
1569       + "Error! Anaglyph has failed";
1570     aCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION,
1571                        GL_DEBUG_TYPE_ERROR,
1572                        0,
1573                        GL_DEBUG_SEVERITY_HIGH,
1574                        aMsg);
1575   }
1576 }
1577
1578 // =======================================================================
1579 // function : copyBackToFront
1580 // purpose  :
1581 // =======================================================================
1582 void OpenGl_View::copyBackToFront()
1583 {
1584 #if !defined(GL_ES_VERSION_2_0)
1585
1586   OpenGl_Mat4 aProjectMat;
1587   Graphic3d_TransformUtils::Ortho2D (aProjectMat,
1588     0.f, static_cast<GLfloat> (myWindow->Width()), 0.f, static_cast<GLfloat> (myWindow->Height()));
1589
1590   Handle(OpenGl_Context) aCtx = myWorkspace->GetGlContext();
1591   aCtx->WorldViewState.Push();
1592   aCtx->ProjectionState.Push();
1593
1594   aCtx->WorldViewState.SetIdentity();
1595   aCtx->ProjectionState.SetCurrent (aProjectMat);
1596
1597   aCtx->ApplyProjectionMatrix();
1598   aCtx->ApplyWorldViewMatrix();
1599
1600   aCtx->DisableFeatures();
1601
1602   switch (aCtx->DrawBuffer())
1603   {
1604     case GL_BACK_LEFT:
1605     {
1606       aCtx->SetReadBuffer (GL_BACK_LEFT);
1607       aCtx->SetDrawBuffer (GL_FRONT_LEFT);
1608       break;
1609     }
1610     case GL_BACK_RIGHT:
1611     {
1612       aCtx->SetReadBuffer (GL_BACK_RIGHT);
1613       aCtx->SetDrawBuffer (GL_FRONT_RIGHT);
1614       break;
1615     }
1616     default:
1617     {
1618       aCtx->SetReadBuffer (GL_BACK);
1619       aCtx->SetDrawBuffer (GL_FRONT);
1620       break;
1621     }
1622   }
1623
1624   glRasterPos2i (0, 0);
1625   glCopyPixels  (0, 0, myWindow->Width() + 1, myWindow->Height() + 1, GL_COLOR);
1626   //glCopyPixels  (0, 0, myWidth + 1, myHeight + 1, GL_DEPTH);
1627
1628   aCtx->EnableFeatures();
1629
1630   aCtx->WorldViewState.Pop();
1631   aCtx->ProjectionState.Pop();
1632   aCtx->ApplyProjectionMatrix();
1633
1634   // read/write from front buffer now
1635   aCtx->SetReadBuffer (aCtx->DrawBuffer());
1636 #endif
1637   myIsImmediateDrawn = Standard_False;
1638 }