OpenWalnut
1.2.5
|
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