Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / multimedia / OpenGL

GLUI Window Template

4.94/5 (35 votes)
31 Jan 2008CPOL23 min read 2   13.2K  
This article describes in detail how to create your first GLUI window with some basic controls inside it, and provides you with a template for your OpenGL applications.

Screenshot - GLUI_Window_Template.jpg

Contents

Introduction

This article describes in detail how to create your first GLUI window with some basic controls inside it, and provides you with a template for your OpenGL applications.

This article can be used in the following ways:

  • Learn how to add GUI components to your OpenGL application in a very straight-forward and simple manner through:
    • Documentation
    • Interactive program that displays to the user how every event is handled and classifies these events into GLUT and GLUI events.
    • Neat and commented code that reflects the simplicity of the GLUI library
  • Learn some totally new controls in the GLUI library created specifically for graphical manipulation, such as the rotation and translation controls.
  • Use the code as a template for your OpenGL applications.

Make sure you read the GLUT Window Template article as a prerequisite to this article. One important thing to note is that GLUI is a C++ library, which means that your code must be written in files with CPP extension rather than C, otherwise the linker will complain.

What is GLUI?

GLUI is a C++ GUI library, built entirely on top of GLUT, to provide GUI controls such as buttons, checkboxes, radio buttons, labels, panels, text fields and spinners to OpenGL applications. It is window-system independent, relying on GLUT to handle all system-dependent issues, such as window, keyboard, joystick and mouse management. The GLUI API is very simple, allowing us to create new GLUI windows and add controls inside them with a single line of code. To add to its simplicity, GLUI automatically positions and sizes controls when placed on their window.

How Does GLUI Look Like?

Here's an example GLUI window taken from the GLUI Manual, showing the different controls. This window is rendered entirely in OpenGL. It therefore looks the same on PCs, Macs, SGIs, and other UNIXes, using either SGI's implementation of OpenGL, Microsoft's, or Mesa's.

GLUI_Window_Template/glui_window_template_1.jpg

In addition to the above controls, GLUI has seen some additional controls after its new 2.35 version release in July 2006. You can see below the new scroll bar, text area, file browser, tree, tree panel and list.

GLUI 3.2 new controls

Why Have a GLUI Window Template?

When OpenGL applications get more complex, we need something more than a GLUT mouse, keyboard, and/or popup menus to interact with our OpenGL objects drawn on the window. GLUI gives us more flexibility by allowing us to add GUI components to interact with our OpenGL objects, such as buttons, check boxes, radio buttons, spinners, list boxes, lists, trees, file browsers, text fields, text areas, and the special controls: rotation and translation.

To avoid having to write the same code every time you want to create an OpenGL graphical application with GUI components, this program code can be used as a template to get you directly started.

Usage

Running the Program

In order to run the program, three dynamic link libraries (DLLs) are required: opengl32.dll, glu32.dll, glut32.dll. The opengl32.dll and glu32.dll already come with your Windows OS and are found in the system folder. To run the executable, you have to download the glut32.dll and copy it into your system folder. You can find all the DLL files in the attached zip file GLUI_Window_Template_dll.zip under Visual C++\dll.

Compiling the Code with Microsoft Visual C++

In order to write a C++ OpenGL application with GLUI using Microsoft Visual Studio on a Windows platform, you need the following files:

  • Header Files: GL.h, GLU.h, GLUT.h and GLUI.h
  • LIB Files: opengl32.lib, glu32.lib, glut32.lib and glui32.lib

You can find all the header files and lib files in the attached zip file GLUI_Window_Template_dll.zip under Visual C++\include\GL and Visual C++\lib respectively.

Microsoft Visual C++ 6

To use the code under a Visual C++ 6.0 environment, perform the following steps:

  • Open Microsoft Visual C++ 6.0
  • Create a new Win32 Console Application Project

    GLUI_Window_Template/glui_window_template_3.jpg
  • Copy the source file GLUI_Window_Template.cpp to your project folder (GLUI_Window_Template_src in our case). You may want to rename the file name to fit your program's needs.
  • Add the source file to the project using the menu option Project\Add To Project\Files.

    Add GLUI Source Code
  • Make sure that the header files are in the include folder, lib files are in the lib folder and DLLs are in the system folder.
     
    Files Description Source Folder (Attached) Target Folder
    GL.H, GLU.H, GLUT.H, GLUI.H Header Files Visual C++/include/GL C:\Program Files\Microsoft Visual Studio\VC98\Include\GL
    OPENGL32.LIB, GLU32.LIB, GLUT32.LIB, GLUI32.LIB Lib Files Visual C++/lib C:\Program Files\Microsoft Visual Studio\VC98\Lib
    OPENGL32.DLL, GLU32.DLL, GLUT32.DLL DLL Files Visual C++/dll C:\WINDOWS\system32
  • Link the code to the libraries. The proper order in which to add libraries is: GLUI, GLUT, GLU, OpenGL.

    Link to GLUI LIB

    To avoid having to set the link settings in every Visual C++ 6.0 project you create, you may want to include the following code segment in your code, which would basically do the same thing as above.

    C++
    // Link the lib files to the program. This is not necessary
    // if you have added the lib names using Project/Settings/Link
    #pragma comment (lib, "glui32.lib")
    #pragma comment (lib, "glut32.lib")
    #pragma comment (lib, "glu32.lib")
    #pragma comment (lib, "opengl32.lib")
  • To avoid getting the console window whenever you want to run your OpenGL window, you may want to include this directive in your code.
     
    C++
    #pragma comment( linker,
        "/subsystem:\"windows\" /entry:\"mainCRTStartup\"" )

