OpenWalnut 1.3.1
|
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 }