OGRE Wiki
Support and community documentation for Ogre3D
Ogre Forums
ogre3d.org
Log in
Username:
Password:
CapsLock is on.
Remember me (for 1 year)
Log in
Home
Tutorials
Tutorials Home
Basic Tutorials
Intermediate Tutorials
Mad Marx Tutorials
In Depth Tutorials
Older Tutorials
External Tutorials
Cookbook
Cookbook Home
CodeBank
Snippets
Experiences
Ogre Articles
Libraries
Libraries Home
Alternative Languages
Assembling A Toolset
Development Tools
OGRE Libraries
List of Libraries
Tools
Tools Home
DCC Tools
DCC Tutorials
DCC Articles
DCC Resources
Assembling a production pipeline
Development
Development Home
Roadmap
Building Ogre
Installing the Ogre SDK
Setting Up An Application
Ogre Wiki Tutorial Framework
Frequently Asked Questions
Google Summer Of Code
Help Requested
Ogre Core Articles
Community
Community Home
Projects Using Ogre
Recommended Reading
Contractors
Wiki
Immediate Wiki Tasklist
Wiki Ideas
Wiki Guidelines
Article Writing Guidelines
Wiki Styles
Wiki Page Tracker
Ogre Wiki Help
Ogre Wiki Help Overview
Help - Basic Syntax
Help - Images
Help - Pages and Structures
Help - Wiki Plugins
Toolbox
Freetags
Categories
List Pages
Structures
Trackers
Statistics
Rankings
List Galleries
Ogre Lexicon
Comments
History: WxOgre for OGRE v1.4
View page
Source of version: 3
(current)
{maketoc} !!wxOgre for OGRE v1.4 This article provides an example of how OGRE and wxWidgets can work together in one application. This can be very useful when writing tools such as 3D world editors or 3D viewers. The following C++ class is a quick and simple wxControl derived object that can be easily used with the GUI toolkit wxWidgets. It is defined as singleton and currently only supports a single OGRE window. This uses the latest wxWidgets release (2.8) and the latest OGRE release v1.4. I also leave you notes on how to make this work with OIS as well. Any trouble, you can discuss it on this thread: [http://www.ogre3d.org/phpBB2/viewtopic.php?t=34889] !!!Requirements * OGRE 1.4 * wxWidgets 2.8 !!!Link Requirements {CODE(wrap="1", colors="c++")} {CODE} Make sure you link to wxCore, wxBase and wxAUI. !!!Limitations * Supports a single OGRE window only * Fully tested on Windows OS. Linux support is there but needs testing (if somebody was able to get this to work on MacOS please add your code). !!!OIS Notes Make sure to pass the TOPMOST window to ois or else directinput won't run on windows and use the following options. {CODE(wrap="1", colors="c++")} pl.insert(std::make_pair(std::string("w32_mouse"), std::string("DISCL_NONEXCLUSIVE"))); pl.insert(std::make_pair(std::string("w32_mouse"), std::string("DISCL_FOREGROUND"))); pl.insert(std::make_pair(std::string("w32_keyboard"), std::string("DISCL_NONEXCLUSIVE"))); pl.insert(std::make_pair(std::string("w32_keyboard"), std::string("DISCL_FOREGROUND")));{CODE} {CODE(wrap="1", colors="c++")} {CODE} !!!Code __wxOgre.h__ {CODE(wrap="1", colors="c++")}#ifndef __WXOGRE_H__ #define __WXOGRE_H__ #include "Ogre.h" #include "wx/wx.h" /** @brief WX widget for and Ogre rendering window This WX widget is a self-contained SINGLETON Ogre rendering window; meaning it contains all Ogre objects necessary to create a rendering window and currently supports only one rendering window at a time! This is due to the limitation of the self contained class. @usage Simply create a new wxOgre object and pass a wxFrame as its parent window. Then work with it just like ay other wxControl object. It can even be passed to an wxAUI pane. */ class wxOgre : public wxControl, public Ogre::Singleton<wxOgre> { DECLARE_CLASS(wxOgre) public: /** A new wxOgre must receive a parent frame to which to attach itself to */ wxOgre (wxFrame* parent, Ogre::RenderSystem* renderSystem = 0); ~wxOgre(); /** Renders a single Ogre frame */ void update(); /** Returns the currently used camera */ inline Ogre::Camera* getCamera() const {return mCamera;} /** Sets a new camera for rendering */ inline void setCamera(Ogre::Camera* camera){mCamera = camera;} inline Ogre::SceneManager* getSceneManager() const {return mSceneMgr;} protected: DECLARE_EVENT_TABLE() private: /** Creates an ogre rendering window and all other default objects such as the Ogre Root, default camera, default scene manager etc */ void createOgreRenderWindow(Ogre::RenderSystem* renderSystem); /** Toggles the rendering timer on/off */ void toggleTimerRendering(); /** Callback function to a window resize event */ void OnSize(wxSizeEvent& event); /** Callback function to a window paint event */ void OnPaint(wxPaintEvent& event); /** Callback function to an EraseBackground event */ void OnEraseBackground( wxEraseEvent& ); /** Callback function to a timer "tick" event */ void OnRenderTimer(wxTimerEvent& event); /* WX members */ /** Rendering timer */ wxTimer mTimer; /* Ogre members */ /** Local Ogre::Root pointer */ Ogre::Root* mRoot; /** Local Ogre::Viewport pointer */ Ogre::Viewport* mViewPort; /** Local Ogre::Camera pointer */ Ogre::Camera* mCamera; /** Local Ogre::SceneManager pointer */ Ogre::SceneManager* mSceneMgr; /** Local Ogre::RenderWindow pointer */ Ogre::RenderWindow* mRenderWindow; /* Set to false until wxOgre is completely initialized */ bool mIsInitialized; public: // ***************************************************** // ----------------------------------------------------- /** @remarks Why do we do this? Well, it's because the Singleton implementation is in a .h file, which means it gets compiled into anybody who includes it. This is needed for the Singleton template to work, but we actually only want it compiled into the implementation of the class based on the Singleton, not all of them. If we don't change this, we get link errors when trying to use the Singleton-based class from an outside dll. @par This method just delegates to the template version anyway, but the implementation stays in this single compilation unit, preventing link errors. */ static wxOgre& getSingleton(); /** @remarks Why do we do this? Well, it's because the Singleton implementation is in a .h file, which means it gets compiled into anybody who includes it. This is needed for the Singleton template to work, but we actually only want it compiled into the implementation of the class based on the Singleton, not all of them. If we don't change this, we get link errors when trying to use the Singleton-based class from an outside dll. @par This method just delegates to the template version anyway, but the implementation stays in this single compilation unit, preventing link errors. */ static wxOgre* getSingletonPtr(); }; #endif // __WXOGRE_H__{CODE} __wxOgre.cpp__ {CODE(wrap="1", colors="c++")}#include "wxOgre.h" #ifdef __WXGTK__ #include <gdk/gdk.h> #include <gtk/gtk.h> // just this should suffice as it should include gdk.h itself /* Seems to be needed under Linux */ #include <wx/gtk/win_gtk.h> #include <gdk/gdkx.h> #include <GL/glx.h> #endif // Required for the timer const long ID_RENDERTIMER = wxNewId(); // Required for WX IMPLEMENT_CLASS(wxOgre, wxControl) // Required for WX BEGIN_EVENT_TABLE(wxOgre, wxControl) EVT_SIZE(wxOgre::OnSize) // EVT_PAINT(wxOgre::OnPaint) // Produces flickers and runs too fast! EVT_ERASE_BACKGROUND( wxOgre::OnEraseBackground ) EVT_TIMER( ID_RENDERTIMER, wxOgre::OnRenderTimer ) END_EVENT_TABLE() wxOgre::wxOgre(wxFrame* parent, Ogre::RenderSystem* renderSystem) : wxControl(parent, -1), mTimer(this, ID_RENDERTIMER), mRoot(0), mViewPort(0), mCamera(0), mSceneMgr(0), mRenderWindow(0) { mIsInitialized = false; // Create all Ogre objects createOgreRenderWindow(renderSystem); // Start the rendering timer toggleTimerRendering(); mIsInitialized = true; } void wxOgre::createOgreRenderWindow(Ogre::RenderSystem* renderSystem) { // See if an Ogre::Root already exists mRoot = Ogre::Root::getSingletonPtr(); // If not, create one if(!mRoot) { mRoot = new Ogre::Root(); } // If we got an Ogre::RenderSystem, we'll use that if(renderSystem) { mRoot->setRenderSystem(renderSystem); } // If not, maybe the Root already has one else if(!mRoot->getRenderSystem()) { // At this point there are no rendersystems, so we // can try to load in the previous configuration if(!mRoot->restoreConfig()) { // That failed so we have to show the Dialog if(!mRoot->showConfigDialog()) { // If the user canceled that there's nothing else we can do! OGRE_EXCEPT(Ogre::Exception::ERR_INVALIDPARAMS, "No RenderSystem chosen", "wxOgre::createOgreRenderWindow"); } } } mRenderWindow = mRoot->initialise(false); // -------------------- // Create a new parameters list according to compiled OS Ogre::NameValuePairList params; Ogre::String handle; #ifdef __WXMSW__ handle = Ogre::StringConverter::toString((size_t)((HWND)GetHandle())); #elif defined(__WXGTK__) // TODO: Someone test this. you might to use "parentWindowHandle" if this // does not work. Ogre 1.2 + Linux + GLX platform wants a string of the // format display:screen:window, which has variable types ulong:uint:ulong. GtkWidget* widget = GetHandle(); gtk_widget_realize( widget ); // Mandatory. Otherwise, a segfault happens. std::stringstream handleStream; Display* display = GDK_WINDOW_XDISPLAY( widget->window ); Window wid = GDK_WINDOW_XWINDOW( widget->window ); // Window is a typedef for XID, which is a typedef for unsigned int /* Get the right display (DisplayString() returns ":display.screen") */ std::string displayStr = DisplayString( display ); displayStr = displayStr.substr( 1, ( displayStr.find( ".", 0 ) - 1 ) ); /* Put all together */ handleStream << displayStr << ':' << DefaultScreen( display ) << ':' << wid; handle = handleStream.str(); #else #error Not supported on this platform. #endif params["externalWindowHandle"] = handle; // Get wx control window size int width; int height; GetSize(&width, &height); // Create the render window mRenderWindow = Ogre::Root::getSingleton().createRenderWindow("OgreRenderWindow", width, height, false, ¶ms); // -------------------- // Create the SceneManager, in this case a generic one mSceneMgr = mRoot->createSceneManager(Ogre::ST_GENERIC, "ExampleSMInstance"); mSceneMgr->setAmbientLight(Ogre::ColourValue(0.5f, 0.5f, 0.5f)); // -------------------- // Create the camera mCamera = mSceneMgr->createCamera("PlayerCam"); // Position it at 500 in Z direction mCamera->setPosition(Ogre::Vector3(0,0,500)); // Look back along -Z mCamera->lookAt(Ogre::Vector3(0,0,-300)); mCamera->setNearClipDistance(5); // Set the viewport mViewPort = mRenderWindow->addViewport(mCamera); // Set the background to match the wxWindow background color mViewPort->setBackgroundColour(Ogre::ColourValue(212.0f/255.0f, 208.0f/255.0f, 200.0f/255.0f, 1.0f)); } void wxOgre::toggleTimerRendering() { // Toggle Start/Stop if (mTimer.IsRunning()) mTimer.Stop(); mTimer.Start(10); } wxOgre::~wxOgre() { // destroy Viewport and RenderWindow if (mViewPort) { mRenderWindow->removeViewport(mViewPort->getZOrder()); mViewPort = 0; } Ogre::Root::getSingleton().detachRenderTarget(mRenderWindow); mRenderWindow = 0; delete mRoot; } void wxOgre::OnSize(wxSizeEvent& event) { if(mIsInitialized){ // Setting new size; int width; int height; GetSize(&width, &height); mRenderWindow->resize( width, height ); // Letting Ogre know the window has been resized; mRenderWindow->windowMovedOrResized(); // Set the aspect ratio for the new size; if (mCamera) mCamera->setAspectRatio(Ogre::Real(width) / Ogre::Real(height)); update(); } } void wxOgre::OnPaint(wxPaintEvent& event) { if(mIsInitialized){ // update(); // Produces flickers and runs too fast! } } void wxOgre::OnEraseBackground( wxEraseEvent& ) { if(mIsInitialized){ update(); } } void wxOgre::OnRenderTimer(wxTimerEvent& event) { if(mIsInitialized){ update(); } } void wxOgre::update() { Ogre::Root::getSingletonPtr()->renderOneFrame(); } template<> wxOgre* Ogre::Singleton<wxOgre>::ms_Singleton = 0; wxOgre& wxOgre::getSingleton() { return ( *ms_Singleton ); } wxOgre* wxOgre::getSingletonPtr() { return ms_Singleton; }{CODE} !!!!Notes Under Ubuntu 7.04, I wasn't able to make it work. Searching through various forum posts, I stumbled with this solution, that actually works here: {CODE(wrap="1", colors="c++")}#elif defined(__WXGTK__) SetBackgroundStyle(wxBG_STYLE_CUSTOM); GtkWidget *widget = m_wxwindow; gtk_widget_set_double_buffered (widget, FALSE); gtk_widget_realize( widget ); // grab the window object GdkWindow *gdkWin = GTK_PIZZA (widget)->bin_window; Display* display = GDK_WINDOW_XDISPLAY(gdkWin); Window wid = GDK_WINDOW_XWINDOW(gdkWin); std::stringstream str; // display str << (unsigned long)display << ':'; // screen (returns "display.screen") std::string screenStr = DisplayString(display); std::string::size_type dotPos = screenStr.find("."); screenStr = screenStr.substr(dotPos+1, screenStr.size()); str << screenStr << ':'; // XID str << wid << ':'; // retrieve XVisualInfo int attrlist[] = { GLX_RGBA, GLX_DOUBLEBUFFER, GLX_DEPTH_SIZE, 16, GLX_STENCIL_SIZE, 8, None }; XVisualInfo* vi = glXChooseVisual(display, DefaultScreen(display), attrlist); str << (unsigned long)vi; handle = str.str(); #else{CODE} In addition to it, seems that the GTK2 development packages are required to build it. Download them with {CODE(wrap="1", colors="c++")}sudo apt-get install libgtk2.0-dev{CODE} If someone confirms these notes are right, they should be merged into the article in order to support Linux. <div align="right">((User:Kencho|Kencho)) 12:34, 29 October 2007 (GMT)</div> !!!Usage - Example with wxAUI __MainFrame.h__ {CODE(wrap="1", colors="c++")}#ifndef __MAINFRAME_H__ #define __MAINFRAME_H__ #include "wx/wx.h" #include "wx/aui/aui.h" #include "wxOgre.h" class MainFrame : public wxFrame { public: MainFrame(wxWindow* parent) : wxFrame(parent, -1, _("wxAUI Test"), wxDefaultPosition, wxSize(800,600), wxDEFAULT_FRAME_STYLE) { // notify wxAUI which frame to use m_mgr.SetFrame(this); // create several text controls wxTextCtrl* text1 = new wxTextCtrl(this, -1, _("Pane 1 - sample text"), wxDefaultPosition, wxSize(200,150), wxNO_BORDER | wxTE_MULTILINE); wxTextCtrl* text2 = new wxTextCtrl(this, -1, _("Pane 2 - sample text"), wxDefaultPosition, wxSize(200,150), wxNO_BORDER | wxTE_MULTILINE); wxTextCtrl* text3 = new wxTextCtrl(this, -1, _("Main content window"), wxDefaultPosition, wxSize(200,150), wxNO_BORDER | wxTE_MULTILINE); // add the panes to the manager m_mgr.AddPane(text1, wxLEFT, wxT("Pane Number One")); m_mgr.AddPane(text2, wxBOTTOM, wxT("Pane Number Two")); m_mgr.AddPane(text3, wxTOP); // ************************ wxOgrePane = new wxOgre(this); m_mgr.AddPane(wxOgrePane, wxCENTER, wxT("Ogre Pane")); // tell the manager to "commit" all the changes just made m_mgr.Update(); } ~MainFrame() { // deinitialize the frame manager m_mgr.UnInit(); } void UpdateOgre() { wxOgrePane->update(); } private: wxAuiManager m_mgr; wxOgre* wxOgrePane; }; // our normal wxApp-derived class, as usual class MyApp : public wxApp { public: MainFrame* frame; bool OnInit() { frame = new MainFrame(NULL); SetTopWindow(frame); frame->Show(); frame->UpdateOgre(); return true; } }; IMPLEMENT_APP_NO_MAIN(MyApp); int main(int argc, char **argv) { return wxEntry(argc, argv); } #endif //__MAINFRAME_H__{CODE} !!Alternative versions There's an alternative version, ((wxOgreRenderWindow for Eihort|wxOgreRenderWindow)), based on wxOgre but decoupling it as most as possible from Ogre, letting total freedom in the Ogre usage and the number of such windows.
Search by Tags
Search Wiki by Freetags
Latest Changes
Minimal Ogre Collision
Artifex Terra
OpenMB
Advanced Mogre Framework
MogreSocks
Critter AI
Mogre Add-ons
MOGRE
Mogre MyGUI wrapper
MOGRE Editable Terrain Manager
...more
Search
Find
Advanced
Search Help
Online Users
15 online users