Using the Code

The source code is intended to be used as a template for your OpenGL applications. To use it in your new application, you can simply rename the CPP file and add it to your Visual Studio project.

Note

Please note that GLUI is a C++ library, and thus doesn't work with C. So if you're obtaining linkage errors while trying to build a GLUI program, just check that all file extensions are CPP and not C.

Explaining the Code

Knowing that GLUI is built on top of GLUT, it requires very little change to integrate GLUI components with an existing GLUT application. Thus, we will start with the GLUT Window Template and apply changes to it until we create our GLUI Window Template.

1- Include

First, we start by including the header file for GLUI using the following include directive:

C++
#include <GL/glui.h>

There is no need to include <GL/gl.h>, <GL/glu.h>, or <GL/glut.h> since <GL/glui.h> already includes them.

2- GLUT Window

After creating our GLUT window, we need to make sure that we keep track of the window id so that GLUI can interact with it and send it redisplay events.

C++
main_window = glutCreateWindow (window_title);

3- Callback Functions

GLUT 'callback' functions are registered as usual, except for the Idle function.

C++
// Set the callback functions
glutDisplayFunc (display);
glutReshapeFunc  (reshape);
glutMouseFunc (mouse);
glutMotionFunc (motion);
glutPassiveMotionFunc (pmotion);
glutKeyboardFunc (keyboard);
glutSpecialFunc (special);
glutEntryFunc (entry);

4- Idle Callback Function

An idle callback function is called whenever an idle state is reached. An idle state is a state where no system events are received for processing as callbacks. The glutIdleFunc sets the idle callback function, which is continuously called as long as there are no events received. This means that we should minimize the amount of computation and rendering in the idle function to have a more interactive application. Passing NULL to glutIdleFunc disables the generation of the idle callback.

In a normal GLUT application, the idle function is registered as follows:

C++
glutIdleFunc (idle);

However, when GLUI is used, the idle callback function is registered through the GLUI global object, GLUI_Master. The reason for this is that GLUI makes extensive use of idle events. Logically, it does so in order to keep refreshing the GLUI controls and to listen to user's interactions with them.

C++
GLUI_Master.set_glutIdleFunc (idle);

If there is no Idle callback to be used, NULL is passed:

C++
GLUI_Master.set_glutIdleFunc (NULL);

Notes

  • In our GLUT idle function, we need to explicitly set the current window before posting a redisplay event. Otherwise, the redisplay may be accidentally sent to the GLUI window rather than the GLUT window.
     
    C++
    void idle ( )
    {
        glutSetWindow(main_window);
        glutPostRedisplay();
    }
  • It is well known that GLUI takes an inordinate amount of the CPU time even when the application is idle. The reason for this is that the GLUI window with all the controls inside it are being refreshed continuously. In order to avoid having a 100% CPU usage whenever we run a GLUI window, we need to call the Windows system function, Sleep, which would help us avoid continuously calling the idle function.

    Even if no idle function is specified, the GLUI application would consume most of the CPU time and cause your system to run slowly.

    Task Manager CPU - GLUI Idle

    When we call the Sleep function as shown below, the CPU usage by the GLUI application reduces to almost 0%.

    Task Manager CPU Utilization - GLUI App with Sleep
     
    C++
    #include <windows.h>
    
    void idle ()
    {
        glutSetWindow (main_window);
        glutPostRedisplay ();
        Sleep (100);
    }

5- GLUI Window

The GLUI window is created as follows:

C++
//  pointer to a GLUI window
GLUI * glui_window;

//  Create GLUI window
glui_window = GLUI_Master.create_glui ("Options");

Here is the create_glui function definition, as described in the GLUI manual:

C++
GLUI *GLUI_Master_Object::create_glui(char *name, int flags=0, int x=-1,
    int y=-1);
Attribute Description
name Name of new GLUI window
flags Initialization flags. No flags are defined in the current version
x,y Initial location of window. Note that no initial size can be specified, because GLUI automatically resizes Windows to fit all controls

Note that flags, x, and y are optional arguments. If they are not specified, default values will be used. GLUI provides default values for arguments whenever possible. The function returns a pointer to a new GLUI window.

