0025556: Visualization - support stereo pair formats recognized by consumer display...
authorkgv <kgv@opencascade.com>
Sat, 20 Jun 2015 13:08:12 +0000 (16:08 +0300)
committerkgv <kgv@opencascade.com>
Sat, 20 Jun 2015 13:08:12 +0000 (16:08 +0300)
Graphic3d_StereoMode - add new enumeration for stereoscopic outputs:
- Graphic3d_StereoMode_QuadBuffer
- Graphic3d_StereoMode_Anaglyph
- Graphic3d_StereoMode_RowInterlaced
- Graphic3d_StereoMode_ColumnInterlaced
- Graphic3d_StereoMode_ChessBoard
- Graphic3d_StereoMode_SideBySide
- Graphic3d_StereoMode_OverUnder

Graphic3d_RenderingParams - add new options controlling stereo output:
- StereoMode
- ToReverseStereo
- AnaglyphFilter

OpenGl_ShaderManager - add predefined GLSL programs for new stereo outputs.
OpenGl_Workspace::Redraw() - do not implicitly disable stereo to allow stereo dump as is.
OpenGl_Caps - add flag swapInterval to control VSync.
OpenGl_Workspace::BufferDump() - handle cases with non-applicable GL_PACK_ROW_LENGTH.

CALL_DEF_WINDOW - drop unused fields; add fields "left" and "top"
to reverse stereo pair for interlaced output depending on window position.

Draw Harness, ViewerTest:
- Extend syntax of command vstereo to setup stereo.
- Extend vdump command to allow dump of stereoscopic pair in different formats.
- Extend command vcaps with option vsync.
- Use mouse scroll to zoom and adjust ZFocus in WinAPI.
- Use "/" and "*" to adjust IOD.

v3d/glsl/stereo - add test case for stereo modes.

Cocoa_LocalPool, OSD_EnvironmentIterator - fix compilation issues on OS X Snow Leopard.

30 files changed:
src/Cocoa/Cocoa_LocalPool.hxx
src/Cocoa/Cocoa_LocalPool.mm
src/Cocoa/Cocoa_Window.mm
src/Graphic3d/FILES
src/Graphic3d/Graphic3d_RenderingParams.hxx
src/Graphic3d/Graphic3d_StereoMode.hxx [new file with mode: 0644]
src/InterfaceGraphic/InterfaceGraphic_Aspect.hxx
src/OSD/OSD_EnvironmentIterator.cxx
src/OpenGl/OpenGl_Caps.cxx
src/OpenGl/OpenGl_Caps.hxx
src/OpenGl/OpenGl_Context.cxx
src/OpenGl/OpenGl_Context.hxx
src/OpenGl/OpenGl_GraphicDriver_7.cxx
src/OpenGl/OpenGl_ShaderManager.cxx
src/OpenGl/OpenGl_ShaderManager.hxx
src/OpenGl/OpenGl_Window.cxx
src/OpenGl/OpenGl_Window.hxx
src/OpenGl/OpenGl_Window_1.mm
src/OpenGl/OpenGl_Workspace.cxx
src/OpenGl/OpenGl_Workspace.hxx
src/V3d/FILES
src/V3d/V3d.cdl
src/V3d/V3d_StereoDumpOptions.hxx [new file with mode: 0644]
src/V3d/V3d_View.cxx
src/ViewerTest/ViewerTest.cxx
src/ViewerTest/ViewerTest_ViewerCommands.cxx
src/Visual3d/Visual3d_View.cxx
tests/bugs/vis/bug23813
tests/bugs/vis/bug24001
tests/v3d/glsl/stereo [new file with mode: 0644]

index 8c8d0d7..7cafbae 100644 (file)
 #ifndef __Cocoa_LocalPool_h_
 #define __Cocoa_LocalPool_h_
 
-#if defined(__clang__) && (__clang_major__ >= 4) && __has_feature(objc_arc)
+#if defined(__clang__) && (__clang_major__ >= 4)
+#if __has_feature(objc_arc)
+  #define HAVE_OBJC_ARC
+#endif
+#endif
+
+#ifdef HAVE_OBJC_ARC
 
 // @autoreleasepool should be used within ARC
 
index e8aa236..aa61be9 100644 (file)
@@ -23,9 +23,7 @@
   #import <Cocoa/Cocoa.h>
 #endif
 
-#if defined(__clang__) && (__clang_major__ >= 4) && __has_feature(objc_arc)
-  // ARC
-#else
+#ifndef HAVE_OBJC_ARC
 
 // =======================================================================
 // function : Cocoa_LocalPool
index 0427b0e..ac7df36 100644 (file)
 IMPLEMENT_STANDARD_HANDLE (Cocoa_Window, Aspect_Window)
 IMPLEMENT_STANDARD_RTTIEXT(Cocoa_Window, Aspect_Window)
 
-#if defined(__clang__) && (__clang_major__ >= 4) && __has_feature(objc_arc)
-  #define HAVE_OBJC_ARC
-#endif
-
 #if defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE
   //
 #else
index d7ad4df..e278192 100755 (executable)
@@ -30,6 +30,7 @@ Graphic3d_ShaderProgram.cxx
 Graphic3d_ShaderVariable.hxx
 Graphic3d_ShaderVariable.cxx
 Graphic3d_ShaderVariable.lxx
+Graphic3d_StereoMode.hxx
 Graphic3d_MapOfStructure.hxx
 Graphic3d_MapIteratorOfMapOfStructure.hxx
 Graphic3d_IndexedMapOfAddress.hxx
index 6f8478f..5222741 100644 (file)
@@ -17,6 +17,9 @@
 #define _Graphic3d_RenderingParams_HeaderFile
 
 #include <Graphic3d_RenderingMode.hxx>
+#include <Graphic3d_StereoMode.hxx>
+#include <Graphic3d_Mat4.hxx>
+#include <Graphic3d_Vec4.hxx>
 
 //! Helper class to store rendering parameters.
 class Graphic3d_RenderingParams
@@ -29,51 +32,64 @@ public:
   //! Default ray-tracing depth.
   static const Standard_Integer THE_DEFAULT_DEPTH = 3;
 
+  //! Anaglyph filter presets.
+  enum Anaglyph
+  {
+    Anaglyph_RedCyan_Simple,       //!< simple    filter for Red-Cyan      glasses (R+GB)
+    Anaglyph_RedCyan_Optimized,    //!< optimized filter for Red-Cyan      glasses (R+GB)
+    Anaglyph_YellowBlue_Simple,    //!< simple    filter for Yellow-Blue   glasses (RG+B)
+    Anaglyph_YellowBlue_Optimized, //!< optimized filter for Yellow-Blue   glasses (RG+B)
+    Anaglyph_GreenMagenta_Simple,  //!< simple    filter for Green-Magenta glasses (G+RB)
+    Anaglyph_UserDefined           //!< use externally specified matrices
+  };
+
 public:
 
   //! Creates default rendering parameters.
   Graphic3d_RenderingParams()
   : Method                      (Graphic3d_RM_RASTERIZATION),
-    RaytracingDepth             (THE_DEFAULT_DEPTH),
+    IsGlobalIlluminationEnabled (Standard_False),
     SamplesPerPixel             (THE_DEFAULT_SPP),
+    RaytracingDepth             (THE_DEFAULT_DEPTH),
     IsShadowEnabled             (Standard_True),
     IsReflectionEnabled         (Standard_False),
     IsAntialiasingEnabled       (Standard_False),
     IsTransparentShadowEnabled  (Standard_False),
-    IsGlobalIlluminationEnabled (Standard_False),
-    UseEnvironmentMapBackground (Standard_False)
+
+    UseEnvironmentMapBackground (Standard_False),
+    StereoMode (Graphic3d_StereoMode_QuadBuffer),
+    AnaglyphFilter (Anaglyph_RedCyan_Optimized),
+    ToReverseStereo (Standard_False)
   {
-    //
+    const Graphic3d_Vec4 aZero (0.0f, 0.0f, 0.0f, 0.0f);
+    AnaglyphLeft .SetRow (0, Graphic3d_Vec4 (1.0f,  0.0f,  0.0f, 0.0f));
+    AnaglyphLeft .SetRow (1, aZero);
+    AnaglyphLeft .SetRow (2, aZero);
+    AnaglyphLeft .SetRow (3, aZero);
+    AnaglyphRight.SetRow (0, aZero);
+    AnaglyphRight.SetRow (1, Graphic3d_Vec4 (0.0f,  1.0f,  0.0f, 0.0f));
+    AnaglyphRight.SetRow (2, Graphic3d_Vec4 (0.0f,  0.0f,  1.0f, 0.0f));
+    AnaglyphRight.SetRow (3, aZero);
   }
 
 public:
 
-  //! Specifies rendering mode.
-  Graphic3d_RenderingMode Method;
-
-  //! Maximum ray-tracing depth.
-  Standard_Integer RaytracingDepth;
-
-  //! Number of samples per pixel (SPP).
-  Standard_Integer SamplesPerPixel;
-
-  //! Enables/disables shadows rendering.
-  Standard_Boolean IsShadowEnabled;
-
-  //! Enables/disables specular reflections.
-  Standard_Boolean IsReflectionEnabled;
-  
-  //! Enables/disables adaptive anti-aliasing.
-  Standard_Boolean IsAntialiasingEnabled;
-
-  //! Enables/disables light propagation through transparent media.
-  Standard_Boolean IsTransparentShadowEnabled;
-
-  //! Enables/disables global illumination effects (uses path tracing).
-  Standard_Boolean IsGlobalIlluminationEnabled;
-
-  //! Enables/disables environment map background (instead of OCCT background).
-  Standard_Boolean UseEnvironmentMapBackground;
+  Graphic3d_RenderingMode Method;                      //!< specifies rendering mode, Graphic3d_RM_RASTERIZATION by default
+
+  Standard_Boolean        IsGlobalIlluminationEnabled; //!< enables/disables global illumination effects (path tracing)
+  Standard_Integer        SamplesPerPixel;             //!< number of samples per pixel (SPP)
+  Standard_Integer        RaytracingDepth;             //!< maximum ray-tracing depth, 3 by default
+  Standard_Boolean        IsShadowEnabled;             //!< enables/disables shadows rendering, True by default
+  Standard_Boolean        IsReflectionEnabled;         //!< enables/disables specular reflections, False by default
+  Standard_Boolean        IsAntialiasingEnabled;       //!< enables/disables adaptive anti-aliasing, False by default
+  Standard_Boolean        IsTransparentShadowEnabled;  //!< enables/disables light propagation through transparent media, False by default
+  Standard_Boolean        UseEnvironmentMapBackground; //!< enables/disables environment map background
+
+  Graphic3d_StereoMode    StereoMode;                  //!< stereoscopic output mode, Graphic3d_StereoMode_QuadBuffer by default
+  Anaglyph                AnaglyphFilter;              //!< filter for anaglyph output, Anaglyph_RedCyan_Optimized by default
+  Graphic3d_Mat4          AnaglyphLeft;                //!< left  anaglyph filter (in normalized colorspace), Color = AnaglyphRight * theColorRight + AnaglyphLeft * theColorLeft;
+  Graphic3d_Mat4          AnaglyphRight;               //!< right anaglyph filter (in normalized colorspace), Color = AnaglyphRight * theColorRight + AnaglyphLeft * theColorLeft;
+  Standard_Boolean        ToReverseStereo;             //!< flag to reverse stereo pair, FALSE by default
 
 };
 
