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