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