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