Visual C++ 2015 Files
Visual C++ 6 Files (Old)
This program sets up a platform-independent OpenGL window using the GLUT library. It can be used in the following ways:
- Learn GLUT and OpenGL through:
- Interactive Program
- Source Code
- Start your first OpenGL program
- Use the code as a template for your OpenGL applications
Make sure you read the “Running the Program” section of the documentation before you download the program and run it.
OpenGL is one of the most widely used APIs for developing portable 2D and 3D graphics applications. It was originally developed in 1992 by Silicon Graphics and is currently controlled and maintained by the OpenGL ARB (Architecture Review Board). ARB representatives include SGI, Microsoft, Apple, nVidia, ATI, Intel, id Software (famous for creating DOOM and QUAKE), and 3D Labs.
OpenGL has become an industry standard and a very popular API for its ease of use, portability, stability and rich documentation. According to OpenGL.org, OpenGL is the only truly open, vendor-neutral, multiplatform graphics standard.
This article was originally written based on OpenGL 2.1, but it should work with the latest OpenGL 4.5 version. I couldn't get a hold of the 4.5 dlls, so the dlls used here are still from 2.1.
OpenGL is a window system independent graphics library. This means that it doesn't handle window system operations that are specific to the Operating System. The reason for this is to make OpenGL portable on even new platforms. Creating a rendering window and handling events is left to the native window system to define. The OpenGL Utility Toolkit (GLUT) is intended to fill this gap, and thus provides developers with a window system independent API for OpenGL programs. GLUT supports the following functionality:
- Window management
- Event handling
- Right click menu
- Rendering fonts
- Rendering various solid and wireframe objects
- Reading from sophisticated input devices
It is important to note that GLUT is not a fully-featured windowing toolkit. It is mostly used for learning OpenGL and developing simple OpenGL programs. GLUT is simple, easy and small. The GLUT library has C, C++, FORTRAN and Ada programming bindings. It is portable to nearly all OpenGL implementations for the X Window System and Windows.
Important: GLUT hasn't been touched since 1998. A better alternative is FreeGLUT. This article was originally written based on GLUT version 3.6, but now has been transitioned to work with FreeGLUT.
Knowing that OpenGL is an API intended for graphical applications, it is very clear that a window is always required to render the graphical objects. To avoid having to write the same code every time you want to create a graphical application using OpenGL, this program code can be used as a template to get you directly started with what matters to you in the program. The OpenGL GLUT window template has the following properties:
- Title: "GLUT Window Template"
- Background Color: black (R = 0, G = 0, B = 0)
- Dimensions: width = 480, height = 480
- Position: x = (Screen Width - Window Width) / 2, y = (Screen Height - Window Height) / 2. This would mean that the window is centered on the screen
- Handling of keyboard, mouse and display events
- Showing when events occur, including their meaning, through the command prompt
Usage on Windows
I highly recommend also looking at the instructions on the official OpenGL wiki for instructions on how to get started with OpenGL on Windows, Linux and Mac: https://www.opengl.org/wiki/Getting_Started
It's just amazing how starting an OpenGL GLUT application has become with recent versions of Visual Studio. All you need to do really is install the NupenGL.Core nuget package, and you're good to go. No more placing around .h, .lib and .dll files. That said, please ignore the "Visual C++ 6" section below as this has been written more than 9 years ago and applies to Visual C++ version 6 (We're at version 14 now!).
Here are the simple steps from scratch:
- Open Visual Studio 2015 Community Edition
- Create a new Visual Studio C++ Windows Console Application
- Keeping it all empty is just fine
- Install the NupenGL.Core nuget package. From Visual Studio, Go to Tools \ NuGet Package Manager \ Manage Nuget Packages for this solution. Search for "NupenGL" and install the package.
- Add the GLUT_Window_Template.c to your project
- The current NunpenGL.Core nuget package (0.0.0.1) was designed to run with Visual Studio 2013. It needs to get updated so it can run fine on Visual Studio 2015. If you build, you will get this error: LNK1104 cannot open file 'freeglut.lib'. To work around this, go to Project Properties, and set the Platform Toolset to Visual Studio 2013 (v120) and you should be able to build and run without any issues.
In order to run the program, three dynamic link libraries (DLLs) are required: opengl32.dll, glu32.dll and glut32.dll. The opengl32.dll and glu32.dll files 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 the same folder where your exe is or in a folder in your system path. You can find all of the DLL files in the attached ZIP file, GLUT_Window_Template_dll.zip under Visual C++\dll.
In order to write a C OpenGL application with GLUT using Microsoft Visual Studio on a Windows platform, you need the following files:
- C header files: GL.h, GLU.h and GLUT.h
- C LIB files: glui32.lib, opengl32.lib and glut32.lib
You can find all of the header and LIB files in the attached ZIP file GLUT_Window_Template_dll.zip under Visual C++\include\GL and Visual C++\lib, respectively.
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
- Copy the source file GLUT_Window_Template.c to your project folder. This is GLUT_Window_Template_src in our case. You may want to rename the file to fit your program's needs.
- Add the source file to the project using the menu option Project\Add To Project\Files:
- 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 ||Header Files ||Visual C++/include/GL ||C:\Program Files\Microsoft Visual Studio\VC98\Include\GL |
|OPENGL32.LIB, GLU32.LIB, GLUT32.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:
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.
#pragma comment (lib, "opengl32.lib")
#pragma comment (lib, "glut32.lib")
#pragma comment (lib, "glu32.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:
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 C file and add it to your Visual Studio project.
The header files for GLUT should be included in GLUT programs with the following include directive:
There is no need to include
<GL/glut.h> already includes them. You can also do <GL/freeglut.h>.
Functions starting with
glutInit are used to initialize the GLUT state. The
glutInit function is the primary initializing routine and must only be called once in a GLUT program. OpenGL or GLUT functions that are not starting with
glutInit are not allowed to be called before the primary
glutInit function. However, other functions starting with
glutInit can be called before the primary
glutInit function. The reason for this is to allow for specifying the window initialization state in command-line arguments and before the session is negotiated with the window system.
Below I show each initialization function prototype, its description and how I used it in my program.
void glutInit(int *argcp, char **argv);
glutInit initializes the GLUT library and negotiates a session with the window system.
void glutInitWindowSize(int width, int height);
glutInitWindowSize to set the initial size of the window that will be created. The value for the
height parameters must be greater than zero. In case no value is specified, i.e. function not called, the default window size is 300 by 300. Note that the window system is not obligated with this information. Thus, GLUT programs must depend on the
glutReshapeFunc to determine the true size of the window.
int window_width = 240;
int window_height = 240;
glutInitWindowSize (window_width, window_height);
void glutInitWindowPosition(int x, int y);
glutInitWindowPosition to set the initial position of a window. The default value is -1 by -1, which tells the window system to determine the appropriate position.
void centerOnScreen (void)
window_x = (glutGet (GLUT_SCREEN_WIDTH) - window_width)/2;
window_y = (glutGet (GLUT_SCREEN_HEIGHT) - window_height)/2;
glutInitWindowPosition (window_x, window_y);
In the code above, I am simply making the window centered on the screen.
glutGet (GLUT_SCREEN_WIDTH) gets the width of the screen in pixels and
glutGet (GLUT_SCREEN_HEIGHT) gets its height.
void glutInitDisplayMode(unsigned int mode);
The display mode specifies what buffers are to be used in order to render the OpenGL graphics. One may choose more than one mode by using the logical
OR operator. The following are the possible modes that can be selected; they have been copied from the GLUT API Version 3 Reference Manual:
|Mode ||Description |
|Bit mask to select a color index mode window. This overrides |
GLUT_RGBA if it is also specified.
|Bit mask to select a single buffered window. This is the default if neither |
GLUT_SINGLE are specified.
|Bit mask to select a double buffered window. This overrides |
GLUT_SINGLE if it is also specified.
|Bit mask to select a window with an accumulation buffer. |
|Bit mask to select a window with an alpha component to the color buffer(s). |
|Bit mask to select a window with a depth buffer. |
|Bit mask to select a window with a stencil buffer. |
|Bit mask to select a window with multisampling support. If multisampling is not available, a non-multisampling window will automatically be chosen. Note: both the OpenGL client-side and server-side implementations must support the |
GLX_SAMPLE_SGIS extension for multisampling to be available.
|Bit mask to select a stereo window. |
|Bit mask to select a window with a "luminance'' color model. This model provides the functionality of OpenGL's RGBA color model, but the green and blue components are not maintained in the frame buffer. Instead, each pixel's red component is converted to an index between zero and |
glutGet(GLUT_WINDOW_COLORMAP_SIZE)-1 and looked up in a per-window color map to determine the color of pixels within the window. The initial colormap of
GLUT_LUMINANCE windows is initialized to be a linear gray ramp, but can be modified with GLUT's colormap routines.
glutInitDisplayMode (GLUT_RGBA | GLUT_DOUBLE);
To display graphical content on a window, we need to tell GLUT whether to use single buffering or double buffering. In case single buffering is to be used, we need to set the
GLUT_SINGLE (by default). To display OpenGL contents on the window, we must call the
glFlush OpenGL function which copies the contents of the frame buffer to the window.
GLUT_DOUBLE is usually the better option, as it allows for faster graphics rendering without flickering due to the use of two frame buffers that are continuously swapped. To swap those buffers, we call the GLUT function
glutSwapBuffers. Note that
GLUT_DOUBLE uses more memory than
GLUT_SINGLE due to the use of 2 frame buffers rather than 1.
int glutCreateWindow(char *name);
Creates the GLUT window with
name as its title. The value returned is a unique small integer identifier for the window. Rendering to a created window is ineffective before the
glutMainLoop function is called because the window cannot yet be displayed.
char *window_title = "GLUT Window Template";
After creating the window, you may want to display it in full screen.
int full_screen = 0;
The purpose here is to set some OpenGL properties and initialize any data structures you have in your program. In our case, we need to set the frame buffer clear color to black. This would mean that whenever we want to refresh our graphics, we need to first clear the old drawing with a black canvas and then redraw our new contents. Otherwise, our graphics won't display in the correct manner.
void init ()
glClearColor (0.0, 0.0, 0.0, 0.0);
The arguments to
B (blue) and
A (alpha). Alpha is used for transparency. The values range between 0.0 and 1.0. For example, in case you want to set the clear color to gray (128, 128, 128), you need to divide each component by 255 in order to get the right parameters for
These are the callback functions that are mostly used. To see the remaining callback functions that GLUT supports, please refer to the GLUT API Version 3 Reference Manual.
void display (void)
glClear (GL_COLOR_BUFFER_BIT) will clear the frame buffer so that things can be re-drawn clearly.
glutSwapBuffer places the contents of the back buffer into the from buffer visible on the window.
drawObject function simply displays an icosahedron and tells us that the
display function is currently being called. When GLUT determines that the window needs to be redisplayed, the
display callback for the window is called. The
display callback function in GLUT can be either set explicitly by calling
glutPostRedisplay or implicitly as the result of window damage reported by the window system. Multiple posted redisplays for a window are coalesced by GLUT to minimize the number of
display callbacks called.
void drawObject ()
printf ("Displaying object...\n");
You will notice the "Displaying object..." message on the command prompt in the following cases:
glutPostRedisplay is explicitly called in the code
- After the window is resized
- When the window loses focus and then gets it back
If you notice this happening in other cases, please let me know.
void reshape (int w, int h)
window_width = w;
window_height = h;
glViewport(0, 0, window_width, window_height);
printf ("Window Width: %d, Window Height: %d.\n",
reshape function will be called every time a window is resized and when the window is first displayed on the screen. The
h parameters of the callback specify the new window size in pixels.
I am using the
glViewport function here to reset the drawing area to be equal to the window size whenever the window is resized. If you try commenting out the
glViewport function, you will notice that the drawing remains the same no matter how you resize the window. However, calling the
glViewport function will enlarge and shrink the drawing area based on the changes in the window size.
When a user presses and releases a mouse button, two events are generated: one for the press and the other for the release. The
state parameter is either
GLUT_DOWN, indicating whether the callback was due to a release or press, respectively. The
button parameter is one of
GLUT_RIGHT_BUTTON and indicates which button was clicked. The
y parameters indicate the mouse coordinates relative to the GLUT window when the mouse button's state changed. If a menu is attached to a button for a window, mouse callbacks will not be generated for that button. Passing
glutMouseFunc disables the generation of mouse callbacks.
void mouse (int button, int state, int x, int y)
printf ("Mouse Left Button Pressed (Down)...\n");
printf ("Mouse Left Button Released (Up)...\n");
printf ("Mouse Middle Button Pressed (Down)...\n");
printf ("Mouse Middle Button Released (Up)...\n");
printf ("Mouse Right Button Pressed (Down)...\n");
printf ("Mouse Right Button Released (Up)...\n");
In order to check if the Shift, Ctrl or Alt key was pressed while the mouse event occurred, we can use the
glutGetModifiers function. This returns the modifier key state at the time the input event for a keyboard, special or mouse callback is generated. The modifiers are
GLUT_ACTIVE_SHIFT (Shift or Caps Lock),
GLUT_ACTIVE_CTRL (Ctrl) and
As long as the user is moving the mouse while a button is pressed (i.e. dragging), this event will be called continuously.
void motion (int x, int y)
printf ("Mouse Drag Position: %d, %d.\n", x, y);
As long as the user is moving the mouse while no button is pressed, this event will be called continuously.
void pmotion (int x, int y)
printf ("Mouse Move Position: %d, %d.\n", x, y);
Each key press generating an ASCII character will generate a keyboard callback. The
key callback parameter is the generated ASCII character. The
y callback parameters indicate the mouse location in window-relative coordinates when the key was pressed. Passing
glutKeyboardFunc disables the generation of keyboard callbacks.
void keyboard (unsigned char key, int x, int y)
printf ("User is hitting the '%c' key.\n", key);
printf ("ASCII code is %d.\n", key);
printf ("User is hitting the Return key.\n");
printf ("User is hitting the Space key.\n");
printf ("User is hitting the Back Space key.\n");
In order to check if the Shift, Ctrl or Alt key was pressed while the ASCII key was pressed, we can use the
glutGetModifiers function. Also, modifiers might have an effect on the ASCII character itself. For example, if Caps Lock is off and we press Shift + A Key, the value of the
key parameter will be set to
A. If only the A key is pressed, then the
key parameter is set to
void special (int key, int x, int y)
case GLUT_KEY_F1 :
printf ("F1 function key.\n");
case GLUT_KEY_F2 :
printf ("F2 function key. \n");
case GLUT_KEY_F3 :
printf ("F3 function key. \n");
case GLUT_KEY_F4 :
printf ("F4 function key. \n");
case GLUT_KEY_F5 :
printf ("F5 function key. \n");
case GLUT_KEY_F6 :
printf ("F6 function key. \n");
case GLUT_KEY_F7 :
printf ("F7 function key. \n");
case GLUT_KEY_F8 :
printf ("F8 function key. \n");
case GLUT_KEY_F9 :
printf ("F9 function key. \n");
case GLUT_KEY_F10 :
printf ("F10 function key. \n");
case GLUT_KEY_F11 :
printf ("F11 function key. \n");
case GLUT_KEY_F12 :
printf ("F12 function key. \n");
case GLUT_KEY_LEFT :
printf ("Left directional key. \n");
case GLUT_KEY_UP :
printf ("Up directional key. \n");
case GLUT_KEY_RIGHT :
printf ("Right directional key. \n");
case GLUT_KEY_DOWN :
printf ("Down directional key. \n");
case GLUT_KEY_PAGE_UP :
printf ("Page up directional key. \n");
case GLUT_KEY_PAGE_DOWN :
printf ("Page down directional key. \n");
case GLUT_KEY_HOME :
printf ("Home directional key. \n");
case GLUT_KEY_END :
printf ("End directional key. \n");
case GLUT_KEY_INSERT :
printf ("Inset directional key. \n");
Each key press generating a non-ASCII character will generate a special callback. The
y callback parameters indicate the mouse location in window relative coordinates when the key was pressed. Passing
glutSpecialFunc disables the generation of special callbacks. Here is the list of special keys as specified in the GLUT API Version 3 Reference Manual:
|Key ||Description |
|F1 function key. |
|F2 function key. |
|F3 function key. |
|F4 function key. |
|F5 function key. |
|F6 function key. |
|F7 function key. |
|F8 function key. |
|F9 function key. |
|F10 function key. |
|F11 function key. |
|F12 function key. |
|Left directional key. |
|Up directional key. |
|Right directional key. |
|Down directional key. |
|Page up directional key. |
|Page down directional key. |
|Home directional key. |
|End directional key. |
|Insert directional key. |
After a GLUT program has completed initial setup, such as creating windows and menus, GLUT programs enter the GLUT event processing loop by calling
glutMainLoop. This function should be called at most once in an OpenGL program.
I think this article can help significantly in getting you started with OpenGL. 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.
- Raise awareness that GLUT should now be replaced with FreeGlut
- Show how easy it is to get setup with Visual Studio 2015 Community Edition and Nupengl Nuget package
- Article reposted at author's request
- Article deleted at author's request