WMFiberDisplay.cpp 16.4 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
//---------------------------------------------------------------------------
//
// Project: OpenWalnut ( http://www.openwalnut.org )
//
// Copyright 2009 OpenWalnut Community, BSV@Uni-Leipzig and CNCF@MPI-CBS
// For more information see http://www.openwalnut.org/copying
//
// This file is part of OpenWalnut.
//
// OpenWalnut is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// OpenWalnut is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with OpenWalnut. If not, see <http://www.gnu.org/licenses/>.
//
//---------------------------------------------------------------------------

25
#include <list>
26
#include <string>
Mathias Goldau's avatar
Mathias Goldau committed
27
#include <vector>
28

29 30
#include <boost/shared_ptr.hpp>

31
#include <osg/Geode>
32
#include <osg/Geometry>
33

34 35 36 37 38 39 40 41 42
#include "../../common/WColor.h"
#include "../../common/WLogger.h"
#include "../../common/WPathHelper.h"
#include "../../dataHandler/WDataHandler.h"
#include "../../dataHandler/WDataTexture3D.h"
#include "../../dataHandler/WSubject.h"
#include "../../graphicsEngine/WGEUtils.h"
#include "../../kernel/WKernel.h"
#include "fiberdisplay2.xpm"
43
#include "WMFiberDisplay.h"
44

45
W_LOADABLE_MODULE( WMFiberDisplay )
46

47
WMFiberDisplay::WMFiberDisplay()
48
    : WModule(),
49
      m_noData( new WCondition, true ),
Mathias Goldau's avatar
Mathias Goldau committed
50
      m_osgNode( osg::ref_ptr< osg::Group >() )
51
{
52 53
    m_shaderTubes = osg::ref_ptr< WShader > ( new WShader( "WMFiberDisplay-FakeTubes" ) );
    m_shaderTexturedFibers = osg::ref_ptr< WShader > ( new WShader( "WMFiberDisplay-Textured" ) );
54
    m_textureChanged = true;
55 56
}

57
WMFiberDisplay::~WMFiberDisplay()
58 59 60
{
}

61 62 63 64 65
boost::shared_ptr< WModule > WMFiberDisplay::factory() const
{
    return boost::shared_ptr< WModule >( new WMFiberDisplay() );
}

66
const char** WMFiberDisplay::getXPMIcon() const
67
{
68
    return fiberdisplay2_xpm;
69 70
}

71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121
void WMFiberDisplay::connectors()
{
    using boost::shared_ptr;
    typedef WModuleInputData< const WDataSetFibers > FiberInputData;  // just an alias

    m_fiberInput = shared_ptr< FiberInputData >( new FiberInputData( shared_from_this(), "fiberInput", "A loaded fiber dataset." ) );

    addConnector( m_fiberInput );

    WModule::connectors();  // call WModules initialization
}

void WMFiberDisplay::activate()
{
    if( m_osgNode )
    {
        if( m_active->get() )
        {
            m_osgNode->setNodeMask( 0xFFFFFFFF );
        }
        else
        {
            m_osgNode->setNodeMask( 0x0 );
        }
    }

    WModule::activate();
}

