OpenWalnut
1.4.0
|
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 \"" << name << "\"."; 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 \"" << texture->name()->get() << "\"."; 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 /** 00258 * Custom comparator which uses a textures sortIndex for comparing. 00259 * 00260 * \param a first element 00261 * \param b second element 00262 * 00263 * \return true if a's sortIndex is smaller than b's. 00264 */ 00265 bool sortIndexComparator( osg::ref_ptr< WGETexture3D > a, osg::ref_ptr< WGETexture3D > b ) 00266 { 00267 return ( a->sortIndex()->get() < b->sortIndex()->get() ); 00268 } 00269 00270 void WGEColormapping::sortByIndex() 00271 { 00272 // use sort with custom comparator 00273 stableSort( &sortIndexComparator ); 00274 } 00275 00276 void WGEColormapping::setSortIndices() 00277 { 00278 TextureContainerType::ReadTicket r = m_textures.getReadTicket(); 00279 size_t index = 0; 00280 for( TextureContainerType::ConstIterator iter = r->get().begin(); iter != r->get().end(); ++iter ) 00281 { 00282 ( *iter )->sortIndex()->set( index ); 00283 index++; 00284 } 00285 } 00286 00287 void WGEColormapping::resetSortIndices() 00288 { 00289 TextureContainerType::ReadTicket r = m_textures.getReadTicket(); 00290 for( TextureContainerType::ConstIterator iter = r->get().begin(); iter != r->get().end(); ++iter ) 00291 { 00292 ( *iter )->sortIndex()->set( WGETexture3D::getUnsetSortIndex() ); 00293 } 00294 } 00295 00296 void WGEColormapping::callback( osg::Node* node ) 00297 { 00298 // get node info 00299 NodeInfoContainerType::ReadTicket r = m_nodeInfo.getReadTicket(); 00300 NodeInfoContainerType::ConstIterator infoItem = r->get().find( node ); 00301 if( infoItem == r->get().end() ) 00302 { 00303 return; 00304 } 00305 r.reset(); 00306 00307 NodeInfo* info = infoItem->second; 00308 00309 // need (re-)binding? 00310 if( info->m_rebind ) 00311 { 00312 info->m_rebind = false; 00313 00314 size_t maxTexUnits = wge::getMaxTexUnits(); 00315 wge::unbindTexture( node, info->m_texUnitStart, maxTexUnits - info->m_texUnitStart ); 00316 00317 TextureContainerType::ReadTicket rt = m_textures.getReadTicket(); 00318 00319 // bind each texture, provide all needed uniforms too 00320 size_t unit = info->m_texUnitStart; 00321 for( TextureContainerType::ConstIterator iter = rt->get().begin(); 00322 ( unit < maxTexUnits ) && ( iter != rt->get().end() ); 00323 ++iter ) 00324 { 00325 wge::bindTexture( node, *iter, unit, "u_colormap" + string_utils::toString( unit - info->m_texUnitStart ) ); 00326 unit++; 00327 } 00328 00329 rt.reset(); 00330 } 00331 } 00332 00333 bool WGEColormapping::moveDown( osg::ref_ptr< WGETexture3D > texture ) 00334 { 00335 TextureContainerType::WriteTicket w = m_textures.getWriteTicket(); 00336 00337 // does the texture exist? 00338 TextureContainerType::Iterator iter = std::find( w->get().begin(), w->get().end(), texture ); 00339 if( iter == w->get().end() ) 00340 { 00341 return false; 00342 } 00343 00344 // is it already the last item? 00345 if( iter + 1 == w->get().end() ) 00346 { 00347 return false; 00348 } 00349 00350 // swap items 00351 std::iter_swap( iter, iter + 1 ); 00352 00353 // unlock and call callbacks 00354 w.reset(); 00355 m_sortSignal(); 00356 00357 return true; 00358 } 00359 00360 bool WGEColormapping::moveUp( osg::ref_ptr< WGETexture3D > texture ) 00361 { 00362 TextureContainerType::WriteTicket w = m_textures.getWriteTicket(); 00363 00364 // does the texture exist? 00365 TextureContainerType::Iterator iter = std::find( w->get().begin(), w->get().end(), texture ); 00366 if( iter == w->get().end() ) 00367 { 00368 return false; 00369 } 00370 00371 // is it already the first item? 00372 if( iter == w->get().begin() ) 00373 { 00374 return false; 00375 } 00376 00377 // swap items 00378 std::iter_swap( iter, iter - 1 ); 00379 00380 // unlock and call callbacks 00381 w.reset(); 00382 m_sortSignal(); 00383 00384 return true; 00385 } 00386 00387 bool WGEColormapping::moveToTop( osg::ref_ptr< WGETexture3D > texture ) 00388 { 00389 TextureContainerType::WriteTicket w = m_textures.getWriteTicket(); 00390 00391 // does the texture exist? 00392 TextureContainerType::Iterator iter = std::find( w->get().begin(), w->get().end(), texture ); 00393 if( iter == w->get().end() ) 00394 { 00395 return false; 00396 } 00397 00398 // is it already the first item? 00399 if( iter == w->get().begin() ) 00400 { 00401 return false; 00402 } 00403 00404 // do the op 00405 w->get().erase( iter ); 00406 w->get().insert( w->get().begin(), texture ); 00407 00408 // unlock and call callbacks 00409 w.reset(); 00410 m_sortSignal(); 00411 00412 return true; 00413 } 00414 00415 bool WGEColormapping::moveToBottom( osg::ref_ptr< WGETexture3D > texture ) 00416 { 00417 TextureContainerType::WriteTicket w = m_textures.getWriteTicket(); 00418 00419 // does the texture exist? 00420 TextureContainerType::Iterator iter = std::find( w->get().begin(), w->get().end(), texture ); 00421 if( iter == w->get().end() ) 00422 { 00423 return false; 00424 } 00425 00426 // is it already the last item? 00427 if( iter + 1 == w->get().end() ) 00428 { 00429 return false; 00430 } 00431 00432 // do the op 00433 w->get().erase( iter ); 00434 w->get().push_back( texture ); 00435 00436 // unlock and call callbacks 00437 w.reset(); 00438 m_sortSignal(); 00439 00440 return true; 00441 } 00442 00443 bool WGEColormapping::moveTo( osg::ref_ptr< WGETexture3D > texture, size_t idx ) 00444 { 00445 TextureContainerType::WriteTicket w = m_textures.getWriteTicket(); 00446 00447 // does the texture exist? 00448 TextureContainerType::Iterator iter = std::find( w->get().begin(), w->get().end(), texture ); 00449 if( iter == w->get().end() ) 00450 { 00451 return false; 00452 } 00453 00454 // valid index? 00455 // NOTE: we accept index == size as the end iterator. 00456 if( idx > w->get().size() ) 00457 { 00458 return false; 00459 } 00460 00461 // is it already there? 00462 if( iter == ( w->get().begin() + idx ) ) 00463 { 00464 return false; 00465 } 00466 00467 // after inserting the item somewhere, the index of the original item might change 00468 size_t eraseIdx = iter - w->get().begin(); // item is inserted behind the current one -> index of the original item stays the same 00469 size_t eraseShift = 0; 00470 // if the inserted element is in front of the old one, the old one's index is increasing 00471 if( ( w->get().begin() + idx ) < iter ) 00472 { 00473 eraseShift++; 00474 } 00475 00476 // do the op 00477 // NOTE: this is not the best way to do it. Manually moving items should be better. But as the colormapper has to handle only a small number 00478 // of elements, this is not critical. 00479 w->get().insert( w->get().begin() + idx, texture ); 00480 w->get().erase( w->get().begin() + eraseIdx + eraseShift ); 00481 00482 // unlock and call callbacks 00483 w.reset(); 00484 m_sortSignal(); 00485 return true; 00486 } 00487 00488 size_t WGEColormapping::size() const 00489 { 00490 return m_textures.size(); 00491 } 00492 00493 boost::signals2::connection WGEColormapping::subscribeSignal( TextureListSignal signal, TextureRegisterHandler notifier ) 00494 { 00495 switch( signal ) 00496 { 00497 case Registered: 00498 return m_registerSignal.connect( notifier ); 00499 case Deregistered: 00500 return m_deregisterSignal.connect( notifier ); 00501 default: 00502 throw new WGESignalSubscriptionFailed( std::string( "Could not register TextureRegisterHandler to sort signal." ) ); 00503 } 00504 } 00505 00506 boost::signals2::connection WGEColormapping::subscribeSignal( TextureListSignal signal, TextureReplaceHandler notifier ) 00507 { 00508 switch( signal ) 00509 { 00510 case Replaced: 00511 return m_replaceSignal.connect( notifier ); 00512 default: 00513 throw new WGESignalSubscriptionFailed( std::string( "Could not register TextureReplaceHandler to signal." ) ); 00514 } 00515 } 00516 00517 boost::signals2::connection WGEColormapping::subscribeSignal( TextureListSignal signal, TextureSortHandler notifier ) 00518 { 00519 switch( signal ) 00520 { 00521 case Sorted: 00522 return m_sortSignal.connect( notifier ); 00523 default: 00524 throw new WGESignalSubscriptionFailed( std::string( "Could not register TextureSortHandler to register/deregister signal." ) ); 00525 } 00526 } 00527 00528 WGEColormapping::TextureContainerType::ReadTicket WGEColormapping::getReadTicket() 00529 { 00530 return m_textures.getReadTicket(); 00531 } 00532 00533 WCondition::SPtr WGEColormapping::getChangeCondition() const 00534 { 00535 return m_textures.getChangeCondition(); 00536 } 00537