OpenWalnut  1.4.0
WGraphicsEngine.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 <stdlib.h>
00026 
00027 #include <iostream>
00028 #include <list>
00029 #include <string>
00030 #include <vector>
00031 
00032 #include <boost/shared_ptr.hpp>
00033 #include <boost/thread/locks.hpp>
00034 
00035 #include <osg/Vec3>
00036 #include <osg/Vec4>
00037 #include <osg/ref_ptr>
00038 #include <osgViewer/CompositeViewer>
00039 #include <osgViewer/View>
00040 #include <osgViewer/Viewer>
00041 
00042 #include "../common/WColor.h"
00043 #include "../common/WLogger.h"
00044 #include "../common/WPathHelper.h"
00045 #include "WGEViewer.h"
00046 #include "exceptions/WGEInitFailed.h"
00047 #include "exceptions/WGESignalSubscriptionFailed.h"
00048 #include "WGraphicsEngineMode.h"
00049 #include "postprocessing/WGEPostprocessor.h"
00050 
00051 #include "WStaticOSGSetup.h"
00052 
00053 #include "WGraphicsEngine.h"
00054 
00055 // graphics engine instance as singleton
00056 boost::shared_ptr< WGraphicsEngine > WGraphicsEngine::m_instance = boost::shared_ptr< WGraphicsEngine >();
00057 
00058 WGraphicsEngine::WGraphicsEngine():
00059     WThreadedRunner()
00060 {
00061     WLogger::getLogger()->addLogMessage( "Initializing Graphics Engine", "GE", LL_INFO );
00062 
00063 #ifdef WGEMODE_MULTITHREADED
00064     // initialize OSG render window
00065     m_viewer = osg::ref_ptr<osgViewer::CompositeViewer>( new osgViewer::CompositeViewer() );
00066     m_viewer->setThreadingModel( osgViewer::ViewerBase::SingleThreaded );
00067 #endif
00068 
00069     // initialize members
00070     m_rootNode = new WGEScene();
00071 
00072     setThreadName( "WGE" );
00073 }
00074 
00075 WGraphicsEngine::~WGraphicsEngine()
00076 {
00077     // cleanup
00078     WLogger::getLogger()->addLogMessage( "Shutting down Graphics Engine", "GE", LL_INFO );
00079 }
00080 
00081 void WGraphicsEngine::setMultiThreadedViews( bool enable )
00082 {
00083 #ifdef  WGEMODE_SINGLETHREADED
00084     if( enable )
00085     {
00086         WLogger::getLogger()->addLogMessage( "WGraphicsEngine::setMultiThreadedViews not implemented for single threaded mode", "GE", LL_INFO );
00087     }
00088 #else
00089     // ThreadingModel: enum with the following possibilities
00090     //
00091     //  SingleThreaded
00092     //  CullDrawThreadPerContext
00093     //  ThreadPerContext
00094     //  DrawThreadPerContext
00095     //  CullThreadPerCameraDrawThreadPerContext
00096     //  ThreadPerCamera
00097     //  AutomaticSelection
00098     if( !enable )
00099     {
00100         m_viewer->setThreadingModel( osgViewer::Viewer::SingleThreaded );
00101     }
00102     else
00103     {
00104         m_viewer->setThreadingModel( osgViewer::Viewer::CullThreadPerCameraDrawThreadPerContext );
00105     }
00106 #endif
00107 }
00108 
00109 bool WGraphicsEngine::isMultiThreadedViews() const
00110 {
00111 #ifdef WGEMODE_MULTITHREADED
00112     return ( osgViewer::Viewer::SingleThreaded != m_viewer->getThreadingModel() );
00113 #endif
00114     // on mac, this always is false currently
00115     return false;
00116 }
00117 
00118 boost::shared_ptr< WGraphicsEngine > WGraphicsEngine::getGraphicsEngine()
00119 {
00120     if( !m_instance )
00121     {
00122         m_instance = boost::shared_ptr< WGraphicsEngine >( new WGraphicsEngine() );
00123     }
00124 
00125     return m_instance;
00126 }
00127 
00128 osg::ref_ptr<WGEScene> WGraphicsEngine::getScene()
00129 {
00130     return m_rootNode;
00131 }
00132 
00133 boost::shared_ptr<WGEViewer> WGraphicsEngine::createViewer( std::string name, osg::ref_ptr<osg::Referenced> wdata, int x, int y,
00134                                                             int width, int height, WGECamera::ProjectionMode projectionMode,
00135                                                             WColor bgColor )
00136 {
00137     boost::shared_ptr<WGEViewer> viewer = boost::shared_ptr<WGEViewer>(
00138         new WGEViewer( name, wdata, x, y, width, height, projectionMode ) );
00139     viewer->setBgColor( bgColor );
00140     viewer->setScene( getScene() );
00141 
00142 #ifdef WGEMODE_MULTITHREADED
00143     // finally add view
00144     m_viewer->addView( viewer->getView() );
00145 #endif
00146 
00147     // store it in viewer list
00148     boost::mutex::scoped_lock lock( m_viewersLock );
00149     bool insertSucceeded = m_viewers.insert( make_pair( name, viewer ) ).second;
00150     assert( insertSucceeded == true ); // if false, viewer with same name already exists
00151 
00152     return viewer;
00153 }
00154 
00155 void WGraphicsEngine::closeViewer( const std::string name )
00156 {
00157     boost::mutex::scoped_lock lock( m_viewersLock );
00158     if( m_viewers.count( name ) > 0 )
00159     {
00160         m_viewers[name]->close();
00161 
00162         m_viewers.erase( name );
00163     }
00164 }
00165 
00166 boost::shared_ptr< WGEViewer > WGraphicsEngine::getViewerByName( std::string name )
00167 {
00168     boost::mutex::scoped_lock lock( m_viewersLock );
00169     boost::shared_ptr< WGEViewer > out = m_viewers.count( name ) > 0 ?
00170         m_viewers[name] :
00171         boost::shared_ptr< WGEViewer >();
00172     return out;
00173 }
00174 
00175 boost::shared_ptr< WGEViewer > WGraphicsEngine::getViewer()
00176 {
00177     boost::mutex::scoped_lock lock( m_viewersLock );
00178     return m_viewers[ "Main View" ];
00179 }
00180 
00181 bool WGraphicsEngine::isRunning()
00182 {
00183     if( !m_instance )
00184     {
00185         return false;
00186     }
00187 
00188     return m_instance->m_running;
00189 }
00190 
00191 bool WGraphicsEngine::waitForStartupComplete()
00192 {
00193     if( !m_instance )
00194     {
00195         WLogger::getLogger()->addLogMessage( "Not Graphics Engine running", "GE", LL_INFO );
00196         return false;
00197     }
00198 
00199     WLogger::getLogger()->addLogMessage( "Blocking for graphics engine startup", "GE", LL_INFO );
00200     // this ensures that the startup is completed if returning.
00201     m_instance->m_startThreadingCondition.wait();
00202 
00203     WLogger::getLogger()->addLogMessage( "Done blocking for graphics engine startup, maybe running now", "GE", LL_INFO );
00204     // did something went wrong? Ensure by checking if really running.
00205     return isRunning();
00206 }
00207 
00208 void WGraphicsEngine::threadMain()
00209 {
00210     WLogger::getLogger()->addLogMessage( "Starting Graphics Engine", "GE", LL_INFO );
00211 
00212     // initialize all available postprocessors
00213     WGEPostprocessor::initPostprocessors();
00214 
00215 #ifdef WGEMODE_MULTITHREADED
00216     // NOTE: this is needed here since the viewer might start without any widgets being initialized properly.
00217     m_startThreadingCondition.wait();
00218     m_running = true;
00219     m_viewer->startThreading();
00220     m_viewer->run();
00221     m_viewer->stopThreading();
00222     m_running = false;
00223 #else
00224     //m_startThreadingCondition.wait();
00225     m_running = true; // we have to make sure, that we are "running"
00226 #endif
00227 }
00228 
00229 void WGraphicsEngine::notifyStop()
00230 {
00231     // when stopping the system while the GE is still waiting.
00232     m_startThreadingCondition.notify();
00233     WLogger::getLogger()->addLogMessage( "Stopping Graphics Engine", "GE", LL_INFO );
00234 #ifdef WGEMODE_MULTITHREADED
00235     m_viewer->setDone( true );
00236 #endif
00237 }
00238 
00239 void WGraphicsEngine::finalizeStartup()
00240 {
00241     m_startThreadingCondition.notify();
00242 }
00243 
00244 void WGraphicsEngine::waitForFinalize()
00245 {
00246     m_startThreadingCondition.wait();
00247 }
00248 
00249 void WGraphicsEngine::requestShaderReload()
00250 {
00251     m_reloadShadersSignal();
00252 }
00253 
00254 boost::signals2::connection WGraphicsEngine::subscribeSignal( GE_SIGNAL signal, t_GEGenericSignalHandlerType notifier )
00255 {
00256     switch( signal )
00257     {
00258         case GE_RELOADSHADERS:
00259             return m_reloadShadersSignal.connect( notifier );
00260         case GE_STARTUPCOMPLETE:
00261             return m_startThreadingCondition.subscribeSignal( notifier );
00262         default:
00263             std::ostringstream s;
00264             s << "Could not subscribe to unknown signal.";
00265             throw WGESignalSubscriptionFailed( s.str() );
00266             break;
00267     }
00268 }