In addition to the function that creates the window, GLUI also supports functions to enable, disable, hide, show, or close a window. Below is the prototype and description of each of these functions, as shown in the GLUI manual:

Name Prototype Description
get_glut_window_id int GLUI::get_glut_window_id( void ); Returns the standard GLUT window ID of a GLUI window
enable, disable void GLUI::enable( void );void GLUI::disable( void ); Enables or disables (grays out) a GLUI window. No controls are active when a GLUI window is disabled
hide void GLUI::hide( void ); Hides a GLUI window or subwindow. A hidden window or subwindow cannot receive any user input
show void GLUI::show( void ); Unhides a previously-hidden GLUI window or subwindow
close void GLUI::close( void ); Cleanly destroys a GLUI window or subwindow
close_all void GLUI_Master_Object::close_all( void ); Cleanly destroys all GLUI windows and subwindows. This function is called by the following example code: GLUI_Master.close_all();

6- Add GUI Controls

Live Variables

GLUI can associate live variables with most types of controls. Live variables are simply C variables that are automatically updated when the user interacts with a GLUI control. If the user directly updates a live variable from the code without using the set method of the control, then we need to call the sync_live () function in order to synchronize the control with the value of the live variable.

For example, let's say we have a checkbox associated with a live variable as follows:

C++
int draw = 0;
glui_window->add_checkbox ( "Draw", &draw );

When the program starts, the Draw checkbox will be un-checked since the value of the draw live variable is 0. If the value of draw was 1, then the Draw checkbox would have appeared as checked. Let's say that after the program loads, the user clicks on the checkbox to make it checked as follows:

GLUI Check Box

When that happens, GLUI automatically updates the value of the draw live variable to 1.

Also, let's assume that somewhere in the code, the programmer updates the value of the draw value back to 0. Doing this will not affect the control, and thus the control and the live variable will become un-synchronized.

C++
draw = 0;

In order to avoid this, we can call the sync_live() method of the current window to update the user interface:

C++
glui_window->sync_live(); 

In case there are multiple windows, we can use the sync_live_all() function of the GLUI Master Object to synchronize live variables and controls in all GLUI windows:

C++
GLUI_Master.sync_live_all();

Otherwise, we should not apply any direct changes to live variables. We can avoid that by directly using the set method(s) of the control:

C++
draw_checkbox.set_int_val ( 0 );

Callbacks

In addition to having live variables to track the values of controls, GLUI can also generate callbacks whenever the value of a control changes. When a control is first created, the user may optionally specify the callback function that will be called whenever the control's value changes, along with an integer ID to identify the calling control. This would mean that multiple controls may call the same callback function, and still be identified through their different IDs passed to the function.

C++
glui_window->add_checkbox ( "Draw", &draw, ID,
    callback_func );

List of Controls

Here is the list of supported control types, their GLUI name, description, accessor functions, live variables and callbacks, as copied from the GLUI Manual:

Control Type Class Name Used for... Set/Get values Live var? Callback?
Panel GLUI_Panel grouping controls into boxes
-
-
N
Column GLUI_Column grouping controls into columns
-
-
N
Rollout GLUI_Rollout grouping controls into collapsible boxes
-
-
N
Button GLUI_Button invoking user actions
-
-
Y
Checkbox GLUI_Checkbox handling booleans
get_int_val
set_int_val
int
Y
Radio Group,
Radio Button
GLUI_RadioGroup, GLUI_RadioButton handling mutually-exclusive options
get_int_val
set_int_val
int
Y
Static Text GLUI_StaticText plain text labels
set_text
-
N
Editable Text GLUI_EditText text that can be edited and optionally interpreted as integers or floats. Upper and lower bounds can be placed on integers and floats

get_int_val
set_int_val
get_float_val
set_float_val
get_text set_text

int
float
text
Y
Rotation GLUI_Rotation Inputting rotation values via an arcball
get_float_array_val
float [16]
Y
Translation GLUI_Translation Inputting X, Y, and Z values
get_x
get_y
get_z
float [1] OR [2]
Y
Listbox GLUI_Listbox Choosing from a list of items
get_int_val
int
Y
Spinner GLUI_Spinner interactively manipulating numeric values. Supports single clicks, click-hold, and click-drag. Upper and lower bounds can be specified
get_int_val
set_int_valget_float_val
set_float_val
int
float
Y
Separator GLUI_Separator separating controls with simple horizontal lines
-
-
N

Common Functions

Knowing that GLUI is implemented through Object Oriented C++, all the GLUI controls inherit from the base class GLUI_Control. There are two functions to create a control: add_control () and add_control_to_panel (), where control is replaced by the type of the control. For example, we can create a checkbox using any of the following two functions:

This function adds a checkbox at the top level of the window.

