WMNavSlices.cpp 22.7 KB
Newer Older
1 2
//---------------------------------------------------------------------------
//
3
// Project: OpenWalnut ( http://www.openwalnut.org )
4
//
5 6
// Copyright 2009 OpenWalnut Community, BSV@Uni-Leipzig and CNCF@MPI-CBS
// For more information see http://www.openwalnut.org/copying
7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
//
// 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/>.
//
//---------------------------------------------------------------------------

#include <iostream>
26
#include <list>
27
#include <string>
28
#include <vector>
29

30 31
#include <boost/shared_ptr.hpp>

32 33
#include <osg/Geode>
#include <osg/Geometry>
34
#include <osg/Group>
35

36
#include "../../dataHandler/WDataSet.h"
37
#include "../../dataHandler/WDataSetSingle.h"
38 39
#include "../../dataHandler/WDataTexture3D.h"
#include "../../dataHandler/WGridRegular3D.h"
40
#include "../../dataHandler/WSubject.h"
41
#include "../../dataHandler/WValueSet.h"
42
#include "../../graphicsEngine/WShader.h"
43 44 45 46 47 48
#include "../../kernel/WKernel.h"
#include "../../kernel/WModule.h"
#include "../../kernel/WModuleConnector.h"
#include "../../kernel/WModuleInputData.h"
#include "../data/WMData.h"
#include "WMNavSlices.h"
49

50
WMNavSlices::WMNavSlices():
51
    WModule()
52
{
53 54
    // WARNING: initializing connectors inside the constructor will lead to an exception.
    // Implement WModule::initializeConnectors instead.
55

56
    // initialize members
57 58
    std::string shaderPath = WKernel::getRunningKernel()->getGraphicsEngine()->getShaderPath();
    m_shader = boost::shared_ptr< WShader > ( new WShader( "slice", shaderPath ) );
59 60
}

61
WMNavSlices::~WMNavSlices()
62 63
{
    // cleanup
64
    removeConnectors();
65 66
}

67 68 69 70 71
boost::shared_ptr< WModule > WMNavSlices::factory() const
{
    return boost::shared_ptr< WModule >( new WMNavSlices() );
}

72
const std::string WMNavSlices::getName() const
73
{
74
    return "Navigation Slice Module";
75 76
}

77
const std::string WMNavSlices::getDescription() const
78
{
79
    return "This module shows 3 orthogonal navigation slices.";
80 81
}

82
void WMNavSlices::connectors()
83 84 85 86
{
    // initialize connectors
    // XXX to add a new connector and to offer it, these simple steps need to be done
    // initialize it first
87 88
    m_input= boost::shared_ptr<WModuleInputData< WDataSetSingle > >(
            new WModuleInputData< WDataSetSingle >( shared_from_this(),
89
                "in1", "List of datasets to show on the slices." )
90
    );
91

92
    // add it to the list of connectors. Please note, that a connector NOT added via addConnector will not work as expected.
Alexander Wiebel's avatar
Alexander Wiebel committed
93
    addConnector( m_input );
94 95

    // call WModules initialization
96
    WModule::connectors();
97 98
}

99
void WMNavSlices::properties()
100
{
101
    m_properties->addBool( "textureChanged", false, true );
schurade's avatar
schurade committed
102 103
    //( m_properties->addBool( "active", true, true ) )->connect( boost::bind( &WMNavSlices::slotPropertyChanged, this, _1 ) );
    m_properties->addBool( "active", true, true );
104 105 106
    m_properties->addInt( "axialPos", 80 );
    m_properties->addInt( "coronalPos", 100 );
    m_properties->addInt( "sagittalPos", 80 );
107

108 109 110 111
    m_properties->addInt( "maxAxial", 160, true );
    m_properties->addInt( "maxCoronal", 200, true );
    m_properties->addInt( "maxSagittal", 160, true );

112

113 114 115
    m_properties->addBool( "showAxial", true );
    m_properties->addBool( "showCoronal", true );
    m_properties->addBool( "showSagittal", true );
116 117
}

118
void WMNavSlices::notifyDataChange( boost::shared_ptr<WModuleConnector> input,
119
                                               boost::shared_ptr<WModuleConnector> output )
120
{
121 122
    WModule::notifyDataChange( input, output );

Alexander Wiebel's avatar
Alexander Wiebel committed
123
    // in this case input==m_input
124 125
}

