OpenWalnut  1.3.1
WGEPostprocessingNode.cpp
1 //---------------------------------------------------------------------------
2 //
3 // Project: OpenWalnut ( http://www.openwalnut.org )
4 //
5 // Copyright 2009 OpenWalnut Community, BSV@Uni-Leipzig and CNCF@MPI-CBS
6 // For more information see http://www.openwalnut.org/copying
7 //
8 // This file is part of OpenWalnut.
9 //
10 // OpenWalnut is free software: you can redistribute it and/or modify
11 // it under the terms of the GNU Lesser General Public License as published by
12 // the Free Software Foundation, either version 3 of the License, or
13 // (at your option) any later version.
14 //
15 // OpenWalnut is distributed in the hope that it will be useful,
16 // but WITHOUT ANY WARRANTY; without even the implied warranty of
17 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 // GNU Lesser General Public License for more details.
19 //
20 // You should have received a copy of the GNU Lesser General Public License
21 // along with OpenWalnut. If not, see <http://www.gnu.org/licenses/>.
22 //
23 //---------------------------------------------------------------------------
24 
25 #include "../../common/WPropertyHelper.h"
26 #include "../../common/WItemSelection.h"
27 
28 #include "../shaders/WGEShaderPropertyDefineOptions.h"
29 #include "../callbacks/WGENodeMaskCallback.h"
30 #include "../WGEUtils.h"
31 
32 #include "WGEPostprocessor.h"
33 
34 #include "WGEPostprocessingNode.h"
35 
36 WGEPostprocessingNode::WGEPostprocessingNode( osg::ref_ptr< osg::Camera > reference, size_t width, size_t height, bool noHud ):
37  osg::Switch(),
38  m_childs( new WGEGroupNode() ),
39  m_properties( boost::shared_ptr< WProperties >( new WProperties( "Post-processing", "Post-processing properties" ) ) )
40 {
41  // the geometry is always the first in the switch node
42  addChild( m_childs );
43 
44  // this node has some properties:
45  boost::shared_ptr< WItemSelection > m_possibleSelections = boost::shared_ptr< WItemSelection >( new WItemSelection() );
46  m_possibleSelections->addItem( "None", "No postprocessing." );
47 
48  m_showHud = m_properties->addProperty( "Texture Debug", "If set, all intermediate texture are shown on screen for debugging.", false );
49  m_active = m_properties->addProperty( "Enable", "If set, post-processing is enabled.", false, true );
50  m_activePostprocessor = m_properties->addProperty( "Postprocessor", "Selection one of the postprocessors.",
51  m_possibleSelections->getSelectorFirst(),
52  boost::bind( &WGEPostprocessingNode::postprocessorSelected, this ) );
55 
56  // control texture HUD
57  osg::ref_ptr< WGENodeMaskCallback > textureHudCallback = new WGENodeMaskCallback( m_showHud );
58 
59  // get available postprocessors and setup the node
61  for( WGEPostprocessor::ProcessorList::const_iterator iter = processors.begin(); iter != processors.end(); ++iter )
62  {
63  // offscreen node
64  osg::ref_ptr< WGEOffscreenRenderNode > offscreen( new WGEOffscreenRenderNode( reference, width, height, noHud ) );
65  offscreen->getTextureHUD()->addUpdateCallback( textureHudCallback );
66 
67  // the geometry render step
68  osg::ref_ptr< WGEOffscreenRenderPass > render = offscreen->addGeometryRenderPass(
69  m_childs,
70  "Rendered"
71  );
72 
73  // create G-Buffer
75 
76  // let the specific post processor build its pipeline
77  WGEPostprocessor::SPtr processor = ( *iter )->create( offscreen, buf );
78  m_postprocs.push_back( processor );
79 
80  // add the postprocessor's properties
81  m_properties->addProperty( processor->getProperties() );
82  processor->getProperties()->setHidden( true );
83 
84  // add it to the selection prop
85  m_possibleSelections->addItem( processor->getName(), processor->getDescription() );
86 
87  // the final step
88  osg::ref_ptr< WGEOffscreenFinalPass > output = offscreen->addFinalOnScreenPass( new WGEShader( "WGEPostprocessorCombiner" ),
89  "Output" );
90  output->bind( processor->getOutput(), 0 );
91 
92  // does this processor provide a depth?
93  osg::ref_ptr< osg::Texture2D > depthTex = processor->getDepth();
94  if( !depthTex )
95  {
96  depthTex = buf.m_depthTexture;
97  }
98  output->bind( depthTex, 1 );
99 
100  // add the offscreen renderer and the original node to the switch
101  addChild( offscreen );
102  }
103 
104  // let the props control some stuff
106 }
107 
109 {
110  // cleanup
111 }
112 
114 {
115  return m_properties;
116 }
117 
118 void WGEPostprocessingNode::insert( osg::ref_ptr< osg::Node > node, WGEShader::RefPtr shader )
119 {
120  // the shader needs an own preprocessor.
122  m_active, "WGE_POSTPROCESSING_DISABLED", "WGE_POSTPROCESSING_ENABLED" )
123  );
124 
125  // we need to inject some code to the shader at this point.
126  shader->addPreprocessor( preproc );
127 
128  // do it thread-safe as we promise to be thread-safe
130  // to keep track of which node is associated with which shader and preprocessor:
131  w->get()[ node ] = std::make_pair( shader, preproc );
132 
133  // insert node to group node of all children
134  m_childs->insert( node );
135 }
136 
137 void WGEPostprocessingNode::remove( osg::ref_ptr< osg::Node > node )
138 {
139  // do it thread-safe as we promise to be thread-safe
141 
142  // remove the item from our map
143  NodeShaderAssociation::Iterator item = w->get().find( node );
144 
145  if( item != w->get().end() )
146  {
147  // we need to remove the preprocessor from the shader.
148  ( *item ).second.first->removePreprocessor( ( *item ).second.second );
149  w->get().erase( item );
150  }
151 
152  // although we may not find the node in our association list, try to remove it
153  m_childs->remove( node );
154 }
155 
157 {
158  // do it thread-safe as we promise to be thread-safe
160 
161  // remove from node-shader association list
162  for( NodeShaderAssociation::Iterator iter = w->get().begin(); iter != w->get().end(); ++iter )
163  {
164  ( *iter ).second.first->removePreprocessor( ( *iter ).second.second );
165  }
166  w->get().clear();
167 
168  // remove the node from the render group
169  m_childs->clear();
170 }
171 
173 {
174  if( m_postprocs.size() == 0 )
175  {
176  m_active->set( false );
177  return;
178  }
179 
180  size_t active = m_activePostprocessor->get();
181 
182  // this triggers several shader preprocessors of all child nodes
183  m_active->set( active != 0 );
184 
185  // hide all, but not the active one
186  for( size_t i = 0; i < m_postprocs.size(); ++i )
187  {
188  m_postprocs[ i ]->getProperties()->setHidden( i != ( active - 1 ) );
189  }
190 }