OpenWalnut 1.3.1
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< osg::Camera > 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 = boost::shared_ptr< WItemSelection >( 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         // the geometry render step
00068         osg::ref_ptr< WGEOffscreenRenderPass > render = offscreen->addGeometryRenderPass(
00069             m_childs,
00070             "Rendered"
00071         );
00072 
00073         // create G-Buffer
00074         WGEPostprocessor::PostprocessorInput buf( WGEPostprocessor::PostprocessorInput::attach( render ) );
00075 
00076         // let the specific post processor build its pipeline
00077         WGEPostprocessor::SPtr processor = ( *iter )->create( offscreen, buf );
00078         m_postprocs.push_back( processor );
00079 
00080         // add the postprocessor's properties
00081         m_properties->addProperty( processor->getProperties() );
00082         processor->getProperties()->setHidden( true );
00083 
00084         // add it to the selection prop
00085         m_possibleSelections->addItem( processor->getName(), processor->getDescription() );
00086 
00087         // the final step
00088         osg::ref_ptr< WGEOffscreenFinalPass > output = offscreen->addFinalOnScreenPass( new WGEShader( "WGEPostprocessorCombiner" ),
00089                                                                                         "Output" );
00090         output->bind( processor->getOutput(), 0 );
00091 
00092         // does this processor provide a depth?
00093         osg::ref_ptr< osg::Texture2D > depthTex = processor->getDepth();
00094         if( !depthTex )
00095         {
00096             depthTex = buf.m_depthTexture;
00097         }
00098         output->bind( depthTex, 1 );
00099 
00100         // add the offscreen renderer and the original node to the switch
00101         addChild( offscreen );
00102     }
00103 
00104     // let the props control some stuff
00105     addUpdateCallback( new WGESwitchCallback< WPropSelection >( m_activePostprocessor ) );
00106 }
00107 
00108 WGEPostprocessingNode::~WGEPostprocessingNode()
00109 {
00110     // cleanup
00111 }
00112 
00113 WPropGroup WGEPostprocessingNode::getProperties() const
00114 {
00115     return m_properties;
00116 }
00117 
00118 void WGEPostprocessingNode::insert( osg::ref_ptr< osg::Node > node, WGEShader::RefPtr shader )
00119 {
00120     // the shader needs an own preprocessor.
00121     WGEShaderPreprocessor::SPtr preproc( new WGEShaderPropertyDefineOptions< WPropBool >(
00122         m_active, "WGE_POSTPROCESSING_DISABLED", "WGE_POSTPROCESSING_ENABLED" )
00123     );
00124 
00125     // we need to inject some code to the shader at this point.
00126     shader->addPreprocessor( preproc );
00127 
00128     // do it thread-safe as we promise to be thread-safe
00129     NodeShaderAssociation::WriteTicket w = m_nodeShaderAssociation.getWriteTicket();
00130     // to keep track of which node is associated with which shader and preprocessor:
00131     w->get()[ node ] = std::make_pair( shader, preproc );
00132 
00133     // insert node to group node of all children
00134     m_childs->insert( node );
00135 }
00136 
00137 void WGEPostprocessingNode::remove( osg::ref_ptr< osg::Node > node )
00138 {
00139     // do it thread-safe as we promise to be thread-safe
00140     NodeShaderAssociation::WriteTicket w = m_nodeShaderAssociation.getWriteTicket();
00141 
00142     // remove the item from our map
00143     NodeShaderAssociation::Iterator item = w->get().find( node );
00144 
00145     if( item != w->get().end() )
00146     {
00147         // we need to remove the preprocessor from the shader.
00148         ( *item ).second.first->removePreprocessor( ( *item ).second.second );
00149         w->get().erase( item );
00150     }
00151 
00152     // although we may not find the node in our association list, try to remove it
00153     m_childs->remove( node );
00154 }
00155 
00156 void WGEPostprocessingNode::clear()
00157 {
00158     // do it thread-safe as we promise to be thread-safe
00159     NodeShaderAssociation::WriteTicket w = m_nodeShaderAssociation.getWriteTicket();
00160 
00161     // remove from node-shader association list
00162     for( NodeShaderAssociation::Iterator iter = w->get().begin(); iter != w->get().end(); ++iter )
00163     {
00164         ( *iter ).second.first->removePreprocessor( ( *iter ).second.second );
00165     }
00166     w->get().clear();
00167 
00168     // remove the node from the render group
00169     m_childs->clear();
00170 }
00171 
00172 void WGEPostprocessingNode::postprocessorSelected()
00173 {
00174     if( m_postprocs.size() == 0 )
00175     {
00176         m_active->set( false );
00177         return;
00178     }
00179 
00180     size_t active = m_activePostprocessor->get();
00181 
00182     // this triggers several shader preprocessors of all child nodes
00183     m_active->set( active != 0 );
00184 
00185     // hide all, but not the active one
00186     for( size_t i = 0; i < m_postprocs.size(); ++i )
00187     {
00188         m_postprocs[ i ]->getProperties()->setHidden( i != ( active - 1 ) );
00189     }
00190 }