Department of Engineering

IT Services

Using GLUI

GLUI is a GLUT-based C++ library that provides buttons, spinners, etc for OpenGL applications. It can run on any machine where OpenGL is available (i.e. just about anywhere) and it's free. It's easy to use, though control over color, fonts, etc is limited.

GLUT routines deal display the graphics, so you need to know how to use them first. These issues are covered on our using GLUT page.

screen dump The first example below spins a shape in 3D. A separate window has controls to make the shape a wireframe and to change the number of line segments used. Most of the code (shown in full later) involves setting up windows and using GLUT routines to draw into them. Adding the controls takes about a dozen lines of code. The GLUI routines take advantage of C++'s way of assigning default values to trailing parameters, so you can often get away with supplying just one or 2 parameters to functions. The GLUI concepts used here are

  • Live variables
    int   wireframe = 0;
    int   segments = 8;
    int   main_window;
    
    These are the variables whose values are displayed and changed via the graphical user interface. If used elsewhere in the code, the changes made via the interface will have an instant effect elsewhere. In this program, the wireframe variable is changed by clicking on the checkbox. The myGlutDisplay routine will automatically react to this change.
  • Creating an interface window
      GLUI *glui = GLUI_Master.create_glui( "GLUI" );
      ...
      glui->set_main_gfx_window( main_window );
    
    The first of these lines creates a window for the components. The second line tells GLUI which window to redraw when values are changed.
  • Creating components
      glui->add_checkbox( "Wireframe", &wireframe );
      GLUI_Spinner *segment_spinner =
        glui->add_spinner( "Segments:", GLUI_SPINNER_INT, &segments );
      segment_spinner->set_int_limits( 3, 60 );
    
    GLUI offers a range of components. Here a checkbox is created, then a spinner is created. Note that no coordinates are provided - components are positioned automatically - and that min/max values can be set for the spinner. The provided live variable, segment, has been initialised with an appropriate value.
  • Callbacks - these are routines called in response to a graphical event. They may not be necessary in simple GLUI applications where (as in this case) live variables may suffice. You will, however, need to register your GlutIdle callback so that your GLUI window can exploit idle events without interfering with your application's idle events.
      
    /* We register the idle callback with GLUI, *not* with GLUT */
      GLUI_Master.set_glutIdleFunc( myGlutIdle );
    

Here's the full code

Example 1

/****************************************************************************

  A simple GLUT program using the GLUI User Interface Library

  This program sets up a checkbox and a spinner, both with live variables.
  No callbacks are used.

  -----------------------------------------------------------------------

  9/9/98 Paul Rademacher (rademach@cs.unc.edu)

****************************************************************************/

#include <string.h>
#include <glut.h>
#include "glui.h"

/** These are the live variables passed into GLUI ***/
int   wireframe = 0;
int   segments = 8;
int   main_window;


/***************************************** myGlutIdle() ***********/

void myGlutIdle( void )
{
  /* According to the GLUT specification, the current window is
     undefined during an idle callback.  So we need to explicitly change
     it if necessary */
  if ( glutGetWindow() != main_window )
    glutSetWindow(main_window);

  glutPostRedisplay();
}

/**************************************** myGlutReshape() *************/

void myGlutReshape( int x, int y )
{
  float xy_aspect;

  xy_aspect = (float)x / (float)y;
  glViewport( 0, 0, x, y );

  glMatrixMode( GL_PROJECTION );
  glLoadIdentity();
  glFrustum( -xy_aspect*.08, xy_aspect*.08, -.08, .08, .1, 15.0 );

  glutPostRedisplay();
}

/***************************************** myGlutDisplay() *****************/

void myGlutDisplay( void )
{
  static float rotationX = 0.0, rotationY = 0.0;

  glClearColor( .9f, .9f, .9f, 1.0f );
  glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );

  /*** Rotate the object ***/
  rotationX += 3.3f;
  rotationY += 4.7f;

  glMatrixMode( GL_MODELVIEW );
  glLoadIdentity();
  glTranslatef( 0.0, 0.0, -1.0 );
  glRotatef( rotationY, 0.0, 1.0, 0.0 );
  glRotatef( rotationX, 1.0, 0.0, 0.0 );

  /*** Now we render object, using the variables 'segments' and
    'wireframe'.  These are _live_ variables, which are transparently
    updated by GLUI ***/

  if ( wireframe )
    glutWireTorus( .2,.5,16,segments );
  else
    glutSolidTorus( .2,.5,16,segments );

  glutSwapBuffers();
}