126
void WMNavSlices::moduleMain()
127
{
128 129 130
    // signal ready state
    ready();

131
    create();
132

133 134
    // Since the modules run in a separate thread: wait
    waitForStop();
135 136

    // clean up stuff
137 138
    // NOTE: ALLAWAYS remove your osg nodes!
    WKernel::getRunningKernel()->getGraphicsEngine()->getScene()->removeChild( m_rootNode );
139 140
}

141 142 143 144 145
void WMNavSlices::create()
{
    m_rootNode = osg::ref_ptr<osg::Group>( new osg::Group() );

    m_xSliceNode = osg::ref_ptr<osg::Geode>( new osg::Geode() );
schurade's avatar
[STYLE]  
schurade committed
146
    m_xSliceNode->setName( "X-Slice" );
147
    m_ySliceNode = osg::ref_ptr<osg::Geode>( new osg::Geode() );
schurade's avatar
[STYLE]  
schurade committed
148
    m_ySliceNode->setName( "Y-Slice" );
149
    m_zSliceNode = osg::ref_ptr<osg::Geode>( new osg::Geode() );
schurade's avatar
[STYLE]  
schurade committed
150
    m_zSliceNode->setName( "Z-Slice" );
151 152 153 154 155 156 157 158 159 160 161 162 163

    m_xSliceNode->addDrawable( createGeometry( 0 ) );
    m_ySliceNode->addDrawable( createGeometry( 1 ) );
    m_zSliceNode->addDrawable( createGeometry( 2 ) );

    m_rootNode->addChild( m_xSliceNode );
    m_rootNode->addChild( m_ySliceNode );
    m_rootNode->addChild( m_zSliceNode );

    WKernel::getRunningKernel()->getGraphicsEngine()->getScene()->addChild( m_rootNode );
    osg::StateSet* rootState = m_rootNode->getOrCreateStateSet();
    initUniforms( rootState );
    rootState->setAttributeAndModes( m_shader->getProgramObject(), osg::StateAttribute::ON );
164 165 166

    m_rootNode->setUserData( this );
    m_rootNode->setUpdateCallback( new sliceNodeCallback );
167 168 169
}

