diff --git a/include/osg/DisplaySettings b/include/osg/DisplaySettings index d67143d43..2b7a41778 100644 --- a/include/osg/DisplaySettings +++ b/include/osg/DisplaySettings @@ -90,7 +90,9 @@ class OSG_EXPORT DisplaySettings : public osg::Referenced HORIZONTAL_SPLIT, VERTICAL_SPLIT, LEFT_EYE, - RIGHT_EYE + RIGHT_EYE, + HORIZONTAL_INTERLACE, + VERTICAL_INTERLACE }; void setStereoMode(StereoMode mode) { _stereoMode = mode; } diff --git a/include/osgUtil/SceneView b/include/osgUtil/SceneView index 88c3777d3..d8c0e39d0 100644 --- a/include/osgUtil/SceneView +++ b/include/osgUtil/SceneView @@ -113,6 +113,13 @@ class OSGUTIL_EXPORT SceneView : public osg::Referenced, public osg::CullSetting void setClearColor(const osg::Vec4& color) { _clearColor=color; } /** Get the color used in glClearColor.*/ const osg::Vec4& getClearColor() const { return _clearColor; } + + + /** Mannually set the redraw interlaced stereo stencil mask request flag to control whether to redraw the stencil buffer on the next frame.*/ + void setRedrawInterlacedStereoStencilMask(bool flag) { _redrawInterlacedStereoStencilMask = flag; } + + /** Get the redraw interlaced stereo stencil mask request flag.*/ + bool getRedrawInterlacedStereoStencilMask() const { return _redrawInterlacedStereoStencilMask; } void setGlobalStateSet(osg::StateSet* state) { _globalStateSet = state; } @@ -504,6 +511,11 @@ class OSGUTIL_EXPORT SceneView : public osg::Referenced, public osg::CullSetting int _activeUniforms; double _previousFrameTime; + bool _redrawInterlacedStereoStencilMask; + int _interlacedStereoStencilWidth; + int _interlacedStereoStencilHeight; + + }; } diff --git a/src/osg/DisplaySettings.cpp b/src/osg/DisplaySettings.cpp index 5a94a2372..f036dc6a0 100644 --- a/src/osg/DisplaySettings.cpp +++ b/src/osg/DisplaySettings.cpp @@ -113,7 +113,7 @@ void DisplaySettings::setDefaults() } static ApplicationUsageProxy DisplaySetting_e0(ApplicationUsage::ENVIRONMENTAL_VARIABLE,"OSG_DISPLAY_TYPE ","MONITOR | POWERWALL | REALITY_CENTER | HEAD_MOUNTED_DISPLAY"); -static ApplicationUsageProxy DisplaySetting_e1(ApplicationUsage::ENVIRONMENTAL_VARIABLE,"OSG_STEREO_MODE ","QUAD_BUFFER | ANAGLYPHIC | HORIZONTAL_SPLIT | VERTICAL_SPLIT | LEFT_EYE | RIGHT_EYE"); +static ApplicationUsageProxy DisplaySetting_e1(ApplicationUsage::ENVIRONMENTAL_VARIABLE,"OSG_STEREO_MODE ","QUAD_BUFFER | ANAGLYPHIC | HORIZONTAL_SPLIT | VERTICAL_SPLIT | LEFT_EYE | RIGHT_EYE | VERTICAL_INTERLACE | HORIZONTAL_INTERLACE"); static ApplicationUsageProxy DisplaySetting_e2(ApplicationUsage::ENVIRONMENTAL_VARIABLE,"OSG_STEREO ","OFF | ON"); static ApplicationUsageProxy DisplaySetting_e3(ApplicationUsage::ENVIRONMENTAL_VARIABLE,"OSG_EYE_SEPARATION ","physical distance between eyes"); static ApplicationUsageProxy DisplaySetting_e4(ApplicationUsage::ENVIRONMENTAL_VARIABLE,"OSG_SCREEN_DISTANCE ","physical distance between eyes and screen"); @@ -159,31 +159,34 @@ void DisplaySettings::readEnvironmentalVariables() { _stereoMode = QUAD_BUFFER; } - else - if (strcmp(ptr,"ANAGLYPHIC")==0) + else if (strcmp(ptr,"ANAGLYPHIC")==0) { _stereoMode = ANAGLYPHIC; } - else - if (strcmp(ptr,"HORIZONTAL_SPLIT")==0) + else if (strcmp(ptr,"HORIZONTAL_SPLIT")==0) { _stereoMode = HORIZONTAL_SPLIT; } - else - if (strcmp(ptr,"VERTICAL_SPLIT")==0) + else if (strcmp(ptr,"VERTICAL_SPLIT")==0) { _stereoMode = VERTICAL_SPLIT; } - else - if (strcmp(ptr,"LEFT_EYE")==0) + else if (strcmp(ptr,"LEFT_EYE")==0) { _stereoMode = LEFT_EYE; } - else - if (strcmp(ptr,"RIGHT_EYE")==0) + else if (strcmp(ptr,"RIGHT_EYE")==0) { _stereoMode = RIGHT_EYE; } + else if (strcmp(ptr,"HORIZONTAL_INTERLACE")==0) + { + _stereoMode = HORIZONTAL_INTERLACE; + } + else if (strcmp(ptr,"VERTICAL_INTERLACE")==0) + { + _stereoMode = VERTICAL_INTERLACE; + } } if( (ptr = getenv("OSG_STEREO")) != 0) diff --git a/src/osgProducer/OsgCameraGroup.cpp b/src/osgProducer/OsgCameraGroup.cpp index 902c997cf..9725d0868 100644 --- a/src/osgProducer/OsgCameraGroup.cpp +++ b/src/osgProducer/OsgCameraGroup.cpp @@ -502,8 +502,31 @@ bool OsgCameraGroup::realize() rs_vc->setSimpleConfiguration(); rs->setVisualChooser(rs_vc); } - if (_ds->getStereo() && _ds->getStereoMode()==osg::DisplaySettings::QUAD_BUFFER) rs_vc->useStereo(); - if (_ds->getStencilBuffer()) rs_vc->setStencilSize(_ds->getMinimumNumStencilBits()); + + unsigned int numStencilBits = 0; + if (_ds->getStereo()) + { + switch(_ds->getStereoMode()) + { + case(osg::DisplaySettings::QUAD_BUFFER): + rs_vc->useStereo(); + break; + case(osg::DisplaySettings::HORIZONTAL_INTERLACE): + case(osg::DisplaySettings::VERTICAL_INTERLACE): + numStencilBits = 8; + break; + default: + break; + } + } + + // set up stencil buffer if required. + numStencilBits = osg::maximum(numStencilBits,_ds->getMinimumNumStencilBits()); + if (numStencilBits > 0) + { + rs_vc->setStencilSize(numStencilBits); + } + if (_ds->getAlphaBuffer()) rs_vc->setAlphaSize(_ds->getMinimumNumAlphaBits()); rs_vc->setDepthSize(24); diff --git a/src/osgUtil/SceneView.cpp b/src/osgUtil/SceneView.cpp index 380a4ce4d..7f5ddfa21 100644 --- a/src/osgUtil/SceneView.cpp +++ b/src/osgUtil/SceneView.cpp @@ -31,6 +31,60 @@ using namespace osg; using namespace osgUtil; +static const GLubyte patternVertEven[] = { + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55}; + +static const GLubyte patternVertOdd[] = { + 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, + 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, + 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, + 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, + 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, + 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, + 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, + 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, + 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, + 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, + 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, + 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, + 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, + 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, + 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, + 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA}; + +static const GLubyte patternHorzEven[] = { + 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, + 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, + 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, + 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, + 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, + 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, + 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, + 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, + 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, + 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, + 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, + 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, + 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, + 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, + 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, + 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00}; + SceneView::SceneView(DisplaySettings* ds) { _displaySettings = ds; @@ -57,6 +111,10 @@ SceneView::SceneView(DisplaySettings* ds) _activeUniforms = DEFAULT_UNIFORMS; _previousFrameTime = 0; + + _redrawInterlacedStereoStencilMask = true; + _interlacedStereoStencilWidth = 0; + _interlacedStereoStencilHeight = 0; } @@ -950,6 +1008,136 @@ void SceneView::draw() _renderStage->draw(*_state,previous); } break; + case(osg::DisplaySettings::VERTICAL_INTERLACE): + { + _localStateSet->setAttribute(_viewport.get()); + + // ensure that all color planes are active. + osg::ColorMask* cmask = static_cast(_localStateSet->getAttribute(osg::StateAttribute::COLORMASK)); + if (cmask) + { + cmask->setMask(true,true,true,true); + } + else + { + cmask = new osg::ColorMask(true,true,true,true); + _localStateSet->setAttribute(cmask); + } + _renderStageLeft->setColorMask(cmask); + _renderStageRight->setColorMask(cmask); + + _renderStageLeft->drawPreRenderStages(*_state,previous); + _renderStageRight->drawPreRenderStages(*_state,previous); + + glEnable(GL_STENCIL_TEST); + + if(_redrawInterlacedStereoStencilMask || + _interlacedStereoStencilWidth != _viewport->width() || + _interlacedStereoStencilHeight != _viewport->height() ) + { + _viewport->apply(*_state); + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + glOrtho(_viewport->x(), _viewport->width(), _viewport->y(), _viewport->height(), -1.0, 1.0); + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + glDisable(GL_LIGHTING); + glDisable(GL_DEPTH_TEST); + glStencilMask(~0); + glClear(GL_STENCIL_BUFFER_BIT); + glStencilOp(GL_REPLACE, GL_REPLACE, GL_REPLACE); + glStencilFunc(GL_ALWAYS, 1, ~0); + glPolygonStipple(patternVertEven); + glEnable(GL_POLYGON_STIPPLE); + glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); + glRecti(_viewport->x(), _viewport->y(), _viewport->width(), _viewport->height()); + glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); + glDisable(GL_POLYGON_STIPPLE); + glEnable(GL_LIGHTING); + glEnable(GL_DEPTH_TEST); + + _redrawInterlacedStereoStencilMask = false; + _interlacedStereoStencilWidth = _viewport->width(); + _interlacedStereoStencilHeight = _viewport->height(); + } + + _renderStageLeft->setClearMask(_renderStageLeft->getClearMask() & ~(GL_STENCIL_BUFFER_BIT)); + _renderStageRight->setClearMask(_renderStageRight->getClearMask() & ~(GL_STENCIL_BUFFER_BIT|GL_COLOR_BUFFER_BIT)); + + glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP); + glStencilFunc(GL_EQUAL, 0, ~0); + _renderStageLeft->draw(*_state,previous); + + glStencilFunc(GL_NOTEQUAL, 0, ~0); + _renderStageRight->draw(*_state,previous); + glDisable(GL_STENCIL_TEST); + } + break; + case(osg::DisplaySettings::HORIZONTAL_INTERLACE): + { + _localStateSet->setAttribute(_viewport.get()); + + // ensure that all color planes are active. + osg::ColorMask* cmask = static_cast(_localStateSet->getAttribute(osg::StateAttribute::COLORMASK)); + if (cmask) + { + cmask->setMask(true,true,true,true); + } + else + { + cmask = new osg::ColorMask(true,true,true,true); + _localStateSet->setAttribute(cmask); + } + _renderStageLeft->setColorMask(cmask); + _renderStageRight->setColorMask(cmask); + + _renderStageLeft->drawPreRenderStages(*_state,previous); + _renderStageRight->drawPreRenderStages(*_state,previous); + + glEnable(GL_STENCIL_TEST); + + if(_redrawInterlacedStereoStencilMask || + _interlacedStereoStencilWidth != _viewport->width() || + _interlacedStereoStencilHeight != _viewport->height() ) + { + _viewport->apply(*_state); + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + glOrtho(_viewport->x(), _viewport->width(), _viewport->y(), _viewport->height(), -1.0, 1.0); + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + glDisable(GL_LIGHTING); + glDisable(GL_DEPTH_TEST); + glStencilMask(~0); + glClear(GL_STENCIL_BUFFER_BIT); + glStencilOp(GL_REPLACE, GL_REPLACE, GL_REPLACE); + glStencilFunc(GL_ALWAYS, 1, ~0); + glPolygonStipple(patternHorzEven); + glEnable(GL_POLYGON_STIPPLE); + glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); + glRecti(_viewport->x(), _viewport->y(), _viewport->width(), _viewport->height()); + glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); + glDisable(GL_POLYGON_STIPPLE); + glEnable(GL_LIGHTING); + glEnable(GL_DEPTH_TEST); + + _redrawInterlacedStereoStencilMask = false; + _interlacedStereoStencilWidth = _viewport->width(); + _interlacedStereoStencilHeight = _viewport->height(); + } + + _renderStageLeft->setClearMask(_renderStageLeft->getClearMask() & ~(GL_STENCIL_BUFFER_BIT)); + _renderStageRight->setClearMask(_renderStageRight->getClearMask() & ~(GL_STENCIL_BUFFER_BIT|GL_COLOR_BUFFER_BIT)); + + glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP); + glStencilFunc(GL_EQUAL, 0, ~0); + _renderStageLeft->draw(*_state,previous); + + glStencilFunc(GL_NOTEQUAL, 0, ~0); + _renderStageRight->draw(*_state,previous); + glDisable(GL_STENCIL_TEST); + } + break; default: { osg::notify(osg::NOTICE)<<"Warning: stereo mode not implemented yet."<< std::endl;