Visual C++ 2015 Files
Visual C++ 6 Files (Old)
Contents
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
- Documentation
- 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:
#pragma comment(
linker,"/subsystem:\"windows\" /entry:\"mainCRTStartup\"")
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:
#include <GL/glut.h>
There is no need to include <GL/gl.h>
or <GL/glu.h>
since <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.
glutInit(&argc, argv);
void glutInitWindowSize(int width, int height);
Use glutInitWindowSize
to set the initial size of the window that will be created. The value for the width
and 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);
Use the 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.
int window_x;
int window_y;
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 |
GLUT_INDEX | Bit mask to select a color index mode window. This overrides GLUT_RGBA if it is also specified. |
GLUT_SINGLE | Bit mask to select a single buffered window. This is the default if neither GLUT_DOUBLE nor GLUT_SINGLE are specified. |
GLUT_DOUBLE | Bit mask to select a double buffered window. This overrides GLUT_SINGLE if it is also specified. |
GLUT_ACCUM | Bit mask to select a window with an accumulation buffer. |
GLUT_ALPHA | Bit mask to select a window with an alpha component to the color buffer(s). |
GLUT_DEPTH | Bit mask to select a window with a depth buffer. |
GLUT_STENCIL | Bit mask to select a window with a stencil buffer. |
GLUT_MULTISAMPLE | 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. |
GLUT_STEREO | Bit mask to select a stereo window. |
GLUT_LUMINANCE | 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 mode
to 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.
However, 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";
glutCreateWindow (window_title);
After creating the window, you may want to display it in full screen.
int full_screen = 0;
if (full_screen)
glutFullScreen ();
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 glClearColor
are R
(red), G
(green), 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 glClearColor
.
glutDisplayFunc (display);
glutReshapeFunc (reshape);
glutMouseFunc (mouse);
glutMotionFunc (motion);
glutPassiveMotionFunc (pmotion);
glutKeyboardFunc (keyboard);
glutSpecialFunc (special);
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);
drawObject ();
glutSwapBuffers ();
}
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.
The 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");
glutWireIcosahedron ();
}
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",
window_width, window_height);
}
The reshape
function will be called every time a window is resized and when the window is first displayed on the screen. The w
and 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_UP
or GLUT_DOWN
, indicating whether the callback was due to a release or press, respectively. The button
parameter is one of GLUT_LEFT_BUTTON
, GLUT_MIDDLE_BUTTON
or GLUT_RIGHT_BUTTON
and indicates which button was clicked. The x
and 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 NULL
to glutMouseFunc
disables the generation of mouse callbacks.
void mouse (int button, int state, int x, int y)
{
switch (button)
{
case GLUT_LEFT_BUTTON:
switch (state)
{
case GLUT_DOWN:
printf ("Mouse Left Button Pressed (Down)...\n");
break;
case GLUT_UP:
printf ("Mouse Left Button Released (Up)...\n");
break;
}
break;
case GLUT_MIDDLE_BUTTON:
switch (state)
{
case GLUT_DOWN:
printf ("Mouse Middle Button Pressed (Down)...\n");
break;
case GLUT_UP:
printf ("Mouse Middle Button Released (Up)...\n");
break;
}
break;
case GLUT_RIGHT_BUTTON:
switch (state)
{
case GLUT_DOWN:
printf ("Mouse Right Button Pressed (Down)...\n");
break;
case GLUT_UP:
printf ("Mouse Right Button Released (Up)...\n");
break;
}
break;
}
}
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 GLUT_ACTIVE_ALT
(Alt).
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);
}
glutPassiveMotionFunc
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);
}
glutKeyboardFunc
Each key press generating an ASCII character will generate a keyboard callback. The key
callback parameter is the generated ASCII character. The x
and y
callback parameters indicate the mouse location in window-relative coordinates when the key was pressed. Passing NULL
to 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);
switch (key)
{
case 'a':
break;
case 'A':
break;
case 13:
printf ("User is hitting the Return key.\n");
break;
case 32:
printf ("User is hitting the Space key.\n");
break;
case 8:
printf ("User is hitting the Back Space key.\n");
break;
case 27:
exit (1);
break;
}
glutPostRedisplay ();
}
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 a
.
glutSpecialFunc
void special (int key, int x, int y)
{
switch (key)
{
case GLUT_KEY_F1 :
printf ("F1 function key.\n");
break;
case GLUT_KEY_F2 :
printf ("F2 function key. \n");
break;
case GLUT_KEY_F3 :
printf ("F3 function key. \n");
break;
case GLUT_KEY_F4 :
printf ("F4 function key. \n");
break;
case GLUT_KEY_F5 :
printf ("F5 function key. \n");
break;
case GLUT_KEY_F6 :
printf ("F6 function key. \n");
break;
case GLUT_KEY_F7 :
printf ("F7 function key. \n");
break;
case GLUT_KEY_F8 :
printf ("F8 function key. \n");
break;
case GLUT_KEY_F9 :
printf ("F9 function key. \n");
break;
case GLUT_KEY_F10 :
printf ("F10 function key. \n");
break;
case GLUT_KEY_F11 :
printf ("F11 function key. \n");
break;
case GLUT_KEY_F12 :
printf ("F12 function key. \n");
break;
case GLUT_KEY_LEFT :
printf ("Left directional key. \n");
break;
case GLUT_KEY_UP :
printf ("Up directional key. \n");
break;
case GLUT_KEY_RIGHT :
printf ("Right directional key. \n");
break;
case GLUT_KEY_DOWN :
printf ("Down directional key. \n");
break;
case GLUT_KEY_PAGE_UP :
printf ("Page up directional key. \n");
break;
case GLUT_KEY_PAGE_DOWN :
printf ("Page down directional key. \n");
break;
case GLUT_KEY_HOME :
printf ("Home directional key. \n");
break;
case GLUT_KEY_END :
printf ("End directional key. \n");
break;
case GLUT_KEY_INSERT :
printf ("Inset directional key. \n");
break;
}
glutPostRedisplay ();
}
Each key press generating a non-ASCII character will generate a special callback. The x
and y
callback parameters indicate the mouse location in window relative coordinates when the key was pressed. Passing NULL
to 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 |
GLUT_KEY_F1 | F1 function key. |
GLUT_KEY_F2 | F2 function key. |
GLUT_KEY_F3 | F3 function key. |
GLUT_KEY_F4 | F4 function key. |
GLUT_KEY_F5 | F5 function key. |
GLUT_KEY_F6 | F6 function key. |
GLUT_KEY_F7 | F7 function key. |
GLUT_KEY_F8 | F8 function key. |
GLUT_KEY_F9 | F9 function key. |
GLUT_KEY_F10 | F10 function key. |
GLUT_KEY_F11 | F11 function key. |
GLUT_KEY_F12 | F12 function key. |
GLUT_KEY_LEFT | Left directional key. |
GLUT_KEY_UP | Up directional key. |
GLUT_KEY_RIGHT | Right directional key. |
GLUT_KEY_DOWN | Down directional key. |
GLUT_KEY_PAGE_UP | Page up directional key. |
GLUT_KEY_PAGE_DOWN | Page down directional key. |
GLUT_KEY_HOME | Home directional key. |
GLUT_KEY_END | End directional key. |
GLUT_KEY_INSERT | Insert directional key. |
void glutMainLoop(void);
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.
8/10/2015
- 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
26/07/2007
- Article reposted at author's request
mid-July, 2007
- Article deleted at author's request
02/07/2007
06/06/2007
21/05/2005: