2010-04-19 19:43:06 +08:00
/* OpenSceneGraph example, osgfpdepth.
*
* Permission is hereby granted , free of charge , to any person obtaining a copy
* of this software and associated documentation files ( the " Software " ) , to deal
* in the Software without restriction , including without limitation the rights
* to use , copy , modify , merge , publish , distribute , sublicense , and / or sell
* copies of the Software , and to permit persons to whom the Software is
* furnished to do so , subject to the following conditions :
*
* THE SOFTWARE IS PROVIDED " AS IS " , WITHOUT WARRANTY OF ANY KIND , EXPRESS OR
* IMPLIED , INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY ,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT . IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM , DAMAGES OR OTHER
* LIABILITY , WHETHER IN AN ACTION OF CONTRACT , TORT OR OTHERWISE , ARISING FROM ,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE .
*/
# include <osg/ColorMask>
# include <osg/CullFace>
# include <osg/Depth>
# include <osg/FrameBufferObject>
# include <osg/Geode>
# include <osg/Geometry>
# include <osg/GLExtensions>
# include <osg/Node>
# include <osg/Notify>
# include <osg/observer_ptr>
# include <osg/Projection>
# include <osg/Switch>
# include <osg/Texture2D>
# include <osgDB/ReadFile>
# include <osgGA/GUIEventHandler>
# include <osgUtil/Optimizer>
# include <osgText/Text>
# include <osgViewer/Renderer>
# include <osgViewer/Viewer>
# include <osgViewer/ViewerEventHandlers>
# include <iostream>
# include <sstream>
/* Demonstration of floating point depth buffers. The most basic way to use
* a floating point depth buffer in OpenGL is to create a frame buffer
* object , attach a color and floating point depth texture , render ,
* and then copy the color texture to the screen . When doing
* multisampling we can ' t use textures directly , so we have to create
* render buffers with the proper format . Then we let OSG handle the
* details of resolving the multisampling .
*
* When using a floating point depth buffer , it ' s advantageous to
* reverse the depth buffer range ( and the depth test , of course ) so
* that 0.0 corresponds to the far plane . See
* e . g . http : //www.humus.name/index.php?ID=25 for details.
*/
using namespace osg ;
using namespace std ;
/* createFBO() and destroyFBO(), and the supporting classes and
* functions below , are only used to test possible valid frame buffer
* configurations at startup . They wouldn ' t be used in a normal OSG
* program unless we wanted to enumerate all the valid FBO
* combinations and let the user choose between them .
*/
// Properties of an FBO that we will try to create
struct FboConfig
{
FboConfig ( )
: colorFormat ( 0 ) , depthFormat ( 0 ) , redbits ( 0 ) , depthBits ( 0 ) ,
depthSamples ( 0 ) , coverageSamples ( 0 )
{
}
FboConfig ( const string & name_ , GLenum colorFormat_ , GLenum depthFormat_ ,
int redbits_ , int depthBits_ , int depthSamples_ = 0 ,
int coverageSamples_ = 0 )
: name ( name_ ) , colorFormat ( colorFormat_ ) , depthFormat ( depthFormat_ ) ,
redbits ( redbits_ ) , depthBits ( depthBits_ ) , depthSamples ( depthSamples_ ) ,
coverageSamples ( coverageSamples_ )
{
}
string name ;
GLenum colorFormat ;
GLenum depthFormat ;
int redbits ;
int depthBits ;
int depthSamples ;
int coverageSamples ;
} ;
// Properties of a buffer
struct BufferConfig
{
BufferConfig ( ) { }
BufferConfig ( const string & name_ , GLenum format_ , int bits_ )
: name ( name_ ) , format ( format_ ) , bits ( bits_ )
{
}
string name ;
GLenum format ;
int bits ;
} ;
typedef vector < BufferConfig > BufferConfigList ;
vector < FboConfig > validConfigs ;
// Ugly global variables for the viewport width and height
int width , height ;
// This is only used when testing possible frame buffer configurations
// to find valid ones.
struct FboData
{
ref_ptr < Texture2D > tex ; // color texture
ref_ptr < Texture2D > depthTex ; // depth texture
ref_ptr < FrameBufferObject > fb ; // render framebuffer
ref_ptr < FrameBufferObject > resolveFB ; // multisample resolve target
} ;
Texture2D * makeDepthTexture ( int width , int height , GLenum internalFormat ) ;
// Assemble lists of the valid buffer configurations, along with the
// possibilities for multisample coverage antialiasing, if any.
void getPossibleConfigs ( GraphicsContext * gc , BufferConfigList & colorConfigs ,
BufferConfigList & depthConfigs ,
vector < int > & coverageConfigs )
{
int maxSamples = 0 ;
int coverageSampleConfigs = 0 ;
unsigned contextID = gc - > getState ( ) - > getContextID ( ) ;
colorConfigs . push_back ( BufferConfig ( " RGBA8 " , GL_RGBA8 , 8 ) ) ;
depthConfigs . push_back ( BufferConfig ( " D24 " , GL_DEPTH_COMPONENT24 , 24 ) ) ;
FBOExtensions * fboe = FBOExtensions : : instance ( contextID , true ) ;
if ( ! fboe - > isSupported ( ) )
return ;
if ( fboe - > isMultisampleSupported ( ) )
glGetIntegerv ( GL_MAX_SAMPLES_EXT , & maxSamples ) ;
// isMultisampleCoverageSupported
if ( isGLExtensionSupported ( contextID ,
" GL_NV_framebuffer_multisample_coverage " ) )
{
glGetIntegerv ( GL_MAX_MULTISAMPLE_COVERAGE_MODES_NV ,
& coverageSampleConfigs ) ;
coverageConfigs . resize ( coverageSampleConfigs * 2 + 4 ) ;
glGetIntegerv ( GL_MULTISAMPLE_COVERAGE_MODES_NV , & coverageConfigs [ 0 ] ) ;
}
if ( isGLExtensionSupported ( contextID , " GL_ARB_depth_buffer_float " ) )
depthConfigs . push_back ( BufferConfig ( " D32F " , GL_DEPTH_COMPONENT32F , 32 ) ) ;
else if ( isGLExtensionSupported ( contextID , " GL_NV_depth_buffer_float " ) )
depthConfigs . push_back ( BufferConfig ( " D32F " , GL_DEPTH_COMPONENT32F_NV ,
32 ) ) ;
}
bool checkFramebufferStatus ( GraphicsContext * gc , bool silent = false )
{
State & state = * gc - > getState ( ) ;
unsigned contextID = state . getContextID ( ) ;
FBOExtensions * fboe = FBOExtensions : : instance ( contextID , true ) ;
switch ( fboe - > glCheckFramebufferStatus ( GL_FRAMEBUFFER_EXT ) ) {
case GL_FRAMEBUFFER_COMPLETE_EXT :
break ;
case GL_FRAMEBUFFER_UNSUPPORTED_EXT :
if ( ! silent )
cout < < " Unsupported framebuffer format \n " ;
return false ;
case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT :
if ( ! silent )
cout < < " Framebuffer incomplete, missing attachment \n " ;
return false ;
case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT :
if ( ! silent )
cout < < " Framebuffer incomplete, duplicate attachment \n " ;
return false ;
case GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT :
if ( ! silent )
cout < < " Framebuffer incomplete, attached images must have same dimensions \n " ;
return false ;
case GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT :
if ( ! silent )
cout < < " Framebuffer incomplete, attached images must have same format \n " ;
return false ;
case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT :
if ( ! silent )
cout < < " Framebuffer incomplete, missing draw buffer \n " ;
return false ;
case GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT :
if ( ! silent )
cout < < " Framebuffer incomplete, missing read buffer \n " ;
return false ;
default :
return false ;
}
return true ;
}
// Attempt to create an FBO with a certain configuration. If the FBO
// is created with fewer bits in any of its parameters, the creation
// is deemed to have failed. Even though the result is a valid FBO,
// we're only interested in discrete, valid configurations.
bool createFBO ( GraphicsContext * gc , FboConfig & config , FboData & data )
{
bool result = true ;
bool multisample = config . depthSamples > 0 ;
bool csaa = config . coverageSamples > config . depthSamples ;
data . fb = new FrameBufferObject ;
int texWidth = 512 , texHeight = 512 ;
data . tex = new Texture2D ;
data . tex - > setTextureSize ( texWidth , texHeight ) ;
data . tex - > setInternalFormat ( config . colorFormat ) ;
data . tex - > setSourceFormat ( GL_RGBA ) ;
data . tex - > setSourceType ( GL_FLOAT ) ;
data . tex - > setFilter ( Texture : : MIN_FILTER , Texture : : LINEAR_MIPMAP_LINEAR ) ;
data . tex - > setFilter ( Texture : : MAG_FILTER , Texture : : LINEAR ) ;
data . tex - > setWrap ( Texture : : WRAP_S , Texture : : CLAMP_TO_EDGE ) ;
data . tex - > setWrap ( Texture : : WRAP_T , Texture : : CLAMP_TO_EDGE ) ;
RenderBuffer * colorRB = 0 ;
RenderBuffer * depthRB = 0 ;
if ( multisample )
{
data . resolveFB = new FrameBufferObject ;
data . resolveFB - > setAttachment ( Camera : : COLOR_BUFFER ,
FrameBufferAttachment ( data . tex . get ( ) ) ) ;
colorRB = new RenderBuffer ( texWidth , texHeight , config . colorFormat ,
config . coverageSamples , config . depthSamples ) ;
data . fb - > setAttachment ( Camera : : COLOR_BUFFER ,
FrameBufferAttachment ( colorRB ) ) ;
depthRB = new RenderBuffer ( texWidth , texHeight , config . depthFormat ,
config . coverageSamples , config . depthSamples ) ;
data . fb - > setAttachment ( Camera : : DEPTH_BUFFER ,
FrameBufferAttachment ( depthRB ) ) ;
}
else
{
data . depthTex = makeDepthTexture ( texWidth , texHeight ,
config . depthFormat ) ;
data . fb - > setAttachment ( Camera : : COLOR_BUFFER ,
FrameBufferAttachment ( data . tex . get ( ) ) ) ;
data . fb - > setAttachment ( Camera : : DEPTH_BUFFER ,
FrameBufferAttachment ( data . depthTex . get ( ) ) ) ;
}
State & state = * gc - > getState ( ) ;
unsigned int contextID = state . getContextID ( ) ;
FBOExtensions * fboe = FBOExtensions : : instance ( contextID , true ) ;
data . fb - > apply ( state ) ;
result = checkFramebufferStatus ( gc , true ) ;
if ( ! result )
{
fboe - > glBindFramebuffer ( GL_FRAMEBUFFER_EXT , 0 ) ;
return false ;
}
int query ;
if ( multisample )
{
GLuint colorRBID = colorRB - > getObjectID ( contextID , fboe ) ;
fboe - > glBindRenderbuffer ( GL_RENDERBUFFER_EXT , colorRBID ) ;
if ( csaa )
{
fboe - > glGetRenderbufferParameteriv ( GL_RENDERBUFFER_EXT ,
GL_RENDERBUFFER_COVERAGE_SAMPLES_NV ,
& query ) ;
if ( query < config . coverageSamples )
result = false ;
else
config . coverageSamples = query ;
fboe - > glGetRenderbufferParameteriv ( GL_RENDERBUFFER_EXT ,
GL_RENDERBUFFER_COLOR_SAMPLES_NV ,
& query ) ;
if ( query < config . depthSamples )
result = false ;
else
config . depthSamples = query ; // report back the actual number
}
else
{
fboe - > glGetRenderbufferParameteriv ( GL_RENDERBUFFER_EXT ,
GL_RENDERBUFFER_SAMPLES_EXT ,
& query ) ;
if ( query < config . depthSamples )
result = false ;
else
config . depthSamples = query ;
}
}
glGetIntegerv ( GL_RED_BITS , & query ) ;
if ( query ! = config . redbits )
result = false ;
glGetIntegerv ( GL_DEPTH_BITS , & query ) ;
if ( query ! = config . depthBits )
result = false ;
if ( result & & multisample & & data . resolveFB . valid ( ) )
{
data . resolveFB - > apply ( state ) ;
result = checkFramebufferStatus ( gc , true ) ;
if ( result )
{
glGetIntegerv ( GL_RED_BITS , & query ) ;
if ( query ! = config . redbits )
result = false ;
}
}
fboe - > glBindFramebuffer ( GL_FRAMEBUFFER_EXT , 0 ) ;
return result ;
}
void destroyFBO ( GraphicsContext * gc , FboData & data )
{
data . tex = 0 ;
data . depthTex = 0 ;
data . fb = 0 ;
data . resolveFB = 0 ;
State & state = * gc - > getState ( ) ;
double availableTime = 100.0 ;
RenderBuffer : : flushDeletedRenderBuffers ( state . getContextID ( ) , 0.0 ,
availableTime ) ;
availableTime = 100.0 ;
FrameBufferObject : : flushDeletedFrameBufferObjects ( state . getContextID ( ) ,
0.0 , availableTime ) ;
}
void setAttachmentsFromConfig ( Camera * camera , const FboConfig & config ) ;
Switch * makeTexturesAndGeometry ( int width , int height , Switch * sw = 0 ) ;
// Application state accessed from event handlers and main function;
// contains state that can be changed by the user and the OSG classes
// used to display / indicate that state.
//
// camera - Camera with fbo, using either fp depth buffer or fixed
// switch child 0 - texture containing rendering of scene
// switch child 1 - fp depth buffer as texture
// switch child 2 - integer depth buffer as texture
// textNotAvailable- "not available" text if texture isn't valid.
struct AppState : public Referenced
{
AppState ( osgViewer : : Viewer * viewer_ ) ;
void setStateFromConfig ( const FboConfig & config ) ;
void advanceConfig ( int increment ) ;
void updateDisplayedTexture ( ) ;
void updateNear ( ) ;
virtual ~ AppState ( ) { }
ref_ptr < Switch > sw ; // switch between displayed texture
bool displayScene ;
bool invertRange ;
int currentConfig ;
osgViewer : : Viewer * viewer ;
double zNear ;
ref_ptr < Camera > camera ;
// text displayed on the screen showing the user's choices
ref_ptr < Projection > textProjection ;
ref_ptr < osgText : : Text > configText ;
ref_ptr < osgText : : Text > zNearText ;
ref_ptr < Geode > textNotAvailable ;
ref_ptr < Geode > textInverted ;
} ;
AppState : : AppState ( osgViewer : : Viewer * viewer_ )
: displayScene ( true ) , invertRange ( true ) , currentConfig ( 0 ) ,
viewer ( viewer_ ) , zNear ( 0.03125 )
{
sw = new Switch ;
string fontName ( " fonts/arial.ttf " ) ;
// Text description of current config
configText = new osgText : : Text ;
configText - > setDataVariance ( Object : : DYNAMIC ) ;
configText - > setFont ( fontName ) ;
configText - > setPosition ( Vec3 ( 50.0f , 50.0f , 0.0f ) ) ;
configText - > setColor ( Vec4 ( 1.0 , 1.0 , 1.0 , 1.0 ) ) ;
Geode * textGeode = new Geode ;
textGeode - > addDrawable ( configText . get ( ) ) ;
// Text for the near plane distance
zNearText = new osgText : : Text ;
zNearText - > setDataVariance ( Object : : DYNAMIC ) ;
zNearText - > setFont ( fontName ) ;
zNearText - > setPosition ( Vec3 ( 1230.0f , 50.0f , 0.0f ) ) ;
zNearText - > setColor ( Vec4 ( 1.0 , 1.0 , 1.0 , 1.0 ) ) ;
zNearText - > setAlignment ( osgText : : Text : : RIGHT_BASE_LINE ) ;
textGeode - > addDrawable ( zNearText . get ( ) ) ;
// Projection that lets the text be placed in pixels.
textProjection = new Projection ;
textProjection - > setMatrix ( Matrix : : ortho2D ( 0 , 1280 , 0 , 1024 ) ) ;
textProjection - > addChild ( textGeode ) ;
// "texture not available" text displayed when the user trys to
// display the depth texture while multisampling.
osgText : : Text * noCanDo = new osgText : : Text ;
noCanDo - > setFont ( fontName ) ;
noCanDo - > setPosition ( Vec3 ( 512.0f , 384.0f , 0.0f ) ) ;
noCanDo - > setColor ( Vec4 ( 1.0 , 0.0 , 0.0 , 1.0 ) ) ;
noCanDo - > setText ( " not available " ) ;
textNotAvailable = new Geode ;
textNotAvailable - > addDrawable ( noCanDo ) ;
textProjection - > addChild ( textNotAvailable . get ( ) ) ;
// Is the depth test inverted?
osgText : : Text * inverted = new osgText : : Text ;
inverted - > setFont ( fontName ) ;
inverted - > setPosition ( Vec3 ( 512.0f , 50.0f , 0.0f ) ) ;
inverted - > setColor ( Vec4 ( 1.0 , 1.0 , 1.0 , 1.0 ) ) ;
inverted - > setText ( " inverted depth test " ) ;
textInverted = new Geode ;
textInverted - > addDrawable ( inverted ) ;
2010-04-23 16:58:57 +08:00
textInverted - > setNodeMask ( ~ 0u ) ;
2010-05-12 19:37:27 +08:00
textProjection - > addChild ( textInverted . get ( ) ) ;
2010-04-19 19:43:06 +08:00
textProjection - > getOrCreateStateSet ( ) - > setRenderBinDetails ( 11 , " RenderBin " ) ;
}
void AppState : : setStateFromConfig ( const FboConfig & config )
{
Camera * camera = viewer - > getSlave ( 0 ) . _camera . get ( ) ;
setAttachmentsFromConfig ( camera , config ) ;
osgViewer : : Renderer * renderer
= dynamic_cast < osgViewer : : Renderer * > ( camera - > getRenderer ( ) ) ;
if ( renderer )
renderer - > setCameraRequiresSetUp ( true ) ;
if ( configText . valid ( ) )
{
configText - > setText ( validConfigs [ currentConfig ] . name ) ;
configText - > update ( ) ;
}
updateDisplayedTexture ( ) ;
}
void AppState : : advanceConfig ( int increment )
{
currentConfig = ( currentConfig + increment ) % validConfigs . size ( ) ;
setStateFromConfig ( validConfigs [ currentConfig ] ) ;
}
void AppState : : updateDisplayedTexture ( )
{
if ( displayScene )
sw - > setSingleChildOn ( 0 ) ;
else if ( validConfigs [ currentConfig ] . depthSamples > 0
| | validConfigs [ currentConfig ] . coverageSamples > 0 )
sw - > setAllChildrenOff ( ) ;
else if ( validConfigs [ currentConfig ] . depthFormat ! = GL_DEPTH_COMPONENT24 )
sw - > setSingleChildOn ( 2 ) ;
else
sw - > setSingleChildOn ( 3 ) ;
if ( displayScene
| | ( validConfigs [ currentConfig ] . depthSamples = = 0
& & validConfigs [ currentConfig ] . coverageSamples = = 0 ) )
2010-04-23 16:58:57 +08:00
textNotAvailable - > setNodeMask ( 0u ) ;
2010-04-19 19:43:06 +08:00
else
2010-04-23 16:58:57 +08:00
textNotAvailable - > setNodeMask ( ~ 0u ) ;
2010-04-19 19:43:06 +08:00
}
void AppState : : updateNear ( )
{
// Assume that the viewing frustum is symmetric.
double fovy , aspectRatio , cNear , cFar ;
viewer - > getCamera ( ) - > getProjectionMatrixAsPerspective ( fovy , aspectRatio ,
cNear , cFar ) ;
viewer - > getCamera ( ) - > setProjectionMatrixAsPerspective ( fovy , aspectRatio ,
zNear , cFar ) ;
stringstream nearStream ;
nearStream < < " near: " < < zNear ;
zNearText - > setText ( nearStream . str ( ) ) ;
zNearText - > update ( ) ;
}
class ConfigHandler : public osgGA : : GUIEventHandler
{
public :
ConfigHandler ( AppState * appState )
: _appState ( appState )
{
}
virtual bool handle ( const osgGA : : GUIEventAdapter & ea ,
osgGA : : GUIActionAdapter & aa ,
Object * , NodeVisitor * /*nv*/ )
{
if ( ea . getHandled ( ) ) return false ;
osgViewer : : Viewer * viewer = dynamic_cast < osgViewer : : Viewer * > ( & aa ) ;
if ( ! viewer ) return false ;
switch ( ea . getEventType ( ) )
{
case osgGA : : GUIEventAdapter : : KEYUP :
{
if ( ea . getKey ( ) = = ' d ' )
{
_appState - > displayScene = ! _appState - > displayScene ;
_appState - > updateDisplayedTexture ( ) ;
return true ;
}
else if ( ea . getKey ( ) = = osgGA : : GUIEventAdapter : : KEY_Right | |
ea . getKey ( ) = = osgGA : : GUIEventAdapter : : KEY_KP_Right )
{
_appState - > advanceConfig ( 1 ) ;
return true ;
}
else if ( ea . getKey ( ) = = osgGA : : GUIEventAdapter : : KEY_Left | |
ea . getKey ( ) = = osgGA : : GUIEventAdapter : : KEY_KP_Left )
{
_appState - > advanceConfig ( - 1 ) ;
return true ;
}
break ;
}
default :
break ;
}
return false ;
}
void getUsage ( ApplicationUsage & usage ) const
{
usage . addKeyboardMouseBinding ( " d " , " display depth texture " ) ;
usage . addKeyboardMouseBinding ( " right arrow " ,
" next frame buffer configuration " ) ;
usage . addKeyboardMouseBinding ( " left arrow " ,
" previous frame buffer configuration " ) ;
}
protected :
virtual ~ ConfigHandler ( ) { }
ref_ptr < AppState > _appState ;
} ;
class DepthHandler : public osgGA : : GUIEventHandler
{
public :
DepthHandler ( AppState * appState , Depth * depth )
: _appState ( appState ) , _depth ( depth )
{
depth - > setDataVariance ( Object : : DYNAMIC ) ;
}
virtual bool handle ( const osgGA : : GUIEventAdapter & ea ,
osgGA : : GUIActionAdapter & /*aa*/ ,
Object * , NodeVisitor * /*nv*/ )
{
if ( ea . getHandled ( ) ) return false ;
2010-05-28 16:57:48 +08:00
ref_ptr < Depth > depth ;
if ( ! _depth . lock ( depth ) ) return false ;
2010-04-19 19:43:06 +08:00
switch ( ea . getEventType ( ) )
{
case ( osgGA : : GUIEventAdapter : : KEYUP ) :
{
if ( ea . getKey ( ) = = ' i ' )
{
_appState - > invertRange = ! _appState - > invertRange ;
if ( ! _appState - > invertRange )
{
_appState - > camera - > setClearDepth ( 1.0f ) ;
depth - > setFunction ( Depth : : LESS ) ;
depth - > setRange ( 0.0f , 1.0f ) ;
2010-04-23 16:58:57 +08:00
_appState - > textInverted - > setNodeMask ( 0u ) ;
2010-04-19 19:43:06 +08:00
}
else
{
_appState - > camera - > setClearDepth ( 0.0f ) ;
depth - > setFunction ( Depth : : GEQUAL ) ;
depth - > setRange ( 1.0f , 0.0f ) ;
2010-04-23 16:58:57 +08:00
_appState - > textInverted - > setNodeMask ( ~ 0u ) ;
2010-04-19 19:43:06 +08:00
}
return true ;
}
else if ( ea . getKey ( ) = = osgGA : : GUIEventAdapter : : KEY_Up | |
ea . getKey ( ) = = osgGA : : GUIEventAdapter : : KEY_KP_Up )
{
_appState - > zNear * = 2.0 ;
_appState - > updateNear ( ) ;
return true ;
}
else if ( ea . getKey ( ) = = osgGA : : GUIEventAdapter : : KEY_Down | |
ea . getKey ( ) = = osgGA : : GUIEventAdapter : : KEY_KP_Down )
{
_appState - > zNear * = .5 ;
_appState - > updateNear ( ) ;
return true ;
}
break ;
}
default :
break ;
}
return false ;
}
void getUsage ( ApplicationUsage & usage ) const
{
usage . addKeyboardMouseBinding ( " i " , " invert depth buffer range " ) ;
usage . addKeyboardMouseBinding ( " up arrow " ,
" double near plane distance " ) ;
usage . addKeyboardMouseBinding ( " down arrow " ,
" half near plane distance " ) ;
}
protected :
virtual ~ DepthHandler ( ) { }
ref_ptr < AppState > _appState ;
observer_ptr < Depth > _depth ;
} ;
Geode * createTextureQuad ( Texture2D * texture )
{
Vec3Array * vertices = new Vec3Array ;
vertices - > push_back ( Vec3 ( - 1.0 , - 1.0 , 0.0 ) ) ;
vertices - > push_back ( Vec3 ( 1.0 , - 1.0 , 0.0 ) ) ;
vertices - > push_back ( Vec3 ( 1.0 , 1.0 , 0.0 ) ) ;
vertices - > push_back ( Vec3 ( - 1.0 , 1.0 , 0.0 ) ) ;
Vec2Array * texcoord = new Vec2Array ;
texcoord - > push_back ( Vec2 ( 0.0 , 0.0 ) ) ;
texcoord - > push_back ( Vec2 ( 1.0 , 0.0 ) ) ;
texcoord - > push_back ( Vec2 ( 1.0 , 1.0 ) ) ;
texcoord - > push_back ( Vec2 ( 0.0 , 1.0 ) ) ;
Geometry * geom = new Geometry ;
geom - > setVertexArray ( vertices ) ;
geom - > setTexCoordArray ( 0 , texcoord ) ;
geom - > addPrimitiveSet ( new DrawArrays ( GL_QUADS , 0 , 4 ) ) ;
Geode * geode = new Geode ;
geode - > addDrawable ( geom ) ;
geode - > getOrCreateStateSet ( ) - > setTextureAttributeAndModes ( 0 , texture , StateAttribute : : ON ) ;
return geode ;
}
struct ResizedCallback : public osg : : GraphicsContext : : ResizedCallback
{
ResizedCallback ( AppState * appState )
: _appState ( appState )
{
}
void resizedImplementation ( GraphicsContext * gc , int x , int y , int width ,
int height ) ;
ref_ptr < AppState > _appState ;
} ;
void ResizedCallback : : resizedImplementation ( GraphicsContext * gc , int x , int y ,
int width , int height )
{
gc - > resizedImplementation ( x , y , width , height ) ;
2010-05-12 19:37:27 +08:00
makeTexturesAndGeometry ( width , height , _appState - > sw . get ( ) ) ;
2010-04-19 19:43:06 +08:00
_appState - > setStateFromConfig ( validConfigs [ _appState
- > currentConfig ] ) ;
osgViewer : : Viewer * viewer = _appState - > viewer ;
Viewport * vp = viewer - > getSlave ( 0 ) . _camera - > getViewport ( ) ;
if ( vp )
{
double oldWidth = vp - > width ( ) , oldHeight = vp - > height ( ) ;
double aspectRatioChange
= ( width / oldWidth ) / ( height / oldHeight ) ;
vp - > setViewport ( 0 , 0 , width , height ) ;
if ( aspectRatioChange ! = 1.0 )
{
Camera * master = viewer - > getCamera ( ) ;
switch ( master - > getProjectionResizePolicy ( ) )
{
case Camera : : HORIZONTAL :
master - > getProjectionMatrix ( )
* = Matrix : : scale ( 1.0 / aspectRatioChange , 1.0 , 1.0 ) ;
break ;
case Camera : : VERTICAL :
master - > getProjectionMatrix ( )
* = Matrix : : scale ( 1.0 , aspectRatioChange , 1.0 ) ;
break ;
default :
break ;
}
}
}
}
// Prefer GL_DEPTH_COMPONENT32F, otherwise use
// GL_DEPTH_COMPONENT32F_NV if available
GLenum depthTextureEnum = 0 ;
// Standard OSG code for initializing osgViewer::Viewer with explicit
// creation of own graphics context. This is also a good time to test
// for valid frame buffer configurations; we have a valid graphics
// context, but multithreading hasn't started, etc.
GraphicsContext * setupGC ( osgViewer : : Viewer & viewer , ArgumentParser & arguments )
{
int x = - 1 , y = - 1 , width = - 1 , height = - 1 ;
while ( arguments . read ( " --window " , x , y , width , height ) ) { }
GraphicsContext : : WindowingSystemInterface * wsi =
GraphicsContext : : getWindowingSystemInterface ( ) ;
if ( ! wsi )
{
OSG_NOTIFY ( NOTICE ) < < " View::setUpViewOnSingleScreen() : Error, no WindowSystemInterface available, cannot create windows. " < < std : : endl ;
return 0 ;
}
2010-05-12 19:37:27 +08:00
DisplaySettings * ds = viewer . getDisplaySettings ( ) ? viewer . getDisplaySettings ( ) : DisplaySettings : : instance ( ) . get ( ) ;
2010-04-19 19:43:06 +08:00
GraphicsContext : : ScreenIdentifier si ;
si . readDISPLAY ( ) ;
// displayNum has not been set so reset it to 0.
if ( si . displayNum < 0 ) si . displayNum = 0 ;
bool decoration = true ;
if ( x < 0 )
{
unsigned int w , h ;
wsi - > getScreenResolution ( si , w , h ) ;
x = 0 ;
y = 0 ;
width = w ;
height = h ;
decoration = false ;
}
ref_ptr < GraphicsContext : : Traits > traits
= new GraphicsContext : : Traits ( ds ) ;
traits - > hostName = si . hostName ;
traits - > displayNum = si . displayNum ;
traits - > screenNum = si . screenNum ;
traits - > x = x ;
traits - > y = y ;
traits - > width = width ;
traits - > height = height ;
traits - > windowDecoration = decoration ;
traits - > doubleBuffer = true ;
traits - > sharedContext = 0 ;
ref_ptr < GraphicsContext > gc
= GraphicsContext : : createGraphicsContext ( traits . get ( ) ) ;
osgViewer : : GraphicsWindow * gw
= dynamic_cast < osgViewer : : GraphicsWindow * > ( gc . get ( ) ) ;
if ( gw )
{
OSG_NOTIFY ( INFO ) < < " View::setUpViewOnSingleScreen - GraphicsWindow has been created successfully. " < < std : : endl ;
gw - > getEventQueue ( ) - > getCurrentEventState ( )
- > setWindowRectangle ( 0 , 0 , width , height ) ;
}
else
{
OSG_NOTIFY ( NOTICE ) < < " GraphicsWindow has not been created successfully. " < < std : : endl ;
}
double fovy , aspectRatio , zNear , zFar ;
viewer . getCamera ( ) - > getProjectionMatrixAsPerspective ( fovy , aspectRatio ,
zNear , zFar ) ;
double newAspectRatio = double ( traits - > width ) / double ( traits - > height ) ;
double aspectRatioChange = newAspectRatio / aspectRatio ;
if ( aspectRatioChange ! = 1.0 )
{
viewer . getCamera ( ) - > getProjectionMatrix ( )
* = Matrix : : scale ( 1.0 / aspectRatioChange , 1.0 , 1.0 ) ;
}
// Context has to be current to test for extensions
gc - > realize ( ) ;
gc - > makeCurrent ( ) ;
unsigned int contextID = gc - > getState ( ) - > getContextID ( ) ;
FBOExtensions * fboe = FBOExtensions : : instance ( contextID , true ) ;
if ( ! fboe - > isSupported ( ) )
{
OSG_NOTIFY ( NOTICE ) < < " Frame buffer objects are not supported \n " ;
gc - > releaseContext ( ) ;
gc - > close ( true ) ;
return 0 ;
}
if ( isGLExtensionSupported ( contextID , " GL_ARB_depth_buffer_float " ) )
depthTextureEnum = GL_DEPTH_COMPONENT32F ;
else if ( isGLExtensionSupported ( contextID , " GL_NV_depth_buffer_float " ) )
depthTextureEnum = GL_DEPTH_COMPONENT32F_NV ;
BufferConfigList colorConfigs ;
BufferConfigList depthConfigs ;
vector < int > coverageConfigs ;
2010-05-12 19:37:27 +08:00
getPossibleConfigs ( gc . get ( ) , colorConfigs , depthConfigs , coverageConfigs ) ;
2010-04-19 19:43:06 +08:00
int coverageSampleConfigs = ( coverageConfigs . size ( ) - 4 ) / 2 ;
cout < < " color configs \n name \t bits \n " ;
for ( BufferConfigList : : const_iterator colorItr = colorConfigs . begin ( ) ,
colorEnd = colorConfigs . end ( ) ;
colorItr ! = colorEnd ;
+ + colorItr )
{
for ( BufferConfigList : : const_iterator depthItr = depthConfigs . begin ( ) ,
depthEnd = depthConfigs . end ( ) ;
depthItr ! = depthEnd ;
+ + depthItr )
{
string root = colorItr - > name + " " + depthItr - > name ;
FboConfig config ( root , colorItr - > format , depthItr - > format ,
colorItr - > bits , depthItr - > bits ) ;
FboData data ;
2010-05-12 19:37:27 +08:00
if ( createFBO ( gc . get ( ) , config , data ) )
2010-04-19 19:43:06 +08:00
validConfigs . push_back ( config ) ;
2010-05-12 19:37:27 +08:00
destroyFBO ( gc . get ( ) , data ) ;
2010-04-19 19:43:06 +08:00
if ( coverageConfigs . size ( ) > 0 )
{
//CSAA provides a list of all supported AA modes for
//quick enumeration
for ( int kk = 0 ; kk < coverageSampleConfigs ; kk + + )
{
stringstream msText ;
msText < < root ;
config . depthSamples = coverageConfigs [ kk * 2 + 1 ] ;
config . coverageSamples = coverageConfigs [ kk * 2 ] ;
if ( config . coverageSamples = = config . depthSamples )
{
// Normal antialiasing
msText < < " - " < < config . depthSamples < < " MSAA " ;
}
else
{
// coverage antialiasing
msText < < " - " < < config . coverageSamples < < " / "
< < config . depthSamples < < " CSAA " ;
}
config . name = msText . str ( ) ;
2010-05-12 19:37:27 +08:00
if ( createFBO ( gc . get ( ) , config , data ) ) {
2010-04-19 19:43:06 +08:00
validConfigs . push_back ( config ) ;
}
2010-05-12 19:37:27 +08:00
destroyFBO ( gc . get ( ) , data ) ;
2010-04-19 19:43:06 +08:00
}
}
}
}
2010-04-22 18:13:05 +08:00
if ( validConfigs . empty ( ) )
{
cout < < " no valid frame buffer configurations! \n " ;
return 0 ;
}
2010-04-19 19:43:06 +08:00
cout < < " valid frame buffer configurations: \n " ;
for ( vector < FboConfig > : : iterator itr = validConfigs . begin ( ) ,
end = validConfigs . end ( ) ;
itr ! = end ;
+ + itr )
cout < < itr - > name < < " \n " ;
gc - > releaseContext ( ) ;
return gc . release ( ) ;
}
ref_ptr < Texture2D > colorTexture ;
ref_ptr < Texture2D > depthTexture ;
ref_ptr < Texture2D > depthTexture24 ;
Texture2D * makeDepthTexture ( int width , int height , GLenum internalFormat )
{
Texture2D * depthTex = new Texture2D ;
depthTex - > setTextureSize ( width , height ) ;
depthTex - > setSourceFormat ( GL_DEPTH_COMPONENT ) ;
depthTex - > setSourceType ( GL_FLOAT ) ;
depthTex - > setInternalFormat ( internalFormat ) ;
depthTex - > setFilter ( Texture2D : : MIN_FILTER , Texture2D : : NEAREST ) ;
depthTex - > setFilter ( Texture2D : : MAG_FILTER , Texture2D : : NEAREST ) ;
depthTex - > setWrap ( Texture : : WRAP_S , Texture : : CLAMP_TO_EDGE ) ;
depthTex - > setWrap ( Texture : : WRAP_T , Texture : : CLAMP_TO_EDGE ) ;
return depthTex ;
}
Camera * makeRttCamera ( GraphicsContext * gc , int width , int height )
{
Camera * rttCamera = new Camera ;
rttCamera - > setGraphicsContext ( gc ) ;
rttCamera - > setClearMask ( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ) ;
rttCamera - > setClearColor ( Vec4 ( 0.0 , 0.4 , 0.5 , 0.0 ) ) ;
// normally the depth test is inverted, although the user can
// change that.
rttCamera - > setClearDepth ( 0.0 ) ;
rttCamera - > setViewport ( 0 , 0 , width , height ) ;
rttCamera - > setDrawBuffer ( GL_FRONT ) ;
rttCamera - > setReadBuffer ( GL_FRONT ) ;
rttCamera - > setRenderTargetImplementation ( Camera : : FRAME_BUFFER_OBJECT ) ;
rttCamera - > setComputeNearFarMode ( CullSettings : : DO_NOT_COMPUTE_NEAR_FAR ) ;
return rttCamera ;
}
void setAttachmentsFromConfig ( Camera * camera , const FboConfig & config )
{
// XXX Detaching the old buffers may not be necessary.
if ( ! camera - > getBufferAttachmentMap ( ) . empty ( ) )
{
camera - > detach ( Camera : : COLOR_BUFFER ) ;
camera - > detach ( Camera : : DEPTH_BUFFER ) ;
}
camera - > attach ( Camera : : COLOR_BUFFER , colorTexture . get ( ) , 0 , 0 , false ,
config . coverageSamples , config . depthSamples ) ;
if ( config . coverageSamples ! = 0 | | config . depthSamples ! = 0 )
camera - > attach ( Camera : : DEPTH_BUFFER , config . depthFormat ) ;
else if ( config . depthFormat = = GL_DEPTH_COMPONENT24 )
2010-05-12 19:37:27 +08:00
camera - > attach ( Camera : : DEPTH_BUFFER , depthTexture24 . get ( ) ) ;
2010-04-19 19:43:06 +08:00
else
2010-05-12 19:37:27 +08:00
camera - > attach ( Camera : : DEPTH_BUFFER , depthTexture . get ( ) ) ;
2010-04-19 19:43:06 +08:00
}
// Create the parts of the local scene graph used to display the final
// results.
Switch * makeTexturesAndGeometry ( int width , int height , Switch * sw )
{
if ( ! sw )
sw = new Switch ;
colorTexture = new Texture2D ;
colorTexture - > setTextureSize ( width , height ) ;
colorTexture - > setInternalFormat ( GL_RGBA ) ;
colorTexture - > setFilter ( Texture2D : : MIN_FILTER , Texture2D : : LINEAR ) ;
colorTexture - > setFilter ( Texture2D : : MAG_FILTER , Texture2D : : LINEAR ) ;
colorTexture - > setWrap ( Texture : : WRAP_S , Texture : : CLAMP_TO_EDGE ) ;
colorTexture - > setWrap ( Texture : : WRAP_T , Texture : : CLAMP_TO_EDGE ) ;
colorTexture - > setBorderColor ( Vec4 ( 0 , 0 , 0 , 0 ) ) ;
depthTexture24 = makeDepthTexture ( width , height , GL_DEPTH_COMPONENT24 ) ;
if ( depthTextureEnum )
depthTexture = makeDepthTexture ( width , height , depthTextureEnum ) ;
else
depthTexture = depthTexture24 ;
sw - > removeChildren ( 0 , sw - > getNumChildren ( ) ) ;
2010-05-12 19:37:27 +08:00
sw - > addChild ( createTextureQuad ( colorTexture . get ( ) ) ) ;
sw - > addChild ( createTextureQuad ( depthTexture . get ( ) ) ) ;
sw - > addChild ( createTextureQuad ( depthTexture24 . get ( ) ) ) ;
2010-04-19 19:43:06 +08:00
sw - > setSingleChildOn ( 0 ) ;
return sw ;
}
int main ( int argc , char * * argv )
{
// use an ArgumentParser object to manage the program arguments.
ArgumentParser arguments ( & argc , argv ) ;
2010-04-22 00:37:28 +08:00
arguments . getApplicationUsage ( ) - > setDescription ( arguments . getApplicationName ( )
2010-04-19 19:43:06 +08:00
+ " demonstrates using a floating point depth buffer. \n The user can invert the depth buffer range and choose among available multi-sample configurations. " ) ;
2010-04-22 00:37:28 +08:00
arguments . getApplicationUsage ( ) - > setCommandLineUsage ( arguments . getApplicationName ( ) + " [options] filename ... " ) ;
arguments . getApplicationUsage ( ) - > addCommandLineOption ( " --far <number> " , " Set far plane value " ) ;
2010-04-19 19:43:06 +08:00
// if user request help write it out to cout.
if ( arguments . read ( " -h " ) | | arguments . read ( " --help " ) )
{
arguments . getApplicationUsage ( ) - > write ( std : : cout ) ;
return 1 ;
}
float zFar = 500.0f ;
while ( arguments . read ( " --far " , zFar ) )
;
// construct the viewer.
osgViewer : : Viewer viewer ;
ref_ptr < AppState > appState = new AppState ( & viewer ) ;
viewer . addEventHandler ( new osgViewer : : StatsHandler ) ;
viewer . addEventHandler ( new osgViewer : : WindowSizeHandler ) ;
viewer . addEventHandler ( new osgViewer : : ScreenCaptureHandler ) ;
// The aspect ratio is set to the correct ratio for the window in
// setupGC().
viewer . getCamera ( )
- > setProjectionMatrixAsPerspective ( 40.0 , 1.0 , appState - > zNear , zFar ) ;
GraphicsContext * gc = setupGC ( viewer , arguments ) ;
if ( ! gc )
return 1 ;
gc - > setResizedCallback ( new ResizedCallback ( appState . get ( ) ) ) ;
const GraphicsContext : : Traits * traits = gc - > getTraits ( ) ;
width = traits - > width ;
height = traits - > height ;
2010-04-22 00:37:28 +08:00
if ( arguments . argc ( ) < = 1 )
{
arguments . getApplicationUsage ( ) - > write ( std : : cout , osg : : ApplicationUsage : : COMMAND_LINE_OPTION ) ;
return 1 ;
}
2010-04-19 19:43:06 +08:00
ref_ptr < Node > loadedModel = osgDB : : readNodeFiles ( arguments ) ;
if ( ! loadedModel ) {
cerr < < " couldn't load " < < argv [ 1 ] < < " \n " ;
return 1 ;
}
osgUtil : : Optimizer optimizer ;
optimizer . optimize ( loadedModel . get ( ) ) ;
// creates texture to be rendered
2010-05-12 19:37:27 +08:00
Switch * sw = makeTexturesAndGeometry ( width , height , appState - > sw . get ( ) ) ;
2010-04-19 19:43:06 +08:00
ref_ptr < Camera > rttCamera = makeRttCamera ( gc , width , height ) ;
rttCamera - > setRenderOrder ( Camera : : PRE_RENDER ) ;
2010-05-12 19:37:27 +08:00
viewer . addSlave ( rttCamera . get ( ) ) ;
2010-04-19 19:43:06 +08:00
appState - > camera = rttCamera ;
// geometry and slave camera to display the result
Group * displayRoot = new Group ;
displayRoot - > addChild ( sw ) ;
2010-05-12 19:37:27 +08:00
displayRoot - > addChild ( appState - > textProjection . get ( ) ) ;
2010-04-19 19:43:06 +08:00
StateSet * displaySS = displayRoot - > getOrCreateStateSet ( ) ;
displaySS - > setMode ( GL_LIGHTING , StateAttribute : : OFF ) ;
displaySS - > setMode ( GL_DEPTH_TEST , StateAttribute : : OFF ) ;
Camera * texCamera = new Camera ;
texCamera - > setGraphicsContext ( gc ) ;
texCamera - > setClearMask ( GL_COLOR_BUFFER_BIT ) ;
texCamera - > setClearColor ( Vec4 ( 0.0 , 0.0 , 0.0 , 0.0 ) ) ;
texCamera - > setReferenceFrame ( Camera : : ABSOLUTE_RF ) ;
texCamera - > setViewport ( 0 , 0 , width , height ) ;
texCamera - > setDrawBuffer ( GL_BACK ) ;
texCamera - > setReadBuffer ( GL_BACK ) ;
texCamera - > addChild ( displayRoot ) ;
texCamera - > setAllowEventFocus ( false ) ;
texCamera - > setCullingMode ( CullSettings : : NO_CULLING ) ;
texCamera - > setProjectionResizePolicy ( Camera : : FIXED ) ;
viewer . addSlave ( texCamera , Matrixd ( ) , Matrixd ( ) , false ) ;
2010-05-12 19:37:27 +08:00
viewer . addEventHandler ( new ConfigHandler ( appState . get ( ) ) ) ;
2010-04-19 19:43:06 +08:00
// add model to the viewer.
Group * sceneRoot = new Group ;
StateSet * sceneSS = sceneRoot - > getOrCreateStateSet ( ) ;
Depth * depth = new Depth ( Depth : : GEQUAL , 1.0 , 0.0 ) ;
sceneSS - > setAttributeAndModes ( depth , ( StateAttribute : : ON
| StateAttribute : : OVERRIDE ) ) ;
#if 0
// Hack to work around Blender osg export bug
sceneSS - > setAttributeAndModes ( new CullFace ( CullFace : : BACK ) ) ;
# endif
sceneRoot - > addChild ( loadedModel . get ( ) ) ;
appState - > setStateFromConfig ( validConfigs [ 0 ] ) ;
appState - > updateNear ( ) ;
viewer . addEventHandler ( new DepthHandler ( appState . get ( ) , depth ) ) ;
// add the help handler
viewer . addEventHandler ( new osgViewer
: : HelpHandler ( arguments . getApplicationUsage ( ) ) ) ;
viewer . setSceneData ( sceneRoot ) ;
return viewer . run ( ) ;
}