/**************************************** main() ********************/

int main(int argc, char* argv[])
{
  /****************************************/
  /*   Initialize GLUT and create window  */
  /****************************************/

  glutInitDisplayMode( GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH );
  glutInitWindowPosition( 50, 50 );
  glutInitWindowSize( 300, 300 );

  main_window = glutCreateWindow( "GLUI Example 1" );
  glutDisplayFunc( myGlutDisplay );
  glutReshapeFunc( myGlutReshape );

  /****************************************/
  /*       Set up OpenGL lights           */
  /****************************************/

  GLfloat light0_ambient[] =  {0.1f, 0.1f, 0.3f, 1.0f};
  GLfloat light0_diffuse[] =  {.6f, .6f, 1.0f, 1.0f};
  GLfloat light0_position[] = {1.0f, 1.0f, 1.0f, 0.0f};

  glEnable(GL_LIGHTING);
  glEnable(GL_LIGHT0);
  glLightfv(GL_LIGHT0, GL_AMBIENT, light0_ambient);
  glLightfv(GL_LIGHT0, GL_DIFFUSE, light0_diffuse);
  glLightfv(GL_LIGHT0, GL_POSITION, light0_position);

  /****************************************/
  /*          Enable z-buffering          */
  /****************************************/

  glEnable(GL_DEPTH_TEST);

  /****************************************/
  /*         Here's the GLUI code         */
  /****************************************/

  GLUI *glui = GLUI_Master.create_glui( "GLUI" );
  glui->add_checkbox( "Wireframe", &wireframe );
  GLUI_Spinner *segment_spinner =
    glui->add_spinner( "Segments:", GLUI_SPINNER_INT, &segments );
  segment_spinner->set_int_limits( 3, 60 );

  glui->set_main_gfx_window( main_window );

  /* We register the idle callback with GLUI, *not* with GLUT */
  GLUI_Master.set_glutIdleFunc( myGlutIdle );

  glutMainLoop();
}

If you call this file simple.cc then it can be compiled using g++ -I/usr/include/GL -o simple simple.cc -lglui -lglut -lGLU -lGL
The compile line is long, but on Unix you can use Makefiles or Shell scripts to save on typing.

Controls inside the main graphics window

If you want your controls to be in the same window as the main graphics, more work is required so that graphical events get handled by GLUI rather than GLUT

  • More callbacks may need to be dealt with
     GLUI_Master.set_glutKeyboardFunc( myGlutKeyboard );
     GLUI_Master.set_glutSpecialFunc( myGlutSpecial );
     GLUI_Master.set_glutMouseFunc( myGlutMouse );
     GLUI_Master.set_glutReshapeFunc( myGlutReshape );
    
  • You can choose where to create the GLUI window within the main GLUT window. Here the GLUI window will be along the top edge
     GLUI *glui_subwin = GLUI_Master.create_glui_subwindow(main_win,
                         GLUI_SUBWINDOW_TOP);
    
    You can have more than one GLUI subwindow in a GLUT window
  • To stop GLUT graphics overwriting the GLUI window, you need to change the GLUT window's glutReshapeFunc command so that it uses
      GLUI_Master.auto_set_viewport();
    
    This replaces the usual
      glViewport( 0, 0, x, y );
    

There's an example later

More controls

screen dump A few more of the available options are introduced here. As with the previous components, they can be created with a single line of code, and their positioning is managed automatically

  • Panels and separators - these are ways to group and visually organise controls. Panels are rectangles, and separators are horizontal lines. You can also create columns of controls, but they're not used here.
  • Text - static and editable text is available
  • Buttons - clicking on them runs a callback routine
  • Arcballs - a rollerball: useful to control rotation of an object in the main graphical window
  • Listbox - a menu where only the selected item is shown
  • Radiobutton - a menu where all items are shown, but only one can be selected

Example 2

This builds on the earlier example, adding recently introduced components inside a GLUT window.

/****
  Adapted from a program by 
  9/9/98 Paul Rademacher (rademach@cs.unc.edu)

****************************************************************************/

#include <string.h>
#include <glut.h>
#include "glui.h"

/** These are the live variables passed into GLUI ***/
int   wireframe = 0;
int   segments = 8;
int   main_window;

/***************************************** myGlutIdle() ***********/

