WGraphicsEngine.cpp 7.49 KB
Newer Older
ebaum's avatar
ebaum committed
1 2
//---------------------------------------------------------------------------
//
3
// Project: OpenWalnut ( http://www.openwalnut.org )
ebaum's avatar
ebaum committed
4
//
5 6
// Copyright 2009 OpenWalnut Community, BSV@Uni-Leipzig and CNCF@MPI-CBS
// For more information see http://www.openwalnut.org/copying
ebaum's avatar
ebaum committed
7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
//
// 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 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48
#include <stdlib.h>

#include <iostream>
#include <list>
#include <string>
#include <vector>

#include <boost/shared_ptr.hpp>
#include <boost/thread/locks.hpp>

#include <osg/Vec3>
#include <osg/Vec4>
#include <osg/ref_ptr>
#include <osgViewer/CompositeViewer>
#include <osgViewer/View>
#include <osgViewer/Viewer>

#include "../common/WColor.h"
#include "../common/WLogger.h"
#include "../common/WPathHelper.h"
#include "../common/math/linearAlgebra/WLinearAlgebra.h"
#include "WGEViewer.h"
#include "exceptions/WGEInitFailed.h"
#include "exceptions/WGESignalSubscriptionFailed.h"
49 50
#include "WGraphicsEngineMode.h"

51 52
#include "WStaticOSGSetup.h"

53
#include "WGraphicsEngine.h"
54 55 56 57 58 59 60 61 62

// graphics engine instance as singleton
boost::shared_ptr< WGraphicsEngine > WGraphicsEngine::m_instance = boost::shared_ptr< WGraphicsEngine >();

WGraphicsEngine::WGraphicsEngine():
    WThreadedRunner()
{
    WLogger::getLogger()->addLogMessage( "Initializing Graphics Engine", "GE", LL_INFO );

63
#ifdef WGEMODE_MULTITHREADED
64 65
    // initialize OSG render window
    m_viewer = osg::ref_ptr<osgViewer::CompositeViewer>( new osgViewer::CompositeViewer() );
66
    m_viewer->setThreadingModel( osgViewer::ViewerBase::SingleThreaded );
67 68 69 70
#endif

    // initialize members
    m_rootNode = new WGEScene();
71 72

    setThreadName( "WGE" );
73 74 75 76 77 78 79
}

WGraphicsEngine::~WGraphicsEngine()
{
    // cleanup
    WLogger::getLogger()->addLogMessage( "Shutting down Graphics Engine", "GE", LL_INFO );
}
80

81 82
void WGraphicsEngine::setMultiThreadedViews( bool enable )
{
83
#ifdef  WGEMODE_SINGLETHREADED
84
    if( enable )
85
    {
86
        WLogger::getLogger()->addLogMessage( "WGraphicsEngine::setMultiThreadedViews not implemented for single threaded mode", "GE", LL_INFO );
87 88
    }
#else
89 90 91 92 93 94 95 96 97
    // ThreadingModel: enum with the following possibilities
    //
    //  SingleThreaded
    //  CullDrawThreadPerContext
    //  ThreadPerContext
    //  DrawThreadPerContext
    //  CullThreadPerCameraDrawThreadPerContext
    //  ThreadPerCamera
    //  AutomaticSelection
98
    if( !enable )
99 100 101 102 103 104 105 106 107 108
    {
        m_viewer->setThreadingModel( osgViewer::Viewer::SingleThreaded );
    }
    else
    {
        m_viewer->setThreadingModel( osgViewer::Viewer::CullThreadPerCameraDrawThreadPerContext );
    }
#endif
}

109
bool WGraphicsEngine::isMultiThreadedViews() const
110
{
111
#ifdef WGEMODE_MULTITHREADED
112 113 114 115
    return ( osgViewer::Viewer::SingleThreaded != m_viewer->getThreadingModel() );
#endif
    // on mac, this always is false currently
    return false;
116 117 118 119
}

boost::shared_ptr< WGraphicsEngine > WGraphicsEngine::getGraphicsEngine()
{
120
    if( !m_instance )
121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141
    {
        m_instance = boost::shared_ptr< WGraphicsEngine >( new WGraphicsEngine() );
    }

    return m_instance;
}

osg::ref_ptr<WGEScene> WGraphicsEngine::getScene()
{
    return m_rootNode;
}