C++
GLUI_Checkbox *GLUI::add_checkbox( char *name, int *live_var=NULL, int id=-1,
    GLUI_Update_CB callback=NULL);

This function nests the checkbox within a panel.

C++
GLUI_Checkbox *GLUI::add_checkbox_to_panel( GLUI_Panel *panel, char *name,
    int *live_var=NULL, int id=-1, GLUI_Update_CB callback=NULL);

In addition to the common method for creating controls, there are common functions that can be used on most of the controls and are all inherited from the GLUI_Control base class. Here is the list of those methods, copied from the GLUI manual:

Name Prototype Description
set_name

void GLUI_Control::set_name( char *name );

name - New label for control

Sets the label on a button, checkbox, etc.
set_w, set_h

void GLUI_Control::set_w( int new_size );<br />
			void GLUI_Control::set_h( int new_size );

new_size - New minimum width or height for control

Sets new minimum width/height for a control. set_w() is especially useful to increase the size of the editable text area in an editable text control or spinner.
get, set
int GLUI_Control::get_int_val( void );<br />
			float GLUI_Control::get_float_val( void );<br />
			void GLUI_Control::get_float_array_val( float float_array_ptr );<br />
			char *GLUI_Control::get_text( void );<br />
			void GLUI_Control::set_int_val( int int_val );<br />
			void GLUI_Control::set_float_val( float float_val );<br />
			void GLUI_Control::set_float_array_val( float *float_array_val );<br />
			void GLUI_Control::set_text( char *text); 
Gets or sets the value of a control. Refer to the individual control descriptions below to see which values can be read and set for each control.
disable, enable
void GLUI_Control::enable( void );<br />
			void GLUI_Control::disable( void );
Disables (grays out) or enables an individual control. A disabled control cannot be activated or used. Disabling a radio group disables all radio buttons within it, and disabling a panel disables all controls within it (including other panels). Enabling behaves similarly.
set_alignment

void GLUI_Control::set_alignment( int align );

align - New alignment. May be one of GLUI_ALIGN_CENTER, GLUI_ALIGN_RIGHT, or GLUI_ALIGN_LEFT.

Sets the alignment of a control to left-aligned, right-aligned, or centered.

Adding Controls

After describing live variables, callbacks, list of controls, and common functions, now it's time to see how controls are added and how they would interact with our OpenGL application. Below is the list of GLUI function prototypes for every control. For more details about each of the following functions, please check the GLUI manual.

Control add_control \ add_control_to_panel \ Other
Panels
  • GLUI_Panel *GLUI::add_panel( char *name, int type = GLUI_PANEL_EMBOSSED );
  • GLUI_Panel *GLUI::add_panel_to_panel( GLUI_Panel *panel, char *name, int type = GLUI_PANEL_EMBOSSED );
Rollouts
  • GLUI_Rollout *GLUI::add_rollout( char *name, int open = true );
  • GLUI_Rollout *GLUI::add_rollout_to_panel( GLUI_Panel *panel, char *name, int open = true );
Columns
  • void GLUI::add_column( int draw_bar = true );
  • void GLUI::add_column_to_panel( GLUI_Panel *panel, int draw_bar = true );
Buttons
  • GLUI_Button *GLUI::add_button( char *name, int id=-1, GLUI_Update_CB callback=NULL);
  • GLUI_Button *GLUI::add_button_to_panel( GLUI_Panel *panel, char *name, int id=-1, GLUI_Update_CB callback=NULL);
Checkboxes
  • GLUI_Checkbox *GLUI::add_checkbox( char *name, int *live_var=NULL, int id=-1, GLUI_Update_CB callback=NULL);
  • GLUI_Checkbox *GLUI::add_checkbox( char *name, int *live_var=NULL, int id=-1, GLUI_Update_CB callback=NULL);
Radio Buttons
  • GLUI_RadioGroup *GLUI::add_radiogroup( int *live_var=NULL, int user_id=-1, GLUI_Update_CB callback=NULL);
  • GLUI_RadioGroup *GLUI::add_radiogroup_to_panel( GLUI_Panel *panel, int *live_var=NULL, int user_id=-1, GLUI_Update_CB callback = NULL );
  • GLUI_RadioButton *GLUI::add_radiobutton_to_group( GLUI_RadioGroup *group, char* name );
Static Text
  • GLUI_StaticText *GLUI::add_statictext( char *name );
  • GLUI_StaticText *GLUI::add_statictext_to_panel( GLUI_Panel *panel, char* name );
Editable Text Boxes
  • GLUI_EditText *GLUI::add_edittext( char *name, int data_type=GLUI_EDITTEXT_TEXT, void *live_var=NULL, int id=-1, GLUI_Update_CB callback = NULL );
  • GLUI_EditText *GLUI::add_edittext_to_panel( GLUI_Panel *panel, char *name, int data_type=GLUI_EDITTEXT_TEXT, void *live_var=NULL, int id=-1, GLUI_Update_CB callback = NULL );
  • void GLUI_EditText::set_int_limits( int low, int high, int limit_type = GLUI_LIMIT_CLAMP );
  • void GLUI_EditText::set_float_limits( float low, float high, int limit_type = GLUI_LIMIT_CLAMP );
