How to use CEGUI with SDL and OpenGL

From CEGUI Wiki - Crazy Eddie's GUI System (Open Source)
Revision as of 19:42, 12 June 2011 by Kulik (Talk | contribs) (fixed badges)

(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to: navigation, search

Written for CEGUI 0.7


Works with versions 0.7.x (obsolete)

Requires at least version
0.7.5

This HOW-TO simply illustrates with a full, runnable, autonomous example, how CEGUI can be used with SDL and OpenGL.

It shows:

  1. a minimal example
  2. a more involved example that includes most of the CEGUI widgets that are available (with the Taharez Look)

The platform used here is GNU/Linux.

Please post comments or questions on the message board thread for this HOW-TO.


Common Topics

Prerequisites

CEGUI depends on various libraries. We used:

  • FreeImage [3.15.0] ; you must specify one library among FreeImage, DevIL or SILLY (this is their usual order in terms of preference), otherwise only TGA images could be loaded (note: FreeImage install must be fixed if targeting a prefixed directory rather than the default one in the system tree; anyway pre-0.8 versions of CEGUI's will need to have FreeImage installed in the system)
  • PCRE [8.12] ; if building if from sources, specify the following configure option: --enable-unicode-properties
  • FreeType [2.4.3]

If you installed PCRE or FreeType in a prefixed directory, prior to executing CEGUI's configure you should specify in your shell respectively:

export pcre_CFLAGS="-I${pcre_PREFIX}/include" export pcre_LIBS="-L${pcre_PREFIX}/lib -lpcre"

and

export freetype2_CFLAGS="-I${freetype_PREFIX}/include -I${freetype_PREFIX}/include/freetype2" export freetype2_LIBS="-L${freetype_PREFIX}/lib -lfreetype"

We used SDL version 1.2.14.

Finally, GLUT is needed for the CEGUI's samples, Ubuntu users may thus execute beforehand, as root:

apt-get install libglut3-dev libglut3

For CEGUI itself, we used the following configuration options: --enable-debug --disable-lua-module --disable-python-module

Locating Resources

For default CEGUI's resources to be found (ex: fonts, images, etc.), the test program must be able to find out what are their paths, which are relative to the place where CEGUI was installed. One must thus update accordingly in the example the CEGUIInstallBasePath variable so that it points to a directory from which /share/CEGUI/ can be found.

Example:

 
const std::string & CEGUIInstallBasePath = "/home/joe/my-CEGUI-0.7.5-install" ;


Building The Examples

A simple yet powerful enough makefile could be this one (ex: save it under the "GNUmakefile" filename ; all our prerequisites are installed in a directory pointed to by the LOANI_INSTALLATIONS environment variable):

CEGUI_INSTALL_ROOT := $$LOANI_INSTALLATIONS/CEGUI-0.7.5
 
SDL_INSTALL_ROOT := $$LOANI_INSTALLATIONS/SDL-1.2.14
 
SDL_CONFIG := $(SDL_INSTALL_ROOT)/bin/sdl-config
 
 
C_COMPILER   := gcc
CPP_COMPILER := g++
 
INC_FLAGS = -I$(CEGUI_INSTALL_ROOT)/include/CEGUI `$(SDL_CONFIG) --cflags`
LD_FLAGS  = -L$(CEGUI_INSTALL_ROOT)/lib -lCEGUIOpenGLRenderer -lCEGUIBase `$(SDL_CONFIG) --libs`
 
EXECUTABLES := $(patsubst %.cc,%.exe,$(wildcard *.cc))
 
# Note: source $LOANI_INSTALLATIONS/OSDL-environment.sh before running produced
# executables.
 
all: $(EXECUTABLES)
 
%.o: %.c
	@echo "    Compiling $@"
	$(C_COMPILER) -c $< -o $@ $(INC_FLAGS)
 
 
%.o: %.cc
	@echo "    Compiling $@"
	$(CPP_COMPILER) -c $< -o $@ $(INC_FLAGS)
 
 
%.exe: %.o %.c
	@echo "    Linking $@"
	$(C_COMPILER) -o $@ $< $(LD_FLAGS)
 
 
%.exe: %.o %.cc
	@echo "    Linking $@"
	$(CPP_COMPILER) -o $@ $< $(LD_FLAGS)
 
clean:
	@echo "    Cleaning"
	-@/bin/rm -f *.o $(EXECUTABLES)
 
infos:
	@echo "CEGUI_INSTALL_ROOT = $(CEGUI_INSTALL_ROOT)"
	@echo "INC_FLAGS = $(INC_FLAGS)"
	@echo "LD_FLAGS = $(LD_FLAGS)"
	@echo "EXECUTABLES = $(EXECUTABLES)"

The main point is to set correctly the compilation and linking flags for SDL and CEGUI.

Then the build should be as easy as: $ make clean all

   Cleaning                                                                                                                                   
   Compiling CEGUI-SDL-all-widgets.o                                                                                                          

g++ -c CEGUI-SDL-all-widgets.cc -o CEGUI-SDL-all-widgets.o -I$LOANI_INSTALLATIONS/CEGUI-0.7.5/include/CEGUI `$LOANI_INSTALLATIONS/SDL-1.2.14/bin/sdl-config --cflags`

   Linking CEGUI-SDL-all-widgets.exe                                                                                                          

g++ -o CEGUI-SDL-all-widgets.exe CEGUI-SDL-all-widgets.o -L$LOANI_INSTALLATIONS/CEGUI-0.7.5/lib -lCEGUIOpenGLRenderer -lCEGUIBase `$LOANI_INSTALLATIONS/SDL-1.2.14/bin/sdl-config --libs`

   Compiling CEGUI-SDL-hello-world.o                                                                                                          

g++ -c CEGUI-SDL-hello-world.cc -o CEGUI-SDL-hello-world.o -I$LOANI_INSTALLATIONS/CEGUI-0.7.5/include/CEGUI `$LOANI_INSTALLATIONS/SDL-1.2.14/bin/sdl-config --cflags`

   Linking CEGUI-SDL-hello-world.exe                                                                                                          

g++ -o CEGUI-SDL-hello-world.exe CEGUI-SDL-hello-world.o -L$LOANI_INSTALLATIONS/CEGUI-0.7.5/lib -lCEGUIOpenGLRenderer -lCEGUIBase `$LOANI_INSTALLATIONS/SDL-1.2.14/bin/sdl-config --libs` rm CEGUI-SDL-all-widgets.o CEGUI-SDL-hello-world.o

A Minimal Example

As you can see in this file (ex: to be saved as CEGUI-SDL-hello-world.cc), it is quite short and easy to understand:

/*
 * This is a rather minimal 'hello world' test of CEGUI, used we SDL and OpenGL,
 * on GNU/Linux.
 *
 * Largely inspired from
 * http://www.cegui.org.uk/wiki/index.php/Using_CEGUI_with_SDL_and_OpenGL_%280.7%29
 *
 * Author: Olivier Boudeville (olivier.boudeville@esperide.com)
 *
 */
 
#include "SDL.h"
 
#include "CEGUI.h"
#include "RendererModules/OpenGL/CEGUIOpenGLRenderer.h"
 
#include <GL/gl.h>
 
#include <iostream>
 
using namespace std ;
 
using namespace CEGUI ;
 
 
// Change according to your installation path:
const std::string & CEGUIInstallBasePath =
  "/home/wondersye/Projects/LOANI-latest/LOANI-installations/CEGUI-0.7.5" ;
 
/*
const std::string & CEGUIInstallBasePath = "/usr" ;
*/
 
 
 
// Input management: from SDL to CEGUI.
 
void handle_mouse_down( Uint8 button )
{
 
  switch ( button )
  {
 
  case SDL_BUTTON_LEFT:
	CEGUI::System::getSingleton().injectMouseButtonDown( CEGUI::LeftButton ) ;
	break ;
 
  case SDL_BUTTON_MIDDLE:
	CEGUI::System::getSingleton().injectMouseButtonDown( CEGUI::MiddleButton ) ;
	break ;
 
  case SDL_BUTTON_RIGHT:
	CEGUI::System::getSingleton().injectMouseButtonDown( CEGUI::RightButton) ;
	break ;
 
  case SDL_BUTTON_WHEELDOWN:
	CEGUI::System::getSingleton().injectMouseWheelChange( -1 ) ;
	break ;
 
  case SDL_BUTTON_WHEELUP:
	CEGUI::System::getSingleton().injectMouseWheelChange( +1 ) ;
	break ;
 
  default:
	cout << "handle_mouse_down ignored '" << static_cast<int>( button )
		 << "'" << endl ;
	break ;
 
  }
 
}
 
 
void handle_mouse_up( Uint8 button )
{
 
  switch ( button )
  {
 
  case SDL_BUTTON_LEFT:
	CEGUI::System::getSingleton().injectMouseButtonUp( CEGUI::LeftButton ) ;
	break ;
 
  case SDL_BUTTON_MIDDLE:
	CEGUI::System::getSingleton().injectMouseButtonUp( CEGUI::MiddleButton ) ;
	break ;
 
  case SDL_BUTTON_RIGHT:
	CEGUI::System::getSingleton().injectMouseButtonUp( CEGUI::RightButton ) ;
	break ;
 
  case SDL_BUTTON_WHEELDOWN:
	break ;
 
  case SDL_BUTTON_WHEELUP:
	break ;
 
  default:
	cout << "handle_mouse_up ignored '" << static_cast<int>( button )
		 << "'" << endl ;
	break ;
 
  }
 
}
 
 
 
void inject_input( bool & must_quit )
{
 
  SDL_Event e ;
 
  // Go through all available events:
  while ( SDL_PollEvent( &e ) )
  {
 
	// Route according to the event type:
	switch( e.type )
	{
 
	// Mouse section:
 
	case SDL_MOUSEMOTION:
	  // We inject the mouse position directly here:
	  CEGUI::System::getSingleton().injectMousePosition(
		static_cast<float>( e.motion.x ), static_cast<float>( e.motion.y ) ) ;
	  break ;
 
	case SDL_MOUSEBUTTONDOWN:
	  handle_mouse_down( e.button.button ) ;
	  break ;
 
	case SDL_MOUSEBUTTONUP:
	  handle_mouse_up( e.button.button ) ;
	  break ;
 
	// Keyboard section:
 
	case SDL_KEYDOWN:
 
	  CEGUI::System::getSingleton().injectKeyDown(e.key.keysym.scancode) ;
 
	  /*
	   * Managing the character is more difficult, we have to use a translated
	   * unicode value:
	   *
	   */
 
	  if ( (e.key.keysym.unicode & 0xFF80) == 0 )
	  {
		CEGUI::System::getSingleton().injectChar(
		  e.key.keysym.unicode & 0x7F ) ;
	  }
	  break ;
 
	case SDL_KEYUP:
	  CEGUI::System::getSingleton().injectKeyUp( e.key.keysym.scancode ) ;
	  break ;
 
	// A WM quit event occured:
	case SDL_QUIT:
	  must_quit = true ;
	  break ;
 
	case SDL_VIDEORESIZE:
	  CEGUI::System::getSingleton().notifyDisplaySizeChanged(
		CEGUI::Size( e.resize.w, e.resize.h ) ) ;
	  break ;
 
	}
 
  }
 
}
 
 
 
void inject_time_pulse( double & last_time_pulse )
{
 
  // Get current "run-time" in seconds:
  double current_time_pulse = 0.001 * SDL_GetTicks() ;
 
  // Inject the time that passed since the last call:
  CEGUI::System::getSingleton().injectTimePulse( static_cast<float>(
	  current_time_pulse - last_time_pulse ) ) ;
 
  // Records the new time as the last time:
  last_time_pulse = current_time_pulse ;
 
}
 
 
 
void render_gui()
{
 
  // Clears the colour buffer:
  glClear( GL_COLOR_BUFFER_BIT ) ;
 
  // Renders the GUI:
  CEGUI::System::getSingleton().renderGUI() ;
 
  // Updates the screen:
  SDL_GL_SwapBuffers() ;
 
}
 
 
void main_loop ()
{
 
  cout << " - entering main loop" << endl ;
 
  bool must_quit = false ;
 
  // get "run-time" in seconds
  double last_time_pulse = 0.001 * static_cast<double>( SDL_GetTicks() ) ;
 
  while ( ! must_quit )
  {
 
	inject_input( must_quit ) ;
	inject_time_pulse( last_time_pulse ) ;
	render_gui() ;
 
  }
 
  cout << " - leaving main loop" << endl ;
 
}
 
 
SDL_Surface & init_SDL()
{
 
  cout << " - initializing SDL" << endl ;
 
  atexit (SDL_Quit) ;
 
  if ( SDL_Init(SDL_INIT_VIDEO) < 0 )
  {
	cerr << "Unable to initialise SDL: " << SDL_GetError() ;
	exit(0) ;
  }
 
  SDL_Surface * screen = SDL_SetVideoMode ( 600, 480, 0, SDL_OPENGL ) ;
 
  if ( screen == 0 )
  {
	cerr << "Unable to set OpenGL videomode: " << SDL_GetError() ;
	SDL_Quit() ;
	exit(0) ;
  }
 
  SDL_ShowCursor( SDL_DISABLE ) ;
  SDL_EnableUNICODE( 1 ) ;
  SDL_EnableKeyRepeat( SDL_DEFAULT_REPEAT_DELAY, SDL_DEFAULT_REPEAT_INTERVAL ) ;
 
  return *screen ;
 
}
 
 
 
void set_CEGUI_paths()
{
 
	// Initialises the required directories for the DefaultResourceProvider:
 
	CEGUI::DefaultResourceProvider & defaultResProvider =
		* static_cast<CEGUI::DefaultResourceProvider*>
			( CEGUI::System::getSingleton().getResourceProvider() ) ;
 
	const string CEGUIInstallSharePath = CEGUIInstallBasePath
	  + "/share/CEGUI/" ;
 
	// For each resource type, sets a corresponding resource group directory:
 
	cout << "Using scheme directory '" << CEGUIInstallSharePath + "schemes/"
		 << "'" << endl ;
 
	defaultResProvider.setResourceGroupDirectory( "schemes",
	  CEGUIInstallSharePath + "schemes/" ) ;
 
	defaultResProvider.setResourceGroupDirectory( "imagesets",
	  CEGUIInstallSharePath + "imagesets/" ) ;
 
	defaultResProvider.setResourceGroupDirectory( "fonts",
	  CEGUIInstallSharePath + "fonts/" ) ;
 
	defaultResProvider.setResourceGroupDirectory( "layouts",
	  CEGUIInstallSharePath + "layouts/" ) ;
 
	defaultResProvider.setResourceGroupDirectory( "looknfeels",
	  CEGUIInstallSharePath + "looknfeel/" ) ;
 
	defaultResProvider.setResourceGroupDirectory( "lua_scripts",
	  CEGUIInstallSharePath + "lua_scripts/" ) ;
 
	defaultResProvider.setResourceGroupDirectory( "schemas",
	  CEGUIInstallSharePath + "xml_schemas/" ) ;
 
	defaultResProvider.setResourceGroupDirectory( "animations",
	  CEGUIInstallSharePath + "animations/" ) ;
 
	// Sets the default resource groups to be used:
	CEGUI::Imageset::setDefaultResourceGroup( "imagesets" ) ;
	CEGUI::Font::setDefaultResourceGroup( "fonts" ) ;
	CEGUI::Scheme::setDefaultResourceGroup( "schemes" ) ;
	CEGUI::WidgetLookManager::setDefaultResourceGroup( "looknfeels" ) ;
	CEGUI::WindowManager::setDefaultResourceGroup( "layouts" ) ;
	CEGUI::ScriptModule::setDefaultResourceGroup( "lua_scripts" ) ;
	CEGUI::AnimationManager::setDefaultResourceGroup( "animations" ) ;
 
	// Set-up default group for validation schemas:
	CEGUI::XMLParser * parser = CEGUI::System::getSingleton().getXMLParser() ;
	if ( parser->isPropertyPresent( "SchemaDefaultResourceGroup" ) )
		parser->setProperty( "SchemaDefaultResourceGroup", "schemas" ) ;
 
}
 
 
WindowManager & init_CEGUI( SDL_Surface & surface )
{
 
  cout << " - initializing CEGUI" << endl ;
 
  CEGUI::OpenGLRenderer::bootstrapSystem() ;
 
  set_CEGUI_paths() ;
 
  SchemeManager::getSingleton().create( "TaharezLook.scheme" ) ;
 
  System::getSingleton().setDefaultMouseCursor( "TaharezLook", "MouseArrow" ) ;
 
  return WindowManager::getSingleton() ;
 
}
 
 
 
void create_gui( WindowManager & winManager )
{
 
  cout << " - creating the GUI" << endl ;
 
  DefaultWindow & rootWin = * static_cast<DefaultWindow*>(
	winManager.createWindow( "DefaultWindow", "Root" ) ) ;
 
  System::getSingleton().setGUISheet( &rootWin ) ;
 
  FrameWindow & myWin = * static_cast<FrameWindow*>( winManager.createWindow(
	  "TaharezLook/FrameWindow", "Demo Window" ) ) ;
 
  rootWin.addChildWindow( &myWin ) ;
 
  myWin.setPosition( UVector2( cegui_reldim(0.25f), cegui_reldim(0.25f) ) ) ;
  myWin.setSize( UVector2( cegui_reldim(0.5f), cegui_reldim(0.5f) ) ) ;
 
  myWin.setMaxSize( UVector2( cegui_reldim(1.0f), cegui_reldim(1.0f) ) ) ;
  myWin.setMinSize( UVector2( cegui_reldim(0.1f), cegui_reldim(0.1f) ) ) ;
 
  myWin.setText( "Hello World! This is a minimal SDL+OpenGL+CEGUI test." ) ;
 
}
 
 
int main( int argc, char *argv[] )
{
 
  cout << " - starting CEGUI test" << endl ;
 
  SDL_Surface & screen = init_SDL() ;
 
  WindowManager & winManager = init_CEGUI( screen ) ;
 
  create_gui( winManager ) ;
 
  main_loop() ;
 
  cout << " - ending CEGUI test" << endl ;
 
}

The point is first to initialize correctly SDL (notably for OpenGL and input settings) and CEGUI (mainly with regard to resource paths).

Then the application-specific GUI itself is to be created, here fully from code (rather than thanks to XML description files).

The main loop can then be run, it just iterates endlessly through the following steps:

  1. inputs (including wallclock-timing) are collected from SDL and then fed appropriately to CEGUI
  2. GUI is requested to update its rendering accordingly

Here is a corresponding screenshot:

CEGUI-SDL-hello-world.png

An Example With Most Widgets

The purpose of this example is to show most CEGUI widgets in the Taharez Look, in order for a developer to know what are the GUI elements that he can use. No wiring or event processing is done for them, we just want to showcase the available widget toolbox.

One can save the following code in, say, CEGUI-SDL-all-widgets.cc:

/*
 * This is a test of CEGUI, targeting to showcase all its widgets, using SDL and
 * OpenGL, on GNU/Linux.
 *
 * Largely inspired from
 * http://www.cegui.org.uk/wiki/index.php/Using_CEGUI_with_SDL_and_OpenGL_%280.7%29
 * and from Sample_Demo6.cpp.
 *
 * Author: Olivier Boudeville (olivier.boudeville@esperide.com)
 *
 */
 
/*
 * Could be added:
 *
 * - drag'n drop testing (see Sample_DragDropDemo.cpp)
 * - scrollable pane testing (see Sample_ScrollablePane.cpp)
 * - tab testing (see Sample_TabControl.cpp)
 *
 */
 
#include "SDL.h"
 
#include "CEGUI.h"
#include "RendererModules/OpenGL/CEGUIOpenGLRenderer.h"
 
#include <GL/gl.h>
 
#include <iostream>
 
using namespace std ;
 
using namespace CEGUI ;
 
 
// Change according to your installation path:
const std::string & CEGUIInstallBasePath =
  "/home/wondersye/Projects/LOANI-latest/LOANI-installations/CEGUI-0.7.5" ;
 
/*
const std::string & CEGUIInstallBasePath = "/usr" ;
*/
 
 
 
// Input management: from SDL to CEGUI.
 
void handle_mouse_down( Uint8 button )
{
 
  switch ( button )
  {
 
  case SDL_BUTTON_LEFT:
	CEGUI::System::getSingleton().injectMouseButtonDown( CEGUI::LeftButton ) ;
	break ;
 
  case SDL_BUTTON_MIDDLE:
	CEGUI::System::getSingleton().injectMouseButtonDown( CEGUI::MiddleButton ) ;
	break ;
 
  case SDL_BUTTON_RIGHT:
	CEGUI::System::getSingleton().injectMouseButtonDown( CEGUI::RightButton) ;
	break ;
 
  case SDL_BUTTON_WHEELDOWN:
	CEGUI::System::getSingleton().injectMouseWheelChange( -1 ) ;
	break ;
 
  case SDL_BUTTON_WHEELUP:
	CEGUI::System::getSingleton().injectMouseWheelChange( +1 ) ;
	break ;
 
  default:
	cout << "handle_mouse_down ignored '" << static_cast<int>( button )
		 << "'" << endl ;
	break ;
 
  }
 
}
 
 
void handle_mouse_up( Uint8 button )
{
 
  switch ( button )
  {
 
  case SDL_BUTTON_LEFT:
	CEGUI::System::getSingleton().injectMouseButtonUp( CEGUI::LeftButton ) ;
	break ;
 
  case SDL_BUTTON_MIDDLE:
	CEGUI::System::getSingleton().injectMouseButtonUp( CEGUI::MiddleButton ) ;
	break ;
 
  case SDL_BUTTON_RIGHT:
	CEGUI::System::getSingleton().injectMouseButtonUp( CEGUI::RightButton ) ;
	break ;
 
  case SDL_BUTTON_WHEELDOWN:
	break ;
 
  case SDL_BUTTON_WHEELUP:
	break ;
 
  default:
	cout << "handle_mouse_up ignored '" << static_cast<int>( button )
		 << "'" << endl ;
	break ;
 
  }
 
}
 
 
 
void inject_input( bool & must_quit )
{
 
  SDL_Event e ;
 
  // Go through all available events:
  while ( SDL_PollEvent( &e ) )
  {
 
	// Route according to the event type:
	switch( e.type )
	{
 
	// Mouse section:
 
	case SDL_MOUSEMOTION:
	  // We inject the mouse position directly here:
	  CEGUI::System::getSingleton().injectMousePosition(
		static_cast<float>( e.motion.x ), static_cast<float>( e.motion.y ) ) ;
	  break ;
 
	case SDL_MOUSEBUTTONDOWN:
	  handle_mouse_down( e.button.button ) ;
	  break ;
 
	case SDL_MOUSEBUTTONUP:
	  handle_mouse_up( e.button.button ) ;
	  break ;
 
	// Keyboard section:
 
	case SDL_KEYDOWN:
 
	  CEGUI::System::getSingleton().injectKeyDown(e.key.keysym.scancode) ;
 
	  /*
	   * Managing the character is more difficult, we have to use a translated
	   * unicode value:
	   *
	   */
 
	  if ( (e.key.keysym.unicode & 0xFF80) == 0 )
	  {
		CEGUI::System::getSingleton().injectChar(
		  e.key.keysym.unicode & 0x7F ) ;
	  }
	  break ;
 
	case SDL_KEYUP:
	  CEGUI::System::getSingleton().injectKeyUp( e.key.keysym.scancode ) ;
	  break ;
 
	// A WM quit event occured:
	case SDL_QUIT:
	  must_quit = true ;
	  break ;
 
	case SDL_VIDEORESIZE:
	  CEGUI::System::getSingleton().notifyDisplaySizeChanged(
		CEGUI::Size( e.resize.w, e.resize.h ) ) ;
	  break ;
 
	}
 
  }
 
}
 
 
 
void inject_time_pulse( double & last_time_pulse )
{
 
  // Get current "run-time" in seconds:
  double current_time_pulse = 0.001 * SDL_GetTicks() ;
 
  // Inject the time that passed since the last call:
  CEGUI::System::getSingleton().injectTimePulse( static_cast<float>(
	  current_time_pulse - last_time_pulse ) ) ;
 
  // Records the new time as the last time:
  last_time_pulse = current_time_pulse ;
 
}
 
 
 
void render_gui()
{
 
  // Clears the colour buffer:
  glClear( GL_COLOR_BUFFER_BIT ) ;
 
  // Renders the GUI:
  CEGUI::System::getSingleton().renderGUI() ;
 
  // Updates the screen:
  SDL_GL_SwapBuffers() ;
 
}
 
 
void main_loop ()
{
 
  cout << " - entering main loop" << endl ;
 
  bool must_quit = false ;
 
  // get "run-time" in seconds
  double last_time_pulse = 0.001 * static_cast<double>( SDL_GetTicks() ) ;
 
  while ( ! must_quit )
  {
 
	inject_input( must_quit ) ;
	inject_time_pulse( last_time_pulse ) ;
	render_gui() ;
 
  }
 
  cout << " - leaving main loop" << endl ;
 
}
 
 
SDL_Surface & init_SDL()
{
 
  cout << " - initializing SDL" << endl ;
 
  atexit (SDL_Quit) ;
 
  if ( SDL_Init(SDL_INIT_VIDEO) < 0 )
  {
	cerr << "Unable to initialise SDL: " << SDL_GetError() ;
	exit(0) ;
  }
 
  SDL_Surface * screen = SDL_SetVideoMode ( 1024, 768,
	/* use the current display bits per pixel */ 0, SDL_OPENGL ) ;
 
  if ( screen == 0 )
  {
	cerr << "Unable to set OpenGL videomode: " << SDL_GetError() ;
	SDL_Quit() ;
	exit(0) ;
  }
 
  SDL_ShowCursor( SDL_DISABLE ) ;
  SDL_EnableUNICODE( 1 ) ;
  SDL_EnableKeyRepeat( SDL_DEFAULT_REPEAT_DELAY, SDL_DEFAULT_REPEAT_INTERVAL ) ;
 
  return *screen ;
 
}
 
 
 
void set_CEGUI_paths()
{
 
	// Initialises the required directories for the DefaultResourceProvider:
 
	CEGUI::DefaultResourceProvider & defaultResProvider =
		* static_cast<CEGUI::DefaultResourceProvider*>
			( CEGUI::System::getSingleton().getResourceProvider() ) ;
 
	const string CEGUIInstallSharePath = CEGUIInstallBasePath
	  + "/share/CEGUI/" ;
 
	// For each resource type, sets a corresponding resource group directory:
 
	cout << "Using scheme directory '" << CEGUIInstallSharePath + "schemes/"
		 << "'" << endl ;
 
	defaultResProvider.setResourceGroupDirectory( "schemes",
	  CEGUIInstallSharePath + "schemes/" ) ;
 
	defaultResProvider.setResourceGroupDirectory( "imagesets",
	  CEGUIInstallSharePath + "imagesets/" ) ;
 
	defaultResProvider.setResourceGroupDirectory( "fonts",
	  CEGUIInstallSharePath + "fonts/" ) ;
 
	defaultResProvider.setResourceGroupDirectory( "layouts",
	  CEGUIInstallSharePath + "layouts/" ) ;
 
	defaultResProvider.setResourceGroupDirectory( "looknfeels",
	  CEGUIInstallSharePath + "looknfeel/" ) ;
 
	defaultResProvider.setResourceGroupDirectory( "lua_scripts",
	  CEGUIInstallSharePath + "lua_scripts/" ) ;
 
	defaultResProvider.setResourceGroupDirectory( "schemas",
	  CEGUIInstallSharePath + "xml_schemas/" ) ;
 
	defaultResProvider.setResourceGroupDirectory( "animations",
	  CEGUIInstallSharePath + "animations/" ) ;
 
	// Sets the default resource groups to be used:
	CEGUI::Imageset::setDefaultResourceGroup( "imagesets" ) ;
	CEGUI::Font::setDefaultResourceGroup( "fonts" ) ;
	CEGUI::Scheme::setDefaultResourceGroup( "schemes" ) ;
	CEGUI::WidgetLookManager::setDefaultResourceGroup( "looknfeels" ) ;
	CEGUI::WindowManager::setDefaultResourceGroup( "layouts" ) ;
	CEGUI::ScriptModule::setDefaultResourceGroup( "lua_scripts" ) ;
	CEGUI::AnimationManager::setDefaultResourceGroup( "animations" ) ;
 
	// Set-up default group for validation schemas:
	CEGUI::XMLParser * parser = CEGUI::System::getSingleton().getXMLParser() ;
	if ( parser->isPropertyPresent( "SchemaDefaultResourceGroup" ) )
		parser->setProperty( "SchemaDefaultResourceGroup", "schemas" ) ;
 
}
 
 
WindowManager & init_CEGUI( SDL_Surface & surface )
{
 
  cout << " - initializing CEGUI" << endl ;
 
  CEGUI::OpenGLRenderer::bootstrapSystem() ;
 
  set_CEGUI_paths() ;
 
  SchemeManager::getSingleton().create( "TaharezLook.scheme" ) ;
 
  System::getSingleton().setDefaultMouseCursor( "TaharezLook", "MouseArrow" ) ;
 
  FontManager::getSingleton().create( "DejaVuSans-10.font" ) ;
 
  return WindowManager::getSingleton() ;
 
}
 
 
Window & create_background_window( WindowManager & winManager )
{
 
  /*
   * Here we will use a StaticImage as the root, then we can use it to place a
   * background image:
   *
   */
  Window & backgroundWin = * winManager.createWindow( "TaharezLook/StaticImage",
	"MyBackgroundWin" ) ;
 
  // Fine-tunes this background window:
 
  // Spread over the full CEGUI window:
  backgroundWin.setPosition( UVector2( cegui_reldim(0), cegui_reldim(0) ) ) ;
  backgroundWin.setSize( UVector2( cegui_reldim(1), cegui_reldim(1) ) ) ;
 
  // Disables the frame and standard background:
  backgroundWin.setProperty( "FrameEnabled", "false" ) ;
  backgroundWin.setProperty( "BackgroundEnabled", "false" ) ;
 
  // Finally sets the previously loaded background image:
  backgroundWin.setProperty( "Image", "set:BackgroundImage image:full_image" ) ;
 
  // Installs this as the root GUI sheet:
  System::getSingleton().setGUISheet( &backgroundWin ) ;
 
  return backgroundWin ;
 
}
 
 
MultiColumnList & create_multi_column_list( WindowManager & winManager,
  Window & backgroundWin )
{
 
  // Creates a multi-column list:
  MultiColumnList & mcl = * static_cast<MultiColumnList*>(
	winManager.createWindow( "TaharezLook/MultiColumnList", "MyMainList" ) ) ;
 
  backgroundWin.addChildWindow( &mcl ) ;
 
  mcl.setPosition( UVector2( cegui_reldim(0.01f), cegui_reldim(0.1f) ) ) ;
  mcl.setSize( UVector2( cegui_reldim(0.6f), cegui_reldim(0.4f) ) ) ;
 
  // We want three columns here:
  mcl.addColumn( "First column",  /* id */ 1, /* width */ cegui_reldim(0.5f) ) ;
  mcl.addColumn( "Second column", /* id */ 2, /* width */ cegui_reldim(0.3f) ) ;
  mcl.addColumn( "Third column",  /* id */ 3, /* width */ cegui_reldim(0.2f) ) ;
 
  // Adds two entries to that list:
 
  ListboxTextItem & firstRowItem1 = * new ListboxTextItem( "First row 1" ) ;
  ListboxTextItem & firstRowItem2 = * new ListboxTextItem( "First row 2" ) ;
  ListboxTextItem & firstRowItem3 = * new ListboxTextItem( "First row 3" ) ;
 
  /*
   * Sets the selection brush to use for this item (blue background when
   * selected); the second row will not react when selected.
   */
  firstRowItem1.setSelectionBrushImage(
	&ImagesetManager::getSingleton().get("TaharezLook").getImage(
	  "MultiListSelectionBrush" ) ) ;
 
  CEGUI::uint firstRow = mcl.addRow( &firstRowItem1, /* column id */ 1 ) ;
  mcl.setItem( &firstRowItem2,  /* column id */ 2, firstRow ) ;
  mcl.setItem( &firstRowItem3,  /* column id */ 3, firstRow ) ;
 
  ListboxTextItem & secondRowItem1 = * new ListboxTextItem( "Second row 1" ) ;
  ListboxTextItem & secondRowItem2 = * new ListboxTextItem( "Second row 2" ) ;
  ListboxTextItem & secondRowItem3 = * new ListboxTextItem( "Second row 3" ) ;
 
  CEGUI::uint secondRow = mcl.addRow( &secondRowItem1, /* column id */ 1 ) ;
  mcl.setItem( &secondRowItem2,  /* column id */ 2, secondRow ) ;
  mcl.setItem( &secondRowItem3,  /* column id */ 3, secondRow ) ;
 
}
 
 
 
void create_basic_widgets_frame( WindowManager & winManager,
  Window & backgroundWin )
{
 
  FrameWindow & frameWin = * static_cast<FrameWindow*>( winManager.createWindow(
	  "TaharezLook/FrameWindow", "MyBasicFrame") ) ;
 
  backgroundWin.addChildWindow( &frameWin ) ;
 
  frameWin.setPosition( UVector2( cegui_reldim(0.13f), cegui_reldim(0.03f) ) ) ;
  frameWin.setMaxSize( UVector2( cegui_reldim(1.0f), cegui_reldim(1.0f) ) ) ;
  frameWin.setSize( UVector2( cegui_reldim(0.44f), cegui_reldim( 0.94f) ) ) ;
  frameWin.setText( "A Frame" ) ;
 
  Listbox & listBox = * static_cast<Listbox *>( winManager.createWindow(
	  "TaharezLook/Listbox", "MyListBox" ) ) ;
 
  frameWin.addChildWindow( &listBox ) ;
  listBox.setPosition( UVector2( cegui_reldim(0.13f), cegui_reldim(0.03f) ) ) ;
  listBox.setSize( UVector2( cegui_reldim(0.44f), cegui_reldim( 0.14f) ) ) ;
 
  ListboxTextItem & firstItem = * new ListboxTextItem( "First list element",
	0 ) ;
  listBox.addItem( &firstItem ) ;
 
  ListboxTextItem & secondItem = * new ListboxTextItem( "Second list element",
	0 ) ;
  listBox.addItem( &secondItem ) ;
 
  ListboxTextItem & thirdItem = * new ListboxTextItem( "Third list element",
	0 ) ;
  listBox.addItem( &thirdItem ) ;
 
 
  Window & firstLabel = * winManager.createWindow( "TaharezLook/StaticText",
	"MyFirstLabel" ) ;
 
  frameWin.addChildWindow( &firstLabel ) ;
 
  firstLabel.setProperty( "FrameEnabled", "false" ) ;
  firstLabel.setProperty( "BackgroundEnabled", "false" ) ;
 
  firstLabel.setPosition( UVector2( cegui_reldim(0.02f),
	  cegui_reldim(0.2f) ) ) ;
 
  firstLabel.setSize( UVector2( cegui_reldim(0.4f), cegui_reldim(0.12f) ) ) ;
  firstLabel.setText( "A (static) label" ) ;
 
  PushButton & firstButton = * static_cast<PushButton*>(
	winManager.createWindow( "TaharezLook/Button", "MyFirstButton" ) ) ;
 
  frameWin.addChildWindow( &firstButton ) ;
 
  firstButton.setPosition( UVector2( cegui_reldim(0.20f),
	  cegui_reldim(0.32f) ) ) ;
 
  firstButton.setSize( UVector2( cegui_reldim(0.3f), cegui_reldim(0.05f) ) ) ;
  firstButton.setText( "First button" ) ;
 
  Combobox & combo = * static_cast<Combobox*>( winManager.createWindow(
	  "TaharezLook/Combobox", "MyComboBox" ) ) ;
 
  frameWin.addChildWindow( &combo ) ;
  combo.setPosition( UVector2( cegui_reldim(0.04f), cegui_reldim(0.6f) ) ) ;
  combo.setSize( UVector2( cegui_reldim(0.66f), cegui_reldim(0.33f) ) ) ;
 
  const CEGUI::Image & selectionImage = ImagesetManager::getSingleton().get(
	"TaharezLook").getImage( "MultiListSelectionBrush" ) ;
 
  ListboxTextItem & firstChoice = * new ListboxTextItem( "First Choice", 0 ) ;
  firstChoice.setSelectionBrushImage( &selectionImage ) ;
 
  combo.addItem( &firstChoice ) ;
 
  ListboxTextItem & secondChoice = * new ListboxTextItem( "Second Choice", 0 ) ;
  secondChoice.setSelectionBrushImage( &selectionImage ) ;
 
  combo.addItem( &secondChoice ) ;
 
  combo.setReadOnly( true ) ;
 
  Editbox & editBox = * static_cast<Editbox*>( winManager.createWindow(
	  "TaharezLook/Editbox", "MyEditBox" ) ) ;
 
  frameWin.addChildWindow( &editBox ) ;
 
  editBox.setPosition( UVector2( cegui_reldim(0.2f), cegui_reldim(0.5f) ) ) ;
  editBox.setSize( UVector2( cegui_reldim(0.5f), cegui_reldim(0.05f) ) ) ;
  editBox.setValidationString( "\\d*" ) ;
  editBox.setText( "A single line editbox" ) ;
 
  GroupBox & radioBox = * static_cast<GroupBox*>(
	winManager.createWindow( "TaharezLook/GroupBox", "MyRadioBox" ) ) ;
 
  radioBox.setPosition( UVector2( cegui_reldim(0.2f), cegui_reldim(0.7f) ) ) ;
  radioBox.setSize( UVector2( cegui_reldim(0.7f), cegui_reldim(0.25f) ) ) ;
  radioBox.setText( "A group box" ) ;
  frameWin.addChildWindow( &radioBox ) ;
 
  RadioButton & firstRadio = * static_cast<RadioButton*>(
	winManager.createWindow( "TaharezLook/RadioButton", "MyFirstRadio" ) ) ;
 
  firstRadio.setSize( UVector2( cegui_reldim(0.6f), cegui_reldim(0.2f) ) ) ;
  firstRadio.setPosition( UVector2( cegui_reldim(0.2f), cegui_reldim(0.1f) ) ) ;
  firstRadio.setText( "First radio button" ) ;
  firstRadio.setGroupID( 0 ) ;
 
  radioBox.addChildWindow( &firstRadio ) ;
 
  RadioButton & secondRadio = * static_cast<RadioButton*>(
	winManager.createWindow( "TaharezLook/RadioButton", "MySecondRadio" ) ) ;
 
  secondRadio.setSize( UVector2( cegui_reldim(0.6f), cegui_reldim(0.2f) ) ) ;
  secondRadio.setPosition( UVector2( cegui_reldim(0.2f),
	  cegui_reldim(0.75f) ) ) ;
  secondRadio.setText( "Second radio button" ) ;
  secondRadio.setGroupID( 0 ) ;
 
  radioBox.addChildWindow( &secondRadio ) ;
 
}
 
 
void create_advanced_widgets_frame(  WindowManager & winManager,
  Window & backgroundWin )
{
 
  FrameWindow & frameWin = * static_cast<FrameWindow*>( winManager.createWindow(
	  "TaharezLook/FrameWindow", "MyAdvancedFrame") ) ;
 
  backgroundWin.addChildWindow( &frameWin ) ;
 
  frameWin.setPosition( UVector2( cegui_reldim(0.33f), cegui_reldim(0.23f) ) ) ;
  frameWin.setMaxSize( UVector2( cegui_reldim(1.0f), cegui_reldim(1.0f) ) ) ;
  frameWin.setSize( UVector2( cegui_reldim(0.44f), cegui_reldim( 0.94f) ) ) ;
  frameWin.setText( "Another Frame" ) ;
  frameWin.setTooltipText( "This is an example tooltip" ) ;
 
  ProgressBar & progressBar = * static_cast<ProgressBar*>(
	winManager.createWindow( "TaharezLook/ProgressBar", "MyProgressBar" ) ) ;
 
  frameWin.addChildWindow( &progressBar ) ;
 
  progressBar.setPosition( UVector2( cegui_reldim(0.1f),
	  cegui_reldim(0.05f) ) ) ;
 
  progressBar.setSize( UVector2( cegui_reldim(0.5f), cegui_reldim(0.04f) ) ) ;
  progressBar.setProgress( 0.8f ) ;
 
 
  // AlternateProgressBar & alternateProgressBar =
  // 	* static_cast<AlternateProgressBar*>(
  // 	  winManager.createWindow( "TaharezLook/AlternateProgressBar",
  // 		"MyAlternateprogressbar" ) ) ;
 
  // frameWin.addChildWindow( &alternateProgressBar ) ;
 
  // alternateProgressBar.setPosition( UVector2( cegui_reldim(0.1f),
  // 	  cegui_reldim(0.05f) ) ) ;
 
  // alternateProgressBar.setSize( UVector2( cegui_reldim(0.5f),
  // 	  cegui_reldim(0.24f) ) ) ;
  // alternateProgressBar.setProgress( 0.8f ) ;
 
 
  MultiLineEditbox & multiLineEditbox = * static_cast<MultiLineEditbox*>(
	winManager.createWindow( "TaharezLook/MultiLineEditbox", "MyMultiEditbox" )
																		 ) ;
  frameWin.addChildWindow( &multiLineEditbox ) ;
 
  multiLineEditbox.setText( "This is a multi-line edit-box." ) ;
 
  multiLineEditbox.setPosition( UVector2( cegui_reldim(0.1f),
	  cegui_reldim(0.1f) ) ) ;
 
  multiLineEditbox.setSize( UVector2( cegui_reldim(0.5f),
	  cegui_reldim(0.1f) ) ) ;
 
  CEGUI::System::getSingleton().setDefaultTooltip( (CEGUI::utf8*)
	"TaharezLook/Tooltip" ) ;
 
  Checkbox & checkBox = * static_cast<Checkbox*>(
	winManager.createWindow( "TaharezLook/Checkbox", "MyCheckbox" ) ) ;
 
  frameWin.addChildWindow( &checkBox ) ;
 
  checkBox.setPosition( UVector2( cegui_reldim(0.1f), cegui_reldim(0.2f) ) ) ;
  checkBox.setSize( UVector2(cegui_reldim(0.4f), cegui_reldim(0.1f) ) ) ;
 
  checkBox.setText( "I am a checkbox" ) ;
 
  Slider & slider = * static_cast<Slider*>( winManager.createWindow(
	  "TaharezLook/Slider", "MySlider" ) ) ;
 
  frameWin.addChildWindow( &slider ) ;
 
  slider.setPosition( UVector2( cegui_reldim(0.1f), cegui_reldim(0.30f) ) ) ;
  slider.setSize( UVector2( cegui_reldim(0.05f), cegui_reldim(0.4f) ) ) ;
  slider.setMaxValue( 1.0f ) ;
  slider.setClickStep( 0.1f ) ;
  slider.setCurrentValue( 0.5f ) ;
 
  Spinner & spinner= * static_cast<Spinner*>( winManager.createWindow(
	  "TaharezLook/Spinner", "MySpinner" ) ) ;
 
  spinner.setPosition( UVector2( cegui_reldim(0.5f), cegui_reldim(0.30f) ) ) ;
  spinner.setSize( UVector2( cegui_reldim(0.4f), cegui_reldim(0.05f) ) ) ;
  spinner.setStepSize( 0.5f ) ;
  spinner.setMinimumValue( 2.0f ) ;
  spinner.setMaximumValue( 5.0f ) ;
  spinner.setCurrentValue( 0.5f ) ;
 
  frameWin.addChildWindow( &spinner ) ;
 
  UDim bar_bottom( 0, /* d_font->getLineSpacing(2) */ 25 ) ;
 
  Window & menuBar = * winManager.createWindow( "TaharezLook/Menubar" ) ;
  menuBar.setArea( UDim(0,0), UDim(0,0), UDim(1,0), bar_bottom ) ;
  menuBar.setAlwaysOnTop( true ) ;
  frameWin.addChildWindow( &menuBar ) ;
 
  Window & firstMenuItem = * winManager.createWindow( "TaharezLook/MenuItem" ) ;
  firstMenuItem.setText( "First Menu" ) ;
  menuBar.addChildWindow( &firstMenuItem ) ;
 
  Window & firstPopUp = * winManager.createWindow( "TaharezLook/PopupMenu" ) ;
  firstMenuItem.addChildWindow( &firstPopUp ) ;
  firstMenuItem.setText( "A menu entry" ) ;
 
  Window & firstEntryOfFirstPopUp = * winManager.createWindow(
	"TaharezLook/MenuItem" ) ;
  firstEntryOfFirstPopUp.setText( "First entry" ) ;
  firstPopUp.addChildWindow( &firstEntryOfFirstPopUp ) ;
 
 
  Window & secondMenuItem = * winManager.createWindow( "TaharezLook/MenuItem" ) ;
  secondMenuItem.setText( "Second Menu" ) ;
  menuBar.addChildWindow( &secondMenuItem ) ;
 
  Window & secondPopUp = * winManager.createWindow( "TaharezLook/PopupMenu" ) ;
  secondMenuItem.addChildWindow( &secondPopUp ) ;
  secondMenuItem.setText( "Another menu entry" ) ;
 
  Window & secondEntryOfSecondPopUp = * winManager.createWindow(
	"TaharezLook/MenuItem" ) ;
  secondEntryOfSecondPopUp.setText( "Second entry" ) ;
  secondPopUp.addChildWindow( &secondEntryOfSecondPopUp ) ;
 
  // VerticalScrollbar & vertScrollbar = *
  // 	static_cast<VerticalScrollbar*>(
  // 	  winManager.createWindow( "TaharezLook/LargeVerticalScrollbar",
  // 		"MyVertScroolbar" ) ) ;
 
  // vertScrollbar.setPosition( UVector2( cegui_reldim(0.8f),
  // 	  cegui_reldim(0.30f) ) ) ;
 
  // vertScrollbar.setSize( UVector2( cegui_reldim(0.4f),
  //   cegui_reldim(0.05f) ) ) ;
 
  // frameWin.addChildWindow( &vertScrollbar ) ;
 
}
 
 
void create_gui( WindowManager & winManager )
{
 
  cout << " - creating the GUI" << endl ;
 
 
  /*
   * Loads an image to use as a background:
   * (will be registered as: "set:BackgroundImage image:full_image")
   *
   */
  ImagesetManager::getSingleton().createFromImageFile( "BackgroundImage",
	"GPN-2000-001437.tga" ) ;
 
  Window & backgroundWin = create_background_window( winManager ) ;
 
  create_multi_column_list( winManager, backgroundWin ) ;
 
 create_basic_widgets_frame( winManager, backgroundWin ) ;
 
 create_advanced_widgets_frame( winManager, backgroundWin ) ;
 
}
 
 
int main( int argc, char *argv[] )
{
 
  cout << " - starting CEGUI test" << endl ;
 
  SDL_Surface & screen = init_SDL() ;
 
  WindowManager & winManager = init_CEGUI( screen ) ;
 
  create_gui( winManager ) ;
 
  main_loop() ;
 
  cout << " - ending CEGUI test" << endl ;
 
}

This more complex example is simply built on the minimal one.

Here is a corresponding screenshot:

CEGUI-SDL-all-widgets.png