osg::ref_ptr<osg::Geometry> WMNavSlices::createGeometry( int slice )
170
{
schurade's avatar
schurade committed
171
    float maxDim = 255.0;
schurade's avatar
schurade committed
172

schurade's avatar
schurade committed
173 174 175
    float xSlice = ( float )( m_properties->getValue< int >( "sagittalPos" ) );
    float ySlice = ( float )( m_properties->getValue< int >( "coronalPos" ) );
    float zSlice = ( float )( m_properties->getValue< int >( "axialPos" ) );
schurade's avatar
schurade committed
176

schurade's avatar
schurade committed
177 178 179
    float xPos = xSlice + 0.5f;
    float yPos = ySlice + 0.5f;
    float zPos = zSlice + 0.5f;
180

181
    osg::ref_ptr<osg::Geometry> sliceGeometry = osg::ref_ptr<osg::Geometry>( new osg::Geometry() );
182 183

    osg::Vec3Array* sliceVertices = new osg::Vec3Array;
184

185
    std::vector< boost::shared_ptr< WDataSet > > dsl = WKernel::getRunningKernel()->getGui()->getDataSetList( 0, true );
schurade's avatar
schurade committed
186

187
    if ( dsl.size() > 0 )
188 189 190 191 192
    {
        switch ( slice )
        {
            case 0:
            {
schurade's avatar
schurade committed
193 194 195 196
                sliceVertices->push_back( osg::Vec3( 0,      yPos, 0      ) );
                sliceVertices->push_back( osg::Vec3( 0,      yPos, maxDim ) );
                sliceVertices->push_back( osg::Vec3( maxDim, yPos, maxDim ) );
                sliceVertices->push_back( osg::Vec3( maxDim, yPos, 0      ) );
197 198 199
                sliceGeometry->setVertexArray( sliceVertices );

                int c = 0;
200
                for ( size_t i = 0; i < dsl.size(); ++i )
201
                {
202 203
                    boost::shared_ptr< WGridRegular3D > grid = boost::shared_dynamic_cast< WGridRegular3D >(
                            boost::shared_dynamic_cast< WDataSetSingle >( dsl[i] )->getGrid() );
204

schurade's avatar
schurade committed
205 206 207
                    float maxX = ( float )( grid->getNbCoordsX() );
                    float maxY = ( float )( grid->getNbCoordsY() );
                    float maxZ = ( float )( grid->getNbCoordsZ() );
208

schurade's avatar
schurade committed
209
                    //float texX = xSlice / maxX;
schurade's avatar
schurade committed
210
                    float texY = ySlice / maxY;
schurade's avatar
schurade committed
211
                    //float texZ = zSlice / maxZ;
212

schurade's avatar
schurade committed
213
                    float texXOff = 255.0 / maxX;
schurade's avatar
schurade committed
214
                    //float texYOff = 255.0 / maxY;
schurade's avatar
schurade committed
215
                    float texZOff = 255.0 / maxZ;
216

schurade's avatar
schurade committed
217 218 219 220 221 222 223 224
                    osg::Vec3Array* texCoords = new osg::Vec3Array;
                    texCoords->push_back( grid->transformTexCoord( osg::Vec3( 0.0,     texY, 0.0     ) ) );
                    texCoords->push_back( grid->transformTexCoord( osg::Vec3( 0.0,     texY, texZOff ) ) );
                    texCoords->push_back( grid->transformTexCoord( osg::Vec3( texXOff, texY, texZOff ) ) );
                    texCoords->push_back( grid->transformTexCoord( osg::Vec3( texXOff, texY, 0.0     ) ) );
                    sliceGeometry->setTexCoordArray( c, texCoords );
                    ++c;
                }
225 226 227 228
                break;
            }
            case 1:
            {
schurade's avatar
schurade committed
229 230 231 232
                sliceVertices->push_back( osg::Vec3( xPos, 0,      0      ) );
                sliceVertices->push_back( osg::Vec3( xPos, 0,      maxDim ) );
                sliceVertices->push_back( osg::Vec3( xPos, maxDim, maxDim ) );
                sliceVertices->push_back( osg::Vec3( xPos, maxDim, 0      ) );
233 234 235
                sliceGeometry->setVertexArray( sliceVertices );

                int c = 0;
236
                for ( size_t i = 0; i < dsl.size(); ++i )
237
                {
238 239
                    boost::shared_ptr< WGridRegular3D > grid = boost::shared_dynamic_cast< WGridRegular3D >(
                            boost::shared_dynamic_cast< WDataSetSingle >( dsl[i] )->getGrid() );
schurade's avatar
schurade committed
240 241 242 243 244 245

                    float maxX = ( float )( grid->getNbCoordsX() );
                    float maxY = ( float )( grid->getNbCoordsY() );
                    float maxZ = ( float )( grid->getNbCoordsZ() );

                    float texX = xSlice / maxX;
schurade's avatar
schurade committed
246 247
                    //float texY = ySlice / maxY;
                    //float texZ = zSlice / maxZ;
schurade's avatar
schurade committed
248

schurade's avatar
schurade committed
249
                    //float texXOff = 255.0 / maxX;
schurade's avatar
schurade committed
250 251 252
                    float texYOff = 255.0 / maxY;
                    float texZOff = 255.0 / maxZ;

253
                    osg::Vec3Array* texCoords = new osg::Vec3Array;
schurade's avatar
schurade committed
254 255 256 257
                    texCoords->push_back( grid->transformTexCoord( osg::Vec3( texX, 0.0,     0.0     ) ) );
                    texCoords->push_back( grid->transformTexCoord( osg::Vec3( texX, 0.0,     texZOff ) ) );
                    texCoords->push_back( grid->transformTexCoord( osg::Vec3( texX, texYOff, texZOff ) ) );
                    texCoords->push_back( grid->transformTexCoord( osg::Vec3( texX, texYOff, 0.0     ) ) );
258 259
                    sliceGeometry->setTexCoordArray( c, texCoords );
                    ++c;
260 261 262 263 264
                }
                break;
            }
            case 2:
            {
schurade's avatar
schurade committed
265 266 267 268
                sliceVertices->push_back( osg::Vec3( 0,      0,      zPos ) );
                sliceVertices->push_back( osg::Vec3( 0,      maxDim, zPos ) );
                sliceVertices->push_back( osg::Vec3( maxDim, maxDim, zPos ) );
                sliceVertices->push_back( osg::Vec3( maxDim, 0,      zPos ) );
269 270
                sliceGeometry->setVertexArray( sliceVertices );
                int c = 0;
271
                for ( size_t i = 0; i < dsl.size(); ++i )
272
                {
273 274
                    boost::shared_ptr< WGridRegular3D > grid = boost::shared_dynamic_cast< WGridRegular3D >(
                            boost::shared_dynamic_cast< WDataSetSingle >( dsl[i] )->getGrid() );
schurade's avatar
schurade committed
275 276 277 278 279

                    float maxX = ( float )( grid->getNbCoordsX() );
                    float maxY = ( float )( grid->getNbCoordsY() );
                    float maxZ = ( float )( grid->getNbCoordsZ() );

schurade's avatar
schurade committed
280 281
                    //float texX = xSlice / maxX;
                    //float texY = ySlice / maxY;
schurade's avatar
schurade committed
282 283 284 285
                    float texZ = zSlice / maxZ;

                    float texXOff = 255.0 / maxX;
                    float texYOff = 255.0 / maxY;
schurade's avatar
schurade committed
286
                    //float texZOff = 255.0 / maxZ;
schurade's avatar
schurade committed
287

288 289
                    osg::Vec3Array* texCoords = new osg::Vec3Array;

schurade's avatar
schurade committed
290 291 292 293
                    texCoords->push_back( grid->transformTexCoord( osg::Vec3( 0.0,     0.0,     texZ ) ) );
                    texCoords->push_back( grid->transformTexCoord( osg::Vec3( 0.0,     texYOff, texZ ) ) );
                    texCoords->push_back( grid->transformTexCoord( osg::Vec3( texXOff, texYOff, texZ ) ) );
                    texCoords->push_back( grid->transformTexCoord( osg::Vec3( texXOff, 0.0,     texZ ) ) );
294 295
                    sliceGeometry->setTexCoordArray( c, texCoords );
                    ++c;
296 297 298 299 300 301
                }
                break;
            }
        }
    }
    else
302
    {
schurade's avatar
schurade committed
303 304 305 306 307 308 309 310 311 312 313 314
        float maxX = ( float )( m_properties->getValue<int>( "maxSagittal") );
        float maxY = ( float )( m_properties->getValue<int>( "maxCoronal") );
        float maxZ = ( float )( m_properties->getValue<int>( "maxAxial") );

        m_properties->setMax( "sagittalPos", maxX );
        m_properties->setMax( "coronalPos", maxY );
        m_properties->setMax( "axialPos", maxZ );

        float texX = xSlice / maxX;
        float texY = ySlice / maxY;
        float texZ = zSlice / maxZ;

315 316 317 318
        osg::Vec3Array* texCoords = new osg::Vec3Array;
        switch ( slice )
        {
            case 0:
schurade's avatar
schurade committed
319 320 321 322
                sliceVertices->push_back( osg::Vec3( 0,       yPos, 0      ) );
                sliceVertices->push_back( osg::Vec3( 0,       yPos, maxDim ) );
                sliceVertices->push_back( osg::Vec3( maxDim,  yPos, maxDim ) );
                sliceVertices->push_back( osg::Vec3( maxDim,  yPos, 0      ) );
323
                sliceGeometry->setVertexArray( sliceVertices );
schurade's avatar
schurade committed
324 325 326 327
                texCoords->push_back( osg::Vec3( 0.0, texY, 0.0 ) );
                texCoords->push_back( osg::Vec3( 0.0, texY, 1.0 ) );
                texCoords->push_back( osg::Vec3( 1.0, texY, 1.0 ) );
                texCoords->push_back( osg::Vec3( 1.0, texY, 0.0 ) );
328 329 330
                sliceGeometry->setTexCoordArray( 0, texCoords );
                break;
            case 1:
schurade's avatar
schurade committed
331 332 333 334
                sliceVertices->push_back( osg::Vec3( xPos, 0,      0      ) );
                sliceVertices->push_back( osg::Vec3( xPos, 0,      maxDim ) );
                sliceVertices->push_back( osg::Vec3( xPos, maxDim, maxDim ) );
                sliceVertices->push_back( osg::Vec3( xPos, maxDim, 0      ) );
335
                sliceGeometry->setVertexArray( sliceVertices );
schurade's avatar
schurade committed
336 337 338 339
                texCoords->push_back( osg::Vec3( texX, 0.0, 0.0 ) );
                texCoords->push_back( osg::Vec3( texX, 0.0, 1.0 ) );
                texCoords->push_back( osg::Vec3( texX, 1.0, 1.0 ) );
                texCoords->push_back( osg::Vec3( texX, 1.0, 0.0 ) );
340 341 342
                sliceGeometry->setTexCoordArray( 0, texCoords );
                break;
            case 2:
schurade's avatar
schurade committed
343 344 345 346
                sliceVertices->push_back( osg::Vec3( 0,      0,      zPos ) );
                sliceVertices->push_back( osg::Vec3( 0,      maxDim, zPos ) );
                sliceVertices->push_back( osg::Vec3( maxDim, maxDim, zPos ) );
                sliceVertices->push_back( osg::Vec3( maxDim, 0,      zPos ) );
347
                sliceGeometry->setVertexArray( sliceVertices );
schurade's avatar
schurade committed
348 349 350 351
                texCoords->push_back( osg::Vec3( 0.0, 0.0, texZ ) );
                texCoords->push_back( osg::Vec3( 0.0, 1.0, texZ ) );
                texCoords->push_back( osg::Vec3( 1.0, 1.0, texZ ) );
                texCoords->push_back( osg::Vec3( 1.0, 0.0, texZ ) );
352 353 354
                sliceGeometry->setTexCoordArray( 0, texCoords );
                break;
        }
355
    }
356

357 358 359 360 361 362
    osg::DrawElementsUInt* quad = new osg::DrawElementsUInt( osg::PrimitiveSet::QUADS, 0 );
    quad->push_back( 3 );
    quad->push_back( 2 );
    quad->push_back( 1 );
    quad->push_back( 0 );
    sliceGeometry->addPrimitiveSet( quad );
363

364
    return sliceGeometry;
365
}
366