void WMFiberDisplay::initUniforms( osg::StateSet* rootState )
{
    m_uniformUseTexture = osg::ref_ptr<osg::Uniform>( new osg::Uniform( "useTexture", false ) );
    m_uniformSampler = osg::ref_ptr<osg::Uniform>( new osg::Uniform( "tex", 0 ) );
    m_uniformType = osg::ref_ptr<osg::Uniform>( new osg::Uniform( "type", 0 ) );
    m_uniformThreshold = osg::ref_ptr<osg::Uniform>( new osg::Uniform( "threshold", 0.0f ) );
    m_uniformsColorMap = osg::ref_ptr<osg::Uniform>( new osg::Uniform( "cMap", 0 ) );

    m_uniformDimX = osg::ref_ptr<osg::Uniform>( new osg::Uniform( "dimX", 1 ) );
    m_uniformDimY = osg::ref_ptr<osg::Uniform>( new osg::Uniform( "dimY", 1 ) );
    m_uniformDimZ = osg::ref_ptr<osg::Uniform>( new osg::Uniform( "dimZ", 1 ) );

    rootState->addUniform( m_uniformUseTexture );
    rootState->addUniform( m_uniformSampler );
    rootState->addUniform( m_uniformType );
    rootState->addUniform( m_uniformThreshold );
    rootState->addUniform( m_uniformsColorMap );

    rootState->addUniform( m_uniformDimX );
    rootState->addUniform( m_uniformDimY );
    rootState->addUniform( m_uniformDimZ );

122 123 124
    m_uniformTubeThickness = osg::ref_ptr<osg::Uniform>( new osg::Uniform( "u_thickness", static_cast<float>( m_tubeThickness->get() ) ) );
    rootState->addUniform( m_uniformTubeThickness );

125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154
    // cull box info
    float xMin = m_cullBox->getMinPos()[0];
    float yMin = m_cullBox->getMinPos()[1];
    float zMin = m_cullBox->getMinPos()[2];
    float xMax = m_cullBox->getMaxPos()[0];
    float yMax = m_cullBox->getMaxPos()[1];
    float zMax = m_cullBox->getMaxPos()[2];

    m_uniformUseCullBox = osg::ref_ptr<osg::Uniform>( new osg::Uniform( "useCullBox", false ) );
    m_uniformInsideCullBox = osg::ref_ptr<osg::Uniform>( new osg::Uniform( "insideCullBox", false ) );

    m_uniformCullBoxLBX = osg::ref_ptr<osg::Uniform>( new osg::Uniform( "cullBoxLBX", static_cast<float>( xMin ) ) );
    m_uniformCullBoxLBY = osg::ref_ptr<osg::Uniform>( new osg::Uniform( "cullBoxLBY", static_cast<float>( yMin ) ) );
    m_uniformCullBoxLBZ = osg::ref_ptr<osg::Uniform>( new osg::Uniform( "cullBoxLBZ", static_cast<float>( zMin ) ) );
    m_uniformCullBoxUBX = osg::ref_ptr<osg::Uniform>( new osg::Uniform( "cullBoxUBX", static_cast<float>( xMax ) ) );
    m_uniformCullBoxUBY = osg::ref_ptr<osg::Uniform>( new osg::Uniform( "cullBoxUBY", static_cast<float>( yMax ) ) );
    m_uniformCullBoxUBZ = osg::ref_ptr<osg::Uniform>( new osg::Uniform( "cullBoxUBZ", static_cast<float>( zMax ) ) );

    rootState->addUniform( m_uniformUseCullBox );
    rootState->addUniform( m_uniformInsideCullBox );

    rootState->addUniform( m_uniformCullBoxLBX );
    rootState->addUniform( m_uniformCullBoxLBY );
    rootState->addUniform( m_uniformCullBoxLBZ );
    rootState->addUniform( m_uniformCullBoxUBX );
    rootState->addUniform( m_uniformCullBoxUBY );
    rootState->addUniform( m_uniformCullBoxUBZ );
}

void WMFiberDisplay::initCullBox()
155
{
156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180
    wmath::WPosition crossHairPos = WKernel::getRunningKernel()->getSelectionManager()->getCrosshair()->getPosition();
    wmath::WPosition minROIPos = crossHairPos - wmath::WPosition( 10., 10., 10. );
    wmath::WPosition maxROIPos = crossHairPos + wmath::WPosition( 10., 10., 10. );

    m_cullBox = osg::ref_ptr< WROIBox >( new WROIBox( minROIPos, maxROIPos ) );
    m_cullBox->setColor( osg::Vec4( 1.0, 0., 1.0, 0.4 ) );
}

