OpenWalnut  1.4.0
WGEPostprocessingNode.cpp
00001 //---------------------------------------------------------------------------
00002 //
00003 // Project: OpenWalnut ( http://www.openwalnut.org )
00004 //
00005 // Copyright 2009 OpenWalnut Community, BSV@Uni-Leipzig and CNCF@MPI-CBS
00006 // For more information see http://www.openwalnut.org/copying
00007 //
00008 // This file is part of OpenWalnut.
00009 //
00010 // OpenWalnut is free software: you can redistribute it and/or modify
00011 // it under the terms of the GNU Lesser General Public License as published by
00012 // the Free Software Foundation, either version 3 of the License, or
00013 // (at your option) any later version.
00014 //
00015 // OpenWalnut is distributed in the hope that it will be useful,
00016 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00017 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00018 // GNU Lesser General Public License for more details.
00019 //
00020 // You should have received a copy of the GNU Lesser General Public License
00021 // along with OpenWalnut. If not, see <http://www.gnu.org/licenses/>.
00022 //
00023 //---------------------------------------------------------------------------
00024 
00025 #include "../../common/WPropertyHelper.h"
00026 #include "../../common/WItemSelection.h"
00027 
00028 #include "../shaders/WGEShaderPropertyDefineOptions.h"
00029 #include "../callbacks/WGENodeMaskCallback.h"
00030 #include "../WGEUtils.h"
00031 
00032 #include "WGEPostprocessor.h"
00033 
00034 #include "WGEPostprocessingNode.h"
00035 
00036 WGEPostprocessingNode::WGEPostprocessingNode( osg::ref_ptr< WGECamera > reference, size_t width, size_t height, bool noHud ):
00037     osg::Switch(),
00038     m_childs( new WGEGroupNode() ),
00039     m_properties( boost::shared_ptr< WProperties >( new WProperties( "Post-processing", "Post-processing properties" ) ) )
00040 {
00041     // the geometry is always the first in the switch node
00042     addChild( m_childs );
00043 
00044     // this node has some properties:
00045     boost::shared_ptr< WItemSelection > m_possibleSelections( new WItemSelection() );
00046     m_possibleSelections->addItem( "None", "No postprocessing." );
00047 
00048     m_showHud = m_properties->addProperty( "Texture Debug", "If set, all intermediate texture are shown on screen for debugging.", false );
00049     m_active = m_properties->addProperty( "Enable", "If set, post-processing is enabled.", false, true );
00050     m_activePostprocessor = m_properties->addProperty( "Postprocessor", "Selection one of the postprocessors.",
00051                                                        m_possibleSelections->getSelectorFirst(),
00052                                                        boost::bind( &WGEPostprocessingNode::postprocessorSelected, this ) );
00053     WPropertyHelper::PC_SELECTONLYONE::addTo( m_activePostprocessor );
00054     WPropertyHelper::PC_NOTEMPTY::addTo( m_activePostprocessor );
00055 
00056     // control texture HUD
00057     osg::ref_ptr< WGENodeMaskCallback > textureHudCallback = new WGENodeMaskCallback( m_showHud );
00058 
00059     // get available postprocessors and setup the node
00060     WGEPostprocessor::ProcessorList processors = WGEPostprocessor::getPostprocessors();
00061     for( WGEPostprocessor::ProcessorList::const_iterator iter = processors.begin(); iter != processors.end(); ++iter )
00062     {
00063         // offscreen node
00064         osg::ref_ptr< WGEOffscreenRenderNode > offscreen( new WGEOffscreenRenderNode( reference, width, height, noHud ) );
00065         offscreen->getTextureHUD()->addUpdateCallback( textureHudCallback );
00066 
00067         // if the specific postprocessor requires us to fix the viewport size to the result-texture size:
00068         offscreen->setLinkViewportToTextureSize( ( *iter )->getFixedViewportSize() );
00069 
00070         // the geometry render step
00071         osg::ref_ptr< WGEOffscreenRenderPass > render = offscreen->addGeometryRenderPass(
00072             m_childs,
00073             "Rendered"
00074         );
00075 
00076         // create G-Buffer
00077         WGEPostprocessor::PostprocessorInput buf( WGEPostprocessor::PostprocessorInput::attach( render ) );
00078 
00079         // let the specific post processor build its pipeline
00080         WGEPostprocessor::SPtr processor = ( *iter )->create( offscreen, buf );
00081         m_postprocs.push_back( processor );
00082 
00083         // add the postprocessor's properties
00084         m_properties->addProperty( processor->getProperties() );
00085         processor->getProperties()->setHidden( true );
00086 
00087         // add it to the selection prop
00088         m_possibleSelections->addItem( processor->getName(), processor->getDescription() );
00089 
00090         // the final step
00091         osg::ref_ptr< WGEOffscreenFinalPass > output = offscreen->addFinalOnScreenPass( new WGEShader( "WGEPostprocessorCombiner" ),
00092                                                                                         "Output" );
00093         output->bind( processor->getOutput(), 0 );
00094 
00095         // does this processor provide a depth?
00096         osg::ref_ptr< osg::Texture2D > depthTex = processor->getDepth();
00097         if( !depthTex )
00098         {
00099             depthTex = buf.m_depthTexture;
00100         }
00101         output->bind( depthTex, 1 );
00102 
00103         // add the offscreen renderer and the original node to the switch
00104         addChild( offscreen );
00105     }
00106 
00107     // let the props control some stuff
00108     addUpdateCallback( new WGESwitchCallback< WPropSelection >( m_activePostprocessor ) );
00109 }
00110 
00111 WGEPostprocessingNode::~WGEPostprocessingNode()
00112 {
00113     // cleanup
00114 }
00115 
00116 WPropGroup WGEPostprocessingNode::getProperties() const
00117 {
00118     return m_properties;
00119 }
00120 
00121 void WGEPostprocessingNode::insert( osg::ref_ptr< osg::Node > node, WGEShader::RefPtr shader )
00122 {
00123     // the shader needs an own preprocessor.
00124     WGEShaderPreprocessor::SPtr preproc( new WGEShaderPropertyDefineOptions< WPropBool >(
00125         m_active, "WGE_POSTPROCESSING_DISABLED", "WGE_POSTPROCESSING_ENABLED" )
00126     );
00127 
00128     // we need to inject some code to the shader at this point.
00129     shader->addPreprocessor( preproc );
00130 
00131     // do it thread-safe as we promise to be thread-safe
00132     NodeShaderAssociation::WriteTicket w = m_nodeShaderAssociation.getWriteTicket();
00133     // to keep track of which node is associated with which shader and preprocessor:
00134     w->get()[ node ] = std::make_pair( shader, preproc );
00135 
00136     // insert node to group node of all children
00137     m_childs->insert( node );
00138 }
00139 
00140 void WGEPostprocessingNode::remove( osg::ref_ptr< osg::Node > node )
00141 {
00142     // do it thread-safe as we promise to be thread-safe
00143     NodeShaderAssociation::WriteTicket w = m_nodeShaderAssociation.getWriteTicket();
00144 
00145     // remove the item from our map
00146     NodeShaderAssociation::Iterator item = w->get().find( node );
00147 
00148     if( item != w->get().end() )
00149     {
00150         // we need to remove the preprocessor from the shader.
00151         ( *item ).second.first->removePreprocessor( ( *item ).second.second );
00152         w->get().erase( item );
00153     }
00154 
00155     // although we may not find the node in our association list, try to remove it
00156     m_childs->remove( node );
00157 }
00158 
00159 void WGEPostprocessingNode::clear()
00160 {
00161     // do it thread-safe as we promise to be thread-safe
00162     NodeShaderAssociation::WriteTicket w = m_nodeShaderAssociation.getWriteTicket();
00163 
00164     // remove from node-shader association list
00165     for( NodeShaderAssociation::Iterator iter = w->get().begin(); iter != w->get().end(); ++iter )
00166     {
00167         ( *iter ).second.first->removePreprocessor( ( *iter ).second.second );
00168     }
00169     w->get().clear();
00170 
00171     // remove the node from the render group
00172     m_childs->clear();
00173 }
00174 
00175 WGEPostprocessor::SPtr WGEPostprocessingNode::getCurrentPostprocessor() const
00176 {
00177     return m_postprocs[ m_activePostprocessor->get() - 1 ];
00178 }
00179 
00180 void WGEPostprocessingNode::postprocessorSelected()
00181 {
00182     if( m_postprocs.size() == 0 )
00183     {
00184         m_active->set( false );
00185         return;
00186     }
00187 
00188     size_t active = m_activePostprocessor->get();
00189 
00190     // this triggers several shader preprocessors of all child nodes
00191     m_active->set( active != 0 );
00192 
00193     // hide all, but not the active one
00194     for( size_t i = 0; i < m_postprocs.size(); ++i )
00195     {
00196         m_postprocs[ i ]->getProperties()->setHidden( i != ( active - 1 ) );
00197     }
00198 }