367
void WMNavSlices::updateGeometry()
368
{
369 370
    boost::shared_lock<boost::shared_mutex> slock;
    slock = boost::shared_lock<boost::shared_mutex>( m_updateLock );
schurade's avatar
schurade committed
371

372 373 374 375 376 377 378 379 380 381 382 383 384 385
//    std::vector< boost::shared_ptr< WModule > > datasetList = WKernel::getRunningKernel()->getGui()->getDataSetList( 0 );
//    if ( datasetList.size() > 0 )
//    {
//        boost::shared_ptr< WDataSetSingle > ds = boost::shared_dynamic_cast< WDataSetSingle >( datasetList[0] );
//        boost::shared_ptr< WGridRegular3D > grid = boost::shared_dynamic_cast< WGridRegular3D >( ds->getGrid() );
//
//        float mx = grid->getNbCoordsX() * grid->getOffsetX();
//        float my = grid->getNbCoordsY() * grid->getOffsetY();
//        float mz = grid->getNbCoordsZ() * grid->getOffsetZ();
//
//        m_properties->setValue( "maxAxial", mx );
//        m_properties->setValue( "maxCoronal", my );
//        m_properties->setValue( "maxSagittal", mz );
//    }
386 387 388
    osg::ref_ptr<osg::Geometry> xSliceGeometry = createGeometry( 0 );
    osg::ref_ptr<osg::Geometry> ySliceGeometry = createGeometry( 1 );
    osg::ref_ptr<osg::Geometry> zSliceGeometry = createGeometry( 2 );
389 390 391 392 393 394 395 396

    osg::ref_ptr<osg::Drawable> oldx = osg::ref_ptr<osg::Drawable>( m_xSliceNode->getDrawable( 0 ) );
    m_xSliceNode->replaceDrawable( oldx, xSliceGeometry );
    osg::ref_ptr<osg::Drawable> oldy = osg::ref_ptr<osg::Drawable>( m_ySliceNode->getDrawable( 0 ) );
    m_ySliceNode->replaceDrawable( oldy, ySliceGeometry );
    osg::ref_ptr<osg::Drawable> oldz = osg::ref_ptr<osg::Drawable>( m_zSliceNode->getDrawable( 0 ) );
    m_zSliceNode->replaceDrawable( oldz, zSliceGeometry );

397
    if ( m_properties->getValue<bool>( "showAxial" ) )
398
    {
399 400 401 402 403
        m_zSliceNode->setNodeMask( 0xFFFFFFFF );
    }
    else
    {
        m_zSliceNode->setNodeMask( 0x0 );
404 405
    }

406
    if ( m_properties->getValue<bool>( "showCoronal" ) )
407
    {
408 409 410 411 412
        m_xSliceNode->setNodeMask( 0xFFFFFFFF );
    }
    else
    {
        m_xSliceNode->setNodeMask( 0x0 );
413 414
    }

415
    if ( m_properties->getValue<bool>( "showSagittal" ) )
416
    {
417 418 419 420 421
        m_ySliceNode->setNodeMask( 0xFFFFFFFF );
    }
    else
    {
        m_ySliceNode->setNodeMask( 0x0 );
422
    }
423 424

    slock.unlock();
425 426 427
}


