WGEColormapping.cpp

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 <algorithm>
00026 #include <iostream>
00027 #include <sstream>
00028 #include <string>
00029 
00030 #include "../common/WLogger.h"
00031 #include "WGETextureUtils.h"
00032 #include "exceptions/WGESignalSubscriptionFailed.h"
00033 
00034 #include "WGEColormapping.h"
00035 
00036 // instance as singleton
00037 boost::shared_ptr< WGEColormapping > WGEColormapping::m_instance = boost::shared_ptr< WGEColormapping >();
00038 
00039 /**
00040  * This functions simply sets some defines to a shader. It sets the texture unit and gl_MultiTexCoord variable names properly.
00041  *
00042  * \param shader the shader where to add the defines
00043  * \param start the start index of the unit for colormap0
00044  */
00045 void setDefines( osg::ref_ptr< WGEShader > shader, size_t start = 0 )
00046 {
00047     // simply set some proper defines for each colormap -> the unit and multitex coords
00048     for( size_t unit = 0; unit < wge::getMaxTexUnits(); ++unit )
00049     {
00050         // disable textures with invalid unit numbers
00051         if( unit < wge::getMaxTexUnits() - start )
00052         {
00053             shader->setDefine( "Colormap" + boost::lexical_cast< std::string >( unit ) + "Enabled", true );
00054             shader->setDefine( "Colormap" + boost::lexical_cast< std::string >( unit ) + "Unit", start + unit );
00055         }
00056     }
00057 }
00058 
00059 /**
00060  * This functions simply sets the specified pre transformation matrix to the shader. It therefore uses a preprocessor define. This allows a
00061  * hard-coded matrix to be optimized be the shader compiler.
00062  *
00063  * \param shader the shader where to add the defines
00064  * \param preTransform the transformation matrix used to pre-multiply with all texture coordinates
00065  */
00066 void setPreTransform( osg::ref_ptr< WGEShader > shader, osg::Matrixd preTransform )
00067 {
00068     std::ostringstream out;
00069     out << "mat4( ";
00070     const osg::Matrixd::value_type* m = preTransform.ptr();
00071 
00072     out.precision( 10 );
00073     out.setf( std::ios::fixed, std::ios::floatfield );
00074 
00075     // print all 16 values
00076     for( size_t i = 0; i < 15; ++i )
00077     {
00078         out << m[ i ] << ", ";
00079     }
00080     out << m[ 15 ] << " )";
00081 
00082     // set as define
00083     shader->setDefine( "ColormapPreTransform", out.str() );
00084 }
00085 
00086 WGEColormapping::WGEColormapping():
00087     m_callback( new WGEFunctorCallback< osg::Node >( boost::bind( &WGEColormapping::callback, this, _1 ) ) )
00088 {
00089     // initialize members
00090     m_textures.getChangeCondition()->subscribeSignal( boost::bind( &WGEColormapping::textureUpdate, this ) );
00091     m_boundingBox.getWriteTicket()->get().set( 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 );
00092 }
00093 
00094 WGEColormapping::~WGEColormapping()
00095 {
00096     // cleanup
00097 }
00098 
00099 boost::shared_ptr< WGEColormapping > WGEColormapping::instance()
00100 {
00101     if( !m_instance )
00102     {
00103         m_instance = boost::shared_ptr< WGEColormapping >( new WGEColormapping() );
00104     }
00105 
00106     return m_instance;
00107 }
00108 
00109 void WGEColormapping::apply( osg::ref_ptr< osg::Node > node, osg::ref_ptr< WGEShader > shader, size_t startTexUnit )
00110 {
00111     instance()->applyInst( NodeList( 1, node ), WMatrix4d( WMatrix4d::identity() ), shader, startTexUnit );
00112 }
00113 
00114 void WGEColormapping::apply( osg::ref_ptr< osg::Node > node, WMatrix4d preTransform, osg::ref_ptr< WGEShader > shader,
00115                              size_t startTexUnit )
00116 {
00117     instance()->applyInst( NodeList( 1, node ), preTransform, shader, startTexUnit );
00118 }
00119 
00120 void WGEColormapping::apply( NodeList nodes, WMatrix4d preTransform, osg::ref_ptr< WGEShader > shader, size_t startTexUnit )
00121 {
00122     instance()->applyInst( nodes, preTransform, shader, startTexUnit );
00123 }
00124 
00125 void WGEColormapping::apply( NodeList nodes, osg::ref_ptr< WGEShader > shader, size_t startTexUnit )
00126 {
00127     instance()->applyInst( nodes, WMatrix4d( WMatrix4d::identity() ), shader, startTexUnit );
00128 }
00129 
00130 void WGEColormapping::registerTexture( osg::ref_ptr< WGETexture3D > texture, std::string name )
00131 {
00132     instance()->registerTextureInst( texture, name );
00133 }
00134 
00135 void WGEColormapping::deregisterTexture( osg::ref_ptr< WGETexture3D > texture )
00136 {
00137     instance()->deregisterTextureInst( texture );
00138 }
00139 
00140 void WGEColormapping::replaceTexture( osg::ref_ptr< WGETexture3D > old, osg::ref_ptr< WGETexture3D > newTex, std::string name )
00141 {
00142     instance()->replaceTextureInst( old, newTex, name );
00143 }
00144 
00145 void WGEColormapping::applyInst( NodeList nodes, WMatrix4d preTransform, osg::ref_ptr< WGEShader > shader,
00146                                  size_t startTexUnit )
00147 {
00148     // init shader
00149     osg::ref_ptr< WGEShader > s = shader;
00150     if( !s )
00151     {
00152         // we use a new instance of the default shader here because the preTransform is varying between several nodes.
00153         s = new WGEShader( "WGEDefaultColormapper" );
00154     }
00155     setDefines( s, startTexUnit );
00156     setPreTransform( s, preTransform );
00157 
00158     // do this for each node
00159     for( NodeList::const_iterator i = nodes.begin(); i != nodes.end(); ++i )
00160     {
00161         // applying to a node simply means adding a callback :-)
00162         NodeInfo* info = new NodeInfo;
00163         info->m_rebind = true;
00164         info->m_texUnitStart = startTexUnit;
00165         info->m_preTransform = preTransform;
00166         m_nodeInfo.insert( std::make_pair( *i, info ) );
00167 
00168         ( *i )->addUpdateCallback( m_callback );
00169 
00170         // add the default shader if no other shader has been specified.
00171         s->apply( *i );
00172     }
00173 }
00174 
00175 void WGEColormapping::registerTextureInst( osg::ref_ptr< WGETexture3D > texture, std::string name )
00176 {
00177     wlog::debug( "WGEColormapping" ) << "Registering texture.";
00178     if( !m_textures.count( texture ) )
00179     {
00180         if( !name.empty() )
00181         {
00182             texture->name()->set( name );
00183         }
00184         m_textures.push_front( texture );
00185         updateBounds();
00186         m_registerSignal( texture );
00187     }
00188 }
00189 
00190 void WGEColormapping::deregisterTextureInst( osg::ref_ptr< WGETexture3D > texture )
00191 {
00192     wlog::debug( "WGEColormapping" ) << "De-registering texture.";
00193     if( m_textures.count( texture ) )
00194     {
00195         m_textures.remove( texture );
00196         updateBounds();
00197         m_deregisterSignal( texture );
00198     }
00199 }
00200 
00201 void WGEColormapping::replaceTextureInst( osg::ref_ptr< WGETexture3D > old, osg::ref_ptr< WGETexture3D > newTex, std::string name )
00202 {
00203     wlog::debug( "WGEColormapping" ) << "Replacing texture.";
00204     if( !name.empty() )
00205     {
00206         newTex->name()->set( name );
00207     }
00208 
00209     // if it exists, replace it
00210     if( m_textures.count( old ) )
00211     {
00212         m_textures.replace( old, newTex );
00213         updateBounds();
00214         m_replaceSignal( old, newTex );
00215     }
00216     else    // <- if not exists: add
00217     {
00218         registerTextureInst( newTex, name );
00219     }
00220 }
00221 
00222 void WGEColormapping::updateBounds()
00223 {
00224     TextureContainerType::ReadTicket r = m_textures.getReadTicket();
00225     WSharedObject< WBoundingBox >::WriteTicket bbw = m_boundingBox.getWriteTicket();
00226 
00227     bool first = true;
00228     for( TextureContainerType::ConstIterator iter = r->get().begin(); iter != r->get().end(); ++iter )
00229     {
00230         if( first )
00231         {
00232             bbw->get() = ( *iter )->getBoundingBox();
00233             first = false;
00234         }
00235         else
00236         {
00237             bbw->get().expandBy( ( *iter )->getBoundingBox() );
00238         }
00239     }
00240 }
00241 
00242 WBoundingBox WGEColormapping::getBoundingBox() const
00243 {
00244     return m_boundingBox.getReadTicket()->get();
00245 }
00246 
00247 void WGEColormapping::textureUpdate()
00248 {
00249     NodeInfoContainerType::WriteTicket w = m_nodeInfo.getWriteTicket();
00250     for( NodeInfoContainerType::Iterator iter = w->get().begin(); iter != w->get().end(); ++iter )
00251     {
00252         iter->second->m_rebind = true;
00253     }
00254 }
00255 
00256 void WGEColormapping::callback( osg::Node* node )
00257 {
00258     // get node info
00259     NodeInfoContainerType::ReadTicket r = m_nodeInfo.getReadTicket();
00260     NodeInfoContainerType::ConstIterator infoItem = r->get().find( node );
00261     if( infoItem == r->get().end() )
00262     {
00263         return;
00264     }
00265     r.reset();
00266 
00267     NodeInfo* info = infoItem->second;
00268 
00269     // need (re-)binding?
00270     if( info->m_rebind )
00271     {
00272         info->m_rebind = false;
00273 
00274         size_t maxTexUnits = wge::getMaxTexUnits();
00275         wge::unbindTexture( node, info->m_texUnitStart, maxTexUnits - info->m_texUnitStart );
00276 
00277         TextureContainerType::ReadTicket rt = m_textures.getReadTicket();
00278 
00279         // bind each texture, provide all needed uniforms too
00280         size_t unit = info->m_texUnitStart;
00281         for( TextureContainerType::ConstIterator iter = rt->get().begin();
00282              ( unit < maxTexUnits ) && ( iter != rt->get().end() );
00283              ++iter )
00284         {
00285             wge::bindTexture( node, *iter, unit, "u_colormap" + boost::lexical_cast< std::string >( unit - info->m_texUnitStart ) );
00286             unit++;
00287         }
00288 
00289         rt.reset();
00290     }
00291 }
00292 
00293 bool WGEColormapping::moveDown( osg::ref_ptr< WGETexture3D > texture )
00294 {
00295     TextureContainerType::WriteTicket w = m_textures.getWriteTicket();
00296 
00297     // does the texture exist?
00298     TextureContainerType::Iterator iter = std::find( w->get().begin(), w->get().end(), texture );
00299     if( iter == w->get().end() )
00300     {
00301         return false;
00302     }
00303 
00304     // is it already the last item?
00305     if( iter + 1 == w->get().end() )
00306     {
00307         return false;
00308     }
00309 
00310     // swap items
00311     std::iter_swap( iter, iter + 1 );
00312 
00313     // unlock and call callbacks
00314     w.reset();
00315     m_sortSignal();
00316 
00317     return true;
00318 }
00319 
00320 bool WGEColormapping::moveUp( osg::ref_ptr< WGETexture3D > texture )
00321 {
00322     TextureContainerType::WriteTicket w = m_textures.getWriteTicket();
00323 
00324     // does the texture exist?
00325     TextureContainerType::Iterator iter = std::find( w->get().begin(), w->get().end(), texture );
00326     if( iter == w->get().end() )
00327     {
00328         return false;
00329     }
00330 
00331     // is it already the first item?
00332     if( iter == w->get().begin() )
00333     {
00334         return false;
00335     }
00336 
00337     // swap items
00338     std::iter_swap( iter, iter - 1 );
00339 
00340     // unlock and call callbacks
00341     w.reset();
00342     m_sortSignal();
00343 
00344     return true;
00345 }
00346 
00347 size_t WGEColormapping::size() const
00348 {
00349     return m_textures.size();
00350 }
00351 
00352 boost::signals2::connection WGEColormapping::subscribeSignal( TextureListSignal signal, TextureRegisterHandler notifier )
00353 {
00354     switch( signal )
00355     {
00356         case Registered:
00357             return m_registerSignal.connect( notifier );
00358         case Deregistered:
00359             return m_deregisterSignal.connect( notifier );
00360         default:
00361             throw new WGESignalSubscriptionFailed( std::string( "Could not register TextureRegisterHandler to sort signal." ) );
00362     }
00363 }
00364 
00365 boost::signals2::connection WGEColormapping::subscribeSignal( TextureListSignal signal, TextureReplaceHandler notifier )
00366 {
00367     switch( signal )
00368     {
00369         case Replaced:
00370             return m_replaceSignal.connect( notifier );
00371         default:
00372             throw new WGESignalSubscriptionFailed( std::string( "Could not register TextureReplaceHandler to signal." ) );
00373     }
00374 }
00375 
00376 boost::signals2::connection WGEColormapping::subscribeSignal( TextureListSignal signal, TextureSortHandler notifier )
00377 {
00378     switch( signal )
00379     {
00380         case Sorted:
00381             return m_sortSignal.connect( notifier );
00382         default:
00383             throw new WGESignalSubscriptionFailed( std::string( "Could not register TextureSortHandler to register/deregister signal." ) );
00384     }
00385 }
00386 
00387 WGEColormapping::TextureContainerType::ReadTicket WGEColormapping::getReadTicket()
00388 {
00389     return m_textures.getReadTicket();
00390 }
00391 
00392 WCondition::SPtr WGEColormapping::getChangeCondition() const
00393 {
00394     return m_textures.getChangeCondition();
00395 }
00396 
 All Classes Namespaces Functions Variables Typedefs Enumerations Enumerator Friends