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