428
void WMNavSlices::updateTextures()
429
{
430 431 432
    boost::shared_lock<boost::shared_mutex> slock;
    slock = boost::shared_lock<boost::shared_mutex>( m_updateLock );

433
    if ( m_properties->getValue< bool >( "textureChanged" ) && WKernel::getRunningKernel()->getGui()->isInitialized()() )
434
    {
435
        m_properties->setValue( "textureChanged", false );
436
        std::vector< boost::shared_ptr< WDataSet > > dsl = WKernel::getRunningKernel()->getGui()->getDataSetList( 0, true );
437

438
        if ( dsl.size() > 0 )
439 440 441 442 443
        {
            for ( int i = 0; i < 10; ++i )
            {
                m_typeUniforms[i]->set( 0 );
            }
444

445
            osg::StateSet* rootState = m_rootNode->getOrCreateStateSet();
446
            int c = 0;
447
            for ( size_t i = 0; i < dsl.size(); ++i )
448
            {
449
                osg::ref_ptr<osg::Texture3D> texture3D = dsl[i]->getTexture()->getTexture();
450

451
                rootState->setTextureAttributeAndModes( c, texture3D, osg::StateAttribute::ON );
452

453
                float t = dsl[i]->getTexture()->getThreshold() / 255.0;
454
                float a = dsl[i]->getTexture()->getAlpha();
455

456 457 458
                m_typeUniforms[c]->set( boost::shared_dynamic_cast<WDataSetSingle>( dsl[i] )->getValueSet()->getDataType() );
                m_thresholdUniforms[c]->set( t );
                m_alphaUniforms[c]->set( a );
459

460
                ++c;
461 462 463
            }
        }
    }
464
    slock.unlock();
465 466
}

