00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030 #include <sstream>
00031
00032 #include <QMetaType>
00033
00034
00035 #include <QtCore/qglobal.h>
00036
00037 #ifndef Q_OS_MAC
00038 #include <X11/Xlib.h>
00039 #include <X11/Xutil.h>
00040 #include <GL/glx.h>
00041 #endif
00042
00043
00044
00045
00046 #ifdef CursorShape
00047 #undef CursorShape
00048 #endif
00049
00050 #include <ros/package.h>
00051 #include <ros/console.h>
00052
00053 #include <OgreRenderWindow.h>
00054 #include <OgreSceneManager.h>
00055 #if ((OGRE_VERSION_MAJOR == 1 && OGRE_VERSION_MINOR >= 9) || OGRE_VERSION_MAJOR >= 2 )
00056 #include <OgreOverlaySystem.h>
00057 #endif
00058
00059 #include "rviz/env_config.h"
00060 #include "rviz/ogre_helpers/ogre_logging.h"
00061
00062 #include "rviz/ogre_helpers/render_system.h"
00063
00064 #include <QMessageBox>
00065
00066 namespace rviz
00067 {
00068
00069 RenderSystem* RenderSystem::instance_ = 0;
00070 int RenderSystem::force_gl_version_ = 0;
00071 bool RenderSystem::use_anti_aliasing_ = true;
00072 bool RenderSystem::force_no_stereo_ = false;
00073
00074 RenderSystem* RenderSystem::get()
00075 {
00076 if( instance_ == 0 )
00077 {
00078 instance_ = new RenderSystem();
00079 }
00080 return instance_;
00081 }
00082
00083 void RenderSystem::forceGlVersion( int version )
00084 {
00085 force_gl_version_ = version;
00086 ROS_INFO_STREAM( "Forcing OpenGl version " << (float)version / 100.0 << "." );
00087 }
00088
00089 void RenderSystem::disableAntiAliasing()
00090 {
00091 use_anti_aliasing_ = false;
00092 ROS_INFO("Disabling Anti-Aliasing");
00093 }
00094
00095 void RenderSystem::forceNoStereo()
00096 {
00097 force_no_stereo_ = true;
00098 ROS_INFO("Forcing Stereo OFF");
00099 }
00100
00101 RenderSystem::RenderSystem()
00102 : ogre_overlay_system_(NULL)
00103 , stereo_supported_(false)
00104 {
00105 OgreLogging::configureLogging();
00106
00107 std::string rviz_path = ros::package::getPath(ROS_PACKAGE_NAME);
00108
00109 setupDummyWindowId();
00110 ogre_root_ = new Ogre::Root( rviz_path+"/ogre_media/plugins.cfg" );
00111 #if ((OGRE_VERSION_MAJOR == 1 && OGRE_VERSION_MINOR >= 9) || OGRE_VERSION_MAJOR >= 2 )
00112 ogre_overlay_system_ = new Ogre::OverlaySystem();
00113 #endif
00114 loadOgrePlugins();
00115 setupRenderSystem();
00116 ogre_root_->initialise(false);
00117 makeRenderWindow( dummy_window_id_, 1, 1 );
00118 detectGlVersion();
00119 setupResources();
00120 Ogre::ResourceGroupManager::getSingleton().initialiseAllResourceGroups();
00121 }
00122
00123 void RenderSystem::prepareOverlays(Ogre::SceneManager* scene_manager)
00124 {
00125 #if ((OGRE_VERSION_MAJOR == 1 && OGRE_VERSION_MINOR >= 9) || OGRE_VERSION_MAJOR >= 2 )
00126 if (ogre_overlay_system_)
00127 scene_manager->addRenderQueueListener(ogre_overlay_system_);
00128 #endif
00129 }
00130
00131 void RenderSystem::setupDummyWindowId()
00132 {
00133 #ifdef Q_OS_MAC
00134 dummy_window_id_ = 0;
00135 #else
00136 Display *display = XOpenDisplay(0);
00137 assert( display );
00138
00139 int screen = DefaultScreen( display );
00140
00141 int attribList[] = { GLX_RGBA, GLX_DOUBLEBUFFER, GLX_DEPTH_SIZE, 16,
00142 GLX_STENCIL_SIZE, 8, None };
00143
00144 XVisualInfo *visual = glXChooseVisual( display, screen, (int*)attribList );
00145
00146 dummy_window_id_ = XCreateSimpleWindow( display,
00147 RootWindow( display, screen ),
00148 0, 0, 1, 1, 0, 0, 0 );
00149
00150 GLXContext context = glXCreateContext( display, visual, NULL, 1 );
00151
00152 glXMakeCurrent( display, dummy_window_id_, context );
00153 #endif
00154 }
00155
00156 void RenderSystem::loadOgrePlugins()
00157 {
00158 std::string plugin_prefix = get_ogre_plugin_path() + "/";
00159 #ifdef Q_OS_MAC
00160 plugin_prefix += "lib";
00161 #endif
00162 ogre_root_->loadPlugin( plugin_prefix + "RenderSystem_GL" );
00163 ogre_root_->loadPlugin( plugin_prefix + "Plugin_OctreeSceneManager" );
00164 ogre_root_->loadPlugin( plugin_prefix + "Plugin_ParticleFX" );
00165 }
00166
00167 void RenderSystem::detectGlVersion()
00168 {
00169 if ( force_gl_version_ )
00170 {
00171 gl_version_ = force_gl_version_;
00172 }
00173 else
00174 {
00175 Ogre::RenderSystem *renderSys = ogre_root_->getRenderSystem();
00176 renderSys->createRenderSystemCapabilities();
00177 const Ogre::RenderSystemCapabilities* caps = renderSys->getCapabilities();
00178 int major = caps->getDriverVersion().major;
00179 int minor = caps->getDriverVersion().minor;
00180 gl_version_ = major * 100 + minor*10;
00181 }
00182
00183 switch ( gl_version_ )
00184 {
00185 case 200:
00186 glsl_version_ = 110;
00187 break;
00188 case 210:
00189 glsl_version_ = 120;
00190 break;
00191 case 300:
00192 glsl_version_ = 130;
00193 break;
00194 case 310:
00195 glsl_version_ = 140;
00196 break;
00197 case 320:
00198 glsl_version_ = 150;
00199 break;
00200 default:
00201 if ( gl_version_ > 320 )
00202 {
00203 glsl_version_ = gl_version_;
00204 }
00205 else
00206 {
00207 glsl_version_ = 0;
00208 }
00209 break;
00210 }
00211 ROS_INFO_STREAM( "OpenGl version: " << (float)gl_version_ / 100.0 << " (GLSL " << (float)glsl_version_ / 100.0 << ")." );
00212 }
00213
00214 void RenderSystem::setupRenderSystem()
00215 {
00216 Ogre::RenderSystem *renderSys;
00217 const Ogre::RenderSystemList *rsList;
00218
00219
00220 #if OGRE_VERSION_MAJOR == 1 && OGRE_VERSION_MINOR == 6
00221 rsList = ogre_root_->getAvailableRenderers();
00222 #else
00223 rsList = &(ogre_root_->getAvailableRenderers());
00224 #endif
00225
00226
00227 renderSys = NULL;
00228 for( unsigned int i = 0; i < rsList->size(); i++ )
00229 {
00230 renderSys = rsList->at( i );
00231 if( renderSys->getName().compare("OpenGL Rendering Subsystem")== 0 )
00232 {
00233 break;
00234 }
00235 }
00236
00237 if( renderSys == NULL )
00238 {
00239 throw std::runtime_error( "Could not find the opengl rendering subsystem!\n" );
00240 }
00241
00242
00243 renderSys->setConfigOption("Full Screen","No");
00244
00250
00251
00252
00253 if (use_anti_aliasing_) {
00254 renderSys->setConfigOption("FSAA", "4");
00255 }
00256
00257 ogre_root_->setRenderSystem(renderSys);
00258 }
00259
00260 void RenderSystem::setupResources()
00261 {
00262 std::string rviz_path = ros::package::getPath(ROS_PACKAGE_NAME);
00263 Ogre::ResourceGroupManager::getSingleton().addResourceLocation( rviz_path + "/ogre_media", "FileSystem", ROS_PACKAGE_NAME );
00264 Ogre::ResourceGroupManager::getSingleton().addResourceLocation( rviz_path + "/ogre_media/textures", "FileSystem", ROS_PACKAGE_NAME );
00265 Ogre::ResourceGroupManager::getSingleton().addResourceLocation( rviz_path + "/ogre_media/fonts", "FileSystem", ROS_PACKAGE_NAME );
00266 Ogre::ResourceGroupManager::getSingleton().addResourceLocation( rviz_path + "/ogre_media/models", "FileSystem", ROS_PACKAGE_NAME );
00267 Ogre::ResourceGroupManager::getSingleton().addResourceLocation( rviz_path + "/ogre_media/materials", "FileSystem", ROS_PACKAGE_NAME );
00268 Ogre::ResourceGroupManager::getSingleton().addResourceLocation( rviz_path + "/ogre_media/materials/scripts", "FileSystem", ROS_PACKAGE_NAME );
00269 Ogre::ResourceGroupManager::getSingleton().addResourceLocation( rviz_path + "/ogre_media/materials/glsl120", "FileSystem", ROS_PACKAGE_NAME );
00270 Ogre::ResourceGroupManager::getSingleton().addResourceLocation( rviz_path + "/ogre_media/materials/glsl120/nogp", "FileSystem", ROS_PACKAGE_NAME );
00271
00272
00273
00274 if ( getGlslVersion() >= 150 )
00275 {
00276 Ogre::ResourceGroupManager::getSingleton().addResourceLocation( rviz_path + "/ogre_media/materials/glsl150", "FileSystem", ROS_PACKAGE_NAME );
00277 Ogre::ResourceGroupManager::getSingleton().addResourceLocation( rviz_path + "/ogre_media/materials/scripts150", "FileSystem", ROS_PACKAGE_NAME );
00278 }
00279 else if ( getGlslVersion() >= 120 )
00280 {
00281 Ogre::ResourceGroupManager::getSingleton().addResourceLocation( rviz_path + "/ogre_media/materials/scripts120", "FileSystem", ROS_PACKAGE_NAME );
00282 }
00283 else
00284 {
00285 std::string s = "Your graphics driver does not support OpenGL 2.1. Please enable software rendering before running RViz (e.g. type 'export LIBGL_ALWAYS_SOFTWARE=1').";
00286 QMessageBox msgBox;
00287 msgBox.setText(s.c_str());
00288 msgBox.exec();
00289 throw std::runtime_error( s );
00290 }
00291
00292
00293 std::vector<std::string> media_paths;
00294 ros::package::getPlugins( "media_export", "ogre_media_path", media_paths );
00295 std::string delim(":");
00296 for( std::vector<std::string>::iterator iter = media_paths.begin(); iter != media_paths.end(); iter++ )
00297 {
00298 if( !iter->empty() )
00299 {
00300 std::string path;
00301 int pos1 = 0;
00302 int pos2 = iter->find(delim);
00303 while( pos2 != (int)std::string::npos )
00304 {
00305 path = iter->substr( pos1, pos2 - pos1 );
00306 ROS_DEBUG("adding resource location: '%s'\n", path.c_str());
00307 Ogre::ResourceGroupManager::getSingleton().addResourceLocation( path, "FileSystem", ROS_PACKAGE_NAME );
00308 pos1 = pos2 + 1;
00309 pos2 = iter->find( delim, pos2 + 1 );
00310 }
00311 path = iter->substr( pos1, iter->size() - pos1 );
00312 ROS_DEBUG("adding resource location: '%s'\n", path.c_str());
00313 Ogre::ResourceGroupManager::getSingleton().addResourceLocation( path, "FileSystem", ROS_PACKAGE_NAME );
00314 }
00315 }
00316 }
00317
00318
00319
00320
00321
00322
00323
00324
00325
00326 static bool x_baddrawable_error = false;
00327 #ifdef Q_WS_X11
00328 static int (*old_error_handler)( Display*, XErrorEvent* );
00329 int checkBadDrawable( Display* display, XErrorEvent* error )
00330 {
00331 if( error->error_code == BadDrawable &&
00332 error->request_code == 136 &&
00333 error->minor_code == 3 )
00334 {
00335 x_baddrawable_error = true;
00336 return 0;
00337 }
00338 else
00339 {
00340
00341
00342 return old_error_handler( display, error );
00343 }
00344 }
00345 #endif // Q_WS_X11
00346
00347 Ogre::RenderWindow* RenderSystem::makeRenderWindow( intptr_t window_id, unsigned int width, unsigned int height, double pixel_ratio )
00348 {
00349 static int windowCounter = 0;
00350
00351 Ogre::NameValuePairList params;
00352 Ogre::RenderWindow *window = NULL;
00353
00354 std::stringstream window_handle_stream;
00355 window_handle_stream << window_id;
00356
00357 #ifdef Q_OS_MAC
00358 params["externalWindowHandle"] = window_handle_stream.str();
00359 #else
00360 params["parentWindowHandle"] = window_handle_stream.str();
00361 #endif
00362
00363 params["externalGLControl"] = true;
00364
00365
00366 if (use_anti_aliasing_) {
00367 params["FSAA"] = "4";
00368 }
00369
00370
00371 #ifdef QT_MAC_USE_COCOA
00372 params["macAPI"] = "cocoa";
00373 params["macAPICocoaUseNSView"] = "true";
00374 #else
00375 params["macAPI"] = "carbon";
00376 #endif
00377 {
00378 std::stringstream ss;
00379 ss << pixel_ratio;
00380 params["contentScalingFactor"] = ss.str();
00381 }
00382
00383 std::ostringstream stream;
00384 stream << "OgreWindow(" << windowCounter++ << ")";
00385
00386
00387
00388 #if !OGRE_STEREO_ENABLE
00389 force_no_stereo_ = true;
00390 #endif
00391
00392
00393 bool is_stereo = false;
00394 if (!force_no_stereo_)
00395 {
00396 params["stereoMode"] = "Frame Sequential";
00397 window = tryMakeRenderWindow( stream.str(), width, height, ¶ms, 100);
00398 params.erase("stereoMode");
00399
00400 if (window)
00401 {
00402 #if OGRE_STEREO_ENABLE
00403 is_stereo = window->isStereoEnabled();
00404 #endif
00405 if (!is_stereo)
00406 {
00407
00408
00409 ogre_root_->detachRenderTarget(window);
00410 window->destroy();
00411 window = NULL;
00412 stream << "x";
00413 is_stereo = false;
00414 }
00415 }
00416 }
00417
00418 if ( window == NULL )
00419 {
00420 window = tryMakeRenderWindow( stream.str(), width, height, ¶ms, 100);
00421 }
00422
00423 if( window == NULL )
00424 {
00425 ROS_ERROR( "Unable to create the rendering window after 100 tries." );
00426 assert(false);
00427 }
00428
00429 if (window)
00430 {
00431 window->setActive(true);
00432
00433 window->setAutoUpdated(false);
00434 }
00435
00436 stereo_supported_ = is_stereo;
00437
00438 ROS_INFO_ONCE("Stereo is %s", stereo_supported_ ? "SUPPORTED" : "NOT SUPPORTED");
00439
00440 return window;
00441 }
00442
00443 Ogre::RenderWindow* RenderSystem::tryMakeRenderWindow(
00444 const std::string& name,
00445 unsigned int width,
00446 unsigned int height,
00447 const Ogre::NameValuePairList* params,
00448 int max_attempts )
00449 {
00450 Ogre::RenderWindow *window = NULL;
00451 int attempts = 0;
00452
00453 #ifdef Q_WS_X11
00454 old_error_handler = XSetErrorHandler( &checkBadDrawable );
00455 #endif
00456
00457 while (window == NULL && (attempts++) < max_attempts)
00458 {
00459 try
00460 {
00461 window = ogre_root_->createRenderWindow( name, width, height, false, params );
00462
00463
00464
00465 if( x_baddrawable_error )
00466 {
00467 ogre_root_->detachRenderTarget( window );
00468 window = NULL;
00469 x_baddrawable_error = false;
00470 }
00471 }
00472 catch( std::exception ex )
00473 {
00474 std::cerr << "rviz::RenderSystem: error creating render window: "
00475 << ex.what() << std::endl;
00476 window = NULL;
00477 }
00478 }
00479
00480 #ifdef Q_WS_X11
00481 XSetErrorHandler( old_error_handler );
00482 #endif
00483
00484 if( window && attempts > 1 )
00485 {
00486 ROS_INFO( "Created render window after %d attempts.", attempts );
00487 }
00488
00489 return window;
00490 }
00491
00492
00493 }