Spinners
  • GLUI_Spinner *GLUI::add_spinner( char *name, int data_type=GLUI_SPINNER_INT, void *live_var=NULL, int id=-1, GLUI_Update_CB callback = NULL );
  • GLUI_Spinner *GLUI::add_spinner_to_panel( GLUI_Panel *panel, char *name, int data_type=GLUI_SPINNER_INT, void *live_var=NULL, int id=-1, GLUI_Update_CB callback = NULL );
  • void GLUI_Spinner::set_int_limits( int low, int high, int limit_type = GLUI_LIMIT_CLAMP );
  • void GLUI_Spinner::set_float_limits( float low, float high, int limit_type = GLUI_LIMIT_CLAMP );
  • void GLUI_Spinner::set_speed( float speed );
Separators
  • void GLUI::add_separator( void );
  • void GLUI::add_separator_to_panel( GLUI_Panel *panel );
Rotation Controls
  • GLUI_Rotation *GLUI::add_rotation( char *name, float *live_var=NULL, int id=-1, GLUI_Update_CB callback = NULL );
  • GLUI_Rotation *GLUI::add_rotation_to_panel( GLUI_Panel *panel, char *name, float *live_var=NULL, int id=-1, GLUI_Update_CB callback = NULL );
  • void GLUI_Rotation::get_float_array_val( float *array_ptr );
  • void GLUI_Rotation::set_float_array_val( float *array_ptr );
  • void GLUI_Rotation::set_spin( float damping_factor );
  • void GLUI_Rotation::reset( void );
Translation Controls
  • GLUI_Translation *GLUI::add_translation( char *name, int trans_type, float *live_var=NULL, int id=-1, GLUI_Update_CB callback = NULL );
  • GLUI_Translation *GLUI::add_translation_to_panel( GLUI_Panel *panel, char *name, int trans_type, float *live_var=NULL, int id=-1, GLUI_Update_CB callback = NULL );
  • float GLUI_Translation::get_x( void );
  • float GLUI_Translation::get_y( void );
  • float GLUI_Translation::get_z( void );
  • void GLUI_Translation::set_x( float x );
  • void GLUI_Translation::set_y( float y );
  • void GLUI_Translation::set_z( float z );
  • void GLUI_Translation::set_speed( float speed_factor );
Listboxes
  • GLUI_Listbox *GLUI::add_listbox( char *name, void *live_var=NULL, int id=-1, GLUI_Update_CB callback = NULL );
  • GLUI_Listbox *GLUI::add_listbox_to_panel( GLUI_Panel *panel, char *name, void *live_var=NULL, int id=-1, GLUI_Update_CB callback = NULL );
  • int GLUI_Listbox::add_item( int id, char *text );
  • int GLUI_Listbox::delete_item( int id );
  • int GLUI_Listbox::delete_item( char *text );
Adding Object Properties

