OpenWalnut  1.4.0
WGETextureHud.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 <iostream>
00026 #include <string>
00027 
00028 #include <boost/bind.hpp>
00029 #include <boost/function.hpp>
00030 
00031 #include <osg/Camera>
00032 #include <osg/Geode>
00033 #include <osg/Geometry>
00034 #include <osg/MatrixTransform>
00035 #include <osg/Node>
00036 #include <osg/TexEnv>
00037 
00038 #include "../common/WPathHelper.h"
00039 
00040 #include "WGETextureHud.h"
00041 
00042 WGETextureHud::WGETextureHud():
00043     osg::Projection(),
00044     m_group( new WGEGroupNode() ),
00045     m_maxElementWidth( 256 ),
00046     m_renderBin( 10000 ),
00047     m_viewport( new osg::Viewport() ),
00048     m_coupleTexViewport( false )
00049 {
00050     getOrCreateStateSet()->setRenderBinDetails( m_renderBin, "RenderBin" );
00051     m_group->addUpdateCallback( new SafeUpdateCallback( this ) );
00052     addChild( m_group );
00053 }
00054 
00055 WGETextureHud::~WGETextureHud()
00056 {
00057     // cleanup
00058 }
00059 
00060 void WGETextureHud::SafeUpdateCallback::operator()( osg::Node* node, osg::NodeVisitor* nv )
00061 {
00062     // set the new size of the widget (how can we get this data?)
00063     unsigned int screenWidth = m_hud->m_viewport->width();
00064     unsigned int screenHeight = m_hud->m_viewport->height();
00065     m_hud->setMatrix( osg::Matrix::ortho2D( 0, screenWidth, 0, screenHeight ) );
00066 
00067     // border around each element
00068     unsigned int border = 5;
00069 
00070     // update all those
00071     osg::Group* group = static_cast< osg::Group* >( node );
00072 
00073     unsigned int nextX = border;
00074     unsigned int nextY = border;
00075 
00076     // iterate all children
00077     for( size_t i = 0; i < group->getNumChildren(); ++i )
00078     {
00079         // all children are WGETextureHudEntries.
00080         WGETextureHudEntry* tex = static_cast< WGETextureHudEntry* >( group->getChild( i ) );
00081         tex->setMaxTextWidth( m_hud->getMaxElementWidth() );    // as this might change each frame, we set it here
00082 
00083         // scale the height of the quad (texture) to have proper aspect ratio
00084         float height = static_cast< float >( m_hud->getMaxElementWidth() * tex->getRealHeight() ) / static_cast< float >( tex->getRealWidth() );
00085 
00086         // scale texture if needed
00087         if( m_hud->m_coupleTexViewport )
00088         {
00089             osg::ref_ptr< osg::TexMat > texMat = tex->getTextureMatrix();
00090             texMat->setMatrix( osg::Matrixd::scale( static_cast< float >( screenWidth ) / static_cast< float >( tex->getRealWidth() ),
00091                                                     static_cast< float >( screenHeight )/ static_cast< float >( tex->getRealHeight() ), 1.0 ) );
00092 
00093             // this also changes the aspect ratio in the texture:
00094             height = static_cast< float >( m_hud->getMaxElementWidth() * screenHeight ) / static_cast< float >( screenWidth );
00095         }
00096 
00097         // scale them to their final size
00098         osg::Matrixd scale = osg::Matrixd::scale( m_hud->getMaxElementWidth(), height, 1.0 );
00099 
00100         // need to add a "line-break"?
00101         if( nextY + height + border > screenHeight )
00102         {
00103             nextX += m_hud->getMaxElementWidth() + border;
00104             nextY = border;
00105         }
00106 
00107         // transform them to the right place
00108         osg::Matrixd translate = osg::Matrixd::translate( static_cast< double >( nextX ), static_cast< double >( nextY ), 0.0 );
00109         tex->setMatrix( scale * translate );
00110 
00111         // calculate the y position of the next texture
00112         nextY += height + border;
00113     }
00114 
00115     // update all the others
00116     traverse( node, nv );
00117 }
00118 
00119 void WGETextureHud::addTexture( osg::ref_ptr< WGETextureHudEntry > texture )
00120 {
00121     m_group->insert( texture );
00122 }
00123 
00124 void WGETextureHud::removeTexture( osg::ref_ptr< WGETextureHudEntry > texture )
00125 {
00126     m_group->remove( texture );
00127 }
00128 
00129 /**
00130  * This method compares a specified texture with the specified node. If the node is an WGETextureHudEntry instance, the containied textures
00131  * get compared.
00132  *
00133  * \param tex the texture to compare to
00134  * \param node the node
00135  *
00136  * \return true if node->m_texture == tex.
00137  */
00138 bool hudEntryPredicate( osg::ref_ptr< osg::Texture > tex, osg::ref_ptr< osg::Node > const& node )
00139 {
00140     // is the node an WGETextureHudEntry?
00141     WGETextureHud::WGETextureHudEntry const* e = dynamic_cast< WGETextureHud::WGETextureHudEntry const* >( node.get() );
00142     if( !e )
00143     {
00144         return false;
00145     }
00146 
00147     // check if textures are equal
00148     return e->getTexture() == tex;
00149 }
00150 
00151 void WGETextureHud::removeTexture( osg::ref_ptr< osg::Texture > texture )
00152 {
00153     typedef WPredicateHelper::ArbitraryPredicate< osg::ref_ptr< osg::Node > const,
00154                                                   boost::function< bool ( osg::ref_ptr< osg::Node > const& ) > > TexCheck;  // NOLINT - if the
00155     // space after bool is removed (as the stylechecker want) it interprets it as old-style cast and complains about it. This is valid syntax for
00156     // boost::function.
00157 
00158     m_group->remove_if(
00159         boost::shared_ptr< WGEGroupNode::NodePredicate >(
00160             new TexCheck( boost::bind( &hudEntryPredicate, texture, _1 ) )
00161         )
00162     );
00163 }
00164 
00165 void WGETextureHud::setViewport( osg::Viewport* viewport )
00166 {
00167     m_viewport = viewport;
00168 }
00169 
00170 void WGETextureHud::coupleViewportWithTextureViewport( bool couple )
00171 {
00172     m_coupleTexViewport = couple;
00173 }
00174 
00175 WGETextureHud::WGETextureHudEntry::WGETextureHudEntry( osg::ref_ptr< osg::Texture2D > texture, std::string name, bool transparency ):
00176     osg::MatrixTransform(),
00177     m_texture( texture ),
00178     m_name( name ),
00179     m_maxTextWidth( 256 )
00180 {
00181     setMatrix( osg::Matrixd::identity() );
00182     setReferenceFrame( osg::Transform::ABSOLUTE_RF );
00183 
00184     //////////////////////////////////////////////////
00185     // Texture Quad
00186 
00187     osg::Geode* geode = new osg::Geode();
00188 
00189     // Set up geometry for the HUD and add it to the HUD
00190     osg::ref_ptr< osg::Geometry > HUDBackgroundGeometry = new osg::Geometry();
00191 
00192     osg::ref_ptr< osg::Vec3Array > HUDBackgroundVertices = new osg::Vec3Array;
00193     HUDBackgroundVertices->push_back( osg::Vec3( 0, 0, -1 ) );
00194     HUDBackgroundVertices->push_back( osg::Vec3( 1, 0, -1 ) );
00195     HUDBackgroundVertices->push_back( osg::Vec3( 1, 1, -1 ) );
00196     HUDBackgroundVertices->push_back( osg::Vec3( 0, 1, -1 ) );
00197 
00198     osg::ref_ptr< osg::Vec3Array > HUDBackgroundTex = new osg::Vec3Array;
00199     HUDBackgroundTex->push_back( osg::Vec3( 0, 0, 0 ) );
00200     HUDBackgroundTex->push_back( osg::Vec3( 1, 0, 0 ) );
00201     HUDBackgroundTex->push_back( osg::Vec3( 1, 1, 0 ) );
00202     HUDBackgroundTex->push_back( osg::Vec3( 0, 1, 0 ) );
00203 
00204     osg::ref_ptr< osg::DrawElementsUInt > HUDBackgroundIndices = new osg::DrawElementsUInt( osg::PrimitiveSet::POLYGON, 0 );
00205     HUDBackgroundIndices->push_back( 0 );
00206     HUDBackgroundIndices->push_back( 1 );
00207     HUDBackgroundIndices->push_back( 2 );
00208     HUDBackgroundIndices->push_back( 3 );
00209 
00210     osg::ref_ptr< osg::Vec4Array > HUDcolors = new osg::Vec4Array;
00211     HUDcolors->push_back( osg::Vec4( 1.0f, 1.0f, 1.0f, 1.0f ) );
00212 
00213     osg::ref_ptr< osg::Vec3Array > HUDnormals = new osg::Vec3Array;
00214     HUDnormals->push_back( osg::Vec3( 0.0f, 0.0f, 1.0f ) );
00215     HUDBackgroundGeometry->setNormalArray( HUDnormals );
00216     HUDBackgroundGeometry->setNormalBinding( osg::Geometry::BIND_OVERALL );
00217     HUDBackgroundGeometry->addPrimitiveSet( HUDBackgroundIndices );
00218     HUDBackgroundGeometry->setVertexArray( HUDBackgroundVertices );
00219     HUDBackgroundGeometry->setColorArray( HUDcolors );
00220     HUDBackgroundGeometry->setColorBinding( osg::Geometry::BIND_OVERALL );
00221     HUDBackgroundGeometry->setTexCoordArray( 0, HUDBackgroundTex );
00222 
00223     geode->addDrawable( HUDBackgroundGeometry );
00224 
00225     // Create and set up a state set using the texture from above
00226     osg::StateSet* state = geode->getOrCreateStateSet();
00227     state->setTextureAttributeAndModes( 0, texture, osg::StateAttribute::ON );
00228     state->setMode( GL_DEPTH_TEST, osg::StateAttribute::OFF );
00229     state->setMode( GL_LIGHTING, osg::StateAttribute::PROTECTED );
00230     state->setMode( GL_LIGHTING, osg::StateAttribute::OFF );
00231 
00232     // enable texture coordinate manipulation via texture matrices
00233     m_texMat = new osg::TexMat;
00234     m_texMat->setMatrix( osg::Matrixd::identity() );
00235     state->setTextureAttributeAndModes( 0, m_texMat, osg::StateAttribute::ON );
00236 
00237     // This disables colorblending of the texture with the underlying quad
00238     // osg::TexEnv* decalState = new osg::TexEnv();
00239     // decalState->setMode( osg::TexEnv::DECAL );
00240     // state->setTextureAttribute( 0, decalState, osg::StateAttribute::ON );
00241 
00242     // en/disable blending
00243     if( !transparency )
00244     {
00245         state->setMode( GL_BLEND, osg::StateAttribute::PROTECTED );
00246         state->setMode( GL_BLEND, osg::StateAttribute::OFF );
00247     }
00248     else
00249     {
00250         state->setMode( GL_BLEND, osg::StateAttribute::PROTECTED );
00251         state->setMode( GL_BLEND, osg::StateAttribute::ON );
00252         state->setRenderingHint( osg::StateSet::TRANSPARENT_BIN );
00253     }
00254 
00255     // add the geode
00256     addChild( geode );
00257 
00258     //////////////////////////////////////////////////
00259     // Text
00260     osg::ref_ptr< osg::Geode > textGeode = new osg::Geode();
00261     state = textGeode->getOrCreateStateSet();
00262     state->setMode( GL_DEPTH_TEST, osg::StateAttribute::OFF );
00263     addChild( textGeode );
00264     m_label = new osgText::Text();
00265     m_label->setFont( WPathHelper::getAllFonts().Default.string() );
00266     m_label->setBackdropType( osgText::Text::OUTLINE );
00267     m_label->setCharacterSize( 15 );
00268     m_label->setText( m_name );
00269     m_label->setAxisAlignment( osgText::Text::SCREEN );
00270     m_label->setPosition( osg::Vec3( 0.02, 0.925, -1.0 ) );
00271     m_label->setColor( osg::Vec4( 1.0, 1.0, 1.0, 1.0 ) );
00272     textGeode->addDrawable( m_label );
00273 }
00274 
00275 WGETextureHud::WGETextureHudEntry::~WGETextureHudEntry()
00276 {
00277     // cleanup
00278 }
00279 
00280 void WGETextureHud::WGETextureHudEntry::setMaxTextWidth( float width )
00281 {
00282     m_maxTextWidth = width;
00283     m_label->setMaximumWidth( width - 20 ); // 20? Ensure some space at the right side
00284 }
00285 
00286 unsigned int WGETextureHud::WGETextureHudEntry::getRealWidth() const
00287 {
00288     return m_texture->getTextureWidth();
00289 }
00290 
00291 unsigned int WGETextureHud::WGETextureHudEntry::getRealHeight() const
00292 {
00293     return m_texture->getTextureHeight();
00294 }
00295 
00296 osg::ref_ptr< osg::TexMat > WGETextureHud::WGETextureHudEntry::getTextureMatrix() const
00297 {
00298     return m_texMat;
00299 }
00300 
00301 std::string WGETextureHud::WGETextureHudEntry::getName() const
00302 {
00303     return m_name;
00304 }
00305 
00306 unsigned int WGETextureHud::getMaxElementWidth() const
00307 {
00308     return m_maxElementWidth;
00309 }
00310 
00311 void WGETextureHud::setMaxElementWidth( unsigned int width )
00312 {
00313     m_maxElementWidth = width;
00314 }
00315 
00316 osg::ref_ptr< osg::Texture2D > WGETextureHud::WGETextureHudEntry::getTexture() const
00317 {
00318     return m_texture;
00319 }
00320 
00321 size_t WGETextureHud::getRenderBin() const
00322 {
00323     return m_renderBin;
00324 }
00325