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.
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 usualglViewport( 0, 0, x, y );
There's an example later
More controls
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
- GLUI User Interface Library page
- GLUI manual
- OpenGL 1.1 Reference
- OpenGL tutorials (OpenGL Tutorial is a simple example)
- OpenGL coding: beginners forum
- GLUT documentation
- GLUT examples (with source code and screenshots)