diff --git a/src/Graphic3d/Graphic3d_StereoMode.hxx b/src/Graphic3d/Graphic3d_StereoMode.hxx
new file mode 100644 (file)
index 0000000..0c0a979
--- /dev/null
@@ -0,0 +1,33 @@
+// Created on: 2015-06-05
+// Created by: Kirill Gavrilov
+// Copyright (c) 2015 OPEN CASCADE SAS
+//
+// This file is part of Open CASCADE Technology software library.
+//
+// This library is free software; you can redistribute it and/or modify it under
+// the terms of the GNU Lesser General Public License version 2.1 as published
+// by the Free Software Foundation, with special exception defined in the file
+// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
+// distribution for complete text of the license and disclaimer of any warranty.
+//
+// Alternatively, this file may be used under the terms of Open CASCADE
+// commercial license or contractual agreement.
+
+#ifndef _Graphic3d_StereoMode_HeaderFile
+#define _Graphic3d_StereoMode_HeaderFile
+
+//! This enumeration defines the list of stereoscopic output modes.
+enum Graphic3d_StereoMode
+{
+  Graphic3d_StereoMode_QuadBuffer,       //!< OpenGL QuadBuffer
+  Graphic3d_StereoMode_Anaglyph,         //!< Anaglyph glasses, the type should be specified in addition
+  Graphic3d_StereoMode_RowInterlaced,    //!< Row-interlaced stereo
+  Graphic3d_StereoMode_ColumnInterlaced, //!< Column-interlaced stereo
+  Graphic3d_StereoMode_ChessBoard,       //!< chess-board stereo for DLP TVs
+  Graphic3d_StereoMode_SideBySide,       //!< horizontal pair
+  Graphic3d_StereoMode_OverUnder,        //!< vertical   pair
+  Graphic3d_StereoMode_SoftPageFlip,     //!< software PageFlip for shutter glasses, should NOT be used!
+  Graphic3d_StereoMode_NB                //!< the number of modes
+};
+
+#endif // _Graphic3d_StereoMode_HeaderFile
index 3c8c838..533bd92 100644 (file)
 #include <Aspect_Drawable.hxx>
 #include <Aspect_RenderingContext.hxx>
 
