OpenWalnut  1.5.0dev
WMSurfaceParameterAnimator.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 <memory>
26 #include <string>
27 #include <utility>
28 
29 #include <osg/Geode>
30 #include <osg/Group>
31 #include <osg/Material>
32 #include <osg/MatrixTransform>
33 #include <osg/Projection>
34 #include <osg/ShapeDrawable>
35 #include <osg/StateAttribute>
36 
37 #include "WMSurfaceParameterAnimator.h"
38 #include "WMSurfaceParameterAnimator.xpm"
39 #include "core/common/WBoundingBox.h"
40 #include "core/common/WColor.h"
41 #include "core/dataHandler/WDataTexture3D.h"
42 #include "core/graphicsEngine/WGEGeodeUtils.h"
43 #include "core/graphicsEngine/WGEUtils.h"
44 #include "core/graphicsEngine/callbacks/WGEShaderAnimationCallback.h"
45 #include "core/graphicsEngine/shaders/WGEShader.h"
46 #include "core/kernel/WKernel.h"
47 
48 // This line is needed by the module loader to actually find your module.
49 W_LOADABLE_MODULE( WMSurfaceParameterAnimator )
50 
52  WModule(),
53  m_rootNode( new WGEGroupNode() )
54 {
55  // Initialize members
56 }
57 
59 {
60  // Cleanup!
61 }
62 
63 std::shared_ptr< WModule > WMSurfaceParameterAnimator::factory() const
64 {
65  return std::shared_ptr< WModule >( new WMSurfaceParameterAnimator() );
66 }
67 
69 {
70  return WMSurfaceParameterAnimator_xpm;
71 }
72 
73 const std::string WMSurfaceParameterAnimator::getName() const
74 {
75  // Specify your module name here. This name must be UNIQUE!
76  return "Surface Parameter Animator";
77 }
78 
80 {
81  // Specify your module description here. Be detailed. This text is read by the user.
82  return "This module can show parameters defined on surfaces using various types of animation.";
83 }
84 
86 {
87  // needs one input: the scalar dataset
88  m_input = std::shared_ptr< WModuleInputData < WDataSetSingle > >(
89  new WModuleInputData< WDataSetSingle >( shared_from_this(), "in", "The scalar dataset shown whose surface gets used for animation." )
90  );
91 
92  // As properties, every connector needs to be added to the list of connectors.
94 
95  // and the fiber directions inside the volume
96  m_tracesInput = std::shared_ptr< WModuleInputData < WDataSetSingle > >(
97  new WModuleInputData< WDataSetSingle >( shared_from_this(), "traces", "The voxelized fiber traces for each voxel in the input \"in\"." )
98  );
99 
100  // As properties, every connector needs to be added to the list of connectors.
102 
103  // call WModules initialization
105 }
106 
108 {
109  // Initialize the properties
110  m_propCondition = std::shared_ptr< WCondition >( new WCondition() );
111 
112  m_isoValue = m_properties->addProperty( "Isovalue", "The Isovalue used whenever the Isosurface Mode is turned on.",
113  50 );
114  m_stepCount = m_properties->addProperty( "Step count", "The number of steps to walk along the ray during raycasting. A low value"
115  "may cause artifacts whilst a high value slows down rendering.", 250 );
116  m_stepCount->setMin( 1 );
117  m_stepCount->setMax( 1000 );
118 
119  m_alpha = m_properties->addProperty( "Opacity %", "The opacity in %. Transparency = 100 - Opacity.", 100 );
120 
121  m_isoColor = m_properties->addProperty( "Iso color", "The color to blend the isosurface with.", WColor( 0.0, 0.0, 0.0, 1.0 ),
122  m_propCondition );
123  m_saturation = m_properties->addProperty( "Saturation %", "The saturation in %.", 100 );
124  m_size1 = m_properties->addProperty( "Beam1 size", "The relative size of the first beam. A value of 0 gets mapped to the "
125  "smallest size, whilst 100 gets mapped to the largest. This is typically "
126  "one third of the size of the voxelized surface.", 10 );
127  m_size2 = m_properties->addProperty( "Beam2 size", "The relative size of the second beam. A value of 0 gets mapped to the "
128  "smallest size, whilst 100 gets mapped to the largest. This is typically "
129  "one third of the size of the voxelized surface.", 50 );
130  m_speed1 = m_properties->addProperty( "Beam1 speed", "The relative speed of the beam. This speed relates to the clock used.", 25 );
131  m_speed2 = m_properties->addProperty( "Beam2 speed", "The relative speed of the beam. This speed relates to the clock used.", 25 );
132  m_parameterScale = m_properties->addProperty( "Parameter scale", "Scaling the parameter space on the fly creates consistently sized and fast "
133  "beams over multiple WMSurfaceParameterAnimator instances.", 1.0 );
134 
136 }
137 
138 osg::ref_ptr< osg::Node > WMSurfaceParameterAnimator::renderSurface( const WBoundingBox& bbox )
139 {
140  // use the OSG Shapes, create unit cube
141  osg::ref_ptr< osg::Node > cube = wge::generateSolidBoundingBoxNode( bbox, m_isoColor->get( true ) );
142  cube->addUpdateCallback( new SafeUpdateCallback( this ) );
143  cube->asTransform()->getChild( 0 )->setName( "DVR Proxy Cube" ); // Be aware that this name is used in the pick handler.
144  m_shader->apply( cube );
145 
146  // bind the texture to the node
147  osg::StateSet* rootState = cube->getOrCreateStateSet();
148 
149  osg::ref_ptr< WGETexture3D > texture3D = m_dataSet->getTexture();
150  osg::ref_ptr< WGETexture3D > tracesTexture3D = m_tracesDataSet->getTexture();
151  texture3D->bind( cube, 0 );
152  tracesTexture3D->bind( cube, 1 );
153 
154  // enable transparency
155  rootState->setMode( GL_BLEND, osg::StateAttribute::ON );
156 
157  ////////////////////////////////////////////////////////////////////////////////////////////////////
158  // setup all those uniforms
159  ////////////////////////////////////////////////////////////////////////////////////////////////////
160 
161  osg::ref_ptr< osg::Uniform > isovalue = new osg::Uniform( "u_isovalue", static_cast< float >( m_isoValue->get() / 100.0 ) );
162  isovalue->setUpdateCallback( new SafeUniformCallback( this ) );
163 
164  osg::ref_ptr< osg::Uniform > steps = new osg::Uniform( "u_steps", m_stepCount->get() );
165  steps->setUpdateCallback( new SafeUniformCallback( this ) );
166 
167  osg::ref_ptr< osg::Uniform > alpha = new osg::Uniform( "u_alpha", static_cast< float >( m_alpha->get() / 100.0 ) );
168  alpha->setUpdateCallback( new SafeUniformCallback( this ) );
169 
170  osg::ref_ptr< osg::Uniform > animationTime = new osg::Uniform( "u_animationTime", 0 );
171  animationTime->setUpdateCallback( new WGEShaderAnimationCallback() );
172 
173  osg::ref_ptr< osg::Uniform > size1 = new osg::Uniform( "u_size1", 0 );
174  osg::ref_ptr< osg::Uniform > size2 = new osg::Uniform( "u_size2", 0 );
175  size1->setUpdateCallback( new SafeUniformCallback( this ) );
176  size2->setUpdateCallback( new SafeUniformCallback( this ) );
177 
178  osg::ref_ptr< osg::Uniform > speed1 = new osg::Uniform( "u_speed1", 0 );
179  osg::ref_ptr< osg::Uniform > speed2 = new osg::Uniform( "u_speed2", 0 );
180  speed1->setUpdateCallback( new SafeUniformCallback( this ) );
181  speed2->setUpdateCallback( new SafeUniformCallback( this ) );
182 
183  osg::ref_ptr< osg::Uniform > paramScale = new osg::Uniform( "u_parameterScale", 1.0f );
184  paramScale->setUpdateCallback( new SafeUniformCallback( this ) );
185 
186  osg::ref_ptr< osg::Uniform > saturation = new osg::Uniform( "u_saturation", 1.0f );
187  saturation->setUpdateCallback( new SafeUniformCallback( this ) );
188 
189  rootState->addUniform( isovalue );
190  rootState->addUniform( steps );
191  rootState->addUniform( alpha );
192  rootState->addUniform( animationTime );
193  rootState->addUniform( size1 );
194  rootState->addUniform( size2 );
195  rootState->addUniform( speed1 );
196  rootState->addUniform( speed2 );
197  rootState->addUniform( paramScale );
198  rootState->addUniform( saturation );
199 
200  return cube;
201 }
202 
204 {
205  m_shader = osg::ref_ptr< WGEShader > ( new WGEShader( "WMSurfaceParameterAnimator-Beams", m_localPath ) );
206 
207  // let the main loop awake if the data changes or the properties changed.
208  m_moduleState.setResetable( true, true );
209  m_moduleState.add( m_input->getDataChangedCondition() );
210  m_moduleState.add( m_tracesInput->getDataChangedCondition() );
212 
213  // Signal ready state.
214  ready();
215 
216  // add this module's group node
217  m_rootNode->setNodeMask( m_active->get() ? 0xFFFFFFFF : 0x0 );
218  WKernel::getRunningKernel()->getGraphicsEngine()->getScene()->insert( m_rootNode );
219 
220  // Now wait for data
221  while( !m_shutdownFlag() )
222  {
224 
225  // woke up since the module is requested to finish
226  if( m_shutdownFlag() )
227  {
228  break;
229  }
230 
231  // has the data changed?
232  std::shared_ptr< WDataSetSingle > newDataSet = m_input->getData();
233  std::shared_ptr< WDataSetSingle > newTracesDataSet = m_tracesInput->getData();
234 
235  bool dataChanged = ( m_dataSet != newDataSet ) || ( m_tracesDataSet != newTracesDataSet );
236  bool dataValid = ( newDataSet && newTracesDataSet );
237 
238  // valid data available?
239  if( !dataValid )
240  {
241  debugLog() << "Resetting.";
242 
243  // reset internal refs to data
244  m_dataSet.reset();
245  m_tracesDataSet.reset();
246 
247  // remove renderings
248  m_rootNode->clear();
249  }
250 
251  // As the data has changed, we need to recreate the texture.
252  if( dataChanged && dataValid )
253  {
254  m_dataSet = newDataSet;
255  m_tracesDataSet = newTracesDataSet;
256 
257  debugLog() << "Data changed. Uploading new data as texture.";
258 
259  // First, grab the grid
260  std::shared_ptr< WGridRegular3D > grid = std::dynamic_pointer_cast< WGridRegular3D >( m_dataSet->getGrid() );
261  if( !grid )
262  {
263  errorLog() << "The dataset does not provide a regular grid. Ignoring dataset.";
264  continue;
265  }
266 
267  // attach the geometry to the first FBO
268  osg::ref_ptr< osg::Node > cube = renderSurface( grid->getBoundingBox() );
269 
270  // **********************************************************************************************
271  // Update scene
272  // **********************************************************************************************
273 
274  // update node
275  debugLog() << "Adding new rendering.";
276  m_rootNode->clear();
277  m_rootNode->insert( cube );
278  }
279  }
280 
281  // At this point, the container managing this module signalled to shutdown. The main loop has ended and you should clean up. Always remove
282  // allocated memory and remove all OSG nodes.
283  WKernel::getRunningKernel()->getGraphicsEngine()->getScene()->remove( m_rootNode );
284 }
285 
286 void WMSurfaceParameterAnimator::SafeUpdateCallback::operator()( osg::Node* node, osg::NodeVisitor* nv )
287 {
288  // update material info
289  if( m_module->m_isoColor->changed() || m_initialUpdate )
290  {
291  // Set the diffuse color and material:
292  osg::ref_ptr< osg::Material > mat = new osg::Material();
293  mat->setDiffuse( osg::Material::FRONT, m_module->m_isoColor->get( true ) );
294  node->getOrCreateStateSet()->setAttribute( mat, osg::StateAttribute::ON );
295 
296  m_initialUpdate = false;
297  }
298 
299  traverse( node, nv );
300 }
301 
302 void WMSurfaceParameterAnimator::SafeUniformCallback::operator()( osg::Uniform* uniform, osg::NodeVisitor* /* nv */ )
303 {
304  // update some uniforms:
305  if( m_module->m_isoValue->changed() && ( uniform->getName() == "u_isovalue" ) )
306  {
307  uniform->set( static_cast< float >( m_module->m_isoValue->get( true ) ) / 100.0f );
308  }
309  if( m_module->m_stepCount->changed() && ( uniform->getName() == "u_steps" ) )
310  {
311  uniform->set( m_module->m_stepCount->get( true ) );
312  }
313  if( m_module->m_alpha->changed() && ( uniform->getName() == "u_alpha" ) )
314  {
315  uniform->set( static_cast< float >( m_module->m_alpha->get( true ) / 100.0 ) );
316  }
317  if( m_module->m_alpha->changed() && ( uniform->getName() == "u_size1" ) )
318  {
319  uniform->set( static_cast< float >( m_module->m_alpha->get( true ) / 100.0 ) );
320  }
321  if( m_module->m_size1->changed() && ( uniform->getName() == "u_size1" ) )
322  {
323  uniform->set( m_module->m_size1->get( true ) );
324  }
325  if( m_module->m_size2->changed() && ( uniform->getName() == "u_size2" ) )
326  {
327  uniform->set( m_module->m_size2->get( true ) );
328  }
329  if( m_module->m_speed1->changed() && ( uniform->getName() == "u_speed1" ) )
330  {
331  uniform->set( m_module->m_speed1->get( true ) );
332  }
333  if( m_module->m_speed2->changed() && ( uniform->getName() == "u_speed2" ) )
334  {
335  uniform->set( m_module->m_speed2->get( true ) );
336  }
337  if( m_module->m_parameterScale->changed() && ( uniform->getName() == "u_parameterScale" ) )
338  {
339  uniform->set( static_cast< float >( m_module->m_parameterScale->get( true ) ) );
340  }
341  if( m_module->m_saturation->changed() && ( uniform->getName() == "u_saturation" ) )
342  {
343  uniform->set( static_cast< float >( m_module->m_saturation->get( true ) ) / 100.0f );
344  }
345 }
346 
348 {
349  // Activate/Deactivate the rendering
350  if( m_rootNode )
351  {
352  if( m_active->get() )
353  {
354  m_rootNode->setNodeMask( 0xFFFFFFFF );
355  }
356  else
357  {
358  m_rootNode->setNodeMask( 0x0 );
359  }
360  }
361 
362  // Always call WModule's activate!
364 }
365 
virtual void wait() const
Wait for the condition.
void setResetable(bool resetable=true, bool autoReset=true)
Sets the resetable flag.
virtual void add(std::shared_ptr< WCondition > condition)
Adds another condition to the set of conditions to wait for.
Class to encapsulate boost::condition_variable_any.
Definition: WCondition.h:42
Class to wrap around the osg Group node and providing a thread safe add/removal mechanism.
Definition: WGEGroupNode.h:48
This is a uniform callback setting the uniform to the current time in milliseconds,...
Class encapsulating the OSG Program class for a more convenient way of adding and modifying shader.
Definition: WGEShader.h:48
static WKernel * getRunningKernel()
Returns pointer to the currently running kernel.
Definition: WKernel.cpp:117
std::shared_ptr< WGraphicsEngine > getGraphicsEngine() const
Returns pointer to currently running instance of graphics engine.
Definition: WKernel.cpp:122
Class handling uniform update during render traversal.
virtual void operator()(osg::Uniform *uniform, osg::NodeVisitor *nv)
The callback.
Node callback to change the color of the shapes inside the root node.
bool m_initialUpdate
Denotes whether the update callback is called the first time.
virtual void operator()(osg::Node *node, osg::NodeVisitor *nv)
operator () - called during the update traversal.
WMSurfaceParameterAnimator * m_module
Pointer used to access members of the module to modify the node.
This module is a ray-tracing based isosurface using special methods for animating particle flow on it...
WPropInt m_isoValue
The Isovalue used in the case m_isoSurface is true.
virtual const std::string getDescription() const
Gives back a description of this module.
WPropInt m_speed2
The speed of beam 2 on the surface.
std::shared_ptr< WCondition > m_propCondition
A condition used to notify about changes in several properties.
std::shared_ptr< WDataSetSingle > m_tracesDataSet
The dataset containing the fiber traces in each voxel in m_dataSet.
virtual ~WMSurfaceParameterAnimator()
Destructor.
WPropInt m_saturation
Saturation of final rendering.
std::shared_ptr< WModuleInputData< WDataSetSingle > > m_input
An input connector used to get datasets from other modules.
std::shared_ptr< WDataSetSingle > m_dataSet
This is a pointer to the dataset the module is currently working on.
WPropInt m_speed1
The speed of beam 1 on the surface.
WPropDouble m_parameterScale
Scaling the parameter space ensures consistent sizes and speeds along multiple WMSurfaceParameterAnim...
virtual const std::string getName() const
Gives back the name of this module.
WPropInt m_alpha
The alpha transparency used for the rendering.
WPropColor m_isoColor
The color used when in isosurface mode for blending.
osg::ref_ptr< osg::Node > renderSurface(const WBoundingBox &bbox)
Renders the surface to an FBO.
WPropInt m_size1
The size of beam 1.
WPropInt m_stepCount
The number of steps to walk along the ray.
WMSurfaceParameterAnimator()
Default constructor.
virtual void moduleMain()
Entry point after loading the module.
virtual void connectors()
Initialize the connectors this module is using.
virtual std::shared_ptr< WModule > factory() const
Due to the prototype design pattern used to build modules, this method returns a new instance of this...
osg::ref_ptr< WGEShader > m_shader
the DVR shader.
virtual const char ** getXPMIcon() const
Get the icon for this module in XPM format.
osg::ref_ptr< WGEGroupNode > m_rootNode
The root node used for this modules graphics.
WPropInt m_size2
The size of beam 1.
std::shared_ptr< WModuleInputData< WDataSetSingle > > m_tracesInput
The input for the volumized fiber traces.
virtual void properties()
Initialize the properties for this module.
virtual void activate()
Callback for m_active.
Class representing a single module of OpenWalnut.
Definition: WModule.h:72
boost::filesystem::path m_localPath
The path where the module binary resides in.
Definition: WModule.h:734
virtual void properties()
Initialize properties in this function.
Definition: WModule.cpp:212
wlog::WStreamedLogger debugLog() const
Logger instance for comfortable debug logging.
Definition: WModule.cpp:575
void addConnector(std::shared_ptr< WModuleInputConnector > con)
Adds the specified connector to the list of inputs.
Definition: WModule.cpp:108
std::shared_ptr< WProperties > m_properties
The property object for the module.
Definition: WModule.h:640
void ready()
Call this whenever your module is ready and can react on property changes.
Definition: WModule.cpp:505
WConditionSet m_moduleState
The internal state of the module.
Definition: WModule.h:703
wlog::WStreamedLogger errorLog() const
Logger instance for comfortable error logging.
Definition: WModule.cpp:570
virtual void activate()
Callback for m_active.
Definition: WModule.cpp:220
WPropBool m_active
True whenever the module should be active.
Definition: WModule.h:723
virtual void connectors()
Initialize connectors in this function.
Definition: WModule.cpp:208
WBoolFlag m_shutdownFlag
Condition getting fired whenever the thread should quit.
osg::ref_ptr< osg::Node > generateSolidBoundingBoxNode(const WBoundingBox &bb, const WColor &color, bool threeDTexCoords=true)
Generates an OSG node for the specified bounding box.