OpenWalnut  1.2.5
 All Classes Namespaces Functions Variables Typedefs Enumerations Enumerator Friends Groups Pages
WGEColormapping.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 <algorithm>
26 #include <iostream>
27 #include <sstream>
28 #include <string>
29 
30 #include "../common/WLogger.h"
31 #include "WGETextureUtils.h"
32 #include "exceptions/WGESignalSubscriptionFailed.h"
33 
34 #include "WGEColormapping.h"
35 
36 // instance as singleton
37 boost::shared_ptr< WGEColormapping > WGEColormapping::m_instance = boost::shared_ptr< WGEColormapping >();
38 
39 /**
40  * This functions simply sets some defines to a shader. It sets the texture unit and gl_MultiTexCoord variable names properly.
41  *
42  * \param shader the shader where to add the defines
43  * \param start the start index of the unit for colormap0
44  */
45 void setDefines( osg::ref_ptr< WGEShader > shader, size_t start = 0 )
46 {
47  // simply set some proper defines for each colormap -> the unit and multitex coords
48  for( size_t unit = 0; unit < wge::getMaxTexUnits(); ++unit )
49  {
50  // disable textures with invalid unit numbers
51  if( unit < wge::getMaxTexUnits() - start )
52  {
53  shader->setDefine( "Colormap" + boost::lexical_cast< std::string >( unit ) + "Enabled", true );
54  shader->setDefine( "Colormap" + boost::lexical_cast< std::string >( unit ) + "Unit", start + unit );
55  }
56  }
57 }
58 
59 /**
60  * This functions simply sets the specified pre transformation matrix to the shader. It therefore uses a preprocessor define. This allows a
61  * hard-coded matrix to be optimized be the shader compiler.
62  *
63  * \param shader the shader where to add the defines
64  * \param preTransform the transformation matrix used to pre-multiply with all texture coordinates
65  */
66 void setPreTransform( osg::ref_ptr< WGEShader > shader, osg::Matrixd preTransform )
67 {
68  std::ostringstream out;
69  out << "mat4( ";
70  const osg::Matrixd::value_type* m = preTransform.ptr();
71 
72  out.precision( 10 );
73  out.setf( std::ios::fixed, std::ios::floatfield );
74 
75  // print all 16 values
76  for( size_t i = 0; i < 15; ++i )
77  {
78  out << m[ i ] << ", ";
79  }
80  out << m[ 15 ] << " )";
81 
82  // set as define
83  shader->setDefine( "ColormapPreTransform", out.str() );
84 }
85 
87  m_callback( new WGEFunctorCallback< osg::Node >( boost::bind( &WGEColormapping::callback, this, _1 ) ) )
88 {
89  // initialize members
90  m_textures.getChangeCondition()->subscribeSignal( boost::bind( &WGEColormapping::textureUpdate, this ) );
91  m_boundingBox.getWriteTicket()->get().set( 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 );
92 }
93 
95 {
96  // cleanup
97 }
98 
99 boost::shared_ptr< WGEColormapping > WGEColormapping::instance()
100 {
101  if( !m_instance )
102  {
103  m_instance = boost::shared_ptr< WGEColormapping >( new WGEColormapping() );
104  }
105 
106  return m_instance;
107 }
108 
109 void WGEColormapping::apply( osg::ref_ptr< osg::Node > node, osg::ref_ptr< WGEShader > shader, size_t startTexUnit )
110 {
111  instance()->applyInst( NodeList( 1, node ), WMatrix4d( WMatrix4d::identity() ), shader, startTexUnit );
112 }
113 
114 void WGEColormapping::apply( osg::ref_ptr< osg::Node > node, WMatrix4d preTransform, osg::ref_ptr< WGEShader > shader,
115  size_t startTexUnit )
116 {
117  instance()->applyInst( NodeList( 1, node ), preTransform, shader, startTexUnit );
118 }
119 
120 void WGEColormapping::apply( NodeList nodes, WMatrix4d preTransform, osg::ref_ptr< WGEShader > shader, size_t startTexUnit )
121 {
122  instance()->applyInst( nodes, preTransform, shader, startTexUnit );
123 }
124 
125 void WGEColormapping::apply( NodeList nodes, osg::ref_ptr< WGEShader > shader, size_t startTexUnit )
126 {
127  instance()->applyInst( nodes, WMatrix4d( WMatrix4d::identity() ), shader, startTexUnit );
128 }
129 
130 void WGEColormapping::registerTexture( osg::ref_ptr< WGETexture3D > texture, std::string name )
131 {
132  instance()->registerTextureInst( texture, name );
133 }
134 
135 void WGEColormapping::deregisterTexture( osg::ref_ptr< WGETexture3D > texture )
136 {
137  instance()->deregisterTextureInst( texture );
138 }
139 
140 void WGEColormapping::replaceTexture( osg::ref_ptr< WGETexture3D > old, osg::ref_ptr< WGETexture3D > newTex, std::string name )
141 {
142  instance()->replaceTextureInst( old, newTex, name );
143 }
144 
145 void WGEColormapping::applyInst( NodeList nodes, WMatrix4d preTransform, osg::ref_ptr< WGEShader > shader,
146  size_t startTexUnit )
147 {
148  // init shader
149  osg::ref_ptr< WGEShader > s = shader;
150  if( !s )
151  {
152  // we use a new instance of the default shader here because the preTransform is varying between several nodes.
153  s = new WGEShader( "WGEDefaultColormapper" );
154  }
155  setDefines( s, startTexUnit );
156  setPreTransform( s, preTransform );
157 
158  // do this for each node
159  for( NodeList::const_iterator i = nodes.begin(); i != nodes.end(); ++i )
160  {
161  // applying to a node simply means adding a callback :-)
162  NodeInfo* info = new NodeInfo;
163  info->m_rebind = true;
164  info->m_texUnitStart = startTexUnit;
165  info->m_preTransform = preTransform;
166  m_nodeInfo.insert( std::make_pair( *i, info ) );
167 
168  ( *i )->addUpdateCallback( m_callback );
169 
170  // add the default shader if no other shader has been specified.
171  s->apply( *i );
172  }
173 }
174 
175 void WGEColormapping::registerTextureInst( osg::ref_ptr< WGETexture3D > texture, std::string name )
176 {
177  wlog::debug( "WGEColormapping" ) << "Registering texture.";
178  if( !m_textures.count( texture ) )
179  {
180  if( !name.empty() )
181  {
182  texture->name()->set( name );
183  }
184  m_textures.push_front( texture );
185  updateBounds();
186  m_registerSignal( texture );
187  }
188 }
189 
190 void WGEColormapping::deregisterTextureInst( osg::ref_ptr< WGETexture3D > texture )
191 {
192  wlog::debug( "WGEColormapping" ) << "De-registering texture.";
193  if( m_textures.count( texture ) )
194  {
195  m_textures.remove( texture );
196  updateBounds();
197  m_deregisterSignal( texture );
198  }
199 }
200 
201 void WGEColormapping::replaceTextureInst( osg::ref_ptr< WGETexture3D > old, osg::ref_ptr< WGETexture3D > newTex, std::string name )
202 {
203  wlog::debug( "WGEColormapping" ) << "Replacing texture.";
204  if( !name.empty() )
205  {
206  newTex->name()->set( name );
207  }
208 
209  // if it exists, replace it
210  if( m_textures.count( old ) )
211  {
212  m_textures.replace( old, newTex );
213  updateBounds();
214  m_replaceSignal( old, newTex );
215  }
216  else // <- if not exists: add
217  {
218  registerTextureInst( newTex, name );
219  }
220 }
221 
223 {
226 
227  bool first = true;
228  for( TextureContainerType::ConstIterator iter = r->get().begin(); iter != r->get().end(); ++iter )
229  {
230  if( first )
231  {
232  bbw->get() = ( *iter )->getBoundingBox();
233  first = false;
234  }
235  else
236  {
237  bbw->get().expandBy( ( *iter )->getBoundingBox() );
238  }
239  }
240 }
241 
243 {
244  return m_boundingBox.getReadTicket()->get();
245 }
246 
248 {
250  for( NodeInfoContainerType::Iterator iter = w->get().begin(); iter != w->get().end(); ++iter )
251  {
252  iter->second->m_rebind = true;
253  }
254 }
255 
256 void WGEColormapping::callback( osg::Node* node )
257 {
258  // get node info
260  NodeInfoContainerType::ConstIterator infoItem = r->get().find( node );
261  if( infoItem == r->get().end() )
262  {
263  return;
264  }
265  r.reset();
266 
267  NodeInfo* info = infoItem->second;
268 
269  // need (re-)binding?
270  if( info->m_rebind )
271  {
272  info->m_rebind = false;
273 
274  size_t maxTexUnits = wge::getMaxTexUnits();
275  wge::unbindTexture( node, info->m_texUnitStart, maxTexUnits - info->m_texUnitStart );
276 
278 
279  // bind each texture, provide all needed uniforms too
280  size_t unit = info->m_texUnitStart;
281  for( TextureContainerType::ConstIterator iter = rt->get().begin();
282  ( unit < maxTexUnits ) && ( iter != rt->get().end() );
283  ++iter )
284  {
285  wge::bindTexture( node, *iter, unit, "u_colormap" + boost::lexical_cast< std::string >( unit - info->m_texUnitStart ) );
286  unit++;
287  }
288 
289  rt.reset();
290  }
291 }
292 
293 bool WGEColormapping::moveDown( osg::ref_ptr< WGETexture3D > texture )
294 {
296 
297  // does the texture exist?
298  TextureContainerType::Iterator iter = std::find( w->get().begin(), w->get().end(), texture );
299  if( iter == w->get().end() )
300  {
301  return false;
302  }
303 
304  // is it already the last item?
305  if( iter + 1 == w->get().end() )
306  {
307  return false;
308  }
309 
310  // swap items
311  std::iter_swap( iter, iter + 1 );
312 
313  // unlock and call callbacks
314  w.reset();
315  m_sortSignal();
316 
317  return true;
318 }
319 
320 bool WGEColormapping::moveUp( osg::ref_ptr< WGETexture3D > texture )
321 {
323 
324  // does the texture exist?
325  TextureContainerType::Iterator iter = std::find( w->get().begin(), w->get().end(), texture );
326  if( iter == w->get().end() )
327  {
328  return false;
329  }
330 
331  // is it already the first item?
332  if( iter == w->get().begin() )
333  {
334  return false;
335  }
336 
337  // swap items
338  std::iter_swap( iter, iter - 1 );
339 
340  // unlock and call callbacks
341  w.reset();
342  m_sortSignal();
343 
344  return true;
345 }
346 
347 size_t WGEColormapping::size() const
348 {
349  return m_textures.size();
350 }
351 
352 boost::signals2::connection WGEColormapping::subscribeSignal( TextureListSignal signal, TextureRegisterHandler notifier )
353 {
354  switch( signal )
355  {
356  case Registered:
357  return m_registerSignal.connect( notifier );
358  case Deregistered:
359  return m_deregisterSignal.connect( notifier );
360  default:
361  throw new WGESignalSubscriptionFailed( std::string( "Could not register TextureRegisterHandler to sort signal." ) );
362  }
363 }
364 
365 boost::signals2::connection WGEColormapping::subscribeSignal( TextureListSignal signal, TextureReplaceHandler notifier )
366 {
367  switch( signal )
368  {
369  case Replaced:
370  return m_replaceSignal.connect( notifier );
371  default:
372  throw new WGESignalSubscriptionFailed( std::string( "Could not register TextureReplaceHandler to signal." ) );
373  }
374 }
375 
376 boost::signals2::connection WGEColormapping::subscribeSignal( TextureListSignal signal, TextureSortHandler notifier )
377 {
378  switch( signal )
379  {
380  case Sorted:
381  return m_sortSignal.connect( notifier );
382  default:
383  throw new WGESignalSubscriptionFailed( std::string( "Could not register TextureSortHandler to register/deregister signal." ) );
384  }
385 }
386 
388 {
389  return m_textures.getReadTicket();
390 }
391 
393 {
395 }
396