-typedef struct {
-  int mapped;
-} EXT_WINDOW ;
-
 /* WINDOW */
 
 typedef struct {
@@ -31,17 +27,8 @@ typedef struct {
   Aspect_Drawable XWindow;
   Aspect_Drawable XParentWindow;
 
-  EXT_WINDOW *ext_data;
-
-  struct {
-    float xm, ym, xM, yM;
-  } Position;
-
   int dx, dy;
-
-  char *Title;
-
-  char *Icon;
+  int left, top;
 
   struct {
     float r, g, b;
index 68e3d16..ec09503 100644 (file)
 
 //const OSD_WhoAmI Iam = OSD_WEnvironmentIterator;
 #ifdef __APPLE__
+  #import <TargetConditionals.h>
   #if defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE
+    extern char **environ;
+  #else
     #include <crt_externs.h>
     #define environ (*_NSGetEnviron())
-  #else
-    extern char **environ;
   #endif
 #else
   extern char **environ;
index 16ca279..f7c4c84 100755 (executable)
@@ -33,6 +33,7 @@ OpenGl_Caps::OpenGl_Caps()
 #else
   ffpEnable         (Standard_False),
 #endif
+  swapInterval      (1),
   buffersNoSwap     (Standard_False),
   contextStereo     (Standard_False),
 #ifdef OCCT_DEBUG
@@ -64,6 +65,7 @@ OpenGl_Caps& OpenGl_Caps::operator= (const OpenGl_Caps& theCopy)
   pntSpritesDisable = theCopy.pntSpritesDisable;
   keepArrayData     = theCopy.keepArrayData;
   ffpEnable         = theCopy.ffpEnable;
+  swapInterval      = theCopy.swapInterval;
   buffersNoSwap     = theCopy.buffersNoSwap;
   contextStereo     = theCopy.contextStereo;
   contextDebug      = theCopy.contextDebug;
index fa60482..10d835e 100755 (executable)
@@ -31,6 +31,7 @@ public: //! @name flags to disable particular functionality, should be used only
   Standard_Boolean pntSpritesDisable; //!< flag permits Point Sprites usage, will significantly affect performance (OFF by default)
   Standard_Boolean keepArrayData;     //!< Disables freeing CPU memory after building VBOs (OFF by default)
   Standard_Boolean ffpEnable;         //!< Enables FFP (fixed-function pipeline), do not use built-in GLSL programs (ON by default on desktop OpenGL and OFF on OpenGL ES)
+  Standard_Integer swapInterval;      //!< controls swap interval - 0 for VSync off and 1 for VSync on, 1 by default
 
 public: //! @name context creation parameters
 
index e03a187..a20436e 100644 (file)
   //
 #elif defined(__APPLE__) && !defined(MACOSX_USE_GLX)
   #include <dlfcn.h>
+  #if defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE
+    //
+  #else
+    #include <OpenGL/OpenGL.h>
+  #endif
 #else
   #include <GL/glx.h> // glXGetProcAddress()
 #endif
@@ -527,6 +532,48 @@ void OpenGl_Context::SwapBuffers()
 #endif // __APPLE__
 
 // =======================================================================
+// function : SetSwapInterval
+// purpose  :
+// =======================================================================
+Standard_Boolean OpenGl_Context::SetSwapInterval (const Standard_Integer theInterval)
+{
+#if defined(HAVE_EGL)
+  if (::eglSwapInterval ((EGLDisplay )myDisplay, theInterval) == EGL_TRUE)
+  {
+    return Standard_True;
+  }
+#elif defined(_WIN32)
+  if (myFuncs->wglSwapIntervalEXT != NULL)
+  {
+    myFuncs->wglSwapIntervalEXT (theInterval);
+    return Standard_True;
+  }
+#elif defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE
+  //
+#elif defined(__APPLE__)
+  if (::CGLSetParameter (CGLGetCurrentContext(), kCGLCPSwapInterval, &theInterval) == kCGLNoError)
+  {
+    return Standard_True;
+  }
+#else
+  if (theInterval == -1
+   && myFuncs->glXSwapIntervalEXT != NULL)
+  {
+    typedef int (*glXSwapIntervalEXT_t_x)(Display* theDisplay, GLXDrawable theDrawable, int theInterval);
+    glXSwapIntervalEXT_t_x aFuncPtr = (glXSwapIntervalEXT_t_x )myFuncs->glXSwapIntervalEXT;
+    aFuncPtr ((Display* )myDisplay, (GLXDrawable )myWindow, theInterval);
+    return Standard_True;
+  }
+  else if (myFuncs->glXSwapIntervalSGI != NULL)
+  {
+    myFuncs->glXSwapIntervalSGI (theInterval);
+    return Standard_True;
+  }
+#endif
+  return Standard_False;
+}
+
+// =======================================================================
 // function : findProc
 // purpose  :
 // =======================================================================
@@ -1127,7 +1174,9 @@ void OpenGl_Context::init (const Standard_Boolean theIsCoreProfile)
   #define FindProcShort(theFunc) FindProc(#theFunc, myFuncs->theFunc)
 
   // retrieve platform-dependent extensions
-#if defined(_WIN32) && !defined(HAVE_EGL)
+#if defined(HAVE_EGL)
+  //
+#elif defined(_WIN32)
   if (FindProcShort (wglGetExtensionsStringARB))
   {
     const char* aWglExts = myFuncs->wglGetExtensionsStringARB (wglGetCurrentDC());
@@ -1155,6 +1204,19 @@ void OpenGl_Context::init (const Standard_Boolean theIsCoreProfile)
       FindProcShort (wglDXUnlockObjectsNV);
     }
   }
+#elif defined(__APPLE__)
+    //
+#else
+    const char* aGlxExts = ::glXQueryExtensionsString ((Display* )myDisplay, DefaultScreen ((Display* )myDisplay));
+    if (CheckExtension (aGlxExts, "GLX_EXT_swap_control"))
+    {
+      FindProcShort (glXSwapIntervalEXT);
+    }
+    if (CheckExtension (aGlxExts, "GLX_SGI_swap_control"))
+    {
+      FindProcShort (glXSwapIntervalSGI);
+    }
+    //extSwapTear = CheckExtension (aGlxExts, "GLX_EXT_swap_control_tear");
 #endif
 
   // initialize debug context extension
index 5f64eaf..8017c35 100644 (file)
@@ -299,6 +299,9 @@ public:
         || (myGlVerMajor == theVerMajor && myGlVerMinor >= theVerMinor);
   }
 
+  //! Access entire map of loaded OpenGL functions.
+  const OpenGl_GlFunctions* Functions() const { return myFuncs.operator->(); }
+
   //! Clean up errors stack for this GL context (glGetError() in loop).
   Standard_EXPORT void ResetErrors();
 
@@ -314,6 +317,9 @@ public:
   //! Swap front/back buffers for this GL context (should be activated before!).
   Standard_EXPORT void SwapBuffers();
 
+  //! Setup swap interval (VSync).
+  Standard_EXPORT Standard_Boolean SetSwapInterval (const Standard_Integer theInterval);
+
   //! Return true if active mode is GL_RENDER (cached state)
   Standard_Boolean IsRender() const
   {
index 7c7ea07..5c22483 100644 (file)
@@ -310,6 +310,13 @@ Standard_Boolean OpenGl_GraphicDriver::BufferDump (const Graphic3d_CView&      t
   return (aCView != NULL) && aCView->WS->BufferDump ((OpenGl_FrameBuffer* )theCView.ptrFBO, theImage, theBufferType);
 }
 
+//! Compute aligned number greater or equal to specified one
+inline Standard_Size getAligned (const Standard_Size theNumber,
+                                 const Standard_Size theAlignment)
+{
+  return theNumber + theAlignment - 1 - (theNumber - 1) % theAlignment;
+}
+
 Standard_Boolean OpenGl_Workspace::BufferDump (OpenGl_FrameBuffer*         theFBOPtr,
                                                Image_PixMap&               theImage,
                                                const Graphic3d_BufferType& theBufferType)
@@ -348,14 +355,30 @@ Standard_Boolean OpenGl_Workspace::BufferDump (OpenGl_FrameBuffer*         theFB
   // setup alignment
   const GLint anAligment   = Min (GLint(theImage.MaxRowAligmentBytes()), 8); // limit to 8 bytes for OpenGL
   glPixelStorei (GL_PACK_ALIGNMENT, anAligment);
+  bool isBatchCopy = !theImage.IsTopDown();
 
+  const GLint   anExtraBytes       = GLint(theImage.RowExtraBytes());
+  GLint         aPixelsWidth       = GLint(theImage.SizeRowBytes() / theImage.SizePixelBytes());
+  Standard_Size aSizeRowBytesEstim = getAligned (theImage.SizePixelBytes() * aPixelsWidth, anAligment);
+  if (anExtraBytes < anAligment)
+  {
+    aPixelsWidth = 0;
+  }
+  else if (aSizeRowBytesEstim != theImage.SizeRowBytes())
+  {
+    aPixelsWidth = 0;
+    isBatchCopy  = false;
+  }
 #if !defined(GL_ES_VERSION_2_0)
-  const GLint anExtraBytes = (GLint )theImage.RowExtraBytes();
-  const GLint aPixelsWidth = GLint(theImage.SizeRowBytes() / theImage.SizePixelBytes());
-  glPixelStorei (GL_PACK_ROW_LENGTH, (anExtraBytes >= anAligment) ? aPixelsWidth : 0);
+  glPixelStorei (GL_PACK_ROW_LENGTH, aPixelsWidth);
+#else
+  if (aPixelsWidth != 0)
+  {
+    isBatchCopy = false;
+  }
 #endif
 
-  if (theImage.IsTopDown())
+  if (!isBatchCopy)
   {
     // copy row by row
     for (Standard_Size aRow = 0; aRow < theImage.SizeY(); ++aRow)
index e8fa317..b9caec7 100644 (file)
@@ -237,7 +237,10 @@ void OpenGl_ShaderManager::clear()
   myMapOfLightPrograms.Clear();
   myFontProgram.Nullify();
   myBlitProgram.Nullify();
-  myAnaglyphProgram.Nullify();
+  for (Standard_Integer aModeIter = 0; aModeIter < Graphic3d_StereoMode_NB; ++aModeIter)
+  {
+    myStereoPrograms[aModeIter].Nullify();
+  }
   switchLightPrograms();
 }
 
@@ -1629,10 +1632,11 @@ Standard_Boolean OpenGl_ShaderManager::prepareStdProgramPhong (Handle(OpenGl_Sha
 }
 
 // =======================================================================
-// function : prepareStdProgramAnaglyph
+// function : prepareStdProgramStereo
 // purpose  :
 // =======================================================================
-Standard_Boolean OpenGl_ShaderManager::prepareStdProgramAnaglyph()
+Standard_Boolean OpenGl_ShaderManager::prepareStdProgramStereo (Handle(OpenGl_ShaderProgram)& theProgram,
+                                                                const Graphic3d_StereoMode    theStereoMode)
 {
   Handle(Graphic3d_ShaderProgram) aProgramSrc = new Graphic3d_ShaderProgram();
   TCollection_AsciiString aSrcVert =
@@ -1643,21 +1647,188 @@ Standard_Boolean OpenGl_ShaderManager::prepareStdProgramAnaglyph()
       EOL"  gl_Position = vec4(occVertex.x, occVertex.y, 0.0, 1.0);"
       EOL"}";
 
-  TCollection_AsciiString aSrcFrag =
-      EOL"uniform sampler2D uLeftSampler;"
-      EOL"uniform sampler2D uRightSampler;"
-      EOL
-      EOL"THE_SHADER_IN vec2 TexCoord;"
-      EOL
-      EOL"void main()"
-      EOL"{"
-      EOL"  vec4 aColorL = occTexture2D (uLeftSampler,  TexCoord);"
-      EOL"  vec4 aColorR = occTexture2D (uRightSampler, TexCoord);"
-      EOL"  aColorL.b = 0.0;"
-      EOL"  aColorL.g = 0.0;"
-      EOL"  aColorR.r = 0.0;"
-      EOL"  occFragColor = aColorL + aColorR;"
-      EOL"}";
+  TCollection_AsciiString aSrcFrag;
+  switch (theStereoMode)
+  {
+    case Graphic3d_StereoMode_Anaglyph:
+    {
+      aSrcFrag =
+          EOL"uniform sampler2D uLeftSampler;"
+          EOL"uniform sampler2D uRightSampler;"
+          EOL
+          EOL"uniform mat4 uMultL;"
+          EOL"uniform mat4 uMultR;"
+          EOL
+          EOL"vec4 THE_POW_UP   = vec4 (2.2, 2.2, 2.2, 1.0);"
+          EOL"vec4 THE_POW_DOWN = 1.0 / THE_POW_UP;"
+          EOL
+          EOL"THE_SHADER_IN vec2 TexCoord;"
+          EOL
+          EOL"void main()"
+          EOL"{"
+          EOL"  vec4 aColorL = occTexture2D (uLeftSampler,  TexCoord);"
+          EOL"  vec4 aColorR = occTexture2D (uRightSampler, TexCoord);"
+          EOL"  aColorL = pow (aColorL, THE_POW_UP);" // normalize
+          EOL"  aColorR = pow (aColorR, THE_POW_UP);"
+          EOL"  vec4 aColor = uMultR * aColorR + uMultL * aColorL;"
+          EOL"  occFragColor = pow (aColor, THE_POW_DOWN);"
+          EOL"}";
+      break;
+    }
+    case Graphic3d_StereoMode_RowInterlaced:
+    {
+      aSrcFrag =
+          EOL"uniform sampler2D uLeftSampler;"
+          EOL"uniform sampler2D uRightSampler;"
+          EOL
+          EOL"THE_SHADER_IN vec2 TexCoord;"
+          EOL
+          EOL"void main()"
+          EOL"{"
+          EOL"  vec4 aColorL = occTexture2D (uLeftSampler,  TexCoord);"
+          EOL"  vec4 aColorR = occTexture2D (uRightSampler, TexCoord);"
+          EOL"  if (int (mod (gl_FragCoord.y + 1.5, 2.0)) == 1)"
+          EOL"  {"
+          EOL"    occFragColor = aColorL;"
+          EOL"  }"
+          EOL"  else"
+          EOL"  {"
+          EOL"    occFragColor = aColorR;"
+          EOL"  }"
+          EOL"}";
+      break;
+    }
+    case Graphic3d_StereoMode_ColumnInterlaced:
+    {
+      aSrcFrag =
+          EOL"uniform sampler2D uLeftSampler;"
+          EOL"uniform sampler2D uRightSampler;"
+          EOL
+          EOL"THE_SHADER_IN vec2 TexCoord;"
+          EOL
+          EOL"void main()"
+          EOL"{"
+          EOL"  vec4 aColorL = occTexture2D (uLeftSampler,  TexCoord);"
+          EOL"  vec4 aColorR = occTexture2D (uRightSampler, TexCoord);"
+          EOL"  if (int (mod (gl_FragCoord.x + 1.5, 2.0)) != 1)"
+          EOL"  {"
+          EOL"    occFragColor = aColorL;"
+          EOL"  }"
+          EOL"  else"
+          EOL"  {"
+          EOL"    occFragColor = aColorR;"
+          EOL"  }"
+          EOL"}";
+      break;
+    }
+    case Graphic3d_StereoMode_ChessBoard:
+    {
+      aSrcFrag =
+          EOL"uniform sampler2D uLeftSampler;"
+          EOL"uniform sampler2D uRightSampler;"
+          EOL
+          EOL"THE_SHADER_IN vec2 TexCoord;"
+          EOL
+          EOL"void main()"
+          EOL"{"
+          EOL"  vec4 aColorL = occTexture2D (uLeftSampler,  TexCoord);"
+          EOL"  vec4 aColorR = occTexture2D (uRightSampler, TexCoord);"
+          EOL"  bool isEvenX = int(mod(floor(gl_FragCoord.x + 1.5), 2.0)) == 1;"
+          EOL"  bool isEvenY = int(mod(floor(gl_FragCoord.y + 1.5), 2.0)) != 1;"
+          EOL"  if ((isEvenX && isEvenY) || (!isEvenX && !isEvenY))"
+          EOL"  {"
+          EOL"    occFragColor = aColorL;"
+          EOL"  }"
+          EOL"  else"
+          EOL"  {"
+          EOL"    occFragColor = aColorR;"
+          EOL"  }"
+          EOL"}";
+      break;
+    }
+    case Graphic3d_StereoMode_SideBySide:
+    {
+      aSrcFrag =
+          EOL"uniform sampler2D uLeftSampler;"
+          EOL"uniform sampler2D uRightSampler;"
+          EOL
+          EOL"THE_SHADER_IN vec2 TexCoord;"
+          EOL
+          EOL"void main()"
+          EOL"{"
+          EOL"  vec2 aTexCoord = vec2 (TexCoord.x * 2.0, TexCoord.y);"
+          EOL"  if (TexCoord.x > 0.5)"
+          EOL"  {"
+          EOL"    aTexCoord.x -= 1.0;"
+          EOL"  }"
+          EOL"  vec4 aColorL = occTexture2D (uLeftSampler,  aTexCoord);"
+          EOL"  vec4 aColorR = occTexture2D (uRightSampler, aTexCoord);"
+          EOL"  if (TexCoord.x <= 0.5)"
+          EOL"  {"
+          EOL"    occFragColor = aColorL;"
+          EOL"  }"
+          EOL"  else"
+          EOL"  {"
+          EOL"    occFragColor = aColorR;"
+          EOL"  }"
+          EOL"}";
+      break;
+    }
+    case Graphic3d_StereoMode_OverUnder:
+    {
+      aSrcFrag =
+          EOL"uniform sampler2D uLeftSampler;"
+          EOL"uniform sampler2D uRightSampler;"
+          EOL
+          EOL"THE_SHADER_IN vec2 TexCoord;"
+          EOL
+          EOL"void main()"
+          EOL"{"
+          EOL"  vec2 aTexCoord = vec2 (TexCoord.x, TexCoord.y * 2.0);"
+          EOL"  if (TexCoord.y > 0.5)"
+          EOL"  {"
+          EOL"    aTexCoord.y -= 1.0;"
+          EOL"  }"
+          EOL"  vec4 aColorL = occTexture2D (uLeftSampler,  aTexCoord);"
+          EOL"  vec4 aColorR = occTexture2D (uRightSampler, aTexCoord);"
+          EOL"  if (TexCoord.y <= 0.5)"
+          EOL"  {"
+          EOL"    occFragColor = aColorL;"
+          EOL"  }"
+          EOL"  else"
+          EOL"  {"
+          EOL"    occFragColor = aColorR;"
+          EOL"  }"
+          EOL"}";
+      break;
+    }
+    case Graphic3d_StereoMode_QuadBuffer:
+    case Graphic3d_StereoMode_SoftPageFlip:
+    default:
+    {
+      /*const Handle(OpenGl_ShaderProgram)& aProgram = myStereoPrograms[Graphic3d_StereoMode_QuadBuffer];
+      if (!aProgram.IsNull())
+      {
+        return aProgram->IsValid();
+      }*/
+      aSrcFrag =
+          EOL"uniform sampler2D uLeftSampler;"
+          EOL"uniform sampler2D uRightSampler;"
+          EOL
+          EOL"THE_SHADER_IN vec2 TexCoord;"
+          EOL
+          EOL"void main()"
+          EOL"{"
+          EOL"  vec4 aColorL = occTexture2D (uLeftSampler,  TexCoord);"
+          EOL"  vec4 aColorR = occTexture2D (uRightSampler, TexCoord);"
+          EOL"  aColorL.b = 0.0;"
+          EOL"  aColorL.g = 0.0;"
+          EOL"  aColorR.r = 0.0;"
+          EOL"  occFragColor = aColorL + aColorR;"
+          EOL"}";
+      break;
+    }
+  }
 
 #if !defined(GL_ES_VERSION_2_0)
   if (myContext->core32 != NULL)
@@ -1669,15 +1840,15 @@ Standard_Boolean OpenGl_ShaderManager::prepareStdProgramAnaglyph()
   aProgramSrc->AttachShader (Graphic3d_ShaderObject::CreateFromSource (Graphic3d_TOS_VERTEX,   aSrcVert));
   aProgramSrc->AttachShader (Graphic3d_ShaderObject::CreateFromSource (Graphic3d_TOS_FRAGMENT, aSrcFrag));
   TCollection_AsciiString aKey;
-  if (!Create (aProgramSrc, aKey, myAnaglyphProgram))
+  if (!Create (aProgramSrc, aKey, theProgram))
   {
-    myAnaglyphProgram = new OpenGl_ShaderProgram(); // just mark as invalid
+    theProgram = new OpenGl_ShaderProgram(); // just mark as invalid
     return Standard_False;
   }
 
-  myContext->BindProgram (myAnaglyphProgram);
-  myAnaglyphProgram->SetSampler (myContext, "uLeftSampler",  0);
-  myAnaglyphProgram->SetSampler (myContext, "uRightSampler", 1);
+  myContext->BindProgram (theProgram);
+  theProgram->SetSampler (myContext, "uLeftSampler",  0);
+  theProgram->SetSampler (myContext, "uRightSampler", 1);
   myContext->BindProgram (NULL);
   return Standard_True;
 }
index 7573314..88f1f9c 100644 (file)
@@ -17,6 +17,7 @@
 #define _OpenGl_ShaderManager_HeaderFile
 
 #include <Graphic3d_ShaderProgram.hxx>
+#include <Graphic3d_StereoMode.hxx>
 
 #include <NCollection_DataMap.hxx>
 #include <NCollection_Sequence.hxx>
@@ -161,15 +162,21 @@ public:
          && myContext->BindProgram (myBlitProgram);
   }
 
-  //! Bind program for rendering Anaglyph image.
-  Standard_Boolean BindAnaglyphProgram()
+  //! Bind program for rendering stereoscopic image.
+  Standard_Boolean BindStereoProgram (const Graphic3d_StereoMode theStereoMode)
   {
-    if (myAnaglyphProgram.IsNull())
+    if (theStereoMode < 0 || theStereoMode >= Graphic3d_StereoMode_NB)
     {
-      prepareStdProgramAnaglyph();
+      return Standard_False;
     }
-    return !myAnaglyphProgram.IsNull()
-         && myContext->BindProgram (myAnaglyphProgram);
+
+    if (myStereoPrograms[theStereoMode].IsNull())
+    {
+      prepareStdProgramStereo (myStereoPrograms[theStereoMode], theStereoMode);
+    }
+    const Handle(OpenGl_ShaderProgram)& aProgram = myStereoPrograms[theStereoMode];
+    return !aProgram.IsNull()
+         && myContext->BindProgram (aProgram);
   }
 
 public:
@@ -370,8 +377,9 @@ protected:
   //! Set pointer myLightPrograms to active lighting programs set from myMapOfLightPrograms
   Standard_EXPORT void switchLightPrograms();
 
-  //! Prepare standard GLSL program for Anaglyph image.
-  Standard_EXPORT Standard_Boolean prepareStdProgramAnaglyph();
+  //! Prepare standard GLSL program for stereoscopic image.
+  Standard_EXPORT Standard_Boolean prepareStdProgramStereo (Handle(OpenGl_ShaderProgram)& theProgram,
+                                                            const Graphic3d_StereoMode    theStereoMode);
 
 protected:
 
@@ -383,7 +391,7 @@ protected:
   Handle(OpenGl_ShaderProgram)       myBlitProgram;        //!< standard program for FBO blit emulation
   OpenGl_MapOfShaderPrograms         myMapOfLightPrograms; //!< map of lighting programs depending on shading model and lights configuration
 
-  Handle(OpenGl_ShaderProgram)       myAnaglyphProgram;    //!< standard program for Anaglyph image
+  Handle(OpenGl_ShaderProgram)       myStereoPrograms[Graphic3d_StereoMode_NB]; //!< standard stereo programs
 
   OpenGl_Context*                    myContext;            //!< OpenGL context
 
index 57c8872..785559c 100644 (file)
@@ -141,7 +141,8 @@ OpenGl_Window::OpenGl_Window (const Handle(OpenGl_GraphicDriver)& theDriver,
   myOwnGContext (theGContext == 0),
   myWidth   (theCWindow.dx),
   myHeight  (theCWindow.dy),
-  myBgColor (THE_DEFAULT_BG_COLOR)
+  myBgColor (THE_DEFAULT_BG_COLOR),
+  mySwapInterval (theCaps->swapInterval)
 {
   myBgColor.rgb[0] = theCWindow.Background.r;
   myBgColor.rgb[1] = theCWindow.Background.g;
@@ -672,7 +673,7 @@ OpenGl_Window::OpenGl_Window (const Handle(OpenGl_GraphicDriver)& theDriver,
   myGlContext->Init ((Aspect_Drawable )aWindow, (Aspect_Display )aDisp, (Aspect_RenderingContext )aGContext, isCoreProfile);
 #endif
   myGlContext->Share (theShareCtx);
-
+  myGlContext->SetSwapInterval (mySwapInterval);
   Init();
 }
 
index 6b0d224..df7f423 100644 (file)
@@ -98,6 +98,8 @@ protected:
   Standard_Integer       myHeight;      //!< window height in pixels
   TEL_COLOUR             myBgColor;     //!< background color
 
+  Standard_Integer       mySwapInterval;//!< last assigned swap interval (VSync) for this window
+
 public:
 
   DEFINE_STANDARD_RTTI(OpenGl_Window) // Type definition
index 6627c7d..a9386ea 100644 (file)
@@ -74,7 +74,8 @@ OpenGl_Window::OpenGl_Window (const Handle(OpenGl_GraphicDriver)& theDriver,
 #endif
   myWidth    (theCWindow.dx),
   myHeight   (theCWindow.dy),
-  myBgColor (THE_DEFAULT_BG_COLOR)
+  myBgColor (THE_DEFAULT_BG_COLOR),
+  mySwapInterval (theCaps->swapInterval)
 {
   myBgColor.rgb[0] = theCWindow.Background.r;
   myBgColor.rgb[1] = theCWindow.Background.g;
@@ -217,6 +218,7 @@ OpenGl_Window::OpenGl_Window (const Handle(OpenGl_GraphicDriver)& theDriver,
 #endif
 
   myGlContext->Share (theShareCtx);
+  myGlContext->SetSwapInterval (mySwapInterval);
   Init();
 }
 
index 565a064..c9177ef 100644 (file)
@@ -706,6 +706,10 @@ bool OpenGl_Workspace::blitBuffers (OpenGl_FrameBuffer* theReadFbo,
   {
     return false;
   }
+  else if (theReadFbo == theDrawFbo)
+  {
+    return true;
+  }
 
   // clear destination before blitting
   if (theDrawFbo != NULL
@@ -807,7 +811,7 @@ bool OpenGl_Workspace::blitBuffers (OpenGl_FrameBuffer* theReadFbo,
 // function : drawStereoPair
 // purpose  :
 // =======================================================================
-void OpenGl_Workspace::drawStereoPair()
+void OpenGl_Workspace::drawStereoPair (const Graphic3d_CView& theCView)
 {
   OpenGl_FrameBuffer* aPair[2] =
   {
@@ -815,7 +819,8 @@ void OpenGl_Workspace::drawStereoPair()
     myImmediateSceneFbos[1]->IsValid() ? myImmediateSceneFbos[1].operator->() : NULL
   };
   if (aPair[0] == NULL
-   || aPair[1] == NULL)
+  ||  aPair[1] == NULL
+  || !myTransientDrawToFront)
   {
     aPair[0] = myMainSceneFbos[0]->IsValid() ? myMainSceneFbos[0].operator->() : NULL;
     aPair[1] = myMainSceneFbos[1]->IsValid() ? myMainSceneFbos[1].operator->() : NULL;
@@ -827,6 +832,27 @@ void OpenGl_Workspace::drawStereoPair()
     return;
   }
 
+  Standard_Boolean toReverse = theCView.RenderParams.ToReverseStereo;
+  const Standard_Boolean isOddY = (theCView.DefWindow.top + theCView.DefWindow.dy) % 2 == 1;
+  const Standard_Boolean isOddX =  theCView.DefWindow.left % 2 == 1;
+  if (isOddY
+   && (theCView.RenderParams.StereoMode == Graphic3d_StereoMode_RowInterlaced
+    || theCView.RenderParams.StereoMode == Graphic3d_StereoMode_ChessBoard))
+  {
+    toReverse = !toReverse;
+  }
+  if (isOddX
+   && (theCView.RenderParams.StereoMode == Graphic3d_StereoMode_ColumnInterlaced
+    || theCView.RenderParams.StereoMode == Graphic3d_StereoMode_ChessBoard))
+  {
+    toReverse = !toReverse;
+  }
+
+  if (toReverse)
+  {
+    std::swap (aPair[0], aPair[1]);
+  }
+
   myGlContext->core20fwd->glDepthFunc (GL_ALWAYS);
   myGlContext->core20fwd->glDepthMask (GL_TRUE);
   myGlContext->core20fwd->glEnable (GL_DEPTH_TEST);
@@ -846,8 +872,71 @@ void OpenGl_Workspace::drawStereoPair()
 
   const Handle(OpenGl_ShaderManager)& aManager = myGlContext->ShaderManager();
   if (myFullScreenQuad.IsValid()
-   && aManager->BindAnaglyphProgram())
+   && aManager->BindStereoProgram (theCView.RenderParams.StereoMode))
   {
+    if (theCView.RenderParams.StereoMode == Graphic3d_StereoMode_Anaglyph)
+    {
+      OpenGl_Mat4 aFilterL, aFilterR;
+      aFilterL.SetDiagonal (Graphic3d_Vec4 (0.0f, 0.0f, 0.0f, 0.0f));
+      aFilterR.SetDiagonal (Graphic3d_Vec4 (0.0f, 0.0f, 0.0f, 0.0f));
+      switch (theCView.RenderParams.AnaglyphFilter)
+      {
+        case Graphic3d_RenderingParams::Anaglyph_RedCyan_Simple:
+        {
+          aFilterL.SetRow (0, Graphic3d_Vec4 (1.0f, 0.0f, 0.0f, 0.0f));
+          aFilterR.SetRow (1, Graphic3d_Vec4 (0.0f, 1.0f, 0.0f, 0.0f));
+          aFilterR.SetRow (2, Graphic3d_Vec4 (0.0f, 0.0f, 1.0f, 0.0f));
+          break;
+        }
+        case Graphic3d_RenderingParams::Anaglyph_RedCyan_Optimized:
+        {
+          aFilterL.SetRow (0, Graphic3d_Vec4 ( 0.4154f,      0.4710f,      0.16666667f, 0.0f));
+          aFilterL.SetRow (1, Graphic3d_Vec4 (-0.0458f,     -0.0484f,     -0.0257f,     0.0f));
+          aFilterL.SetRow (2, Graphic3d_Vec4 (-0.0547f,     -0.0615f,      0.0128f,     0.0f));
+          aFilterL.SetRow (3, Graphic3d_Vec4 ( 0.0f,         0.0f,         0.0f,        0.0f));
+          aFilterR.SetRow (0, Graphic3d_Vec4 (-0.01090909f, -0.03636364f, -0.00606061f, 0.0f));
+          aFilterR.SetRow (1, Graphic3d_Vec4 ( 0.37560000f,  0.73333333f,  0.01111111f, 0.0f));
+          aFilterR.SetRow (2, Graphic3d_Vec4 (-0.06510000f, -0.12870000f,  1.29710000f, 0.0f));
+          aFilterR.SetRow (3, Graphic3d_Vec4 ( 0.0f,                0.0f,  0.0f,        0.0f));
+          break;
+        }
+        case Graphic3d_RenderingParams::Anaglyph_YellowBlue_Simple:
+        {
+          aFilterL.SetRow (0, Graphic3d_Vec4 (1.0f, 0.0f, 0.0f, 0.0f));
+          aFilterL.SetRow (1, Graphic3d_Vec4 (0.0f, 1.0f, 0.0f, 0.0f));
+          aFilterR.SetRow (2, Graphic3d_Vec4 (0.0f, 0.0f, 1.0f, 0.0f));
+          break;
+        }
+        case Graphic3d_RenderingParams::Anaglyph_YellowBlue_Optimized:
+        {
+          aFilterL.SetRow (0, Graphic3d_Vec4 ( 1.062f, -0.205f,  0.299f, 0.0f));
+          aFilterL.SetRow (1, Graphic3d_Vec4 (-0.026f,  0.908f,  0.068f, 0.0f));
+          aFilterL.SetRow (2, Graphic3d_Vec4 (-0.038f, -0.173f,  0.022f, 0.0f));
+          aFilterL.SetRow (3, Graphic3d_Vec4 ( 0.0f,    0.0f,    0.0f,   0.0f));
+          aFilterR.SetRow (0, Graphic3d_Vec4 (-0.016f, -0.123f, -0.017f, 0.0f));
+          aFilterR.SetRow (1, Graphic3d_Vec4 ( 0.006f,  0.062f, -0.017f, 0.0f));
+          aFilterR.SetRow (2, Graphic3d_Vec4 ( 0.094f,  0.185f,  0.911f, 0.0f));
+          aFilterR.SetRow (3, Graphic3d_Vec4 ( 0.0f,    0.0f,    0.0f,   0.0f));
+          break;
+        }
+        case Graphic3d_RenderingParams::Anaglyph_GreenMagenta_Simple:
+        {
+          aFilterR.SetRow (0, Graphic3d_Vec4 (1.0f, 0.0f, 0.0f, 0.0f));
+          aFilterL.SetRow (1, Graphic3d_Vec4 (0.0f, 1.0f, 0.0f, 0.0f));
+          aFilterR.SetRow (2, Graphic3d_Vec4 (0.0f, 0.0f, 1.0f, 0.0f));
+          break;
+        }
+        case Graphic3d_RenderingParams::Anaglyph_UserDefined:
+        {
+          aFilterL = theCView.RenderParams.AnaglyphLeft;
+          aFilterR = theCView.RenderParams.AnaglyphRight;
+          break;
+        }
+      }
+      myGlContext->ActiveProgram()->SetUniform (myGlContext, "uMultL", aFilterL);
+      myGlContext->ActiveProgram()->SetUniform (myGlContext, "uMultR", aFilterR);
+    }
+
     aPair[0]->ColorTexture()->Bind (myGlContext, GL_TEXTURE0 + 0);
     aPair[1]->ColorTexture()->Bind (myGlContext, GL_TEXTURE0 + 1);
     myFullScreenQuad.BindVertexAttrib (myGlContext, 0);
@@ -883,8 +972,17 @@ void OpenGl_Workspace::Redraw (const Graphic3d_CView& theCView,
     return;
   }
 
+  if (mySwapInterval != myGlContext->caps->swapInterval)
+  {
+    mySwapInterval = myGlContext->caps->swapInterval;
+    myGlContext->SetSwapInterval (mySwapInterval);
+  }
+
   ++myFrameCounter;
   myIsCullingEnabled = theCView.IsCullingEnabled;
+  const Graphic3d_StereoMode      aStereoMode  = theCView.RenderParams.StereoMode;
+  const Handle(Graphic3d_Camera)& aCamera      = myView->Camera();
+  Graphic3d_Camera::Projection    aProjectType = aCamera->ProjectionType();
 
   // release pending GL resources
   myGlContext->ReleaseDelayed();
@@ -908,7 +1006,7 @@ void OpenGl_Workspace::Redraw (const Graphic3d_CView& theCView,
   }
 
   if (myHasFboBlit
-   && myTransientDrawToFront)
+   && (myTransientDrawToFront || aProjectType == Graphic3d_Camera::Projection_Stereo))
   {
     if (myMainSceneFbos[0]->GetVPSizeX() != aSizeX
      || myMainSceneFbos[0]->GetVPSizeY() != aSizeY)
@@ -933,35 +1031,29 @@ void OpenGl_Workspace::Redraw (const Graphic3d_CView& theCView,
     myImmediateSceneFbos[1]->ChangeViewport (0, 0);
   }
 
-  // draw entire frame using normal OpenGL pipeline
-  const Handle(Graphic3d_Camera)& aCamera      = myView->Camera();
-  Graphic3d_Camera::Projection    aProjectType = aCamera->ProjectionType();
-  if (aProjectType == Graphic3d_Camera::Projection_Stereo)
+  if (aProjectType == Graphic3d_Camera::Projection_Stereo
+   && myMainSceneFbos[0]->IsValid())
   {
-    if (aFrameBuffer != NULL
-    || !myGlContext->IsRender())
+    myMainSceneFbos[1]->InitLazy (myGlContext, aSizeX, aSizeY);
+    if (!myMainSceneFbos[1]->IsValid())
     {
-      // implicitly switch to mono camera for image dump
+      // no enough memory?
       aProjectType = Graphic3d_Camera::Projection_Perspective;
     }
-    else if (myMainSceneFbos[0]->IsValid())
+    else if (!myTransientDrawToFront)
     {
-      myMainSceneFbos[1]->InitLazy (myGlContext, aSizeX, aSizeY);
-      if (!myMainSceneFbos[1]->IsValid())
+      //
+    }
+    else if (!myGlContext->HasStereoBuffers()
+           || aStereoMode != Graphic3d_StereoMode_QuadBuffer)
+    {
+      myImmediateSceneFbos[0]->InitLazy (myGlContext, aSizeX, aSizeY);
+      myImmediateSceneFbos[1]->InitLazy (myGlContext, aSizeX, aSizeY);
+      if (!myImmediateSceneFbos[0]->IsValid()
+       || !myImmediateSceneFbos[1]->IsValid())
       {
-        // no enough memory?
         aProjectType = Graphic3d_Camera::Projection_Perspective;
       }
-      else if (!myGlContext->HasStereoBuffers())
-      {
-        myImmediateSceneFbos[0]->InitLazy (myGlContext, aSizeX, aSizeY);
-        myImmediateSceneFbos[1]->InitLazy (myGlContext, aSizeX, aSizeY);
-        if (!myImmediateSceneFbos[0]->IsValid()
-         || !myImmediateSceneFbos[1]->IsValid())
-        {
-          aProjectType = Graphic3d_Camera::Projection_Perspective;
-        }
-      }
     }
   }
 
@@ -978,23 +1070,40 @@ void OpenGl_Workspace::Redraw (const Graphic3d_CView& theCView,
       myImmediateSceneFbos[1]->IsValid() ? myImmediateSceneFbos[1].operator->() : NULL
     };
 
+    if (!myTransientDrawToFront)
+    {
+      anImmFbos[0] = aMainFbos[0];
+      anImmFbos[1] = aMainFbos[1];
+    }
+    else if (aStereoMode == Graphic3d_StereoMode_SoftPageFlip
+          || aStereoMode == Graphic3d_StereoMode_QuadBuffer)
+    {
+      anImmFbos[0] = NULL;
+      anImmFbos[1] = NULL;
+    }
+
   #if !defined(GL_ES_VERSION_2_0)
-    myGlContext->SetReadDrawBuffer (GL_BACK_LEFT);
+    myGlContext->SetReadDrawBuffer (aStereoMode == Graphic3d_StereoMode_QuadBuffer ? GL_BACK_LEFT : GL_BACK);
   #endif
     redraw1 (theCView, theCUnderLayer, theCOverLayer,
              aMainFbos[0], Graphic3d_Camera::Projection_MonoLeftEye);
     myBackBufferRestored = Standard_True;
     myIsImmediateDrawn   = Standard_False;
   #if !defined(GL_ES_VERSION_2_0)
-    myGlContext->SetReadDrawBuffer (GL_BACK_LEFT);
+    myGlContext->SetReadDrawBuffer (aStereoMode == Graphic3d_StereoMode_QuadBuffer ? GL_BACK_LEFT : GL_BACK);
   #endif
     if (!redrawImmediate (theCView, theCOverLayer, theCUnderLayer, aMainFbos[0], aProjectType, anImmFbos[0]))
     {
       toSwap = false;
     }
+    else if (aStereoMode == Graphic3d_StereoMode_SoftPageFlip
+          && toSwap)
+    {
+      myGlContext->SwapBuffers();
+    }
 
   #if !defined(GL_ES_VERSION_2_0)
-    myGlContext->SetReadDrawBuffer (GL_BACK_RIGHT);
+    myGlContext->SetReadDrawBuffer (aStereoMode == Graphic3d_StereoMode_QuadBuffer ? GL_BACK_RIGHT : GL_BACK);
   #endif
     redraw1 (theCView, theCUnderLayer, theCOverLayer,
              aMainFbos[1], Graphic3d_Camera::Projection_MonoRightEye);
@@ -1008,7 +1117,7 @@ void OpenGl_Workspace::Redraw (const Graphic3d_CView& theCView,
     if (anImmFbos[0] != NULL)
     {
       bindDefaultFbo (aFrameBuffer);
-      drawStereoPair();
+      drawStereoPair (theCView);
     }
   }
   else
@@ -1227,6 +1336,7 @@ void OpenGl_Workspace::RedrawImmediate (const Graphic3d_CView& theCView,
     aFrameBuffer = myGlContext->DefaultFrameBuffer().operator->();
   }
 
+  const Graphic3d_StereoMode aStereoMode = theCView.RenderParams.StereoMode;
   if (aProjectType == Graphic3d_Camera::Projection_Stereo)
   {
     if (aFrameBuffer != NULL)
@@ -1266,6 +1376,12 @@ void OpenGl_Workspace::RedrawImmediate (const Graphic3d_CView& theCView,
       myImmediateSceneFbos[0]->IsValid() ? myImmediateSceneFbos[0].operator->() : NULL,
       myImmediateSceneFbos[1]->IsValid() ? myImmediateSceneFbos[1].operator->() : NULL
     };
+    if (aStereoMode == Graphic3d_StereoMode_SoftPageFlip
+     || aStereoMode == Graphic3d_StereoMode_QuadBuffer)
+    {
+      anImmFbos[0] = NULL;
+      anImmFbos[1] = NULL;
+    }
 
     if (myGlContext->arbFBO != NULL)
     {
@@ -1274,7 +1390,7 @@ void OpenGl_Workspace::RedrawImmediate (const Graphic3d_CView& theCView,
   #if !defined(GL_ES_VERSION_2_0)
     if (anImmFbos[0] == NULL)
     {
-      myGlContext->SetReadDrawBuffer (GL_BACK_LEFT);
+      myGlContext->SetReadDrawBuffer (aStereoMode == Graphic3d_StereoMode_QuadBuffer ? GL_BACK_LEFT : GL_BACK);
     }
   #endif
     toSwap = redrawImmediate (theCView, theCUnderLayer, theCOverLayer,
@@ -1282,6 +1398,12 @@ void OpenGl_Workspace::RedrawImmediate (const Graphic3d_CView& theCView,
                               Graphic3d_Camera::Projection_MonoLeftEye,
                               anImmFbos[0],
                               Standard_True) || toSwap;
+    if (aStereoMode == Graphic3d_StereoMode_SoftPageFlip
+    &&  toSwap
+    && !myGlContext->caps->buffersNoSwap)
+    {
+      myGlContext->SwapBuffers();
+    }
 
     if (myGlContext->arbFBO != NULL)
     {
@@ -1290,7 +1412,7 @@ void OpenGl_Workspace::RedrawImmediate (const Graphic3d_CView& theCView,
   #if !defined(GL_ES_VERSION_2_0)
     if (anImmFbos[1] == NULL)
     {
-      myGlContext->SetReadDrawBuffer (GL_BACK_RIGHT);
+      myGlContext->SetReadDrawBuffer (aStereoMode == Graphic3d_StereoMode_QuadBuffer ? GL_BACK_RIGHT : GL_BACK);
     }
   #endif
     toSwap = redrawImmediate (theCView, theCUnderLayer, theCOverLayer,
@@ -1301,7 +1423,7 @@ void OpenGl_Workspace::RedrawImmediate (const Graphic3d_CView& theCView,
     if (anImmFbos[0] != NULL)
     {
       bindDefaultFbo (aFrameBuffer);
-      drawStereoPair();
+      drawStereoPair (theCView);
     }
   }
   else
index 565e5f5..4a40ebc 100644 (file)
@@ -295,7 +295,7 @@ protected:
   void bindDefaultFbo (OpenGl_FrameBuffer* theCustomFbo = NULL);
 
   //! Blend together views pair into stereo image.
-  void drawStereoPair();
+  void drawStereoPair (const Graphic3d_CView& theCView);
 
   //! Blit snapshot containing main scene (myMainSceneFbos or BackBuffer)
   //! into presentation buffer (myMainSceneFbos -> offscreen FBO or myMainSceneFbos -> BackBuffer or BackBuffer -> FrontBuffer),
index e50a4dc..0b9a930 100755 (executable)
@@ -12,3 +12,4 @@ V3d_View_5.cxx
 V3d_Plane.hxx
 V3d_Plane.cxx
 V3d_ListOfTransient.hxx
+V3d_StereoDumpOptions.hxx
index 7d1f50d..96a9a2a 100644 (file)
@@ -156,16 +156,7 @@ is
         --            TOBM_ALWAYS_DISPLAYED     force display of back faces
         --            TOBM_NEVER_DISPLAYED      disable display of back faces
 
-        enumeration StereoDumpOptions is
-            SDO_MONO,
-            SDO_LEFT_EYE,
-            SDO_RIGHT_EYE
-        end StereoDumpOptions;
-        ---Purpose : Options to be used with image dumping.
-        --
-        --            SDO_MONO dump monographic projection for stereo camera
-        --            SDO_LEFT_EYE dump left eye projection for stereo camera
-        --            SDO_RIGHT_EYE dump right eye projection for stereo camera
+        primitive StereoDumpOptions;
 
         ------------------------
         ---Category: The classes
diff --git a/src/V3d/V3d_StereoDumpOptions.hxx b/src/V3d/V3d_StereoDumpOptions.hxx
new file mode 100644 (file)
index 0000000..f4b0b33
--- /dev/null
@@ -0,0 +1,29 @@
+// Created on: 2015-06-05
+// Created by: Kirill Gavrilov
+// Copyright (c) 2015 OPEN CASCADE SAS
+//
+// This file is part of Open CASCADE Technology software library.
+//
+// This library is free software; you can redistribute it and/or modify it under
+// the terms of the GNU Lesser General Public License version 2.1 as published
+// by the Free Software Foundation, with special exception defined in the file
+// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
+// distribution for complete text of the license and disclaimer of any warranty.
+//
+// Alternatively, this file may be used under the terms of Open CASCADE
+// commercial license or contractual agreement.
+
+#ifndef _V3d_StereoDumpOptions_HeaderFile
+#define _V3d_StereoDumpOptions_HeaderFile
+
+//! Options to be used with image dumping.
+//! Notice that the value will have no effect with disabled stereo output.
+enum V3d_StereoDumpOptions
+{
+  V3d_SDO_MONO,      //!< ignore stereo mode and dump monographic projection for stereo camera
+  V3d_SDO_LEFT_EYE,  //!< dump only left  eye projection for stereo camera
+  V3d_SDO_RIGHT_EYE, //!< dump only right eye projection for stereo camera
+  V3d_SDO_BLENDED    //!< dump blended pair specific to the active device output Graphic3d_StereoMode (result will be undefined for modes like Graphic3d_StereoMode_QuadBuffer)
+};
+
+#endif // _V3d_StereoDumpOptions_HeaderFile
index 132caf8..27e7708 100644 (file)
@@ -2872,17 +2872,25 @@ Standard_Boolean V3d_View::ToPixMap (Image_PixMap&               theImage,
   {
     switch (theStereoOptions)
     {
-      case V3d_SDO_MONO :
+      case V3d_SDO_MONO:
+      {
         myCamera->SetProjectionType (Graphic3d_Camera::Projection_Perspective);
         break;
-
-      case V3d_SDO_LEFT_EYE :
+      }
+      case V3d_SDO_LEFT_EYE:
+      {
         myCamera->SetProjectionType (Graphic3d_Camera::Projection_MonoLeftEye);
         break;
-
-      case V3d_SDO_RIGHT_EYE :
+      }
+      case V3d_SDO_RIGHT_EYE:
+      {
         myCamera->SetProjectionType (Graphic3d_Camera::Projection_MonoRightEye);
         break;
+      }
+      case V3d_SDO_BLENDED:
+      {
+        break; // dump as is
+      }
     }
   }
 
index 7f16c6d..fc76b2f 100644 (file)
@@ -759,6 +759,14 @@ static int VSelPrecision(Draw_Interpretor& di, Standard_Integer argc, const char
   return 0;
 }
 
+//! Auxiliary enumeration
+enum ViewerTest_StereoPair
+{
+  ViewerTest_SP_Single,
+  ViewerTest_SP_SideBySide,
+  ViewerTest_SP_OverUnder
+};
+
 //==============================================================================
 //function : VDump
 //purpose  : To dump the active view snapshot to image file
@@ -777,42 +785,108 @@ static Standard_Integer VDump (Draw_Interpretor& theDI,
   Standard_CString      aFilePath   = theArgVec[anArgIter++];
   Graphic3d_BufferType  aBufferType = Graphic3d_BT_RGB;
   V3d_StereoDumpOptions aStereoOpts = V3d_SDO_MONO;
+  ViewerTest_StereoPair aStereoPair = ViewerTest_SP_Single;
   Standard_Integer      aWidth      = 0;
   Standard_Integer      aHeight     = 0;
   for (; anArgIter < theArgNb; ++anArgIter)
   {
     TCollection_AsciiString anArg (theArgVec[anArgIter]);
     anArg.LowerCase();
-    if (anArg == "rgba")
+    if (anArg == "-buffer")
     {
-      aBufferType = Graphic3d_BT_RGBA;
-    }
-    else if (anArg == "rgb")
-    {
-      aBufferType = Graphic3d_BT_RGB;
+      if (++anArgIter >= theArgNb)
+      {
+        std::cout << "Error: wrong syntax at '" << anArg << "'\n";
+        return 1;
+      }
+
+      TCollection_AsciiString aBufArg (theArgVec[anArgIter]);
+      aBufArg.LowerCase();
+      if (aBufArg == "rgba")
+      {
+        aBufferType = Graphic3d_BT_RGBA;
+      }
+      else if (aBufArg == "rgb")
+      {
+        aBufferType = Graphic3d_BT_RGB;
+      }
+      else if (aBufArg == "depth")
+      {
+        aBufferType = Graphic3d_BT_Depth;
+      }
+      else
+      {
+        std::cout << "Error: unknown buffer '" << aBufArg << "'\n";
+        return 1;
+      }
     }
-    else if (anArg == "depth")
+    else if (anArg == "-stereo")
     {
-      aBufferType = Graphic3d_BT_Depth;
+      if (++anArgIter >= theArgNb)
+      {
+        std::cout << "Error: wrong syntax at '" << anArg << "'\n";
+        return 1;
+      }
+
+      TCollection_AsciiString aStereoArg (theArgVec[anArgIter]);
+      aStereoArg.LowerCase();
+      if (aStereoArg == "l"
+       || aStereoArg == "left")
+      {
+        aStereoOpts = V3d_SDO_LEFT_EYE;
+      }
+      else if (aStereoArg == "r"
+            || aStereoArg == "right")
+      {
+        aStereoOpts = V3d_SDO_RIGHT_EYE;
+      }
+      else if (aStereoArg == "mono")
+      {
+        aStereoOpts = V3d_SDO_MONO;
+      }
+      else if (aStereoArg == "blended"
+            || aStereoArg == "blend"
+            || aStereoArg == "stereo")
+      {
+        aStereoOpts = V3d_SDO_BLENDED;
+      }
+      else if (aStereoArg == "sbs"
+            || aStereoArg == "sidebyside")
+      {
+        aStereoPair = ViewerTest_SP_SideBySide;
+      }
+      else if (aStereoArg == "ou"
+            || aStereoArg == "overunder")
+      {
+        aStereoPair = ViewerTest_SP_OverUnder;
+      }
+      else
+      {
+        std::cout << "Error: unknown stereo format '" << aStereoArg << "'\n";
+        return 1;
+      }
     }
-    else if (anArg == "l"
-          || anArg == "left")
+    else if (anArg == "-rgba"
+          || anArg ==  "rgba")
     {
-      aStereoOpts = V3d_SDO_LEFT_EYE;
+      aBufferType = Graphic3d_BT_RGBA;
     }
-    else if (anArg == "r"
-          || anArg == "right")
+    else if (anArg == "-rgb"
+          || anArg ==  "rgb")
     {
-      aStereoOpts = V3d_SDO_RIGHT_EYE;
+      aBufferType = Graphic3d_BT_RGB;
     }
-    else if (anArg == "mono")
+    else if (anArg == "-depth"
+          || anArg ==  "depth")
     {
-      aStereoOpts = V3d_SDO_MONO;
+      aBufferType = Graphic3d_BT_Depth;
     }
-    else if (anArg == "w"
-          || anArg == "width")
+
+    else if (anArg == "-width"
+          || anArg ==  "width"
+          || anArg ==  "sizex")
     {
-      if (aWidth  != 0)
+      if (aWidth != 0)
       {
         std::cout << "Error: wrong syntax at " << theArgVec[anArgIter] << "\n";
         return 1;
@@ -824,36 +898,20 @@ static Standard_Integer VDump (Draw_Interpretor& theDI,
       }
       aWidth = Draw::Atoi (theArgVec[anArgIter]);
     }
-    else if (anArg == "h"
-          || anArg == "height")
+    else if (anArg == "-height"
+          || anArg ==  "height"
+          || anArg ==  "-sizey")
     {
       if (aHeight != 0)
       {
         std::cout << "Error: wrong syntax at " << theArgVec[anArgIter] << "\n";
         return 1;
       }
-      if (++anArgIter >= theArgNb)
-      {
-        std::cout << "Error: integer value is expected right after 'height'\n";
-        return 1;
-      }
-      aHeight = Draw::Atoi (theArgVec[anArgIter]);
-    }
-    else if (anArg.IsIntegerValue())
-    {
-      // compatibility with old syntax
-      if (aWidth  != 0
-       || aHeight != 0)
-      {
-        std::cout << "Error: wrong syntax at " << theArgVec[anArgIter] << "\n";
-        return 1;
-      }
       else if (++anArgIter >= theArgNb)
       {
-        std::cout << "Error: height value is expected right after width\n";
+        std::cout << "Error: integer value is expected right after 'height'\n";
         return 1;
       }
-      aWidth  = Draw::Atoi (theArgVec[anArgIter - 1]);
       aHeight = Draw::Atoi (theArgVec[anArgIter]);
     }
     else
@@ -878,33 +936,82 @@ static Standard_Integer VDump (Draw_Interpretor& theDI,
 
   if (aWidth <= 0 || aHeight <= 0)
   {
-    if (aStereoOpts != V3d_SDO_MONO)
+    aView->Window()->Size (aWidth, aHeight);
+  }
+
+  Image_AlienPixMap aPixMap;
+
+  bool isBigEndian = Image_PixMap::IsBigEndianHost();
+  Image_PixMap::ImgFormat aFormat = Image_PixMap::ImgUNKNOWN;
+  switch (aBufferType)
+  {
+    case Graphic3d_BT_RGB:   aFormat = isBigEndian ? Image_PixMap::ImgRGB  : Image_PixMap::ImgBGR;  break;
+    case Graphic3d_BT_RGBA:  aFormat = isBigEndian ? Image_PixMap::ImgRGBA : Image_PixMap::ImgBGRA; break;
+    case Graphic3d_BT_Depth: aFormat = Image_PixMap::ImgGrayF; break;
+  }
+
+  switch (aStereoPair)
+  {
+    case ViewerTest_SP_Single:
     {
-      aView->Window()->Size (aWidth, aHeight);
+      if (!aView->ToPixMap (aPixMap, aWidth, aHeight, aBufferType, Standard_True, aStereoOpts))
+      {
+        theDI << "Fail: view dump failed!\n";
+        return 0;
+      }
+      else if (aPixMap.SizeX() != Standard_Size(aWidth)
+            || aPixMap.SizeY() != Standard_Size(aHeight))
+      {
+        theDI << "Fail: dumped dimensions "    << (Standard_Integer )aPixMap.SizeX() << "x" << (Standard_Integer )aPixMap.SizeY()
+              << " are lesser than requested " << aWidth << "x" << aHeight << "\n";
+      }
+      break;
     }
-    else
+    case ViewerTest_SP_SideBySide:
     {
-      if (!aView->Dump (aFilePath, aBufferType))
+      if (!aPixMap.InitZero (aFormat, aWidth * 2, aHeight))
+      {
+        theDI << "Fail: not enough memory for image allocation!\n";
+        return 0;
+      }
+
+      Image_PixMap aPixMapL, aPixMapR;
+      aPixMapL.InitWrapper (aPixMap.Format(), aPixMap.ChangeData(),
+                            aWidth, aHeight, aPixMap.SizeRowBytes());
+      aPixMapR.InitWrapper (aPixMap.Format(), aPixMap.ChangeData() + aPixMap.SizePixelBytes() * aWidth,
+                            aWidth, aHeight, aPixMap.SizeRowBytes());
+      if (!aView->ToPixMap (aPixMapL, aWidth, aHeight, aBufferType, Standard_True, V3d_SDO_LEFT_EYE)
+       || !aView->ToPixMap (aPixMapR, aWidth, aHeight, aBufferType, Standard_True, V3d_SDO_RIGHT_EYE)
+       )
       {
         theDI << "Fail: view dump failed!\n";
+        return 0;
       }
-      return 0;
+      break;
     }
-  }
+    case ViewerTest_SP_OverUnder:
+    {
+      if (!aPixMap.InitZero (aFormat, aWidth, aHeight * 2))
+      {
+        theDI << "Fail: not enough memory for image allocation!\n";
+        return 0;
+      }
 
-  Image_AlienPixMap aPixMap;
-  if (!aView->ToPixMap (aPixMap, aWidth, aHeight, aBufferType, Standard_True, aStereoOpts))
-  {
-    theDI << "Fail: view dump failed!\n";
-    return 0;
+      Image_PixMap aPixMapL, aPixMapR;
+      aPixMapL.InitWrapper (aFormat, aPixMap.ChangeData(),
+                            aWidth, aHeight, aPixMap.SizeRowBytes());
+      aPixMapR.InitWrapper (aFormat, aPixMap.ChangeData() + aPixMap.SizeRowBytes() * aHeight,
+                            aWidth, aHeight, aPixMap.SizeRowBytes());
+      if (!aView->ToPixMap (aPixMapL, aWidth, aHeight, aBufferType, Standard_True, V3d_SDO_LEFT_EYE)
+       || !aView->ToPixMap (aPixMapR, aWidth, aHeight, aBufferType, Standard_True, V3d_SDO_RIGHT_EYE))
+      {
+        theDI << "Fail: view dump failed!\n";
+        return 0;
+      }
+      break;
+    }
   }
 
-  if (aPixMap.SizeX() != Standard_Size(aWidth)
-   || aPixMap.SizeY() != Standard_Size(aHeight))
-  {
-    theDI << "Fail: dumped dimensions "    << (Standard_Integer )aPixMap.SizeX() << "x" << (Standard_Integer )aPixMap.SizeY()
-          << " are lesser than requested " << aWidth << "x" << aHeight << "\n";
-  }
   if (!aPixMap.Save (aFilePath))
   {
     theDI << "Fail: image can not be saved!\n";
@@ -912,7 +1019,6 @@ static Standard_Integer VDump (Draw_Interpretor& theDI,
   return 0;
 }
 
-
 //==============================================================================
 //function : Displays,Erase...
 //purpose  :
@@ -5348,16 +5454,16 @@ void ViewerTest::Commands(Draw_Interpretor& theCommands)
                  "Lists all objects displayed in 3D viewer",
                  __FILE__,VDir,group);
 
+#ifdef HAVE_FREEIMAGE
+  #define DUMP_FORMATS "{png|bmp|jpg|gif}"
+#else
+  #define DUMP_FORMATS "{ppm}"
+#endif
   theCommands.Add("vdump",
-    #ifdef HAVE_FREEIMAGE
-              "vdump <filename>.{png|bmp|jpg|gif} [rgb|rgba|depth=rgb] [mono|left|right=mono]"
-      "\n\t\t:                                    [width Width=0 height Height=0]"
-      "\n\t\t: Dumps content of the active view into PNG, BMP, JPEG or GIF file",
-    #else
-              "vdump <filename>.{ppm} [rgb|rgba|depth=rgb] [mono|left|right=mono]"
-      "\n\t\t:                        [width Width=0 height Height=0]"
-      "\n\t\t: Dumps content of the active view into PPM image file",
-    #endif
+              "vdump <filename>." DUMP_FORMATS " [-width Width -height Height]"
+      "\n\t\t:       [-buffer rgb|rgba|depth=rgb]"
+      "\n\t\t:       [-stereo mono|left|right|blend|sideBySide|overUnder=mono]"
+      "\n\t\t: Dumps content of the active view into image file",
                  __FILE__,VDump,group);
 
   theCommands.Add("vsub",      "vsub 0/1 (off/on) [obj]        : Subintensity(on/off) of selected objects",
index 22e5ce6..03b31d1 100644 (file)
@@ -1512,6 +1512,24 @@ void VT_ProcessKeyPress (const char* buf_ret)
   {
     ViewerTest::GetAISContext()->HilightPreviousDetected(ViewerTest::CurrentView());
   }
+  else if (!strcasecmp (buf_ret, "/"))
+  {
+    Handle(Graphic3d_Camera) aCamera = aView->Camera();
+    if (aCamera->IsStereo())
+    {
+      aCamera->SetIOD (aCamera->GetIODType(), aCamera->IOD() - 0.01);
+      aView->Redraw();
+    }
+  }
+  else if (!strcasecmp (buf_ret, "*"))
+  {
+    Handle(Graphic3d_Camera) aCamera = aView->Camera();
+    if (aCamera->IsStereo())
+    {
+      aCamera->SetIOD (aCamera->GetIODType(), aCamera->IOD() + 0.01);
+      aView->Redraw();
+    }
+  }
   else if (*buf_ret == THE_KEY_DELETE)
   {
     Handle(AIS_InteractiveContext) aCtx = ViewerTest::GetAISContext();
@@ -1983,8 +2001,12 @@ static LRESULT WINAPI ViewerWindowProc( HWND hwnd,
                                        LPARAM lParam )
 {
   static int Up = 1;
+  const Handle(V3d_View)& aView = ViewerTest::CurrentView();
+  if (aView.IsNull())
+  {
+    return DefWindowProc( hwnd, Msg, wParam, lParam );
+  }
 
-  if ( !ViewerTest::CurrentView().IsNull() ) {
     PAINTSTRUCT    ps;
 
     switch( Msg ) {
@@ -1997,6 +2019,20 @@ static LRESULT WINAPI ViewerWindowProc( HWND hwnd,
     case WM_SIZE:
       VT_ProcessConfigure();
       break;
+    case WM_MOVE:
+    case WM_MOVING:
+    case WM_SIZING:
+      switch (aView->RenderingParams().StereoMode)
+      {
+        case Graphic3d_StereoMode_RowInterlaced:
+        case Graphic3d_StereoMode_ColumnInterlaced:
+        case Graphic3d_StereoMode_ChessBoard:
+          VT_ProcessConfigure(); // track window moves to reverse stereo pair
+          break;
+        default:
+          break;
+      }
+      break;
 
     case WM_KEYDOWN:
       if ((wParam != VK_SHIFT) && (wParam != VK_CONTROL))
@@ -2018,6 +2054,15 @@ static LRESULT WINAPI ViewerWindowProc( HWND hwnd,
         {
           c[0] = '.';
         }
+        else if (wParam == VK_DIVIDE)
+        {
+          c[0] = '/';
+        }
+        // dot
+        else if (wParam == VK_MULTIPLY)
+        {
+          c[0] = '*';
+        }
         VT_ProcessKeyPress (c);
       }
       break;
@@ -2059,6 +2104,29 @@ static LRESULT WINAPI ViewerWindowProc( HWND hwnd,
       }
       break;
 
+    case WM_MOUSEWHEEL:
+    {
+      int aDelta = GET_WHEEL_DELTA_WPARAM (wParam);
+      if (wParam & MK_CONTROL)
+      {
+        if (aView->Camera()->IsStereo())
+        {
+          Standard_Real aFocus = aView->Camera()->ZFocus() + (aDelta > 0 ? 0.05 : -0.05);
+          if (aFocus > 0.2
+           && aFocus < 2.0)
+          {
+            aView->Camera()->SetZFocus (aView->Camera()->ZFocusType(), aFocus);
+            aView->Redraw();
+          }
+        }
+      }
+      else
+      {
+        aView->Zoom (0, 0, aDelta / 40, aDelta / 40);
+      }
+      break;
+    }
+
     case WM_MOUSEMOVE:
       {
         //cout << "\t WM_MOUSEMOVE" << endl;
@@ -2120,9 +2188,6 @@ static LRESULT WINAPI ViewerWindowProc( HWND hwnd,
       return( DefWindowProc( hwnd, Msg, wParam, lParam ));
     }
     return 0L;
-  }
-
-  return DefWindowProc( hwnd, Msg, wParam, lParam );
 }
 
 
@@ -5413,7 +5478,9 @@ static int VCaps (Draw_Interpretor& theDI,
     theDI << "Sprites: " << (aCaps->pntSpritesDisable ? "0" : "1") << "\n";
     theDI << "SoftMode:" << (aCaps->contextNoAccel    ? "1" : "0") << "\n";
     theDI << "FFP:     " << (aCaps->ffpEnable         ? "1" : "0") << "\n";
+    theDI << "VSync:   " <<  aCaps->swapInterval                   << "\n";
     theDI << "Compatible:" << (aCaps->contextCompatible ? "1" : "0") << "\n";
+    theDI << "Stereo:  " << (aCaps->contextStereo ? "1" : "0") << "\n";
     return 0;
   }
 
@@ -5427,6 +5494,17 @@ static int VCaps (Draw_Interpretor& theDI,
     {
       continue;
     }
+    else if (anArgCase == "-vsync"
+          || anArgCase == "-swapinterval")
+    {
+      Standard_Boolean toEnable = Standard_True;
+      if (++anArgIter < theArgNb
+      && !parseOnOff (theArgVec[anArgIter], toEnable))
+      {
+        --anArgIter;
+      }
+      aCaps->swapInterval = toEnable;
+    }
     else if (anArgCase == "-ffp")
     {
       Standard_Boolean toEnable = Standard_True;
@@ -5511,6 +5589,17 @@ static int VCaps (Draw_Interpretor& theDI,
         aCaps->ffpEnable = Standard_False;
       }
     }
+    else if (anArgCase == "-stereo"
+          || anArgCase == "-quadbuffer")
+    {
+      Standard_Boolean toEnable = Standard_True;
+      if (++anArgIter < theArgNb
+      && !parseOnOff (theArgVec[anArgIter], toEnable))
+      {
+        --anArgIter;
+      }
+      aCaps->contextStereo = toEnable;
+    }
     else
     {
       std::cout << "Error: unknown argument '" << anArg << "'\n";
@@ -7301,6 +7390,94 @@ static int VCamera (Draw_Interpretor& theDI,
   return 0;
 }
 
+//! Parse stereo output mode
+inline Standard_Boolean parseStereoMode (Standard_CString      theArg,
+                                         Graphic3d_StereoMode& theMode)
+{
+  TCollection_AsciiString aFlag (theArg);
+  aFlag.LowerCase();
+  if (aFlag == "quadbuffer")
+  {
+    theMode = Graphic3d_StereoMode_QuadBuffer;
+  }
+  else if (aFlag == "anaglyph")
+  {
+    theMode = Graphic3d_StereoMode_Anaglyph;
+  }
+  else if (aFlag == "row"
+        || aFlag == "rowinterlaced")
+  {
+    theMode = Graphic3d_StereoMode_RowInterlaced;
+  }
+  else if (aFlag == "col"
+        || aFlag == "colinterlaced"
+        || aFlag == "columninterlaced")
+  {
+    theMode = Graphic3d_StereoMode_ColumnInterlaced;
+  }
+  else if (aFlag == "chess"
+        || aFlag == "chessboard")
+  {
+    theMode = Graphic3d_StereoMode_ChessBoard;
+  }
+  else if (aFlag == "sbs"
+        || aFlag == "sidebyside")
+  {
+    theMode = Graphic3d_StereoMode_SideBySide;
+  }
+  else if (aFlag == "ou"
+        || aFlag == "overunder")
+  {
+    theMode = Graphic3d_StereoMode_OverUnder;
+  }
+  else if (aFlag == "pageflip"
+        || aFlag == "softpageflip")
+  {
+    theMode = Graphic3d_StereoMode_SoftPageFlip;
+  }
+  else
+  {
+    return Standard_False;
+  }
+  return Standard_True;
+}
+
+//! Parse anaglyph filter
+inline Standard_Boolean parseAnaglyphFilter (Standard_CString                     theArg,
+                                             Graphic3d_RenderingParams::Anaglyph& theFilter)
+{
+  TCollection_AsciiString aFlag (theArg);
+  aFlag.LowerCase();
+  if (aFlag == "redcyansimple")
+  {
+    theFilter = Graphic3d_RenderingParams::Anaglyph_RedCyan_Simple;
+  }
+  else if (aFlag == "redcyan"
+        || aFlag == "redcyanoptimized")
+  {
+    theFilter = Graphic3d_RenderingParams::Anaglyph_RedCyan_Optimized;
+  }
+  else if (aFlag == "yellowbluesimple")
+  {
+    theFilter = Graphic3d_RenderingParams::Anaglyph_YellowBlue_Simple;
+  }
+  else if (aFlag == "yellowblue"
+        || aFlag == "yellowblueoptimized")
+  {
+    theFilter = Graphic3d_RenderingParams::Anaglyph_YellowBlue_Optimized;
+  }
+  else if (aFlag == "greenmagenta"
+        || aFlag == "greenmagentasimple")
+  {
+    theFilter = Graphic3d_RenderingParams::Anaglyph_GreenMagenta_Simple;
+  }
+  else
+  {
+    return Standard_False;
+  }
+  return Standard_True;
+}
+
 //==============================================================================
 //function : VStereo
 //purpose  :
@@ -7310,12 +7487,12 @@ static int VStereo (Draw_Interpretor& theDI,
                     Standard_Integer  theArgNb,
                     const char**      theArgVec)
 {
+  Handle(V3d_View) aView = ViewerTest::CurrentView();
   if (theArgNb < 2)
   {
-    Handle(V3d_View) aView = ViewerTest::CurrentView();
     if (aView.IsNull())
     {
-      std::cerr << "No active view. Please call vinit.\n";
+      std::cout << "Error: no active viewer!\n";
       return 0;
     }
 
@@ -7324,7 +7501,130 @@ static int VStereo (Draw_Interpretor& theDI,
     return 0;
   }
 
-  ViewerTest_myDefaultCaps.contextStereo = Draw::Atoi (theArgVec[1]) != 0;
+  Handle(Graphic3d_Camera) aCamera;
+  Graphic3d_RenderingParams*   aParams   = NULL;
+  Graphic3d_StereoMode         aMode     = Graphic3d_StereoMode_QuadBuffer;
+  if (!aView.IsNull())
+  {
+    aParams   = &aView->ChangeRenderingParams();
+    aMode     = aParams->StereoMode;
+    aCamera   = aView->Camera();
+  }
+
+  ViewerTest_AutoUpdater anUpdateTool (ViewerTest::GetAISContext(), aView);
+  for (Standard_Integer anArgIter = 1; anArgIter < theArgNb; ++anArgIter)
+  {
+    Standard_CString        anArg = theArgVec[anArgIter];
+    TCollection_AsciiString aFlag (anArg);
+    aFlag.LowerCase();
+    if (anUpdateTool.parseRedrawMode (aFlag))
+    {
+      continue;
+    }
+    else if (aFlag == "0"
+          || aFlag == "off")
+    {
+      if (++anArgIter < theArgNb)
+      {
+        std::cout << "Error: wrong number of arguments!\n";
+        return 1;
+      }
+
+      if (!aCamera.IsNull()
+       &&  aCamera->ProjectionType() == Graphic3d_Camera::Projection_Stereo)
+      {
+        aCamera->SetProjectionType (Graphic3d_Camera::Projection_Perspective);
+      }
+      ViewerTest_myDefaultCaps.contextStereo = Standard_False;
+      return 0;
+    }
+    else if (aFlag == "1"
+          || aFlag == "on")
+    {
+      if (++anArgIter < theArgNb)
+      {
+        std::cout << "Error: wrong number of arguments!\n";
+        return 1;
+      }
+
+      if (!aCamera.IsNull())
+      {
+        aCamera->SetProjectionType (Graphic3d_Camera::Projection_Stereo);
+      }
+      ViewerTest_myDefaultCaps.contextStereo = Standard_True;
+      return 0;
+    }
+    else if (aFlag == "-reverse"
+          || aFlag == "-reversed"
+          || aFlag == "-swap")
+    {
+      Standard_Boolean toEnable = Standard_True;
+      if (++anArgIter < theArgNb
+      && !parseOnOff (theArgVec[anArgIter], toEnable))
+      {
+        --anArgIter;
+      }
+      aParams->ToReverseStereo = toEnable;
+    }
+    else if (aFlag == "-noreverse"
+          || aFlag == "-noswap")
+    {
+      Standard_Boolean toDisable = Standard_True;
+      if (++anArgIter < theArgNb
+      && !parseOnOff (theArgVec[anArgIter], toDisable))
+      {
+        --anArgIter;
+      }
+      aParams->ToReverseStereo = !toDisable;
+    }
+    else if (aFlag == "-mode"
+          || aFlag == "-stereomode")
+    {
+      if (++anArgIter >= theArgNb
+      || !parseStereoMode (theArgVec[anArgIter], aMode))
+      {
+        std::cout << "Error: syntax error at '" << anArg << "'\n";
+        return 1;
+      }
+
+      if (aMode == Graphic3d_StereoMode_QuadBuffer)
+      {
+        ViewerTest_myDefaultCaps.contextStereo = Standard_True;
+      }
+    }
+    else if (aFlag == "-anaglyph"
+          || aFlag == "-anaglyphfilter")
+    {
+      Graphic3d_RenderingParams::Anaglyph aFilter = Graphic3d_RenderingParams::Anaglyph_RedCyan_Simple;
+      if (++anArgIter >= theArgNb
+      || !parseAnaglyphFilter (theArgVec[anArgIter], aFilter))
+      {
+        std::cout << "Error: syntax error at '" << anArg << "'\n";
+        return 1;
+      }
+
+      aMode = Graphic3d_StereoMode_Anaglyph;
+      aParams->AnaglyphFilter = aFilter;
+    }
+    else if (parseStereoMode (anArg, aMode)) // short syntax
+    {
+      if (aMode == Graphic3d_StereoMode_QuadBuffer)
+      {
+        ViewerTest_myDefaultCaps.contextStereo = Standard_True;
+      }
+    }
+    else
+    {
+      std::cout << "Error: syntax error at '" << anArg << "'\n";
+      return 1;
+    }
+  }
+
+  if (!aView.IsNull())
+  {
+    aParams->StereoMode = aMode;
+    aCamera->SetProjectionType (Graphic3d_Camera::Projection_Stereo);
+  }
   return 0;
 }
 
@@ -8761,11 +9061,27 @@ void ViewerTest::ViewerCommands(Draw_Interpretor& theCommands)
     "vvbo [{0|1}] : turn VBO usage On/Off; affects only newly displayed objects",
     __FILE__, VVbo, group);
   theCommands.Add ("vstereo",
-    "\nvstereo [{0|1}] : turn stereo usage On/Off; affects only newly displayed objects",
+            "vstereo [0|1] [-mode Mode] [-reverse {0|1}]"
+    "\n\t\t:         [-anaglyph Filter]"
+    "\n\t\t: Control stereo output mode. Available modes for -mode:"
+    "\n\t\t:  quadBuffer        - OpenGL QuadBuffer stereo,"
+    "\n\t\t:                     requires driver support."
+    "\n\t\t:                     Should be called BEFORE vinit!"
+    "\n\t\t:  anaglyph         - Anaglyph glasses"
+    "\n\t\t:  rowInterlaced    - row-interlaced display"
+    "\n\t\t:  columnInterlaced - column-interlaced display"
+    "\n\t\t:  chessBoard       - chess-board output"
+    "\n\t\t:  sideBySide       - horizontal pair"
+    "\n\t\t:  overUnder        - vertical   pair"
+    "\n\t\t: Available Anaglyph filters for -anaglyph:"
+    "\n\t\t:  redCyan, redCyanSimple, yellowBlue, yellowBlueSimple,"
+    "\n\t\t:  greenMagentaSimple",
     __FILE__, VStereo, group);
   theCommands.Add ("vcaps",
             "vcaps [-vbo {0|1}] [-sprites {0|1}] [-ffp {0|1}]"
     "\n\t\t:       [-compatibleContext {0|1}]"
+    "\n\t\t:       [-vsync {0|1}]"
+    "\n\t\t:       [-quadBuffer {0|1}] [-stereo {0|1}]"
     "\n\t\t:       [-softMode {0|1}] [-noupdate|-update]"
     "\n\t\t: Modify particular graphic driver options:"
     "\n\t\t:  FFP      - use fixed-function pipeline instead of"
@@ -8774,9 +9090,11 @@ void ViewerTest::ViewerCommands(Draw_Interpretor& theCommands)
     "\n\t\t:  VBO      - use Vertex Buffer Object (copy vertex"
     "\n\t\t:             arrays to GPU memory)"
     "\n\t\t:  sprite   - use textured sprites instead of bitmaps"
+    "\n\t\t:  vsync    - switch VSync on or off"
     "\n\t\t: Context creation options:"
     "\n\t\t:  softMode          - software OpenGL implementation"
     "\n\t\t:  compatibleProfile - backward-compatible profile"
+    "\n\t\t:  quadbuffer        - QuadBuffer"
     "\n\t\t: Unlike vrenderparams, these parameters control alternative"
     "\n\t\t: rendering paths producing the same visual result when"
     "\n\t\t: possible."
index 6ae88c7..8b1ede2 100644 (file)
@@ -109,10 +109,13 @@ void Visual3d_View::SetWindow (const Handle(Aspect_Window)& theWindow)
   MyCView.DefWindow.XWindow       = theWindow->NativeHandle();
   MyCView.DefWindow.XParentWindow = theWindow->NativeParentHandle();
 
-  Standard_Integer Width, Height;
-  theWindow->Size (Width, Height);
-  MyCView.DefWindow.dx = Width;
-  MyCView.DefWindow.dy = Height;
+  Standard_Integer aWidth = 0, aHeight = 0, aLeft = 0, aTop = 0;
+  theWindow->Position (aLeft, aTop, aWidth, aHeight);
+  theWindow->Size (aWidth, aHeight);
+  MyCView.DefWindow.left = aLeft;
+  MyCView.DefWindow.top  = aTop;
+  MyCView.DefWindow.dx   = aWidth;
+  MyCView.DefWindow.dy   = aHeight;
 
   Standard_Real R, G, B;
   MyBackground = MyWindow->Background ();
@@ -270,7 +273,11 @@ void Visual3d_View::SetRatio()
   const Aspect_TypeOfUpdate anUpdateMode = myViewManager->UpdateMode();
   myViewManager->SetUpdateMode (Aspect_TOU_WAIT);
 
-  Standard_Integer aWidth, aHeight;
+  Standard_Integer aWidth = 0, aHeight = 0, aLeft = 0, aTop = 0;
+  MyWindow->Position (aLeft, aTop, aWidth, aHeight);
+  MyCView.DefWindow.left = aLeft;
+  MyCView.DefWindow.top  = aTop;
+
   MyWindow->Size (aWidth, aHeight);
   if (aWidth > 0 && aHeight > 0)
   {
index 85e0b56..2551bce 100644 (file)
@@ -16,8 +16,8 @@ vinit
 vsetdispmode 1
 vdisplay b
 vfit
-vdump ${imagedir}/texture_409.png rgb 409 409
-vdump ${imagedir}/texture_412.png rgb 412 412
+vdump ${imagedir}/texture_409.png -buffer rgb -width 409 -height 409
+vdump ${imagedir}/texture_412.png -buffer rgb -width 412 -height 412
 
 # texture loaded correctly
 vtexture b ${imagedir}/texture_412.png
index 58f9bb7..59b6e27 100644 (file)
@@ -15,16 +15,16 @@ vcamera -fov 45 -iodType relative -iod 0.05 -zfocustype relative -zfocus 1.0
 vcamera -ortho
 vfit
 set aTitle "ortho"
-vdump $imagedir/${casename}_${aTitle}.png rgb 512 512
+vdump $imagedir/${casename}_${aTitle}.png -buffer rgb -width 512 -height 512
 vcamera -persp
 vfit
 set aTitle "persp"
-vdump $imagedir/${casename}_${aTitle}.png rgb 512 512
+vdump $imagedir/${casename}_${aTitle}.png -buffer rgb -width 512 -height 512
 vcamera -stereo
 set aTitle "stereoR"
-vdump $imagedir/${casename}_${aTitle}.png rgb 512 512 R
+vdump $imagedir/${casename}_${aTitle}.png -buffer rgb -width 512 -height 512 -stereo R
 set aTitle "stereoL"
-vdump $imagedir/${casename}_${aTitle}.png rgb 512 512 L
+vdump $imagedir/${casename}_${aTitle}.png -buffer rgb -width 512 -height 512 -stereo L
 
 # test context stereo mode swicthing
 # if not supported by hardware it must not crash
@@ -35,4 +35,4 @@ vdisplay b
 vcamera -stereo
 vfit
 set aTitle "afterSwitch"
-vdump $imagedir/${casename}_${aTitle}.png rgb 512 512 R
+vdump $imagedir/${casename}_${aTitle}.png -buffer rgb -width 512 -height 512 -stereo R
diff --git a/tests/v3d/glsl/stereo b/tests/v3d/glsl/stereo
new file mode 100644 (file)
index 0000000..2ba9754
--- /dev/null
@@ -0,0 +1,33 @@
+puts "========"
+puts "Stereo output modes"
+puts "========"
+
+restore [locate_data_file occ/fuse.brep] f
+vinit View1
+vclear
+vsetdispmode 1
+vaxo
+vdisplay f
+vfit
+vrotate -0.5 0.0 0.0
+
+vstereo -mode anaglyph
+vfit
+vdump $::imagedir/${::casename}_anaglyph.png -stereo blend
+
+vstereo -mode columnInterlaced
+vdump $::imagedir/${::casename}_col.png -stereo blend
+
+vstereo -mode chessBoard
+vdump $::imagedir/${::casename}_chess.png -stereo blend
+
+vstereo -mode rowInterlaced
+vdump $::imagedir/${::casename}_row.png -stereo blend
+
+vstereo -mode sideBySide
+vdump $::imagedir/${::casename}_sbs_anamorph.png -stereo blend
+
+vstereo -mode overUnder
+vdump $::imagedir/${::casename}_overunder_anamorph.png -stereo blend
+
+vdump $::imagedir/${::casename}_sbs.png -stereo sbs