render_system.cpp
Go to the documentation of this file.
00001 /*
00002  * Copyright (c) 2011, Willow Garage, Inc.
00003  * All rights reserved.
00004  *
00005  * Redistribution and use in source and binary forms, with or without
00006  * modification, are permitted provided that the following conditions are met:
00007  *
00008  *     * Redistributions of source code must retain the above copyright
00009  *       notice, this list of conditions and the following disclaimer.
00010  *     * Redistributions in binary form must reproduce the above copyright
00011  *       notice, this list of conditions and the following disclaimer in the
00012  *       documentation and/or other materials provided with the distribution.
00013  *     * Neither the name of the Willow Garage, Inc. nor the names of its
00014  *       contributors may be used to endorse or promote products derived from
00015  *       this software without specific prior written permission.
00016  *
00017  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
00018  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00019  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00020  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
00021  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
00022  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
00023  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
00024  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
00025  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
00026  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
00027  * POSSIBILITY OF SUCH DAMAGE.
00028  */
00029 
00030 // This is required for QT_MAC_USE_COCOA to be set
00031 #include <QtCore/qglobal.h>
00032 
00033 #ifndef Q_OS_MAC
00034 #include <X11/Xlib.h>
00035 #include <X11/Xutil.h>
00036 #include <GL/glx.h>
00037 #endif
00038 
00039 #include <ros/package.h> // This dependency should be moved out of here, it is just used for a search path.
00040 #include <ros/console.h>
00041 
00042 #include <OGRE/OgreRenderWindow.h>
00043 
00044 #include "render_system.h"
00045 
00046 namespace rviz
00047 {
00048 
00049 RenderSystem* RenderSystem::instance_ = 0;
00050 
00051 RenderSystem* RenderSystem::get()
00052 {
00053   if( instance_ == 0 )
00054   {
00055     instance_ = new RenderSystem();
00056   }
00057   return instance_;
00058 }
00059 
00060 RenderSystem::RenderSystem()
00061 {
00062   setupDummyWindowId();
00063   ogre_root_ = new Ogre::Root();
00064   loadOgrePlugins();
00065   setupRenderSystem();
00066   ogre_root_->initialise(false);
00067   setupResources();
00068   makeRenderWindow( dummy_window_id_, 1, 1 );
00069   Ogre::ResourceGroupManager::getSingleton().initialiseAllResourceGroups();
00070 }
00071 
00072 void RenderSystem::setupDummyWindowId()
00073 {
00074 #ifdef Q_OS_MAC
00075   dummy_window_id_ = 0;
00076 #else
00077   Display *display = XOpenDisplay(0);
00078   assert( display );
00079 
00080   int screen = DefaultScreen( display );
00081 
00082   int attribList[] = { GLX_RGBA, GLX_DOUBLEBUFFER, GLX_DEPTH_SIZE, 16, 
00083                        GLX_STENCIL_SIZE, 8, None };
00084 
00085   XVisualInfo *visual = glXChooseVisual( display, screen, (int*)attribList );
00086 
00087   dummy_window_id_ = XCreateSimpleWindow( display,
00088                                           RootWindow( display, screen ),
00089                                           0, 0, 1, 1, 0, 0, 0 );
00090 
00091   GLXContext context = glXCreateContext( display, visual, NULL, 1 );
00092 
00093   glXMakeCurrent( display, dummy_window_id_, context );
00094 #endif
00095 }
00096 
00097 void RenderSystem::loadOgrePlugins()
00098 {
00099   std::string suffix = "";
00100 
00101   std::string plugin_prefix;
00102 #ifdef OGRE_PLUGIN_PATH
00103   // OGRE_PLUGIN_PATH is defined in package "ogre"'s manifest.xml in
00104   // the <export><cpp> entry for OSX.
00105   plugin_prefix = OGRE_PLUGIN_PATH + std::string("/");
00106 #endif
00107 
00108   ogre_root_->loadPlugin( plugin_prefix + "RenderSystem_GL" + suffix );
00109   ogre_root_->loadPlugin( plugin_prefix + "Plugin_OctreeSceneManager" + suffix );
00110   ogre_root_->loadPlugin( plugin_prefix + "Plugin_ParticleFX" + suffix );
00111   ogre_root_->loadPlugin( plugin_prefix + "Plugin_CgProgramManager" + suffix );
00112 }
00113 
00114 void RenderSystem::setupRenderSystem()
00115 {
00116   Ogre::RenderSystem *renderSys;
00117   const Ogre::RenderSystemList *rsList;
00118 
00119   // Get the list of available renderers.
00120 #if OGRE_VERSION_MAJOR == 1 && OGRE_VERSION_MINOR == 6
00121   rsList = ogre_root_->getAvailableRenderers();
00122 #else
00123   rsList = &(ogre_root_->getAvailableRenderers());
00124 #endif
00125    
00126   // Look for the OpenGL one, which we require.
00127   renderSys = NULL;
00128   for( unsigned int i = 0; i < rsList->size(); i++ )
00129   {
00130     renderSys = rsList->at( i );
00131     if( renderSys->getName().compare("OpenGL Rendering Subsystem")== 0 )
00132     {
00133       break;
00134     }
00135   }
00136 
00137   if( renderSys == NULL )
00138   {
00139     throw std::runtime_error( "Could not find the opengl rendering subsystem!\n" );
00140   }
00141 
00142   // We operate in windowed mode
00143   renderSys->setConfigOption("Full Screen","No");
00144 
00150   //  renderSys->setConfigOption("RTT Preferred Mode", "FBO");
00151 
00152   // Set the Full Screen Anti-Aliasing factor.
00153   renderSys->setConfigOption("FSAA", "2");
00154 
00155   ogre_root_->setRenderSystem(renderSys);
00156 }
00157 
00158 void RenderSystem::setupResources()
00159 {
00160   std::string rviz_path = ros::package::getPath(ROS_PACKAGE_NAME);
00161   Ogre::ResourceGroupManager::getSingleton().addResourceLocation( rviz_path + "/ogre_media", "FileSystem", ROS_PACKAGE_NAME );
00162   Ogre::ResourceGroupManager::getSingleton().addResourceLocation( rviz_path + "/ogre_media/textures", "FileSystem", ROS_PACKAGE_NAME );
00163   Ogre::ResourceGroupManager::getSingleton().addResourceLocation( rviz_path + "/ogre_media/fonts", "FileSystem", ROS_PACKAGE_NAME );
00164   Ogre::ResourceGroupManager::getSingleton().addResourceLocation( rviz_path + "/ogre_media/models", "FileSystem", ROS_PACKAGE_NAME );
00165   Ogre::ResourceGroupManager::getSingleton().addResourceLocation( rviz_path + "/ogre_media/materials", "FileSystem", ROS_PACKAGE_NAME );
00166   Ogre::ResourceGroupManager::getSingleton().addResourceLocation( rviz_path + "/ogre_media/materials/scripts", "FileSystem", ROS_PACKAGE_NAME );
00167   Ogre::ResourceGroupManager::getSingleton().addResourceLocation( rviz_path + "/ogre_media/materials/programs", "FileSystem", ROS_PACKAGE_NAME );
00168 }
00169 
00170 // On Intel graphics chips under X11, there sometimes comes a
00171 // BadDrawable error during Ogre render window creation.  It is not
00172 // consistent, happens sometimes but not always.  Underlying problem
00173 // seems to be a driver bug.  My workaround here is to notice when
00174 // that specific BadDrawable error happens on request 136 minor 3
00175 // (which is what the problem looks like when it happens) and just try
00176 // over and over again until it works (or until 100 failures, which
00177 // makes it seem like it is a different bug).
00178 static bool x_baddrawable_error = false;
00179 #ifdef Q_WS_X11
00180 static int (*old_error_handler)( Display*, XErrorEvent* );
00181 int checkBadDrawable( Display* display, XErrorEvent* error )
00182 {
00183   if( error->error_code == BadDrawable &&
00184       error->request_code == 136 &&
00185       error->minor_code == 3 )
00186   {
00187     x_baddrawable_error = true;
00188     return 0;
00189   }
00190   else
00191   {
00192     // If the error does not exactly match the one from the driver bug,
00193     // handle it the normal way so we see it.
00194     return old_error_handler( display, error );
00195   }
00196 }
00197 #endif // Q_WS_X11
00198 
00199 Ogre::RenderWindow* RenderSystem::makeRenderWindow( intptr_t window_id, unsigned int width, unsigned int height )
00200 {
00201   static int windowCounter = 0; // Every RenderWindow needs a unique name, oy.
00202 
00203   Ogre::NameValuePairList params;
00204   Ogre::RenderWindow *window = NULL;
00205 
00206   std::stringstream window_handle_stream;
00207   window_handle_stream << window_id;
00208 
00209 #ifdef Q_OS_MAC
00210   params["externalWindowHandle"] = window_handle_stream.str();
00211 #else
00212   params["parentWindowHandle"] = window_handle_stream.str();
00213 #endif
00214 
00215   params["externalGLControl"] = true;
00216 
00217 // Set the macAPI for Ogre based on the Qt implementation
00218 #ifdef QT_MAC_USE_COCOA
00219   params["macAPI"] = "cocoa";
00220   params["macAPICocoaUseNSView"] = "true";
00221 #else
00222   params["macAPI"] = "carbon";
00223 #endif
00224 
00225   std::ostringstream stream;
00226   stream << "OgreWindow(" << windowCounter++ << ")";
00227 
00228 #ifdef Q_WS_X11
00229   old_error_handler = XSetErrorHandler( &checkBadDrawable );
00230 #endif
00231 
00232   int attempts = 0;
00233   while (window == NULL && (attempts++) < 100)
00234   {
00235     try
00236     {
00237       window = ogre_root_->createRenderWindow( stream.str(), width, height, false, &params );
00238 
00239       // If the driver bug happened, tell Ogre we are done with that
00240       // window and then try again.
00241       if( x_baddrawable_error )
00242       {
00243         ogre_root_->detachRenderTarget( window );
00244         window = NULL;
00245         x_baddrawable_error = false;
00246       }
00247     }
00248     catch( std::exception ex )
00249     {
00250       std::cerr << "rviz::RenderSystem: error creating render window: "
00251                 << ex.what() << std::endl;
00252       window = NULL;
00253     }
00254   }
00255 
00256 #ifdef Q_WS_X11
00257   XSetErrorHandler( old_error_handler );
00258 #endif
00259 
00260   if( window == NULL )
00261   {
00262     ROS_ERROR( "Unable to create the rendering window after 100 tries." );
00263     assert(false);
00264   }
00265 
00266   if( attempts > 1 )
00267   {
00268     ROS_INFO( "Created render window after %d attempts.", attempts );
00269   }
00270 
00271   if (window)
00272   {
00273     window->setActive(true);
00274     //window->setVisible(true);
00275     window->setAutoUpdated(false);
00276   }
00277 
00278   return window;
00279 }
00280 
00281 } // end namespace rviz


rviz
Author(s): Dave Hershberger, Josh Faust
autogenerated on Mon Jan 6 2014 11:54:32