Table of contents
Let's see how one can use Ogre with FLTK gui toolkit - Fast Light Toolkit
What we want is to be able to render via Ogre into window created with FLTK.
Worth to notice that we worked with GL render system with GLX platform manager. Of course main principles will remain the same for win32 platform and it's render systems.
So we let fltk create some nice window and now have to tell Ogre to render to it somehow.
When you create render window in Ogre there is a block of platform dependent parameters. One of them is externalWindowHandle. It is said in Ogre source code that one have to pass Display*:screen:Window to accomplish our goal. One thing is that fltk requires visual info to be passed on window creation. So visual info should be passed as fourth param. On the other hand this parameter should be optional because one could use GLX render system with other gui toolkits or perhaps manually created window.
I discovered that GLX render system just ignores externalWindowHandle param. So here the patch that should be applied to get that new functionality.
The next thing is to setup FLTK properly.
Let's look at the code.
First file is here because we want our window to work with 2 major versions of FLTK: 1.1.x and 2.
So, here Prerequisites.h:
#ifndef OGRE_FLTK_PREREQUISITES_H #define OGRE_FLTK_PREREQUISITES_H #include <FL/Enumerations.H> #endif
Easy enough! ๐ That includes definition for FL_MAJOR_VERSION preprocessor variable.
The next step - we're going to subclass fltk::Window (Fl_Window in 1.1.x). Derived class will be called OgreWindow.
OgreWindow.h:
#ifndef OGRE_WINDOW_H #define OGRE_WINDOW_H #include "Prerequisites.h" #if FL_MAJOR_VERSION == 2 #include <fltk/visual.h> #include <fltk/Window.h> #include <fltk/x.h> typedef fltk::Window FLTKWindow; #elif FL_MAJOR_VERSION == 1 #include <FL/Fl_Window.H> #include <FL/x.H> typedef Fl_Window FLTKWindow; #endif namespace ogre_interface { class EmbeddedOgre; } class OgreWindow : public FLTKWindow { public: OgreWindow( int x, int y, int w, int h, const char* label = NULL ); virtual ~OgreWindow(); virtual void create(); // not in FLTK 1.1.x virtual void destroy(); virtual void show(); virtual void draw(); virtual void flush(); bool isWindowCreated(); // for compatibility with fltk 1.1.x virtual void setEmbeddedOgre( ogre_interface::EmbeddedOgre* pOgreApp ); protected: ogre_interface::EmbeddedOgre* mOgre; }; #endif
OgreWindow is almost everything we need! But notice mOgre member variable there. That's where Ogre realy hides ๐
Look at the OgreWindow.cpp:
#include "Prerequisites.h" #if FL_MAJOR_VERSION == 2 #include "GlChoice.h" #include "OgreWindow.h" #include "EmbeddedOgre.h" #include <fltk/run.h> typedef fltk::GlChoice GLChoiceType; #define CAP_DOUBLE_BUFFER DOUBLE_BUFFER #define CAP_DEPTH_BUFFER DEPTH_BUFFER #define XDISPLAY fltk::xdisplay #define XSCREEN fltk::xscreen using namespace fltk; #elif FL_MAJOR_VERSION == 1 #include "Fl_Gl_Choice.H" #include "OgreWindow.h" #include "EmbeddedOgre.h" #include <FL/Fl.H> typedef Fl_Gl_Choice GLChoiceType; #define CAP_DOUBLE_BUFFER FL_DOUBLE #define CAP_DEPTH_BUFFER FL_DEPTH #define XDISPLAY fl_display #define XSCREEN fl_screen #endif ///--------------------------------------------------- OgreWindow::OgreWindow( int x, int y, int w, int h, const char* label ) : FLTKWindow( x, y, w, h, label ), mOgre( NULL ) {} ///--------------------------------------------------- OgreWindow::~OgreWindow() { destroy(); } ///--------------------------------------------------- void OgreWindow::destroy() { #if FL_MAJOR_VERSION == 2 FLTKWindow::destroy(); #endif delete mOgre; } ///--------------------------------------------------- void OgreWindow::show() { #if FL_MAJOR_VERSION == 1 if ( !mOgre->isWindowCreated() ) create(); #endif FLTKWindow::show(); } ///--------------------------------------------------- void OgreWindow::create() { #if FL_MAJOR_VERSION == 2 fltk::open_display(); GLChoiceType* glChoice = GLChoiceType::find( CAP_DEPTH_BUFFER | CAP_DOUBLE_BUFFER ); fltk::CreatedWindow::create( this, glChoice->vis, glChoice->colormap, -1 ); #elif FL_MAJOR_VERSION == 1 fl_open_display(); GLChoiceType* glChoice = GLChoiceType::find( CAP_DEPTH_BUFFER | CAP_DOUBLE_BUFFER, NULL ); Fl_X::make_xid( this, glChoice->vis, glChoice->colormap ); #endif if ( mOgre != NULL ) { mOgre->init( XDISPLAY, XSCREEN, this, glChoice->vis ); } } ///--------------------------------------------------- void OgreWindow::draw() { if ( mOgre != NULL ) mOgre->update(); } ///--------------------------------------------------- void OgreWindow::flush() { draw(); } ///--------------------------------------------------- void OgreWindow::setEmbeddedOgre( ogre_interface::EmbeddedOgre* pOgreApp ) { if ( mOgre != NULL ) delete mOgre; mOgre = pOgreApp; }
As you can see in function OgreWindow::create we choose best visual for glx and create window via FLTK. Next step - we pass window parameters to mOgre->init.
Let's see what inside EmbeddedOgre.h:
#ifndef EMBEDDED_OGRE_H #define EMBEDDED_OGRE_H namespace ogre_interface { class EmbeddedOgreImplementation; // compilation brandmauer class EmbeddedOgre { public: EmbeddedOgre(); virtual ~EmbeddedOgre(); virtual void init( Display* display, unsigned screen, FLTKWindow* flWnd, XVisualInfo* visualInfo ); virtual void update(); virtual void setupResources(); virtual void chooseSceneManager(); virtual void loadResources(); virtual void createCameras(); virtual void createViewports(); virtual void createScene(); bool isWindowCreated(); // for compatibility with fltk 1.1.x void setImplementation( EmbeddedOgreImplementation* pImpl ); protected: EmbeddedOgreImplementation* mImpl; }; } #endif
Of course the most important method here is init. All other virtual methods are for customization of application behaviour. For most of them default implementation a-la ExampleApplication is provided.
EmbeddedOgre.cpp:
#include "Prerequisites.h" #include "OgreWindow.h" #if FL_MAJOR_VERSION == 2 #include <fltk/Window.h> #include <fltk/x.h> #elif FL_MAJOR_VERSION == 1 #include <FL/Fl_Window.h> #include <FL/x.H> #endif #include "EmbeddedOgre.h" #include "EmbeddedOgreImplementation.h" #include "OgreGLXWindowInterface.h" namespace ogre_interface { using namespace Ogre; ///--------------------------------------------------- EmbeddedOgre::EmbeddedOgre() { mImpl = new EmbeddedOgreImplementation; } ///--------------------------------------------------- EmbeddedOgre::~EmbeddedOgre() { delete mImpl; } ///--------------------------------------------------- void EmbeddedOgre::setImplementation( EmbeddedOgreImplementation* pImpl ) { mImpl = pImpl; // TODO insecure... add some checks } ///--------------------------------------------------- bool EmbeddedOgre::isWindowCreated() { return mImpl->getWindow() != NULL; } ///--------------------------------------------------- void EmbeddedOgre::init( Display* display, unsigned screen, FLTKWindow* flWnd, XVisualInfo* visualInfo ) { // Make the root mImpl->mRoot = new Root(); try { setupResources(); // Set parameters of render system (window size, etc.) mImpl->mRoot->restoreConfig(); // Root and Scene. mImpl->mWnd = mImpl->mRoot->initialise( false ); StringVector paramsVector; paramsVector.push_back( StringConverter::toString( reinterpret_cast<unsigned int>( display ) ) ); paramsVector.push_back( StringConverter::toString( reinterpret_cast<unsigned int>( screen ) ) ); #if FL_MAJOR_VERSION == 2 XWindow xWnd = fltk::xid( flWnd ); #elif FL_MAJOR_VERSION == 1 Window xWnd = fl_xid( flWnd ); #endif paramsVector.push_back( StringConverter::toString( ( unsigned int)( xWnd ) ) ); paramsVector.push_back( StringConverter::toString( reinterpret_cast< unsigned int>( visualInfo ) ) ); NameValuePairList params; params["externalWindowHandle"] = StringConverter::toString( paramsVector ); mImpl->mWnd = mImpl->mRoot->createRenderWindow( "fltk", flWnd->w(), flWnd->h(), false, ¶ms ); chooseSceneManager(); createCameras(); createViewports(); // Set default mipmap level (NB some APIs ignore this) TextureManager::getSingleton().setDefaultNumMipmaps( 2 ); loadResources(); createScene(); GLXWindowInterface* pWindowInterface = NULL; mImpl->mWnd->getCustomAttribute( "GLXWINDOWINTERFACE", &pWindowInterface ); pWindowInterface->exposed( true ); } catch( Ogre::Exception& e ) { String s = "EmbeddedOgre::init() - Exception:\n" + e.getFullDescription() + "\n"; LogManager::getSingleton().logMessage( s, LML_CRITICAL ); if( mImpl->mRoot ) delete mImpl->mRoot; } } ///--------------------------------------------------- void EmbeddedOgre::update() { mImpl->mRoot->renderOneFrame(); } ///--------------------------------------------------- void EmbeddedOgre::setupResources() { // Load resource paths from config file ConfigFile cf; cf.load( "resources.cfg" ); // Go through all sections & settings in the file ConfigFile::SectionIterator seci = cf.getSectionIterator(); String secName, typeName, archName; while ( seci.hasMoreElements() ) { secName = seci.peekNextKey(); ConfigFile::SettingsMultiMap* settings = seci.getNext(); ConfigFile::SettingsMultiMap::iterator i; for ( i = settings->begin(); i != settings->end(); ++i ) { typeName = i->first; archName = i->second; ResourceGroupManager::getSingleton().addResourceLocation( archName, typeName, secName ); } } } ///--------------------------------------------------- void EmbeddedOgre::chooseSceneManager() { // Get the SceneManager, in this case a generic one mImpl->mSceneMgr = mImpl->mRoot->getSceneManager( ST_GENERIC ); } ///--------------------------------------------------- void EmbeddedOgre::createCameras() { } ///--------------------------------------------------- void EmbeddedOgre::createViewports() { } ///--------------------------------------------------- void EmbeddedOgre::loadResources() { // Initialise, parse scripts etc ResourceGroupManager::getSingleton().initialiseAllResourceGroups(); } ///--------------------------------------------------- void EmbeddedOgre::createScene() { } }
You should look at init method closely. Params for GLXWindow are packed and sent there.
Line #include "OgreGLXWindowInterface.h" includes file that is found in Ogre's RenderSystem dir.
There are a couple of still unfamiliar files. Let's take a closer look at them ๐
The first one is a simple "pImpl"-idiom implementor (reduces compile-time dependencies in code) - EmbeddedOgreImplementation.h:
#ifndef EMBEDDED_OGRE_IMPLEMENTATION_H #define EMBEDDED_OGRE_IMPLEMENTATION_H #include "Ogre.h" #include "OgreStringConverter.h" #include "OgreException.h" namespace ogre_interface { class EmbeddedOgreImplementation { friend class EmbeddedOgre; public: EmbeddedOgreImplementation(); virtual ~EmbeddedOgreImplementation(); Ogre::Root* getRoot() { return mRoot; } Ogre::RenderWindow* getWindow() { return mWnd; } Ogre::SceneManager* getSceneManager() { return mSceneMgr; } protected: Ogre::Root* mRoot; Ogre::RenderWindow* mWnd; Ogre::SceneManager* mSceneMgr; }; } #endif
-
It's implementation file EmbeddedOgreImplementation.cpp is so simplistic ๐
#include "Prerequisites.h" #include "OgreWindow.h" #if FL_MAJOR_VERSION == 2 #include <fltk/Window.h> #include <fltk/x.h> #elif FL_MAJOR_VERSION == 1 #include <FL/Fl_Window.h> #include <FL/x.H> #endif #include "EmbeddedOgreImplementation.h" namespace ogre_interface { ///--------------------------------------------------- EmbeddedOgreImplementation::EmbeddedOgreImplementation() : mRoot( NULL ), mWnd( NULL ), mSceneMgr( NULL ) { } ///--------------------------------------------------- EmbeddedOgreImplementation::~EmbeddedOgreImplementation() { } }
Some files were included from FLTK:
GlChoice.h — from fltk-2
Fl_Gl_Choice.H — from fltk-1.1.x
Fl_Gl_Choice.cxx was included in project and consists from two versions of same file from fltk-2 and fltk-1.1.x. It is here so we are able to choose right glx visual in window creation code.
Fl_Gl_Choice.cxx:
// // "$Id: Fl_Gl_Choice.cxx 4242 2005-04-06 06:59:36Z spitzak $" // // OpenGL visual selection code for the Fast Light Tool Kit (FLTK). // // Copyright 1998-2000 by Bill Spitzak and others. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Library General Public // License as published by the Free Software Foundation; either // version 2 of the License, or (at your option) any later version. // // This library is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU // Library General Public License for more details. // // You should have received a copy of the GNU Library General Public // License along with this library; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 // USA. // // Please report all bugs and problems to "fltk-bugs@fltk.org". // #include "Prerequisites.h" #if FL_API_VERSION == 2 #include <config.h> #if HAVE_GL #include "GlChoice.h" #include <fltk/visual.h> #include <stdlib.h> using namespace fltk; static GlChoice* first; GlChoice* GlChoice::find(int mode) { GlChoice* g; for (g = first; g; g = g->next) if (g->mode == mode) return g; int list[32]; int n = 0; if (mode & INDEXED_COLOR) { list[n++] = GLX_BUFFER_SIZE; list[n++] = 8; // glut tries many sizes, but this should work... } else { list[n++] = GLX_RGBA; list[n++] = GLX_GREEN_SIZE; const int bits = (mode & RGB24_COLOR) ? 8 : 1; list[n++] = bits; if (mode & ALPHA_BUFFER) { list[n++] = GLX_ALPHA_SIZE; list[n++] = bits; } if (mode & ACCUM_BUFFER) { list[n++] = GLX_ACCUM_GREEN_SIZE; list[n++] = bits; if (mode & ALPHA_BUFFER) { list[n++] = GLX_ACCUM_ALPHA_SIZE; list[n++] = bits; } } } if (mode & DOUBLE_BUFFER) { list[n++] = GLX_DOUBLEBUFFER; } if (mode & DEPTH_BUFFER) { list[n++] = GLX_DEPTH_SIZE; list[n++] = 1; } if (mode & STENCIL_BUFFER) { list[n++] = GLX_STENCIL_SIZE; list[n++] = 1; } if (mode & STEREO) { list[n++] = GLX_STEREO; } #if defined(GLX_VERSION_1_1) && defined(GLX_SGIS_multisample) if (mode & MULTISAMPLE) { list[n++] = GLX_SAMPLES_SGIS; list[n++] = 4; // value Glut uses } #endif list[n] = 0; open_display(); XVisualInfo* vis = glXChooseVisual(xdisplay, xscreen, list); if (!vis) { # if defined(GLX_VERSION_1_1) && defined(GLX_SGIS_multisample) if (mode&MULTISAMPLE) return find(mode&~MULTISAMPLE); # endif return 0; } g = new GlChoice; g->mode = mode; g->next = first; first = g; g->vis = vis; if (/*MaxCmapsOfScreen(ScreenOfDisplay(xdisplay,xscreen))==1 && */ vis->visualid == xvisual->visualid && !getenv("MESA_PRIVATE_CMAP")) g->colormap = xcolormap; else g->colormap = XCreateColormap(xdisplay, RootWindow(xdisplay,xscreen), vis->visual, AllocNone); return g; } static GLContext first_context; #if USE_X11 GLContext fltk::create_gl_context(XVisualInfo* vis) { GLContext context = glXCreateContext(xdisplay, vis, first_context, 1); if (!first_context) first_context = context; return context; } #endif GLContext fl_current_glcontext; static const Window* cached_window; void fltk::set_gl_context(const Window* window, GLContext context) { if (context != fl_current_glcontext || window != cached_window) { fl_current_glcontext = context; cached_window = window; #if USE_X11 glXMakeCurrent(xdisplay, xid(window), context); #endif } } void fltk::no_gl_context() { #if USE_X11 glXMakeCurrent(xdisplay, 0, 0); #endif fl_current_glcontext = 0; cached_window = 0; } void fltk::delete_gl_context(GLContext context) { if (fl_current_glcontext == context) no_gl_context(); if (context != first_context) { #if USE_X11 glXDestroyContext(xdisplay, context); #endif } } #elif FL_API_VERSION == 1 #include <config.h> #if HAVE_GL # include <FL/Fl.H> # include <FL/x.H> # include <stdlib.h> # include "Fl_Gl_Choice.H" # include <FL/gl_draw.H> # include "flstring.h" # ifdef __APPLE__ # include <FL/Fl_Window.H> # endif static Fl_Gl_Choice *first; // this assummes one of the two arguments is zero: // We keep the list system in Win32 to stay compatible and interpret // the list later... Fl_Gl_Choice *Fl_Gl_Choice::find(int m, const int *alistp) { Fl_Gl_Choice *g; for (g = first; g; g = g->next) if (g->mode == m && g->alist == alistp) return g; # ifdef __APPLE_QD__ const int *blist; int list[32]; if (alistp) blist = alistp; else { int n = 0; if (m & FL_INDEX) { list[n++] = AGL_BUFFER_SIZE; list[n++] = 8; // glut tries many sizes, but this should work... } else { list[n++] = AGL_RGBA; list[n++] = AGL_GREEN_SIZE; list[n++] = (m & FL_RGB8) ? 8 : 1; if (m & FL_ALPHA) { list[n++] = AGL_ALPHA_SIZE; list[n++] = (m & FL_RGB8) ? 8 : 1; } if (m & FL_ACCUM) { list[n++] = AGL_ACCUM_GREEN_SIZE; list[n++] = 1; if (m & FL_ALPHA) { list[n++] = AGL_ACCUM_ALPHA_SIZE; list[n++] = 1; } } } if (m & FL_DOUBLE) { list[n++] = AGL_DOUBLEBUFFER; } if (m & FL_DEPTH) { list[n++] = AGL_DEPTH_SIZE; list[n++] = 24; } if (m & FL_STENCIL) { list[n++] = AGL_STENCIL_SIZE; list[n++] = 1; } list[n] = AGL_NONE; blist = list; } fl_open_display(); AGLPixelFormat fmt = aglChoosePixelFormat(NULL, 0, (GLint*)blist); if (!fmt) return 0; #elif defined(__APPLE_QUARTZ__) // warning: the Quartz version should probably use Core GL (CGL) instead of AGL const int *blist; int list[32]; if (alistp) blist = alistp; else { int n = 0; if (m & FL_INDEX) { list[n++] = AGL_BUFFER_SIZE; list[n++] = 8; // glut tries many sizes, but this should work... } else { list[n++] = AGL_RGBA; list[n++] = AGL_GREEN_SIZE; list[n++] = (m & FL_RGB8) ? 8 : 1; if (m & FL_ALPHA) { list[n++] = AGL_ALPHA_SIZE; list[n++] = (m & FL_RGB8) ? 8 : 1; } if (m & FL_ACCUM) { list[n++] = AGL_ACCUM_GREEN_SIZE; list[n++] = 1; if (m & FL_ALPHA) { list[n++] = AGL_ACCUM_ALPHA_SIZE; list[n++] = 1; } } } if (m & FL_DOUBLE) { list[n++] = AGL_DOUBLEBUFFER; } if (m & FL_DEPTH) { list[n++] = AGL_DEPTH_SIZE; list[n++] = 24; } if (m & FL_STENCIL) { list[n++] = AGL_STENCIL_SIZE; list[n++] = 1; } list[n] = AGL_NONE; blist = list; } fl_open_display(); AGLPixelFormat fmt = aglChoosePixelFormat(NULL, 0, (GLint*)blist); if (!fmt) return 0; # elif !defined(WIN32) const int *blist; int list[32]; if (alistp) blist = alistp; else { int n = 0; if (m & FL_INDEX) { list[n++] = GLX_BUFFER_SIZE; list[n++] = 8; // glut tries many sizes, but this should work... } else { list[n++] = GLX_RGBA; list[n++] = GLX_GREEN_SIZE; list[n++] = (m & FL_RGB8) ? 8 : 1; if (m & FL_ALPHA) { list[n++] = GLX_ALPHA_SIZE; list[n++] = (m & FL_RGB8) ? 8 : 1; } if (m & FL_ACCUM) { list[n++] = GLX_ACCUM_GREEN_SIZE; list[n++] = 1; if (m & FL_ALPHA) { list[n++] = GLX_ACCUM_ALPHA_SIZE; list[n++] = 1; } } } if (m & FL_DOUBLE) { list[n++] = GLX_DOUBLEBUFFER; } if (m & FL_DEPTH) { list[n++] = GLX_DEPTH_SIZE; list[n++] = 1; } if (m & FL_STENCIL) { list[n++] = GLX_STENCIL_SIZE; list[n++] = 1; } if (m & FL_STEREO) { list[n++] = GLX_STEREO; } # if defined(GLX_VERSION_1_1) && defined(GLX_SGIS_multisample) if (m & FL_MULTISAMPLE) { list[n++] = GLX_SAMPLES_SGIS; list[n++] = 4; // value Glut uses } # endif list[n] = 0; blist = list; } fl_open_display(); XVisualInfo *visp = glXChooseVisual(fl_display, fl_screen, (int *)blist); if (!visp) { # if defined(GLX_VERSION_1_1) && defined(GLX_SGIS_multisample) if (m&FL_MULTISAMPLE) return find(m&~FL_MULTISAMPLE,0); # endif return 0; } # else // Replacement for ChoosePixelFormat() that finds one with an overlay // if possible: if (!fl_gc) fl_GetDC(0); int pixelformat = 0; PIXELFORMATDESCRIPTOR chosen_pfd; for (int i = 1; ; i++) { PIXELFORMATDESCRIPTOR pfd; if (!DescribePixelFormat(fl_gc, i, sizeof(pfd), &pfd)) break; // continue if it does not satisfy our requirements: if (~pfd.dwFlags & (PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL)) continue; if (pfd.iPixelType != ((m&FL_INDEX)?PFD_TYPE_COLORINDEX:PFD_TYPE_RGBA)) continue; if ((m & FL_ALPHA) && !pfd.cAlphaBits) continue; if ((m & FL_ACCUM) && !pfd.cAccumBits) continue; if ((!(m & FL_DOUBLE)) != (!(pfd.dwFlags & PFD_DOUBLEBUFFER))) continue; if ((!(m & FL_STEREO)) != (!(pfd.dwFlags & PFD_STEREO))) continue; if ((m & FL_DEPTH) && !pfd.cDepthBits) continue; if ((m & FL_STENCIL) && !pfd.cStencilBits) continue; // see if better than the one we have already: if (pixelformat) { // offering non-generic rendering is better (read: hardware accelleration) if (!(chosen_pfd.dwFlags & PFD_GENERIC_FORMAT) && (pfd.dwFlags & PFD_GENERIC_FORMAT)) continue; // offering overlay is better: else if (!(chosen_pfd.bReserved & 15) && (pfd.bReserved & 15)) {} // otherwise more bit planes is better: else if (chosen_pfd.cColorBits > pfd.cColorBits) continue; else if (chosen_pfd.cDepthBits > pfd.cDepthBits) continue; } pixelformat = i; chosen_pfd = pfd; } //printf("Chosen pixel format is %d\n", pixelformat); if (!pixelformat) return 0; # endif g = new Fl_Gl_Choice; g->mode = m; g->alist = alistp; g->next = first; first = g; # ifdef WIN32 g->pixelformat = pixelformat; g->pfd = chosen_pfd; # elif defined(__APPLE_QD__) g->pixelformat = fmt; # elif defined(__APPLE_QUARTZ__) // warning: the Quartz version should probably use Core GL (CGL) instead of AGL g->pixelformat = fmt; # else g->vis = visp; if (/*MaxCmapsOfScreen(ScreenOfDisplay(fl_display,fl_screen))==1 && */ visp->visualid == fl_visual->visualid && !getenv("MESA_PRIVATE_CMAP")) g->colormap = fl_colormap; else g->colormap = XCreateColormap(fl_display, RootWindow(fl_display,fl_screen), visp->visual, AllocNone); # endif return g; } static GLContext *context_list = 0; static int nContext = 0, NContext = 0; static void add_context(GLContext ctx) { if (!ctx) return; if (nContext==NContext) { if (!NContext) NContext = 8; NContext *= 2; context_list = (GLContext*)realloc( context_list, NContext*sizeof(GLContext)); } context_list[nContext++] = ctx; } static void del_context(GLContext ctx) { int i; for (i=0; i<nContext; i++) { if (context_list[i]==ctx) { memmove(context_list+i, context_list+i+1, (nContext-i-1) * sizeof(GLContext)); context_list[--nContext] = 0; break; } } if (!nContext) gl_remove_displaylist_fonts(); } # ifdef WIN32 GLContext fl_create_gl_context(Fl_Window* window, const Fl_Gl_Choice* g, int layer) { Fl_X* i = Fl_X::i(window); HDC hdc = i->private_dc; if (!hdc) { hdc = i->private_dc = GetDCEx(i->xid, 0, DCX_CACHE); SetPixelFormat(hdc, g->pixelformat, (PIXELFORMATDESCRIPTOR*)(&g->pfd)); # if USE_COLORMAP if (fl_palette) SelectPalette(hdc, fl_palette, FALSE); # endif } GLContext context = layer ? wglCreateLayerContext(hdc, layer) : wglCreateContext(hdc); if (context) { if (context_list && context_list[0]) wglShareLists(context_list[0], context); add_context(context); } return context; } # elif defined(__APPLE_QD__) GLContext fl_create_gl_context(Fl_Window* window, const Fl_Gl_Choice* g, int layer) { GLContext context, shared_ctx = context_list ? context_list[0] : 0; context = aglCreateContext( g->pixelformat, shared_ctx); if (!context) return 0; add_context((GLContext)context); if ( window->parent() ) { Rect wrect; GetWindowPortBounds( fl_xid(window), &wrect ); GLint rect[] = { window->x(), wrect.bottom-window->h()-window->y(), window->w(), window->h() }; aglSetInteger( (GLContext)context, AGL_BUFFER_RECT, rect ); aglEnable( (GLContext)context, AGL_BUFFER_RECT ); } aglSetDrawable( context, GetWindowPort( fl_xid(window) ) ); return (context); } # elif defined(__APPLE_QUARTZ__) // warning: the Quartz version should probably use Core GL (CGL) instead of AGL GLContext fl_create_gl_context(Fl_Window* window, const Fl_Gl_Choice* g, int layer) { GLContext context, shared_ctx = context_list ? context_list[0] : 0; context = aglCreateContext( g->pixelformat, shared_ctx); if (!context) return 0; add_context((GLContext)context); if ( window->parent() ) { Rect wrect; GetWindowPortBounds( fl_xid(window), &wrect ); GLint rect[] = { window->x(), wrect.bottom-window->h()-window->y(), window->w(), window->h() }; aglSetInteger( (GLContext)context, AGL_BUFFER_RECT, rect ); aglEnable( (GLContext)context, AGL_BUFFER_RECT ); } aglSetDrawable( context, GetWindowPort( fl_xid(window) ) ); return (context); } # else GLContext fl_create_gl_context(XVisualInfo* vis) { GLContext shared_ctx = context_list ? context_list[0] : 0; GLContext context = glXCreateContext(fl_display, vis, shared_ctx, 1); if (context) add_context(context); return context; } # endif static GLContext cached_context; static Fl_Window* cached_window; void fl_set_gl_context(Fl_Window* w, GLContext context) { if (context != cached_context || w != cached_window) { cached_context = context; cached_window = w; # ifdef WIN32 wglMakeCurrent(Fl_X::i(w)->private_dc, context); # elif defined(__APPLE_QD__) if ( w->parent() ) { //: resize our GL buffer rectangle Rect wrect; GetWindowPortBounds( fl_xid(w), &wrect ); GLint rect[] = { w->x(), wrect.bottom-w->h()-w->y(), w->w(), w->h() }; aglSetInteger( context, AGL_BUFFER_RECT, rect ); aglEnable( context, AGL_BUFFER_RECT ); } aglSetDrawable(context, GetWindowPort( fl_xid(w) ) ); aglSetCurrentContext(context); # elif defined(__APPLE_QUARTZ__) // warning: the Quartz version should probably use Core GL (CGL) instead of AGL if ( w->parent() ) { //: resize our GL buffer rectangle Rect wrect; GetWindowPortBounds( fl_xid(w), &wrect ); GLint rect[] = { w->x(), wrect.bottom-w->h()-w->y(), w->w(), w->h() }; aglSetInteger( context, AGL_BUFFER_RECT, rect ); aglEnable( context, AGL_BUFFER_RECT ); } aglSetDrawable(context, GetWindowPort( fl_xid(w) ) ); aglSetCurrentContext(context); # else glXMakeCurrent(fl_display, fl_xid(w), context); # endif } } void fl_no_gl_context() { cached_context = 0; cached_window = 0; # ifdef WIN32 wglMakeCurrent(0, 0); # elif defined(__APPLE_QD__) aglSetCurrentContext(0); # elif defined(__APPLE_QUARTZ__) // warning: the Quartz version should probably use Core GL (CGL) instead of AGL aglSetCurrentContext(0); # else glXMakeCurrent(fl_display, 0, 0); # endif } void fl_delete_gl_context(GLContext context) { if (cached_context == context) fl_no_gl_context(); # ifdef WIN32 wglDeleteContext(context); # elif defined(__APPLE_QD__) aglSetCurrentContext( NULL ); aglSetDrawable( context, NULL ); aglDestroyContext( context ); # elif defined(__APPLE_QUARTZ__) // warning: the Quartz version should probably use Core GL (CGL) instead of AGL aglSetCurrentContext( NULL ); aglSetDrawable( context, NULL ); aglDestroyContext( context ); # else glXDestroyContext(fl_display, context); # endif del_context(context); } #endif // HAVE_GL #endif //FL_API_VERSION == 2 #endif // // End of "$Id: Fl_Gl_Choice.cxx 4242 2005-04-06 06:59:36Z spitzak $". //
Example of use
Finally let's get down to some example! ๐
Code:
#include "Prerequisites.h" #if FL_MAJOR_VERSION == 2 #include <fltk/run.h> #elif FL_MAJOR_VERSION == 1 #include <FL/Fl.H> #endif #include "Ogre.h" #include "OgreWindow.h" #include "EmbeddedOgre.h" #include "EmbeddedOgreImplementation.h" using namespace Ogre; class MyOgreApp : public ogre_interface::EmbeddedOgre { Camera* mCamera; public: MyOgreApp() {} virtual void createCameras() { // Create the camera mCamera = mImpl->getSceneManager()->createCamera( "PlayerCam" ); // Position it mCamera->setPosition( Vector3(0,0,500) ); mCamera->lookAt( Vector3(0,0,0) ); mCamera->setNearClipDistance( 5 ); } virtual void createViewports() { // Create one viewport, entire window Viewport* vp = mImpl->getWindow()->addViewport( mCamera ); vp->setBackgroundColour( ColourValue( 0,0,0 ) ); // Alter the camera aspect ratio to match the viewport mCamera->setAspectRatio( Real(vp->getActualWidth()) / Real(vp->getActualHeight())); } virtual void createScene() { // Lights. mImpl->getSceneManager()->setAmbientLight(ColourValue(0.2f, 0.2f, 0.8f, 1.0f)); Entity *ninjaEntity = mImpl->getSceneManager()->createEntity("Ninja", "ninja.mesh"); SceneNode *ninjaNode = static_cast<SceneNode *>(mImpl->getSceneManager()->getRootSceneNode()->createChild()); ninjaNode->attachObject(ninjaEntity); ninjaNode->yaw( Radian( -1 ) ); } }; OgreWindow* window = NULL; void idle_cp( void * ) { window->draw(); } int main(int argc, char **argv) { window = new OgreWindow( 100, 290, 800, 400, "OGRE#FLTK Window" ); //window->clear_border(); MyOgreApp myApp; window->setEmbeddedOgre( &myApp ); #if FL_MAJOR_VERSION == 2 fltk::add_idle( idle_cp, 0); window->show(); return fltk::run(); #elif FL_MAJOR_VERSION == 1 Fl::add_idle( idle_cp ); window->show(); return Fl::run(); #endif }
The main part of it of course is MyOgreApp! It's so obvious. FLTK users with some experience could notice that it is possible to use OgreWindow from within FLUID ๐.
The code is not excellent (at all ๐ ) and several refactorings are just obvious ๐)
Well feel free to make them :P !
My intention was to make code highly customizable. That's why user can change implementations in both OgreWindow and even in ogre_interface::EmbeddedOgre!
Hope you find it useful ๐
Cheers!
--Mj 04:51, 20 รลรยฐรยน 2005 (CDT)
Alias: Using_Ogre_with_FLTK