boost::shared_ptr<WGEViewer> WGraphicsEngine::createViewer( std::string name, osg::ref_ptr<osg::Referenced> wdata, int x, int y,
                                                            int width, int height, WGECamera::ProjectionMode projectionMode,
                                                            WColor bgColor )
{
    boost::shared_ptr<WGEViewer> viewer = boost::shared_ptr<WGEViewer>(
        new WGEViewer( name, wdata, x, y, width, height, projectionMode ) );
    viewer->setBgColor( bgColor );
    viewer->setScene( getScene() );

142
#ifdef WGEMODE_MULTITHREADED
143 144 145 146 147 148 149
    // finally add view
    m_viewer->addView( viewer->getView() );
#endif

    // store it in viewer list
    boost::mutex::scoped_lock lock( m_viewersLock );
    bool insertSucceeded = m_viewers.insert( make_pair( name, viewer ) ).second;
150
    assert( insertSucceeded == true ); // if false, viewer with same name already exists
151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177

    return viewer;
}

void WGraphicsEngine::closeViewer( const std::string name )
{
    boost::mutex::scoped_lock lock( m_viewersLock );
    if( m_viewers.count( name ) > 0 )
    {
        m_viewers[name]->close();

        m_viewers.erase( name );
    }
}

boost::shared_ptr< WGEViewer > WGraphicsEngine::getViewerByName( std::string name )
{
    boost::mutex::scoped_lock lock( m_viewersLock );
    boost::shared_ptr< WGEViewer > out = m_viewers.count( name ) > 0 ?
        m_viewers[name] :
        boost::shared_ptr< WGEViewer >();
    return out;
}

boost::shared_ptr< WGEViewer > WGraphicsEngine::getViewer()
{
    boost::mutex::scoped_lock lock( m_viewersLock );
178
    return m_viewers[ "Main View" ];
179 180 181 182
}

bool WGraphicsEngine::isRunning()
{
183
    if( !m_instance )
184 185 186 187 188 189 190
    {
        return false;
    }

    return m_instance->m_running;
}

191 192 193 194
bool WGraphicsEngine::waitForStartupComplete()
{
    if( !m_instance )
    {
195
        WLogger::getLogger()->addLogMessage( "Not Graphics Engine running", "GE", LL_INFO );
196 197 198
        return false;
    }

199
    WLogger::getLogger()->addLogMessage( "Blocking for graphics engine startup", "GE", LL_INFO );
200 201 202
    // this ensures that the startup is completed if returning.
    m_instance->m_startThreadingCondition.wait();

203
    WLogger::getLogger()->addLogMessage( "Done blocking for graphics engine startup, maybe running now", "GE", LL_INFO );
204 205 206 207
    // did something went wrong? Ensure by checking if really running.
    return isRunning();
}

208 209 210 211
void WGraphicsEngine::threadMain()
{
    WLogger::getLogger()->addLogMessage( "Starting Graphics Engine", "GE", LL_INFO );

212
#ifdef WGEMODE_MULTITHREADED
213 214
    // NOTE: this is needed here since the viewer might start without any widgets being initialized properly.
    m_startThreadingCondition.wait();
215 216 217 218 219
    m_running = true;
    m_viewer->startThreading();
    m_viewer->run();
    m_viewer->stopThreading();
    m_running = false;
220 221 222
#else
    //m_startThreadingCondition.wait();
    m_running = true; // we have to make sure, that we are "running"
223 224 225 226 227 228
#endif
}

void WGraphicsEngine::notifyStop()
{
    WLogger::getLogger()->addLogMessage( "Stopping Graphics Engine", "GE", LL_INFO );
229
#ifdef WGEMODE_MULTITHREADED
230 231 232 233
    m_viewer->setDone( true );
#endif
}

234 235 236 237 238
void WGraphicsEngine::finalizeStartup()
{
    m_startThreadingCondition.notify();
}

239 240 241 242 243 244 245
void WGraphicsEngine::requestShaderReload()
{
    m_reloadShadersSignal();
}

boost::signals2::connection WGraphicsEngine::subscribeSignal( GE_SIGNAL signal, t_GEGenericSignalHandlerType notifier )
{
246
    switch( signal )
247 248 249
    {
        case GE_RELOADSHADERS:
            return m_reloadShadersSignal.connect( notifier );
250 251
        case GE_STARTUPCOMPLETE:
            return m_startThreadingCondition.subscribeSignal( notifier );
252 253 254 255 256 257 258
        default:
            std::ostringstream s;
            s << "Could not subscribe to unknown signal.";
            throw WGESignalSubscriptionFailed( s.str() );
            break;
    }
}