Object Properties GLUI Panel

  • Add the 'Object Properties' Panel to the GLUI window. A "panel" is used to group controls together. Panels can be nested, and thus one can say add_panel_to_panel ().
     
    C++
    //  Add the 'Object Properties' Panel to the GLUI window
    GLUI_Panel *op_panel = glui_window->add_panel (
        "Object Properties");
  • Add the Draw checkbox to the panel.
     
    C++
    //  Draw Check Box Live Variable
    int draw = 1;
    
    // Add the Draw Check box to the 'Object Properties' Panel
    glui_window->add_checkbox_to_panel (op_panel, "Draw", &draw );

    When the Draw checkbox is checked or unchecked, it affects whether the object is displayed on the window. This is done by placing the following code segment in the display function:

    C++
    if (draw)
    {
        //  Draw Object...
    }
  • Add the Wireframe checkbox.
     
    C++
    //  Wireframe checkbox Live Variable
    int wireframe = 1;
    
    //  Add the Wireframe checkbox to the 'Object Properties' Panel
    glui_window->add_checkbox_to_panel (op_panel, "Wireframe",
        &wireframe );

    When the Wireframe checkbox is checked or unchecked, it affects whether the object is displayed in solid or wireframe. This is done by placing the following code segment in the display function:

    C++
    if (wireframe)
    {
        drawWireObject ();
    }
    else
    {
        drawSolidObject ();
    }
  • Add a "separator":
     
    C++
    //  Add a separator
    glui_window->add_separator_to_panel (op_panel);
  • Add the Color listbox. The add_listbox_to_panel takes the following arguments: the panel to which the listbox is to be added, the name of the listbox, the live variable which will be updated with the id of the selected item, the listbox control id that will be passed to the callback function, and the callback function. After creating the listbox, an item is added to it by calling the add_item function, which takes the item id and item name as arguments. After creating the listbox, we set the default item in the listbox by calling the set_int_val () function.
     
    C++
    //  Id of the selected item in the list box (List Box Live Variable)
    int listbox_item_id = 12;
    
    //  Add the Color listbox to the 'Object Properties' Panel
    GLUI_Listbox *color_listbox = glui_window->add_listbox_to_panel (
        op_panel, "Color", &listbox_item_id, COLOR_LISTBOX, glui_callback);
    
    //  Add the items to the listbox
    color_listbox->add_item (1, "Black");
    color_listbox->add_item (2, "Blue");
    color_listbox->add_item (3, "Cyan");
    color_listbox->add_item (4, "Dark Grey");
    color_listbox->add_item (5, "Grey");
    color_listbox->add_item (6, "Green");
    color_listbox->add_item (7, "Light Grey");
    color_listbox->add_item (8, "Magenta");
    color_listbox->add_item (9, "Orange");
    color_listbox->add_item (10, "Pink");
    color_listbox->add_item (11, "Red");
    color_listbox->add_item (12, "White");
    color_listbox->add_item (13, "Yellow");
    
    //  Select the White Color by default
    color_listbox->set_int_val (12);

    Whenever a user selects a color from the listbox, the glui_callback function is called and the COLOR_LISTBOX id is passed to it. Based on the item selected, the color array will be filled with the appropriate RGB components. For example, when the user selects the Grey color, the following code is executed in the glui_callback function:

    C++
    switch (control_id)
    {
        //  Color Listbox item changed
        case COLOR_LISTBOX:
    
            switch (listbox_item_id)
            {
                //  Select grey color
                case 5:
                    color[0] = 128/255.0;
                    color[1] = 128/255.0;
                    color[2] = 128/255.0;
                    break;
            }
        break;
    }

    After a GLUI callback, GLUI automatically posts a redisplay event, and the display function is called. In order to reflect the changes in the color of the object, the following code fragment is placed in the display function before the object is drawn:

    C++
    //  Set the color
    glColor3fv (color);
    
    //  Draw object
    drawObject ();
Adding Object Type
Object Type GLUI Rollout Panel
Rollout Panel
Object Type GLUI Rollout Panel Collapsed
Collapsed Rollout Panel
  • Add the 'Object Type' rollout to the GLUI window. A rollout is a collapsible panel.
     
    C++
    //  Add the 'Object Type' Rollout Panel to the GLUI window
    GLUI_Rollout *ot_rollout = glui_window->add_rollout (
        "Object Type");
  • Add a radio group to the 'Object Type' panel. A radio group is a collection of related radio buttons.
     
    C++
    //  Id of the selected radio button
    int radiogroup_item_id = 0;
    
    //  Create radio button group
    GLUI_RadioGroup *ot_group = glui_window->add_radiogroup_to_panel (ot_panel,
        &radiogroup_item_id, OBJECTYPE_RADIOGROUP, glui_callback);
  • Add the radio buttons representing object types to the group. Radio buttons are used to handle mutually exclusive options, and have no meaning if they are not added to a radio group. Radio buttons are assigned a number in the order in which they are added to the group, beginning with zero. The currently selected button can be determined with GLUI_RadioGroup::get_int_val(), or set with GLUI_RadioGroup::set_int_val().
     
    C++
    //  Add the radio buttons to the radio group
    glui_window->add_radiobutton_to_group( ot_group, "Cube" );
    glui_window->add_radiobutton_to_group( ot_group, "Sphere" );
    glui_window->add_radiobutton_to_group( ot_group, "Cone" );
    glui_window->add_radiobutton_to_group( ot_group, "Torus" );
    glui_window->add_radiobutton_to_group( ot_group, "Dodecahedron" );
    glui_window->add_radiobutton_to_group( ot_group, "Octahedron" );
    glui_window->add_radiobutton_to_group( ot_group, "Tetrahedron" );
    glui_window->add_radiobutton_to_group( ot_group, "Icosahedron" );
    glui_window->add_radiobutton_to_group( ot_group, "Teapot" );

    Based on the radio button selected and the wireframe checkbox state, we need to display the right GLUT geometric shape.

    C++
    //  The different GLUT shapes
    enum GLUT_SHAPES
    {
        GLUT_WIRE_CUBE = 0,
        GLUT_SOLID_CUBE,
        GLUT_WIRE_SPHERE,
        GLUT_SOLID_SPHERE,
        GLUT_WIRE_CONE,
        GLUT_SOLID_CONE,
        GLUT_WIRE_TORUS,
        GLUT_SOLID_TORUS,
        GLUT_WIRE_DODECAHEDRON,
        GLUT_SOLID_DODECAHEDRON,
        GLUT_WIRE_OCTAHEDRON,
        GLUT_SOLID_OCTAHEDRON,
        GLUT_WIRE_TETRAHEDRON,
        GLUT_SOLID_TETRAHEDRON,
        GLUT_WIRE_ICOSAHEDRON,
        GLUT_SOLID_ICOSAHEDRON,
        GLUT_WIRE_TEAPOT,
        GLUT_SOLID_TEAPOT
    };
    //  Get the id of the selected object
    int selected_object = (radiogroup_item_id * 2) + 1 - wireframe;
    
    switch (selected_object)
    {
        //  draw glut wire cube
        case GLUT_WIRE_CUBE:
    
            glutWireCube (0.5);
    
            break;
        //  draw glut solid cube
        case GLUT_SOLID_CUBE:
    
            glutSolidCube (0.5);
    
            break;
        //  draw glut wire sphere
        case GLUT_WIRE_SPHERE:
    
            glutWireSphere (0.5, 50, 50);
    
            break;
        //  draw glut solid sphere
        case GLUT_SOLID_SPHERE:
    
            glutSolidSphere (0.5, 50, 50);
    
            break;
        //  and so on...
    }

    For example, let's say that the wireframe checkbox is checked and the Teapot radio button is clicked. Then, the wireframe live variable would be 1 since the checkbox is checked. The radiogroup_item_id value would be 8, which is the id of the Teapot radio button. Thus, the selected object would be calculated as follows:

    C++
    selected_object = (8 * 2) + 1 - 1 = 16.

    where 16 is the same as GLUT_WIRE_TEAPOT, and thus the following code segment would be executed to draw the GLUT wire teapot.

    C++
    glutWireTeapot (0.5);

    For more information about the GLUT geometric shapes, you may check the GLUT Geometric Shapes article.

