$search
00001 #include "wx_ogre_render_window.h" 00002 #include "orthographic.h" 00003 00004 #include <OGRE/OgreRoot.h> 00005 #include <OGRE/OgreViewport.h> 00006 #include <OGRE/OgreCamera.h> 00007 #include <OGRE/OgreRenderWindow.h> 00008 #include <OGRE/OgreStringConverter.h> 00009 00010 #ifdef __WXGTK__ 00011 #include <gdk/gdk.h> 00012 #include <gtk/gtk.h> 00013 #include <gdk/gdkx.h> 00014 #include <wx/gtk/win_gtk.h> 00015 #include <GL/glx.h> 00016 #endif 00017 00018 #include <ros/console.h> 00019 #include <ros/assert.h> 00020 00021 #if OGRE_PLATFORM == OGRE_PLATFORM_LINUX 00022 #include <stdlib.h> 00023 #endif 00024 00025 namespace ogre_tools 00026 { 00027 00028 IMPLEMENT_CLASS (wxOgreRenderWindow, wxControl) 00029 00030 BEGIN_EVENT_TABLE (wxOgreRenderWindow, wxControl) 00031 EVT_PAINT (wxOgreRenderWindow::onPaint) 00032 EVT_SIZE (wxOgreRenderWindow::onSize) 00033 EVT_MOUSE_EVENTS (wxOgreRenderWindow::onMouseEvents) 00034 EVT_MOVE(wxOgreRenderWindow::onMove) 00035 END_EVENT_TABLE () 00036 00037 //------------------------------------------------------------------------------ 00038 unsigned int wxOgreRenderWindow::sm_NextRenderWindowId = 1; 00039 //------------------------------------------------------------------------------ 00040 wxOgreRenderWindow::wxOgreRenderWindow (Ogre::Root* ogre_root, wxWindow *parent, wxWindowID id, 00041 const wxPoint &pos, const wxSize &size, long style, const wxValidator &validator, bool create_render_window) 00042 : wxControl( parent, id, pos, size, style, validator ) 00043 , render_window_( 0 ) 00044 , ogre_root_( ogre_root ) 00045 , ortho_scale_( 1.0f ) 00046 , auto_render_(true) 00047 { 00048 SetBackgroundStyle(wxBG_STYLE_CUSTOM); 00049 00050 if (create_render_window) 00051 { 00052 createRenderWindow(); 00053 } 00054 } 00055 00056 //------------------------------------------------------------------------------ 00057 wxOgreRenderWindow::~wxOgreRenderWindow () 00058 { 00059 if (render_window_) 00060 { 00061 render_window_->removeViewport( 0 ); 00062 render_window_->destroy(); 00063 ogre_root_->detachRenderTarget(render_window_); 00064 } 00065 00066 render_window_ = 0; 00067 } 00068 00069 //------------------------------------------------------------------------------ 00070 inline wxSize wxOgreRenderWindow::DoGetBestSize () const 00071 { 00072 return wxSize (320, 240); 00073 } 00074 //------------------------------------------------------------------------------ 00075 Ogre::RenderWindow* wxOgreRenderWindow::getRenderWindow () const 00076 { 00077 return render_window_; 00078 } 00079 00080 //------------------------------------------------------------------------------ 00081 Ogre::Viewport* wxOgreRenderWindow::getViewport () const 00082 { 00083 return viewport_; 00084 } 00085 00086 void wxOgreRenderWindow::setCamera( Ogre::Camera* camera ) 00087 { 00088 viewport_->setCamera( camera ); 00089 00090 setCameraAspectRatio(); 00091 00092 Refresh(); 00093 } 00094 00095 void wxOgreRenderWindow::setCameraAspectRatio() 00096 { 00097 Ogre::Camera* camera = viewport_->getCamera(); 00098 if ( camera ) 00099 { 00100 int width; 00101 int height; 00102 GetSize( &width, &height ); 00103 00104 camera->setAspectRatio( Ogre::Real( width ) / Ogre::Real( height ) ); 00105 00106 if ( camera->getProjectionType() == Ogre::PT_ORTHOGRAPHIC ) 00107 { 00108 Ogre::Matrix4 proj; 00109 buildScaledOrthoMatrix( proj, -width / ortho_scale_ / 2, width / ortho_scale_ / 2, -height / ortho_scale_ / 2, height / ortho_scale_ / 2, 00110 camera->getNearClipDistance(), camera->getFarClipDistance() ); 00111 camera->setCustomProjectionMatrix(true, proj); 00112 } 00113 } 00114 } 00115 00116 void wxOgreRenderWindow::setOrthoScale( float scale ) 00117 { 00118 ortho_scale_ = scale; 00119 00120 setCameraAspectRatio(); 00121 } 00122 00123 void wxOgreRenderWindow::setPreRenderCallback( boost::function<void ()> func ) 00124 { 00125 pre_render_callback_ = func; 00126 } 00127 00128 void wxOgreRenderWindow::setPostRenderCallback( boost::function<void ()> func ) 00129 { 00130 post_render_callback_ = func; 00131 } 00132 00133 //------------------------------------------------------------------------------ 00134 void wxOgreRenderWindow::onPaint (wxPaintEvent &evt) 00135 { 00136 evt.Skip(); 00137 00138 if (auto_render_) 00139 { 00140 if ( pre_render_callback_ ) 00141 { 00142 pre_render_callback_(); 00143 } 00144 00145 if( ogre_root_->_fireFrameStarted() ) 00146 { 00147 #if (OGRE_VERSION_MAJOR >= 1 && OGRE_VERSION_MINOR >= 6) 00148 ogre_root_->_fireFrameRenderingQueued(); 00149 #endif 00150 00151 render_window_->update(); 00152 00153 ogre_root_->_fireFrameEnded(); 00154 } 00155 00156 if ( post_render_callback_ ) 00157 { 00158 post_render_callback_(); 00159 } 00160 } 00161 } 00162 00163 //------------------------------------------------------------------------------ 00164 void wxOgreRenderWindow::onSize (wxSizeEvent &evt) 00165 { 00166 int width; 00167 int height; 00168 wxSize size = evt.GetSize (); 00169 width = size.GetWidth (); 00170 height = size.GetHeight (); 00171 00172 if (render_window_) 00173 { 00174 #if !defined(__WXMAC__) 00175 render_window_->resize (width, height); 00176 #endif 00177 // Letting Ogre know the window has been resized; 00178 render_window_->windowMovedOrResized (); 00179 00180 setCameraAspectRatio(); 00181 00182 if (auto_render_) 00183 { 00184 Refresh(); 00185 } 00186 } 00187 00188 evt.Skip(); 00189 } 00190 00191 void wxOgreRenderWindow::onMove(wxMoveEvent& evt) 00192 { 00193 evt.Skip(); 00194 00195 if (render_window_) 00196 { 00197 00198 } 00199 } 00200 00201 //------------------------------------------------------------------------------ 00202 void wxOgreRenderWindow::onMouseEvents (wxMouseEvent &evt) 00203 { 00204 evt.Skip(); 00205 } 00206 //------------------------------------------------------------------------------ 00207 void wxOgreRenderWindow::createRenderWindow () 00208 { 00209 Ogre::NameValuePairList params; 00210 #if defined(__WXMAC__) 00211 params["externalWindowHandle"] = getOgreHandle(); 00212 #else 00213 params["parentWindowHandle"] = getOgreHandle(); 00214 #endif 00215 00216 // Set the macAPI for Ogre based on the WX implementation 00217 #ifdef __WXOSX_COCOA__ 00218 params["macAPI"] = "cocoa"; 00219 params["macAPICocoaUseNSView"] = "true"; 00220 #else 00221 params["macAPI"] = "carbon"; 00222 #endif 00223 00224 // Set the macAPI for Ogre based on the WX implementation 00225 #ifdef __WXOSX_COCOA__ 00226 params["macAPI"] = "cocoa"; 00227 params["macAPICocoaUseNSView"] = "true"; 00228 #else 00229 params["macAPI"] = "carbon"; 00230 #endif 00231 00232 // Get wx control window size 00233 int width; 00234 int height; 00235 GetSize (&width, &height); 00236 00237 #if OGRE_PLATFORM == OGRE_PLATFORM_LINUX 00238 { 00239 // The RTT mode seems to cause trouble. Some platforms have an 00240 // error with PBuffer, some have an error with FBO. Both are 00241 // supposed to be faster than Copy, which is another option. 00242 // Until I get a more elegant fix, I'm allowing people to set the 00243 // RTT mode via an environment variable. 00244 char *rtt_default = "PBuffer"; 00245 00246 char* rtt_preferred_mode = getenv("OGRE_RTT_MODE"); 00247 if( rtt_preferred_mode ) 00248 { 00249 if( strcmp( rtt_preferred_mode, "Copy" ) != 0 && 00250 strcmp( rtt_preferred_mode, "PBuffer" ) != 0 && 00251 strcmp( rtt_preferred_mode, "FBO" ) != 0 ) 00252 { 00253 ROS_ERROR( "Environtment variable OGRE_RTT_MODE has invalid value: '%s'. Should be", rtt_preferred_mode ); 00254 ROS_ERROR( "either FBO, PBuffer, Copy, or should not be set. Using default value %s.", rtt_default ); 00255 rtt_preferred_mode = rtt_default; 00256 } 00257 } 00258 else 00259 { 00260 rtt_preferred_mode = rtt_default; 00261 } 00262 ogre_root_->getRenderSystem()->setConfigOption( "RTT Preferred Mode", rtt_preferred_mode ); 00263 ROS_INFO( "RTT Preferred Mode is %s.", rtt_preferred_mode ); 00264 } 00265 #endif 00266 00267 // Create the render window 00268 render_window_ = ogre_root_->createRenderWindow ( 00269 Ogre::String ("OgreRenderWindow") + Ogre::StringConverter::toString (sm_NextRenderWindowId++), 00270 width, height, false, ¶ms); 00271 00272 render_window_->setActive (true); 00273 render_window_->setVisible(true); 00274 render_window_->setAutoUpdated(true); 00275 00276 viewport_ = render_window_->addViewport( NULL ); 00277 } 00278 //------------------------------------------------------------------------------ 00279 std::string wxOgreRenderWindow::getOgreHandle () const 00280 { 00281 std::string handle; 00282 00283 #ifdef __WXMSW__ 00284 // Handle for Windows systems 00285 handle = Ogre::StringConverter::toString((size_t)((HWND)GetHandle())); 00286 #elif defined(__WXGTK__) 00287 // Handle for GTK-based systems 00288 std::stringstream str; 00289 GtkWidget* widget = m_wxwindow; 00290 gtk_widget_set_double_buffered (widget, FALSE); 00291 if (!GTK_WIDGET_REALIZED(widget)) 00292 { 00293 gtk_widget_realize( widget ); 00294 } 00295 00296 // Grab the window object 00297 GtkPizza* pizza = GTK_PIZZA(widget); 00298 GdkWindow* gdkWin = pizza->bin_window; 00299 Window wid = GDK_WINDOW_XWINDOW(gdkWin); 00300 00301 XSync(GDK_WINDOW_XDISPLAY(widget->window), False); 00302 XSync(GDK_WINDOW_XDISPLAY(pizza->bin_window), False); 00303 00304 str << wid;// << ':'; 00305 handle = str.str(); 00306 #elif defined(__WXMAC__) 00307 handle = Ogre::StringConverter::toString((size_t)(GetHandle())); 00308 #else 00309 // Any other unsupported system 00310 #error("Not supported on this platform.") 00311 #endif 00312 00313 return handle; 00314 } 00315 00316 bool wxOgreRenderWindow::Reparent(wxWindowBase* new_parent) 00317 { 00318 // Dear god I hate GTK. Because gtk_widget_reparent() does not work properly (https://netfiles.uiuc.edu/rvmorale/www/gtk-faq-es/x639.html), 00319 // When a window is reparented in wx the drawable client area has to be destroyed and re-created, causing its XID to change. This causes both: 00320 // 1) Any window that was its child (like the Ogre render window's) is destroyed 00321 // 2) The XID changes 00322 // The following seems to be the only thing that actually works when trying to work around this: 00323 // 1) Reparent the render window's window to the root window 00324 // 2) Allow wx to reparent the window 00325 // 3) Reparent the render window's window to the new parent window 00326 #if defined(__WXGTK__) 00327 Window win; 00328 Display* disp; 00329 00330 if (render_window_) 00331 { 00332 render_window_->getCustomAttribute("WINDOW", &win); 00333 render_window_->getCustomAttribute("XDISPLAY", &disp); 00334 00335 wxWindow* top = wxTheApp->GetTopWindow(); 00336 GtkPizza* pizza = GTK_PIZZA(top->m_wxwindow); 00337 Window parent = GDK_WINDOW_XWINDOW(pizza->bin_window); 00338 00339 XSync(disp, False); 00340 XReparentWindow(disp, win, parent, 0, 0); 00341 XSync(disp, False); 00342 } 00343 #endif 00344 00345 bool ret = wxControl::Reparent(new_parent); 00346 00347 #if defined(__WXGTK__) 00348 if (render_window_) 00349 { 00350 XSync(disp, False); 00351 00352 gtk_widget_set_double_buffered(m_wxwindow, FALSE); 00353 if (!GTK_WIDGET_REALIZED(m_wxwindow)) 00354 { 00355 gtk_widget_realize(m_wxwindow); 00356 } 00357 00358 GtkPizza* pizza = GTK_PIZZA(m_wxwindow); 00359 00360 XSync(GDK_WINDOW_XDISPLAY(m_wxwindow->window), False); 00361 XSync(GDK_WINDOW_XDISPLAY(pizza->bin_window), False); 00362 00363 GdkWindow* gdkWin = pizza->bin_window; 00364 Window parent = GDK_WINDOW_XWINDOW(gdkWin); 00365 XReparentWindow(disp, win, parent, 0, 0); 00366 00367 // XSync(disp, False); 00368 00369 XMapWindow(disp, win); 00370 00371 XSync(disp, False); 00372 } 00373 #endif 00374 00375 return ret; 00376 } 00377 00378 } // namespace ogre_tools