467
void WMNavSlices::initUniforms( osg::StateSet* rootState )
468
{
469 470 471
    boost::shared_lock<boost::shared_mutex> slock;
    slock = boost::shared_lock<boost::shared_mutex>( m_updateLock );

472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514
    m_typeUniforms.push_back( osg::ref_ptr<osg::Uniform>( new osg::Uniform( "type0", 0 ) ) );
    m_typeUniforms.push_back( osg::ref_ptr<osg::Uniform>( new osg::Uniform( "type1", 0 ) ) );
    m_typeUniforms.push_back( osg::ref_ptr<osg::Uniform>( new osg::Uniform( "type2", 0 ) ) );
    m_typeUniforms.push_back( osg::ref_ptr<osg::Uniform>( new osg::Uniform( "type3", 0 ) ) );
    m_typeUniforms.push_back( osg::ref_ptr<osg::Uniform>( new osg::Uniform( "type4", 0 ) ) );
    m_typeUniforms.push_back( osg::ref_ptr<osg::Uniform>( new osg::Uniform( "type5", 0 ) ) );
    m_typeUniforms.push_back( osg::ref_ptr<osg::Uniform>( new osg::Uniform( "type6", 0 ) ) );
    m_typeUniforms.push_back( osg::ref_ptr<osg::Uniform>( new osg::Uniform( "type7", 0 ) ) );
    m_typeUniforms.push_back( osg::ref_ptr<osg::Uniform>( new osg::Uniform( "type8", 0 ) ) );
    m_typeUniforms.push_back( osg::ref_ptr<osg::Uniform>( new osg::Uniform( "type9", 0 ) ) );

    m_alphaUniforms.push_back( osg::ref_ptr<osg::Uniform>( new osg::Uniform( "alpha0", 1.0f ) ) );
    m_alphaUniforms.push_back( osg::ref_ptr<osg::Uniform>( new osg::Uniform( "alpha1", 1.0f ) ) );
    m_alphaUniforms.push_back( osg::ref_ptr<osg::Uniform>( new osg::Uniform( "alpha2", 1.0f ) ) );
    m_alphaUniforms.push_back( osg::ref_ptr<osg::Uniform>( new osg::Uniform( "alpha3", 1.0f ) ) );
    m_alphaUniforms.push_back( osg::ref_ptr<osg::Uniform>( new osg::Uniform( "alpha4", 1.0f ) ) );
    m_alphaUniforms.push_back( osg::ref_ptr<osg::Uniform>( new osg::Uniform( "alpha5", 1.0f ) ) );
    m_alphaUniforms.push_back( osg::ref_ptr<osg::Uniform>( new osg::Uniform( "alpha6", 1.0f ) ) );
    m_alphaUniforms.push_back( osg::ref_ptr<osg::Uniform>( new osg::Uniform( "alpha7", 1.0f ) ) );
    m_alphaUniforms.push_back( osg::ref_ptr<osg::Uniform>( new osg::Uniform( "alpha8", 1.0f ) ) );
    m_alphaUniforms.push_back( osg::ref_ptr<osg::Uniform>( new osg::Uniform( "alpha9", 1.0f ) ) );

    m_thresholdUniforms.push_back( osg::ref_ptr<osg::Uniform>( new osg::Uniform( "threshold0", 0.0f ) ) );
    m_thresholdUniforms.push_back( osg::ref_ptr<osg::Uniform>( new osg::Uniform( "threshold1", 0.0f ) ) );
    m_thresholdUniforms.push_back( osg::ref_ptr<osg::Uniform>( new osg::Uniform( "threshold2", 0.0f ) ) );
    m_thresholdUniforms.push_back( osg::ref_ptr<osg::Uniform>( new osg::Uniform( "threshold3", 0.0f ) ) );
    m_thresholdUniforms.push_back( osg::ref_ptr<osg::Uniform>( new osg::Uniform( "threshold4", 0.0f ) ) );
    m_thresholdUniforms.push_back( osg::ref_ptr<osg::Uniform>( new osg::Uniform( "threshold5", 0.0f ) ) );
    m_thresholdUniforms.push_back( osg::ref_ptr<osg::Uniform>( new osg::Uniform( "threshold6", 0.0f ) ) );
    m_thresholdUniforms.push_back( osg::ref_ptr<osg::Uniform>( new osg::Uniform( "threshold7", 0.0f ) ) );
    m_thresholdUniforms.push_back( osg::ref_ptr<osg::Uniform>( new osg::Uniform( "threshold8", 0.0f ) ) );
    m_thresholdUniforms.push_back( osg::ref_ptr<osg::Uniform>( new osg::Uniform( "threshold9", 0.0f ) ) );

    m_samplerUniforms.push_back( osg::ref_ptr<osg::Uniform>( new osg::Uniform( "tex0", 0 ) ) );
    m_samplerUniforms.push_back( osg::ref_ptr<osg::Uniform>( new osg::Uniform( "tex1", 1 ) ) );
    m_samplerUniforms.push_back( osg::ref_ptr<osg::Uniform>( new osg::Uniform( "tex2", 2 ) ) );
    m_samplerUniforms.push_back( osg::ref_ptr<osg::Uniform>( new osg::Uniform( "tex3", 3 ) ) );
    m_samplerUniforms.push_back( osg::ref_ptr<osg::Uniform>( new osg::Uniform( "tex4", 4 ) ) );
    m_samplerUniforms.push_back( osg::ref_ptr<osg::Uniform>( new osg::Uniform( "tex5", 5 ) ) );
    m_samplerUniforms.push_back( osg::ref_ptr<osg::Uniform>( new osg::Uniform( "tex6", 6 ) ) );
    m_samplerUniforms.push_back( osg::ref_ptr<osg::Uniform>( new osg::Uniform( "tex7", 7 ) ) );
    m_samplerUniforms.push_back( osg::ref_ptr<osg::Uniform>( new osg::Uniform( "tex8", 8 ) ) );
    m_samplerUniforms.push_back( osg::ref_ptr<osg::Uniform>( new osg::Uniform( "tex9", 9 ) ) );
515 516 517

    for ( int i = 0; i < 10; ++i )
    {
518 519 520 521
        rootState->addUniform( m_typeUniforms[i] );
        rootState->addUniform( m_thresholdUniforms[i] );
        rootState->addUniform( m_alphaUniforms[i] );
        rootState->addUniform( m_samplerUniforms[i] );
522
    }
523
    slock.unlock();
524
}