Adding Transformation

GLUI Transformatoin Panel

  • Add the transformation panel to the GLUI window.
     
    C++
    // Add the 'Transformation' Panel to the GLUI window
    GLUI_Panel *transformation_panel = glui_window->add_panel (
        "Transformation");
  • Add a panel to the 'Transformation' Panel. This panel is without a label and is used to hold together the translation controls.
    C++
    //  Create transformation panel 1 that will contain the Translation
    //  controls
    GLUI_Panel *transformation_panel1 = glui_window->add_panel_to_panel (
        transformation_panel, "");
  • Add the XY Translation control to transformation panel 1 above. The translation control allows the user to change the X, Y, or Z position of objects drawn on the window. The rate of change of translation can be varied by holding down SHIFT for fast movement (100 times faster), or CTRL for slow movement (100 times slower). The four types of translation controls are shown below. When using the XY control, movement can be restricted to a single axis (either X or Y) by holding down ALT and clicking on either the horizontal or the vertical arrows.
GLUI Translation Control XY
GLUI Translation Control X
GLUI Translation Control Y
GLUI Translation Control Z
GLUI_TRANSLATION_XY
GLUI_TRANSLATION_X
GLUI_TRANSLATION_Y
GLUI_TRANSLATION_Z

In order to add the XY translation control, we execute the following code segment:

C++
//  Translation XY Live Variable
float translate_xy[2] = {0, 0};

//  Add the xy translation control
GLUI_Translation *translation_xy = glui_window->add_translation_to_panel(
    transformation_panel1, "Translation XY",
    GLUI_TRANSLATION_XY, translate_xy,
    TRANSLATION_XY, glui_callback );
//  Set the translation speed
translation_xy->set_speed( 0.005 );

The first parameter of the add_translation_to_panel is the panel to which we want to add the translation control. The second parameter is the name of the translation control. The third parameter represents the type of the translation, which could be any of GLUI_TRANSLATION_XY, GLUI_TRANSLATION_X, GLUI_TRANSLATION_Y, or GLUI_TRANSLATION_Z. The fourth parameter is the live variable used to track the x, y, or z coordinates being changed. The fifth parameter represents the ID of the control as it gets passed to the callback function, which is specified in the sixth parameter.