void myGlutIdle( void )
{
  /* According to the GLUT specification, the current window is
     undefined during an idle callback.  So we need to explicitly change
     it if necessary */
  if ( glutGetWindow() != main_window )
    glutSetWindow(main_window);

  glutPostRedisplay();
}

/**************************************** myGlutReshape() *************/

void myGlutReshape( int x, int y )
{
  float xy_aspect;

  xy_aspect = (float)x / (float)y;
  GLUI_Master.auto_set_viewport();

  glMatrixMode( GL_PROJECTION );
  glLoadIdentity();
  glFrustum( -xy_aspect*.08, xy_aspect*.08, -.08, .08, .1, 15.0 );

  glutPostRedisplay();
}

/***************************************** myGlutDisplay() *****************/

void myGlutDisplay( void )
{
  static float rotationX = 0.0, rotationY = 0.0;

  glClearColor( .9f, .9f, .9f, 1.0f );
  glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );

  /*** Rotate the object ***/
  rotationX += 3.3f;
  rotationY += 4.7f;

  glMatrixMode( GL_MODELVIEW );
  glLoadIdentity();
  glTranslatef( 0.0, 0.0, -1.0 );
  glRotatef( rotationY, 0.0, 1.0, 0.0 );
  glRotatef( rotationX, 1.0, 0.0, 0.0 );

  /*** Now we render object, using the variables 'segments' and
    'wireframe'.  These are _live_ variables, which are transparently
    updated by GLUI ***/

  if ( wireframe )
    glutWireTorus( .2,.5,16,segments );
  else
    glutSolidTorus( .2,.5,16,segments );

  glutSwapBuffers();
}

/**************************************** main() ********************/

int main(int argc, char* argv[])
{
  /****************************************/
  /*   Initialize GLUT and create window  */
  /****************************************/

  glutInitDisplayMode( GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH );
  glutInitWindowPosition( 50, 50 );
  glutInitWindowSize( 300, 300 );

  main_window = glutCreateWindow( "GLUI Example 1" );
  glutDisplayFunc( myGlutDisplay );
  glutReshapeFunc( myGlutReshape );

  /****************************************/
  /*       Set up OpenGL lights           */
  /****************************************/

  GLfloat light0_ambient[] =  {0.1f, 0.1f, 0.3f, 1.0f};
  GLfloat light0_diffuse[] =  {.6f, .6f, 1.0f, 1.0f};
  GLfloat light0_position[] = {1.0f, 1.0f, 1.0f, 0.0f};

  glEnable(GL_LIGHTING);
  glEnable(GL_LIGHT0);
  glLightfv(GL_LIGHT0, GL_AMBIENT, light0_ambient);
  glLightfv(GL_LIGHT0, GL_DIFFUSE, light0_diffuse);
  glLightfv(GL_LIGHT0, GL_POSITION, light0_position);

  /****************************************/
  /*          Enable z-buffering          */
  /****************************************/

  glEnable(GL_DEPTH_TEST);

  /****************************************/
  /*         Here's the GLUI code         */
  /****************************************/

  GLUI *glui = GLUI_Master.create_glui_subwindow(main_window,
                     GLUI_SUBWINDOW_TOP);

  glui->add_checkbox( "Wireframe", &wireframe );
  GLUI_Spinner *segment_spinner =
    glui->add_spinner( "Segments:", GLUI_SPINNER_INT, &segments );
  segment_spinner->set_int_limits( 3, 60 );

  glui->set_main_gfx_window( main_window );
  GLUI_Listbox *listbox = glui->add_listbox("A listbox");
  listbox->add_item(1,"Red");
  listbox->add_item(2,"Green");
  listbox->add_item(3,"Blue");

  glui->add_statictext("Example 2");
  glui->add_separator();
  GLUI_Panel *obj_panel = glui->add_panel ("Test Panel");
  glui->add_button("Quit",0,(GLUI_Update_CB)exit);
  GLUI_RadioGroup *group1 = glui->add_radiogroup_to_panel(obj_panel);
  glui->add_radiobutton_to_group(group1,"Option 1");
  glui->add_radiobutton_to_group(group1,"Option 2");
  GLUI_Rotation *arcball = glui->add_rotation("ball (doesn't do anything)");
  
  /* We register the idle callback with GLUI, *not* with GLUT */
  GLUI_Master.set_glutIdleFunc( myGlutIdle );
  GLUI_Master.set_glutReshapeFunc( myGlutReshape );
  glutMainLoop();
}

References