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, &params );
 
             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

<HR>
Creative Commons Copyright -- Some rights reserved.


THE WORK (AS DEFINED BELOW) IS PROVIDED UNDER THE TERMS OF THIS CREATIVE COMMONS PUBLIC LICENSE ("CCPL" OR "LICENSE"). THE WORK IS PROTECTED BY COPYRIGHT AND/OR OTHER APPLICABLE LAW. ANY USE OF THE WORK OTHER THAN AS AUTHORIZED UNDER THIS LICENSE OR COPYRIGHT LAW IS PROHIBITED.

BY EXERCISING ANY RIGHTS TO THE WORK PROVIDED HERE, YOU ACCEPT AND AGREE TO BE BOUND BY THE TERMS OF THIS LICENSE. THE LICENSOR GRANTS YOU THE RIGHTS CONTAINED HERE IN CONSIDERATION OF YOUR ACCEPTANCE OF SUCH TERMS AND CONDITIONS.

1. Definitions

  • "Collective Work" means a work, such as a periodical issue, anthology or encyclopedia, in which the Work in its entirety in unmodified form, along with a number of other contributions, constituting separate and independent works in themselves, are assembled into a collective whole. A work that constitutes a Collective Work will not be considered a Derivative Work (as defined below) for the purposes of this License.
  • "Derivative Work" means a work based upon the Work or upon the Work and other pre-existing works, such as a translation, musical arrangement, dramatization, fictionalization, motion picture version, sound recording, art reproduction, abridgment, condensation, or any other form in which the Work may be recast, transformed, or adapted, except that a work that constitutes a Collective Work will not be considered a Derivative Work for the purpose of this License. For the avoidance of doubt, where the Work is a musical composition or sound recording, the synchronization of the Work in timed-relation with a moving image ("synching") will be considered a Derivative Work for the purpose of this License.
  • "Licensor" means the individual or entity that offers the Work under the terms of this License.
  • "Original Author" means the individual or entity who created the Work.
  • "Work" means the copyrightable work of authorship offered under the terms of this License.
  • "You" means an individual or entity exercising rights under this License who has not previously violated the terms of this License with respect to the Work, or who has received express permission from the Licensor to exercise rights under this License despite a previous violation.
  • "License Elements" means the following high-level license attributes as selected by Licensor and indicated in the title of this License: Attribution, ShareAlike.

2. Fair Use Rights

Nothing in this license is intended to reduce, limit, or restrict any rights arising from fair use, first sale or other limitations on the exclusive rights of the copyright owner under copyright law or other applicable laws.

3. License Grant

Subject to the terms and conditions of this License, Licensor hereby grants You a worldwide, royalty-free, non-exclusive, perpetual (for the duration of the applicable copyright) license to exercise the rights in the Work as stated below:

  • to reproduce the Work, to incorporate the Work into one or more Collective Works, and to reproduce the Work as incorporated in the Collective Works;
  • to create and reproduce Derivative Works;
  • to distribute copies or phonorecords of, display publicly, perform publicly, and perform publicly by means of a digital audio transmission the Work including as incorporated in Collective Works;
  • to distribute copies or phonorecords of, display publicly, perform publicly, and perform publicly by means of a digital audio transmission Derivative Works.
  • For the avoidance of doubt, where the work is a musical composition:
    • Performance Royalties Under Blanket Licenses. Licensor waives the exclusive right to collect, whether individually or via a performance rights society (e.g. ASCAP, BMI, SESAC), royalties for the public performance or public digital performance (e.g. webcast) of the Work.
    • Mechanical Rights and Statutory Royalties. Licensor waives the exclusive right to collect, whether individually or via a music rights society or designated agent (e.g. Harry Fox Agency), royalties for any phonorecord You create from the Work ("cover version") and distribute, subject to the compulsory license created by 17 USC Section 115 of the US Copyright Act (or the equivalent in other jurisdictions).
    • Webcasting Rights and Statutory Royalties. For the avoidance of doubt, where the Work is a sound recording, Licensor waives the exclusive right to collect, whether individually or via a performance-rights society (e.g. SoundExchange), royalties for the public digital performance (e.g. webcast) of the Work, subject to the compulsory license created by 17 USC Section 114 of the US Copyright Act (or the equivalent in other jurisdictions).


The above rights may be exercised in all media and formats whether now known or hereafter devised. The above rights include the right to make such modifications as are technically necessary to exercise the rights in other media and formats. All rights not expressly granted by Licensor are hereby reserved.

4. Restrictions

