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