The set_speed method allows us to adjust the speed of the translation control in response to user mouse movements.

  • Add an invisible column to transformation panel 1 in order to place the XY and Z translation controls horizontally.
     
    C++
    //  Add column, but don't draw it
    glui_window->add_column_to_panel (transformation_panel1, false);
  • Add the Z "translation control" to transformation panel 1.
     
    C++
    //  Translation Z Live Variable
    float translate_z = 0;
    
    //  Add the z translation control
    GLUI_Translation *translation_z = glui_window->add_translation_to_panel (
        transformation_panel1, "Translation Z",
        GLUI_TRANSLATION_Z, &translate_z,
        TRANSLATION_Z, glui_callback );
    //  Set the translation speed
    translation_z->set_speed( 0.005 );

    In order to have our objects translated whenever the user moves with the translation control, we need to apply the translation to the matrix on top of the model stack before we display our object. This is done using the glTranslate OpenGL function as follows:

    C++
    //  Apply the translation
    glTranslatef (translate_xy[0], translate_xy[1], -translate_z);
  • Create transformation panel 2 and add to the main 'Transformation' Panel.
     
    C++
    //  Create transformation panel 2 that will contain the rotation and
    //  spinner controls
    GLUI_Panel *transformation_panel2 = glui_window->add_panel_to_panel (
        transformation_panel, "");
  • Add the rotation control to the transformation panel 2.
     
    C++
    //  Rotation Matrix Live Variable Array (Initialize as Identity Matrix)
    float rotation_matrix[16] = { 1.0, 0.0, 0.0, 0.0,
                                  0.0, 1.0, 0.0, 0.0,
                                  0.0, 0.0, 1.0, 0.0,
                                  0.0, 0.0, 0.0, 1.0 };
    //  Add the rotation control
    glui_window->add_rotation_to_panel (transformation_panel2,
        "Rotation", rotation_matrix, ROTATION, glui_callback);

    The ROTATION is a constant representing the id of the rotation control, which will be sent to the callback function whenever the user rotates the archball. The rotation_matrix is the live variable for the rotation control and is automatically updated whenever the archball is rotated. The rotation_matrix represents the matrix that will cause rotation when multiplied to the current matrix at the top of our model view stack. To cause our object to rotate, we must multiply the rotation_matrix by the current matrix before our object gets displayed. This is done as follows:

    C++
    //  Apply the rotation matrix
    glMultMatrixf (rotation_matrix);

    The rotation control can be constrained to horizontal-only movement by holding the CTRL key, or to vertical rotation by holding the ALT key.

    GLUI Rotation Control
  • Add a separator:
     
    C++
    //  Add separator
    glui_window->add_separator_to_panel (transformation_panel2);
  • Add a spinner to allow for scaling our object. The spinner is added to transformation panel 2, and it is named Scale.
     
    C++
    //  Add the scale spinner
    GLUI_Spinner *spinner = glui_window->add_spinner_to_panel (
        transformation_panel2, "Scale", GLUI_SPINNER_FLOAT,
        &scale, SCALE_SPINNER, glui_callback);
    //  Set the limits for the spinner
    spinner->set_float_limits ( -4.0, 4.0 );

    The spinner is an integer or floating point editable textbox with two attached arrows, which increases or decreases the current value of the control. The rate at which the spinner changes can be controlled using the set_speed function. Also, one can hold SHIFT while initially clicking an arrow to increase the step amount by a factor of 100, or CONTROL to decrease the step amount to 1/100th its usual value. The data type of the spinner can be either GLUI_SPINNER_INT or GLUI_SPINNER_FLOAT, and it is passed as the third parameter to the add_spinner_to_panel method. The live variable could be a float or int data type, based on the selected data type of the control. The SCALE_SPINNER is the ID of the spinner control, which would be passed to the glui_callback function whenever the user manipulates the spinner control.

    GLUI Spinner

    We can use the set_float_limits and set_int_limits methods to set the upper and lower limits on the integer or float values that an editable text box can accept.

    In order for our value in the spinner to affect the scaling of our object, we need to use the OpenGL glScalef function to apply the scaling on the object before it gets drawn:

    C++
    //  Apply the scaling
    glScalef (scale, scale, scale);
Adding Quit Button

GLUI Quit Button

Finally, after adding all of the above controls, we add the Quit button as follows:

C++
//  Add the Quit Button
glui_window->add_button ("Quit", QUIT_BUTTON, glui_callback);

When the Quit button is clicked, the glui_callback function is executed with QUIT_BUTTON ID as its parameter and causes the program to exit:

C++
//  Quit Button clicked
case QUIT_BUTTON:
    printf ("Quit Button clicked... Exit!\n");

    exit (1);

break;

7- Merge GLUT & GLUI

After creating the GLUI window and adding controls to it, we need to associate it with the "main graphics window" as follows:

C++
glui_window->set_main_gfx_window (main_window);

When a control in the GLUI window changes value, a redisplay request will be sent to this main graphics window.

8- Main Event Loop

Invoke the standard GLUT main "event loop":

C++
glutMainLoop();

Conclusion

I think this article can significantly help in creating an OpenGL application with graphical user controls, and at the same time, the template can be used to save lots of copy and paste from old projects or the Internet.

In case you find this template useful or have suggestions, please let me know.

References

Revision History

25/09/2007

  • Added table of contents

30/08/2007

  • Deleted and re-posted at author's request

16/07/2007

  • Modified article to meet criteria specified in "A Guide To Writing Articles For Code Project" by Marc Clifton
  • Added more controls
  • Notes difference between GLUI and GLUT events by placing GLUT or GLUI in front of a message at the command prompt
  • Added references

21/07/2005

  • Original article

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)