void WMFiberDisplay::properties()
{
    m_propCondition = boost::shared_ptr< WCondition >( new WCondition() );

    m_useTubesProp = m_properties->addProperty( "Use tubes", "Draw fiber tracts as fake tubes.", false, m_propCondition );
    m_useTextureProp = m_properties->addProperty( "Use texture", "Texture fibers with the texture on top of the list.", false, m_propCondition );
    m_tubeThickness = m_properties->addProperty( "Tube thickness", "Adjusts the thickness of the tubes.", 50., m_propCondition );
    m_tubeThickness->setMin( 0 );
    m_tubeThickness->setMax( 300 );

    m_save = m_properties->addProperty( "Save", "Saves the selected fiber bundles.", false, m_propCondition );
    m_saveFileName = m_properties->addProperty( "File name", "", WPathHelper::getAppPath() );

    m_cullBoxGroup    = m_properties->addPropertyGroup( "Box Culling",  "Properties only related to the box culling.", m_propCondition );
    m_activateCullBox = m_cullBoxGroup->addProperty( "Activate", "Activates the cull box", false, m_propCondition );
    m_showCullBox     = m_cullBoxGroup->addProperty( "Show cull box", "Shows/hides the cull box", false, m_propCondition );
    m_insideCullBox   = m_cullBoxGroup->addProperty( "Inside - outside", "Show fibers inside or outside the cull box", true, m_propCondition );
181 182
}

183

184
void WMFiberDisplay::moduleMain()
185
{
186
    // additional fire-condition: "data changed" flag
Mathias Goldau's avatar
Mathias Goldau committed
187
    m_moduleState.setResetable( true, true );
188
    m_moduleState.add( m_fiberInput->getDataChangedCondition() );
189 190
    m_moduleState.add( m_propCondition );
    m_moduleState.add( m_active->getUpdateCondition() );
191

192 193
    // now, to watch changing/new textures use WSubject's change condition
    boost::signals2::connection con = WDataHandler::getDefaultSubject()->getChangeCondition()->subscribeSignal(
194 195 196
            boost::bind( &WMFiberDisplay::notifyTextureChange, this ) );

    initCullBox();
197

198
    m_cullBox->hide();
199

200
    ready();
201

202
    while ( !m_shutdownFlag() ) // loop until the module container requests the module to quit
203
    {
Mathias Goldau's avatar
Mathias Goldau committed
204 205
        m_moduleState.wait(); // waits for firing of m_moduleState ( dataChanged, shutdown, etc. )

206 207 208 209
        if ( m_shutdownFlag() )
        {
            break;
        }
Mathias Goldau's avatar
Mathias Goldau committed
210 211 212

        // data changed?
        if ( m_dataset != m_fiberInput->getData() )
213
        {
214
            inputUpdated();
Mathias Goldau's avatar
Mathias Goldau committed
215
        }
216 217 218 219 220 221 222 223 224 225 226 227

        if ( m_showCullBox->changed() )
        {
            if( m_showCullBox->get() )
            {
                m_cullBox->unhide();
            }
            else
            {
                m_cullBox->hide();
            }
        }
Mathias Goldau's avatar
Mathias Goldau committed
228
    }
229

230 231
    con.disconnect();

232
    WKernel::getRunningKernel()->getGraphicsEngine()->getScene()->remove( m_osgNode );
233
}
234

235 236 237 238 239 240 241 242 243 244 245 246 247
void WMFiberDisplay::inputUpdated()
{
    // data has changed
    // -> recalculate
    debugLog() << "Data changed on " << m_fiberInput->getCanonicalName();

    m_dataset = m_fiberInput->getData();

    // ensure the data is valid (not NULL)
    if ( !m_fiberInput->getData().get() ) // ok, the output has been reset, so we can ignore the "data change"
    {
        m_noData.set( true );
        debugLog() << "Data reset on " << m_fiberInput->getCanonicalName() << ". Ignoring.";
248
        return;
249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271
    }
    infoLog() << "Fiber dataset for display with: " << m_dataset->size() << " fibers loaded.";

    if( m_dataset->size() != 0 ) // incase of an empty fiber dataset nothing is to display
    {
        boost::shared_ptr< WProgress > progress = boost::shared_ptr< WProgress >( new WProgress( "Fiber Display", 2 ) );
        m_progress->addSubProgress( progress );

        WKernel::getRunningKernel()->getGraphicsEngine()->getScene()->removeChild( m_osgNode.get() );
        ++*progress;
        m_fiberSelector = boost::shared_ptr<WFiberSelector>( new WFiberSelector( m_dataset ) );
        ++*progress;
        create();
        progress->finish();

        m_noData.set( false );
    }
    else
    {
        warnLog() << "Nothing to display for an empty fiber dataset";
    }
}

