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