The license granted in Section 3 above is expressly made subject to and limited by the following restrictions:

  • You may distribute, publicly display, publicly perform, or publicly digitally perform the Work only under the terms of this License, and You must include a copy of, or the Uniform Resource Identifier for, this License with every copy or phonorecord of the Work You distribute, publicly display, publicly perform, or publicly digitally perform. You may not offer or impose any terms on the Work that alter or restrict the terms of this License or the recipients' exercise of the rights granted hereunder. You may not sublicense the Work. You must keep intact all notices that refer to this License and to the disclaimer of warranties. You may not distribute, publicly display, publicly perform, or publicly digitally perform the Work with any technological measures that control access or use of the Work in a manner inconsistent with the terms of this License Agreement. The above applies to the Work as incorporated in a Collective Work, but this does not require the Collective Work apart from the Work itself to be made subject to the terms of this License. If You create a Collective Work, upon notice from any Licensor You must, to the extent practicable, remove from the Collective Work any credit as required by clause 4(c), as requested. If You create a Derivative Work, upon notice from any Licensor You must, to the extent practicable, remove from the Derivative Work any credit as required by clause 4(c), as requested.
  • You may distribute, publicly display, publicly perform, or publicly digitally perform a Derivative Work only under the terms of this License, a later version of this License with the same License Elements as this License, or a Creative Commons iCommons license that contains the same License Elements as this License (e.g. Attribution-ShareAlike 2.5 Japan). You must include a copy of, or the Uniform Resource Identifier for, this License or other license specified in the previous sentence with every copy or phonorecord of each Derivative Work You distribute, publicly display, publicly perform, or publicly digitally perform. You may not offer or impose any terms on the Derivative Works that alter or restrict the terms of this License or the recipients' exercise of the rights granted hereunder, and You must keep intact all notices that refer to this License and to the disclaimer of warranties. You may not distribute, publicly display, publicly perform, or publicly digitally perform the Derivative Work with any technological measures that control access or use of the Work in a manner inconsistent with the terms of this License Agreement. The above applies to the Derivative Work as incorporated in a Collective Work, but this does not require the Collective Work apart from the Derivative Work itself to be made subject to the terms of this License.
  • If you distribute, publicly display, publicly perform, or publicly digitally perform the Work or any Derivative Works or Collective Works, You must keep intact all copyright notices for the Work and provide, reasonable to the medium or means You are utilizing: (i) the name of the Original Author (or pseudonym, if applicable) if supplied, and/or (ii) if the Original Author and/or Licensor designate another party or parties (e.g. a sponsor institute, publishing entity, journal) for attribution in Licensor's copyright notice, terms of service or by other reasonable means, the name of such party or parties; the title of the Work if supplied; to the extent reasonably practicable, the Uniform Resource Identifier, if any, that Licensor specifies to be associated with the Work, unless such URI does not refer to the copyright notice or licensing information for the Work; and in the case of a Derivative Work, a credit identifying the use of the Work in the Derivative Work (e.g., "French translation of the Work by Original Author," or "Screenplay based on original Work by Original Author"). Such credit may be implemented in any reasonable manner; provided, however, that in the case of a Derivative Work or Collective Work, at a minimum such credit will appear where any other comparable authorship credit appears and in a manner at least as prominent as such other comparable authorship credit.

5. Representations, Warranties and Disclaimer

UNLESS OTHERWISE AGREED TO BY THE PARTIES IN WRITING, LICENSOR OFFERS THE WORK AS-IS AND MAKES NO REPRESENTATIONS OR WARRANTIES OF ANY KIND CONCERNING THE MATERIALS, EXPRESS, IMPLIED, STATUTORY OR OTHERWISE, INCLUDING, WITHOUT LIMITATION, WARRANTIES OF TITLE, MERCHANTIBILITY, FITNESS FOR A PARTICULAR PURPOSE, NONINFRINGEMENT, OR THE ABSENCE OF LATENT OR OTHER DEFECTS, ACCURACY, OR THE PRESENCE OF ABSENCE OF ERRORS, WHETHER OR NOT DISCOVERABLE. SOME JURISDICTIONS DO NOT ALLOW THE EXCLUSION OF IMPLIED WARRANTIES, SO SUCH EXCLUSION MAY NOT APPLY TO YOU.

6. Limitation on Liability.

EXCEPT TO THE EXTENT REQUIRED BY APPLICABLE LAW, IN NO EVENT WILL LICENSOR BE LIABLE TO YOU ON ANY LEGAL THEORY FOR ANY SPECIAL, INCIDENTAL, CONSEQUENTIAL, PUNITIVE OR EXEMPLARY DAMAGES ARISING OUT OF THIS LICENSE OR THE USE OF THE WORK, EVEN IF LICENSOR HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.

7. Termination

  • This License and the rights granted hereunder will terminate automatically upon any breach by You of the terms of this License. Individuals or entities who have received Derivative Works or Collective Works from You under this License, however, will not have their licenses terminated provided such individuals or entities remain in full compliance with those licenses. Sections 1, 2, 5, 6, 7, and 8 will survive any termination of this License.
  • Subject to the above terms and conditions, the license granted here is perpetual (for the duration of the applicable copyright in the Work). Notwithstanding the above, Licensor reserves the right to release the Work under different license terms or to stop distributing the Work at any time; provided, however that any such election will not serve to withdraw this License (or any other license that has been, or is required to be, granted under the terms of this License), and this License will continue in full force and effect unless terminated as stated above.

8. Miscellaneous

  • Each time You distribute or publicly digitally perform the Work or a Collective Work, the Licensor offers to the recipient a license to the Work on the same terms and conditions as the license granted to You under this License.
  • Each time You distribute or publicly digitally perform a Derivative Work, Licensor offers to the recipient a license to the original Work on the same terms and conditions as the license granted to You under this License.
  • If any provision of this License is invalid or unenforceable under applicable law, it shall not affect the validity or enforceability of the remainder of the terms of this License, and without further action by the parties to this agreement, such provision shall be reformed to the minimum extent necessary to make such provision valid and enforceable.
  • No term or provision of this License shall be deemed waived and no breach consented to unless such waiver or consent shall be in writing and signed by the party to be charged with such waiver or consent.
  • This License constitutes the entire agreement between the parties with respect to the Work licensed here. There are no understandings, agreements or representations with respect to the Work not specified here. Licensor shall not be bound by any additional provisions that may appear in any communication from You. This License may not be modified without the mutual written agreement of the Licensor and You.