Mathias Goldau's avatar
Mathias Goldau committed
272
void WMFiberDisplay::create()
273 274
{
    // create new node
275
    osg::ref_ptr< osg::Group > osgNodeNew = osg::ref_ptr< osg::Group >( new osg::Group );
schurade's avatar
schurade committed
276

277 278
    m_fiberDrawable = osg::ref_ptr< WFiberDrawable >( new WFiberDrawable );
    m_fiberDrawable->setBoundingBox( osg::BoundingBox( m_dataset->getBoundingBox().first[0],
279 280 281 282 283
                                                      m_dataset->getBoundingBox().first[1],
                                                      m_dataset->getBoundingBox().first[2],
                                                      m_dataset->getBoundingBox().second[0],
                                                      m_dataset->getBoundingBox().second[1],
                                                      m_dataset->getBoundingBox().second[2] ) );
284 285 286 287 288 289 290 291

    m_fiberDrawable->setStartIndexes( m_dataset->getLineStartIndexes() );
    m_fiberDrawable->setPointsPerLine( m_dataset->getLineLengths() );
    m_fiberDrawable->setVerts( m_dataset->getVertices() );
    m_fiberDrawable->setTangents( m_dataset->getTangents() );
    m_fiberDrawable->setColor( m_dataset->getGlobalColors() );
    m_fiberDrawable->setBitfield( m_fiberSelector->getBitfield() );

292 293
    m_fiberDrawable->setUseDisplayList( false );
    m_fiberDrawable->setDataVariance( osg::Object::DYNAMIC );
schurade's avatar
schurade committed
294 295

    osg::ref_ptr< osg::Geode > geode = osg::ref_ptr< osg::Geode >( new osg::Geode );
296
    geode->addDrawable( m_fiberDrawable );
schurade's avatar
schurade committed
297

298 299 300 301
    osgNodeNew->addChild( geode );

    osgNodeNew->getOrCreateStateSet()->setMode( GL_LIGHTING, osg::StateAttribute::OFF );

302
    osgNodeNew->addUpdateCallback( new WGEFunctorCallback< osg::Node >( boost::bind( &WMFiberDisplay::updateCallback, this ) ) );
303 304
    // remove previous nodes if there are any
    WKernel::getRunningKernel()->getGraphicsEngine()->getScene()->removeChild( m_osgNode.get() );
schurade's avatar
schurade committed
305

306
    m_osgNode = osgNodeNew;
Mathias Goldau's avatar
Mathias Goldau committed
307

308
    activate();
309 310 311

    osg::StateSet* rootState = m_osgNode->getOrCreateStateSet();
    initUniforms( rootState );
312 313

    WKernel::getRunningKernel()->getGraphicsEngine()->getScene()->addChild( m_osgNode.get() );
314 315
}

316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347
void WMFiberDisplay::update()
{
    if( m_osgNode && m_noData.changed() )
    {
        if ( m_noData.get( true ) )
        {
            m_osgNode->setNodeMask( 0x0 );
        }
        else
        {
            m_osgNode->setNodeMask( 0xFFFFFFFF );
        }
    }

    float xMin = m_cullBox->getMinPos()[0];
    float yMin = m_cullBox->getMinPos()[1];
    float zMin = m_cullBox->getMinPos()[2];
    float xMax = m_cullBox->getMaxPos()[0];
    float yMax = m_cullBox->getMaxPos()[1];
    float zMax = m_cullBox->getMaxPos()[2];

    m_uniformUseCullBox->set( m_activateCullBox->get() );
    m_uniformInsideCullBox->set( m_insideCullBox->get() );

    m_uniformCullBoxLBX->set( static_cast<float>( xMin ) );
    m_uniformCullBoxLBY->set( static_cast<float>( yMin ) );
    m_uniformCullBoxLBZ->set( static_cast<float>( zMin ) );
    m_uniformCullBoxUBX->set( static_cast<float>( xMax ) );
    m_uniformCullBoxUBY->set( static_cast<float>( yMax ) );
    m_uniformCullBoxUBZ->set( static_cast<float>( zMax ) );
}

348
void WMFiberDisplay::updateRenderModes()
349
{
350 351 352 353 354 355 356 357
    osg::StateSet* rootState = m_osgNode->getOrCreateStateSet();

    if ( m_textureChanged )
    {
        m_textureChanged = false;
        updateTexture();
    }

358
    if( m_useTubesProp->changed() || m_useTextureProp->changed() || m_activateCullBox->changed() )
schurade's avatar
schurade committed
359
    {
360 361
        if ( m_useTubesProp->get( true ) )
        {
schurade's avatar
schurade committed
362
            updateTexture();
363
            m_fiberDrawable->setUseTubes( true );
364
            m_shaderTubes->apply( m_osgNode );
365
            m_uniformUseTexture->set( m_useTextureProp->get( true ) );
366
        }
367
        else if ( ( m_useTextureProp->get( true ) && !m_useTubesProp->get() ) || m_activateCullBox->get( true) )
368
        {
369
            m_fiberDrawable->setUseTubes( false );
370 371 372
            updateTexture();
            m_shaderTubes->deactivate( m_osgNode );
            m_shaderTexturedFibers->apply( m_osgNode );
373
            m_uniformUseTexture->set( m_useTextureProp->get() );
374
        }
375 376
        else
        {
377
            m_fiberDrawable->setUseTubes( false );
378 379
            m_shaderTubes->deactivate( m_osgNode );
            m_shaderTexturedFibers->deactivate( m_osgNode );
380
        }
381
    }
382

383
    if  ( !m_useTextureProp->get() && !m_useTubesProp->get() )
384 385 386
    {
        rootState->setTextureMode( 0, GL_TEXTURE_3D, osg::StateAttribute::OFF );
    }
387
}
Mathias Goldau's avatar
Mathias Goldau committed
388

389 390
void WMFiberDisplay::saveSelected()
{
391
    boost::shared_ptr< std::vector< bool > > active = m_fiberSelector->getBitfield();
392 393
    m_dataset->saveSelected( m_saveFileName->getAsString(), active );
}
394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419

void WMFiberDisplay::updateTexture()
{
    osg::StateSet* rootState = m_osgNode->getOrCreateStateSet();

    // grab a list of data textures
    std::vector< boost::shared_ptr< WDataTexture3D > > tex = WDataHandler::getDefaultSubject()->getDataTextures();

    if ( tex.size() > 0 )
    {
        osg::ref_ptr<osg::Texture3D> texture3D = tex[0]->getTexture();

        if ( tex[0]->isInterpolated() )
        {
            texture3D->setFilter( osg::Texture::MIN_FILTER, osg::Texture::LINEAR );
            texture3D->setFilter( osg::Texture::MAG_FILTER, osg::Texture::LINEAR );
        }
        else
        {
            texture3D->setFilter( osg::Texture::MIN_FILTER, osg::Texture::NEAREST );
            texture3D->setFilter( osg::Texture::MAG_FILTER, osg::Texture::NEAREST );
        }
        rootState->setTextureAttributeAndModes( 0, texture3D, osg::StateAttribute::ON );


        m_uniformType->set( tex[0]->getDataType() );
420 421 422 423 424
        float minValue = tex[0]->getMinValue();
        float maxValue = tex[0]->getMaxValue();
        float thresh = ( tex[0]->getThreshold() - minValue ) / ( maxValue - minValue ); // rescale to [0,1]

        m_uniformThreshold->set( thresh );
425 426 427 428 429 430 431 432 433 434 435 436
        m_uniformsColorMap->set( tex[0]->getSelectedColormap() );

        m_uniformDimX->set( static_cast<int>( tex[0]->getGrid()->getNbCoordsX() ) );
        m_uniformDimY->set( static_cast<int>( tex[0]->getGrid()->getNbCoordsY() ) );
        m_uniformDimZ->set( static_cast<int>( tex[0]->getGrid()->getNbCoordsZ() ) );
    }
}

void WMFiberDisplay::notifyTextureChange()
{
    m_textureChanged = true;
}
437

438
void WMFiberDisplay::updateCallback()
439
{
440
    update();
441 442 443 444 445 446 447 448

    m_fiberDrawable->setColor( m_dataset->getColorScheme()->getColor() );

    if ( m_tubeThickness->changed() && m_useTubesProp->get() )
    {
        m_uniformTubeThickness->set( static_cast<float>( m_tubeThickness->get( true ) ) );
    }

449
    updateRenderModes();
ledig's avatar
[STYLE]  
ledig committed
450
}