OpenGL

What is OpenGL?

OpenGL (originally developed by SGI) is the premier environment for developing portable, interactive 2D and 3D graphics applications. Since its introduction in 1992, OpenGL has become the industry's most widely used and supported 2D and 3D graphics application programming interface (API).

http://www.sgi.com/software/opengl/
http://www.opengl.org/

OpenGL runs on every major operating system including Mac OS, OS/2, UNIX, Windows 95/98, Windows NT, Windows 2000, Linux, OPENStep, and BeOS; it also works with every major windowing system, including Win32, MacOS, Presentation Manager, and X-Window System. OpenGL is callable from Ada, C, C++, Fortran, Python, Perl and Java and offers complete independence from network protocols and topologies.

I will be providing links, examples and other information for the following programming languages.

C/C++, Java and Visual Basic

 

OpenGL/GLUT

In order to use OpenGL there are files that you will need on your system. If you have a Windows system that's win98 and newer you probably already have OpenGL Dll files. However in order to program with OpenGL there are other files that will be needed. Also if you visited either the Silicon Graphics or OpenGL.org site you should know what is needed. Just in case below is a list of files you will need and where they should be copied to your windows system. By the way since I work in Windows this information will be for Windows users. I have also tested all the examples using VC++ 5.0 and GLUT 3.7

User Files:

Opengl32.dll and glu32.dll in the "C:\Windows\system" (you should already have these...
if you do not have these files on your system you can download them off Microsoft's site here.)

Developer Files:

glut.h Install this file as: C:\Program Files\Microsoft Visual Studio\VC\Include\GL\glut.h
glut32.lib Install this file as: C:\Program Files\Microsoft Visual Studio\VC\Lib\glut32.lib
glut32.dll Install this file as: C:\WINDOWS\system32\glut32.dll / on NT /C:\WINNT\system32\glut32.dll

Glut for Windows user can be downloaded at Gult for Windows.

Helpful Information

To get ride of the console window when using win32 console application click on Project|Settings then select the link tab. Under Project Options add the following at the end of the edit box:

VC++
/SUBSYSTEM:WINDOWS /ENTRY:mainCRTStartup

Also add the opengl32.lib glut32.lib glu32.lib to your link files . This should be added under PROJECT|SETTINGS|LINK in front of kernel32.lib user32.lib gdi32.lib.

In some cases when compiling the examples on the web you will get a float to double warning. This is a meaningless warning and can be disabled by adding the following at the end of the #include files.

/* Disable Float to Double warning: C4305 */
#ifdef WIN32
#pragma warning( disable : 4305)
#endif

Also some math.h do not define M_PI so this would go under the last #include statement.

/* Some <math.h> files do not define M_PI... */
#ifndef M_PI
#define M_PI 3.14159265
#endif

While all the examples I will be using have been changed to correct the above problems, if you do any of the other examples that I will be pointing out they may not.

What is GLUT

GLUT (pronounced like the glut in gluttony) is the OpenGL Utility Toolkit, a window system independent toolkit for writing OpenGL programs. Mark J. Kilgard, to enable the construction of OpenGL applications that are truly window system independent, conceived the GLUT library. Thanks to GLUT, we can write applications without having to learn about X windows or Microsoft's own window system. Kilgard implemented the version for X windows, and later Nate Robins ported it to Microsoft Windows.

Because OpenGL doesn't provide routines for interfacing with a windowing system or input devices, an application must use a variety of other platform-specific routines for this purpose. The result is non-portable code. GLUT is a library that addresses these issues by providing a platform-independent interface to window management, menus, and input devices in a simple and elegant manner.

The site below provides more information of GLUT.

http://www.opengl.org/developers/faqs/technical/glut.htm#glot0010

Understanding GLUT

Before we get started you should take a look at the tutorial below, it will go over the many GLUT routines and functions. It will give you a better understanding of the up coming examples I will be providing. Bookmark the site, it makes a good reference guide.

GULT Tutorial

Example 1 - Creating a window

Firstly don't forget to add opengl32.lib, glut32.lib, glu32.lib to your linker. It should be added under PROJECT|SETTINGS|LINK in front of kernel32.lib, user32.lib and gdi32.lib. Also since the first few examples are win32 console programs,don't forget to add; /SUBSYSTEM:WINDOWS /ENTRY:mainCRTStartup at the end of "Object Options" edit box on the link tab. This will get ride of the console window.

//TestGLTest.cpp
#include <stdio.h>
#include <GL/glut.h>
void display(void)
{
glClear( GL_COLOR_BUFFER_BIT);
glColor3f(0.0, 1.0, 0.0);
glBegin(GL_POLYGON);
glVertex3f(2.0, 4.0, 0.0);
glVertex3f(8.0, 4.0, 0.0);
glVertex3f(8.0, 6.0, 0.0);
glVertex3f(2.0, 6.0, 0.0);
glEnd();
glFlush();
}

int main(int argc, char **argv)
{
//printf("hello world\n"); since we got ride of the console this is not needed
glutInit(&argc, argv);
glutInitDisplayMode ( GLUT_SINGLE | GLUT_RGB | GLUT_DEPTH);

glutInitWindowPosition(100,100);
glutInitWindowSize(300,300);
glutCreateWindow ("square");

glClearColor(0.0, 0.0, 0.0, 0.0);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0.0, 10.0, 0.0, 10.0, -1.0, 1.0);

glutDisplayFunc(display);
glutMainLoop();

return 0;
}

What does this all means?

First we will take a look at the code with in main(). After the print statement(which we are not using) there is a call to glutInit(). When using GLUT you must always call Init to all function that need initialization, this will start the event processing loop. Since all GLUT functions are prefixed by glut we call glutInit. Now glutInit takes 2 parameters.

argc - A pointer to the unmodified argc variable from the main function.
argv - A pointer to the unmodified argv variable from the main function

Next we initiate the display mode by calling gultInitDisplayMode(). It takes one parameter.

mode - specifies the display mode

The mode parameter is a Boolean combination (OR bit wise) of the possible predefined values in the GLUT library. You use mode to specify the color mode, and the number and type of buffers.

The predefined constants to specify the color model are:

GLUT_RGBA or GLUT_RGB - selects a RGBA window. This is the default color mode
GLUT_INDEX - selects a color index mode.

The display mode also allows you to select either a single or double buffer window. The predefined constants for this are:

GLUT_SINGLE - single buffer window
GLUT_DOUBLE - double buffer window, required to have smooth animation

You can specify if you want a window with a particular set of buffers. The most common are:

GLUT_ACCUM - The accumulation buffer
GLUT_STENCIL - The stencil buffer
GLUT_DEPTH - The depth buffer

Next well call glutInitWindowPosition(100,100), glutInitWindowSize(300,300), glutCreateWindow ("square") respectively. This call sets the windows position, the size and names the window.

Next we call glClearColor(), glMatrixMode(), glLoadIdentity(), glOrtho(). The first call sets the color to clear the window( in this case black). The remaining calls are used to define the type of camera projection.

Lastly in main we call glutDisplayFunc(display), glutMainLoop(). The glutDisplayFunc calls the display function, this function is needed any time the window needs to be redrawn. glutDisplayFunc() registers the call-back function, while glutMainLoop() hands execution control over to the glut library.

display()
The display() call-back function clears the screen, sets the current color to red and draws a square polygon. The last call, glFlush(), forces previously issued OpenGL commands to begin execution.

That's it you have just completed your first OpenGL program.

Example 2 - Creating a window 2

For our second example you will be creating 3 files, CreateWindow.cpp, model.cpp and model.h. Before you compile this program don't forget to prepare VC++ by referencing the opengl link files as well as adding the statement that will get ride of the console window.

//CreateWindow.cpp
#include <GL/glut.h>
#include "model.h"

void init(void)
{
glClearColor(1.0, 1.0, 1.0, 0.0)
glShadeModel(GL_FLAT) ;
}

void display(void)
{
glClear(GL_COLOR_BUFFER_BIT) ;
Draw_Wireframe_Cube() ;
glutSwapBuffers() ;
}

int main(int argc, char** argv)
{
glutInit (&argc, argv) ;
glutInitDisplayMode (GLUT_DOUBLE | GLUT_RGB) ;
glutInitWindowSize (400, 100) ;
glutInitWindowPosition (100, 100);
glutCreateWindow ("First Chapter - Opening an OpenGL Window") ;

init() ;
glutDisplayFunc (display) ;

glutMainLoop () ;

return 0 ;
}

//model.cpp
#include "model.h"
void Draw_Wireframe_Cube (void)
{
glColor3f(0.0,0.0,0.0) ;
glutWireCube(1.0) ;
}

//model.h
#ifndef MODEL
#define MODEL

#ifdef __FLAT__
#include <windows.h>
#endif

#include <gl/glut.h>

void Draw_Wireframe_Cube(void) ;

#endif

If you compile the above code and run it you will see a windows with a wire cube inside. To get a explanation of the above code you can read chapter 2 of the tutorial below. You well probably notice that the code in the main() section looks familiar.

http://www.dev-gallery.com/programming/opengl/book/thesis_contents.htm

Example 3 - Animation

This example illustrates the use of glutSwapBuffers() to create animation, the example draws a spinning cube. The following example also shows how to use GLUT to control an input device and turn on and off an idle function. In this example, the mouse buttons toggle the spinning on and off. The animation is achieved using double buffering.

//double.cpp
#include <GL/glut.h>
#include <stdlib.h>

static GLfloat spin = 0.0;

void init(void)
{
glClearColor (0.0, 0.0, 0.0, 0.0);
glShadeModel (GL_FLAT);
}

void display(void)
{
glClear(GL_COLOR_BUFFER_BIT);
glPushMatrix();
glRotatef(spin, 0.0, 0.0, 1.0);
glColor3f(1.0, 1.0, 1.0);
glRectf(-25.0, -25.0, 25.0, 25.0);
glPopMatrix();
glutSwapBuffers();
}

void spinDisplay(void)
{
spin = spin + 2.0;
if (spin > 360.0)
spin = spin - 360.0;
glutPostRedisplay();
}

void reshape(int w, int h)
{
glViewport (0, 0, (GLsizei) w, (GLsizei) h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(-50.0, 50.0, -50.0, 50.0, -1.0, 1.0);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
}

void mouse(int button, int state, int x, int y)
{
switch (button) {
case GLUT_LEFT_BUTTON:
if (state == GLUT_DOWN)
glutIdleFunc(spinDisplay);
break;
case GLUT_RIGHT_BUTTON:
if (state == GLUT_DOWN)
glutIdleFunc(NULL);
break;
default:
break;
}
}

/*
* Request double buffer display mode.
* Register mouse input callback functions
*/
int main(int argc, char** argv)
{
glutInit(&argc, argv);
glutInitDisplayMode (GLUT_DOUBLE | GLUT_RGB);
glutInitWindowSize (250, 250);
glutInitWindowPosition (100, 100);
glutCreateWindow (argv[0]);
init ();
glutDisplayFunc(display);
glutReshapeFunc(reshape);
glutMouseFunc(mouse);
glutMainLoop();
return 0;
}

I won't be going over the code that's in the main(), display() or init()since I already explained this on the first example.

void spinDisplay(void) - This function defines the spinning it checks it see if the object has turned 360 and if so it will call the glutPostRedisplay() to keep the object spinning.

void reshape(int w, int h)- This function draws the box that will be spinning.

void mouse(int button, int state, int x, int y) - This function will check and see which mouse button was pressed and act accordingly. If it was the left mouse button the box will spin, if it was the right mouse button the box will stop spinning.

Example4 - Spinning Cube

In example 3 I introduced you to animation using double buffering via glutSwapBuffer and the keyboard. This example goes a little further and allows you to spin the cube in different directions.  Quick note, if the middle button on your mouse is not enabled then the middle button will have no effect on the cube.

//cube.cpp
#include <stdlib.h>
#include <GL/glut.h>


GLfloat vertices[][3] = {{-1.0,-1.0,-1.0},{1.0,-1.0,-1.0},
{1.0,1.0,-1.0}, {-1.0,1.0,-1.0}, {-1.0,-1.0,1.0},
{1.0,-1.0,1.0}, {1.0,1.0,1.0}, {-1.0,1.0,1.0}};

GLfloat normals[][3] = {{-1.0,-1.0,-1.0},{1.0,-1.0,-1.0},
{1.0,1.0,-1.0}, {-1.0,1.0,-1.0}, {-1.0,-1.0,1.0},
{1.0,-1.0,1.0}, {1.0,1.0,1.0}, {-1.0,1.0,1.0}};

GLfloat colors[][3] = {{0.0,0.0,0.0},{1.0,0.0,0.0},
{1.0,1.0,0.0}, {0.0,1.0,0.0}, {0.0,0.0,1.0},
{1.0,0.0,1.0}, {1.0,1.0,1.0}, {0.0,1.0,1.0}};

void polygon(int a, int b, int c , int d)
{

/* draw a polygon via list of vertices */

glBegin(GL_POLYGON);
glColor3fv(colors[a]);
glNormal3fv(normals[a]);
glVertex3fv(vertices[a]);
glColor3fv(colors[b]);
glNormal3fv(normals[b]);
glVertex3fv(vertices[b]);
glColor3fv(colors[c]);
glNormal3fv(normals[c]);
glVertex3fv(vertices[c]);
glColor3fv(colors[d]);
glNormal3fv(normals[d]);
glVertex3fv(vertices[d]);
glEnd();
}

void colorcube(void)
{

/* map vertices to faces */

polygon(0,3,2,1);
polygon(2,3,7,6);
polygon(0,4,7,3);
polygon(1,2,6,5);
polygon(4,5,6,7);
polygon(0,1,5,4);
}

static GLfloat theta[] = {0.0,0.0,0.0};
static GLint axis = 2;

void display(void)
{
/* display callback, clear frame buffer and z buffer,
rotate cube and draw, swap buffers */

glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glLoadIdentity();
glRotatef(theta[0], 1.0, 0.0, 0.0);
glRotatef(theta[1], 0.0, 1.0, 0.0);
glRotatef(theta[2], 0.0, 0.0, 1.0);

colorcube();

glFlush();
glutSwapBuffers();
}

void spinCube()
{

/* Idle callback, spin cube 2 degrees about selected axis */

theta[axis] += 2.0;
if( theta[axis] > 360.0 ) theta[axis] -= 360.0;
display();
}

void mouse(int btn, int state, int x, int y)
{

/* mouse callback, selects an axis about which to rotate */

if(btn==GLUT_LEFT_BUTTON && state== GLUT_DOWN) axis = 0;
if(btn==GLUT_MIDDLE_BUTTON && state == GLUT_DOWN) axis = 1;
if(btn==GLUT_RIGHT_BUTTON && state== GLUT_DOWN) axis = 2;
}

void myReshape(int w, int h)
{
glViewport(0, 0, w, h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
if (w <= h)
glOrtho(-2.0, 2.0, -2.0 * (GLfloat) h / (GLfloat) w,
2.0 * (GLfloat) h / (GLfloat) w, -10.0, 10.0);
else
glOrtho(-2.0 * (GLfloat) w / (GLfloat) h,
2.0 * (GLfloat) w / (GLfloat) h, -2.0, 2.0, -10.0, 10.0);
glMatrixMode(GL_MODELVIEW);
}

void
main(int argc, char **argv)
{
glutInit(&argc, argv);

/* need both double buffering and z buffer */

glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
glutInitWindowSize(500, 500);
glutCreateWindow("colorcube");
glutReshapeFunc(myReshape);
glutDisplayFunc(display);
glutIdleFunc(spinCube);
glutMouseFunc(mouse);
glEnable(GL_DEPTH_TEST); /* Enable hidden--surface--removal */
glutMainLoop();
}

Example5 Texture Mapping

One of the problems with showing sample programs to illustrate texture mapping is that interesting textures are large. Typically, textures are read from an image file, since specifying a texture programmatically could take hundreds of lines of code. This example, which consists of alternating white and black squares, like a checkerboard - is generated by the program. The program applies this texture to two squares, which are then rendered in perspective, one of them facing the viewer squarely and the other tilting back at 45 degrees.

//checker.cpp
#include <GL/glut.h>
#include <stdlib.h>
#include <stdio.h>

/* Create checkerboard texture */
#define checkImageWidth 64
#define checkImageHeight 64

/* Disable Float to Double warning: C4305 */
#ifdef WIN32
#pragma warning( disable : 4305)
#endif


static GLubyte checkImage[checkImageHeight][checkImageWidth][4];

static GLuint texName;

void makeCheckImage(void)
{
int i, j, c;

for (i = 0; i < checkImageHeight; i++) {
for (j = 0; j < checkImageWidth; j++) {
c = ((((i&0x8)==0)^((j&0x8))==0))*255;
checkImage[i][j][0] = (GLubyte) c;
checkImage[i][j][1] = (GLubyte) c;
checkImage[i][j][2] = (GLubyte) c;
checkImage[i][j][3] = (GLubyte) 255;
}
}
}

void init(void)
{
glClearColor (0.0, 0.0, 0.0, 0.0);
glShadeModel(GL_FLAT);
glEnable(GL_DEPTH_TEST);

makeCheckImage();
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);

glGenTextures(1, &texName);
glBindTexture(GL_TEXTURE_2D, texName);

glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,
GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
GL_NEAREST);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, checkImageWidth,
checkImageHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE,
checkImage);
}

void display(void)
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glEnable(GL_TEXTURE_2D);
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL);
glBindTexture(GL_TEXTURE_2D, texName);
glBegin(GL_QUADS);
glTexCoord2f(0.0, 0.0); glVertex3f(-2.0, -1.0, 0.0);
glTexCoord2f(0.0, 1.0); glVertex3f(-2.0, 1.0, 0.0);
glTexCoord2f(1.0, 1.0); glVertex3f(0.0, 1.0, 0.0);
glTexCoord2f(1.0, 0.0); glVertex3f(0.0, -1.0, 0.0);

glTexCoord2f(0.0, 0.0); glVertex3f(1.0, -1.0, 0.0);
glTexCoord2f(0.0, 1.0); glVertex3f(1.0, 1.0, 0.0);
glTexCoord2f(1.0, 1.0); glVertex3f(2.41421, 1.0, -1.41421);
glTexCoord2f(1.0, 0.0); glVertex3f(2.41421, -1.0, -1.41421);
glEnd();
glFlush();
glDisable(GL_TEXTURE_2D);
}

void reshape(int w, int h)
{
glViewport(0, 0, (GLsizei) w, (GLsizei) h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(60.0, (GLfloat) w/(GLfloat) h, 1.0, 30.0);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glTranslatef(0.0, 0.0, -3.6);
}

void keyboard (unsigned char key, int x, int y)
{
switch (key) {
case 27:
exit(0);
break;
default:
break;
}
}

int main(int argc, char** argv)
{
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB | GLUT_DEPTH);
glutInitWindowSize(250, 250);
glutInitWindowPosition(100, 100);
glutCreateWindow(argv[0]);
init();
glutDisplayFunc(display);
glutReshapeFunc(reshape);
glutKeyboardFunc(keyboard);
glutMainLoop();
return 0;
}

The checkerboard texture is generated in the routine makeCheckImage(), and all the texture-mapping initialization occurs in the routine init(). glGenTextures() and glBindTexture() name and create a texture object for a texture image.The single, full-resolution texture map is specified by glTexImage2D(), whose parameters indicate the size of the image, type of the image, location of the image, and other properties of it.

The four calls to glTexParameter*() specify how the texture is to be wrapped and how the colors are to be filtered if there isn't an exact match between pixels in the texture and pixels on the screen.

In display(), glEnable() turns on texturing. glTexEnv*() sets the drawing mode to GL_DECAL so that the textured polygons are drawn using the colors from the texture map (rather than taking into account what color the polygons would have been drawn without the texture).

The command glTexImage2D() defines a two-dimensional texture. It takes several arguments.

Example6 - Texture Subimage

This examples modified some of the code in Example 5 and uses the keyboard to turn on and off a colored checkbox within the checker board. See if you can tell which lines of code were modified.

//texSub.cpp
#include <GL/glut.h>
#include <stdlib.h>
#include <stdio.h>

/* Disable Float to Double warning: C4305 */
#ifdef WIN32
#pragma warning( disable : 4305)
#endif

/* Create checkerboard texture */
#define checkImageWidth 64
#define checkImageHeight 64
#define subImageWidth 16
#define subImageHeight 16

static GLubyte checkImage[checkImageHeight][checkImageWidth][4];
static GLubyte subImage[subImageHeight][subImageWidth][4];
static GLuint texName;

void makeCheckImage(void)
{
int i, j, c;

for (i = 0; i < checkImageHeight; i++) {
for (j = 0; j < checkImageWidth; j++) {
c = ((((i&0x8)==0)^((j&0x8))==0))*255;
checkImage[i][j][0] = (GLubyte) c;
checkImage[i][j][1] = (GLubyte) c;
checkImage[i][j][2] = (GLubyte) c;
checkImage[i][j][3] = (GLubyte) 255;
}
}
for (i = 0; i < subImageHeight; i++) {
for (j = 0; j < subImageWidth; j++) {
c = ((((i&0x4)==0)^((j&0x4))==0))*255;
subImage[i][j][0] = (GLubyte) c;
subImage[i][j][1] = (GLubyte) 0;
subImage[i][j][2] = (GLubyte) 0;
subImage[i][j][3] = (GLubyte) 255;
}
}
}

void init(void)
{
glClearColor (0.0, 0.0, 0.0, 0.0);
glShadeModel(GL_FLAT);
glEnable(GL_DEPTH_TEST);

makeCheckImage();
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);

glGenTextures(1, &texName);
glBindTexture(GL_TEXTURE_2D, texName);

glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,
GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
GL_NEAREST);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, checkImageWidth,
checkImageHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE,
checkImage);
}

void display(void)
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glEnable(GL_TEXTURE_2D);
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL);
glBindTexture(GL_TEXTURE_2D, texName);
glBegin(GL_QUADS);
glTexCoord2f(0.0, 0.0); glVertex3f(-2.0, -1.0, 0.0);
glTexCoord2f(0.0, 1.0); glVertex3f(-2.0, 1.0, 0.0);
glTexCoord2f(1.0, 1.0); glVertex3f(0.0, 1.0, 0.0);
glTexCoord2f(1.0, 0.0); glVertex3f(0.0, -1.0, 0.0);

glTexCoord2f(0.0, 0.0); glVertex3f(1.0, -1.0, 0.0);
glTexCoord2f(0.0, 1.0); glVertex3f(1.0, 1.0, 0.0);
glTexCoord2f(1.0, 1.0); glVertex3f(2.41421, 1.0, -1.41421);
glTexCoord2f(1.0, 0.0); glVertex3f(2.41421, -1.0, -1.41421);
glEnd();
glFlush();
glDisable(GL_TEXTURE_2D);
}

void reshape(int w, int h)
{
glViewport(0, 0, (GLsizei) w, (GLsizei) h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(60.0, (GLfloat) w/(GLfloat) h, 1.0, 30.0);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glTranslatef(0.0, 0.0, -3.6);
}

void keyboard (unsigned char key, int x, int y)
{
switch (key) {
case 's':
case 'S':
glBindTexture(GL_TEXTURE_2D, texName);
glTexSubImage2D(GL_TEXTURE_2D, 0, 12, 44,
subImageWidth, subImageHeight, GL_RGBA,
GL_UNSIGNED_BYTE, subImage);
glutPostRedisplay();
break;
case 'r':
case 'R':
glBindTexture(GL_TEXTURE_2D, texName);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA,
checkImageWidth, checkImageHeight, 0,
GL_RGBA, GL_UNSIGNED_BYTE, checkImage);
glutPostRedisplay();
break;
case 27:
exit(0);
break;
default:
break;
}
}

int main(int argc, char** argv)
{
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB | GLUT_DEPTH);
glutInitWindowSize(250, 250);
glutInitWindowPosition(100, 100);
glutCreateWindow(argv[0]);
init();
glutDisplayFunc(display);
glutReshapeFunc(reshape);
glutKeyboardFunc(keyboard);
glutMainLoop();
return 0;
}

OpenGL and Win32

Until now we have created console programs using GLUT. This section of the tutorial will create OpenGL programs using Win32 applications. While you will not have to add the /entry:mainCRTStartup or change the /subsystem:console to /subsystem:windows, you still have to add lib files to link to (opengl32.lib glut32.lib glu32.lib ).

Win32 Example 1 - Minimal window

//minimal.cpp
/* An example of the minimal Win32 & OpenGL program. It only works in
16 bit color modes or higher (since it doesn't create a
palette). */


#include <windows.h>/* must include this before GL/gl.h */
#include <GL/gl.h>/* OpenGL header file */
#include <GL/glu.h>/* OpenGL utilities header file */
#include <stdio.h>


void
display()
{
/* rotate a triangle around */
glClear(GL_COLOR_BUFFER_BIT);
glBegin(GL_TRIANGLES);
glColor3f(1.0f, 0.0f, 0.0f);
glVertex2i(0, 1);
glColor3f(0.0f, 1.0f, 0.0f);
glVertex2i(-1, -1);
glColor3f(0.0f, 0.0f, 1.0f);
glVertex2i(1, -1);
glEnd();
glFlush();
}


LONG WINAPI
WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
static PAINTSTRUCT ps;

switch(uMsg) {
case WM_PAINT:
display();
BeginPaint(hWnd, &ps);
EndPaint(hWnd, &ps);
return 0;

case WM_SIZE:
glViewport(0, 0, LOWORD(lParam), HIWORD(lParam));
PostMessage(hWnd, WM_PAINT, 0, 0);
return 0;

case WM_CHAR:
switch (wParam) {
case 27:/* ESC key */
PostQuitMessage(0);
break;
}
return 0;

case WM_CLOSE:
PostQuitMessage(0);
return 0;
}

return DefWindowProc(hWnd, uMsg, wParam, lParam);
}

HWND
CreateOpenGLWindow(char* title, int x, int y, int width, int height,
BYTE type, DWORD flags)
{
int pf;
HDC hDC;
HWND hWnd;
WNDCLASS wc;
PIXELFORMATDESCRIPTOR pfd;
static HINSTANCE hInstance = 0;

/* only register the window class once - use hInstance as a flag. */
if (!hInstance) {
hInstance = GetModuleHandle(NULL);
wc.style = CS_OWNDC;
wc.lpfnWndProc = (WNDPROC)WindowProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hInstance;
wc.hIcon = LoadIcon(NULL, IDI_WINLOGO);
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = NULL;
wc.lpszMenuName = NULL;
wc.lpszClassName = "OpenGL";

if (!RegisterClass(&wc)) {
MessageBox(NULL, "RegisterClass() failed: "
"Cannot register window class.", "Error", MB_OK);
return NULL;
}
}

hWnd = CreateWindow("OpenGL", title, WS_OVERLAPPEDWINDOW |
WS_CLIPSIBLINGS | WS_CLIPCHILDREN,
x, y, width, height, NULL, NULL, hInstance, NULL);

if (hWnd == NULL) {
MessageBox(NULL, "CreateWindow() failed: Cannot create a window.",
"Error", MB_OK);
return NULL;
}

hDC = GetDC(hWnd);

/* there is no guarantee that the contents of the stack that become
the pfd are zeroed, therefore _make sure_ to clear these bits. */
memset(&pfd, 0, sizeof(pfd));
pfd.nSize = sizeof(pfd);
pfd.nVersion = 1;
pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | flags;
pfd.iPixelType = type;
pfd.cColorBits = 32;

pf = ChoosePixelFormat(hDC, &pfd);
if (pf == 0) {
MessageBox(NULL, "ChoosePixelFormat() failed: "
"Cannot find a suitable pixel format.", "Error", MB_OK);
return 0;
}

if (SetPixelFormat(hDC, pf, &pfd) == FALSE) {
MessageBox(NULL, "SetPixelFormat() failed: "
"Cannot set format specified.", "Error", MB_OK);
return 0;
}

DescribePixelFormat(hDC, pf, sizeof(PIXELFORMATDESCRIPTOR), &pfd);

ReleaseDC(hDC, hWnd);

return hWnd;
}

int APIENTRY
WinMain(HINSTANCE hCurrentInst, HINSTANCE hPreviousInst,
LPSTR lpszCmdLine, int nCmdShow)
{
HDC hDC;/* device context */
HGLRC hRC;/* opengl context */
HWND hWnd;/* window */
MSG msg;/* message */

hWnd = CreateOpenGLWindow("minimal", 0, 0, 256, 256, PFD_TYPE_RGBA, 0);
if (hWnd == NULL)
exit(1);

hDC = GetDC(hWnd);
hRC = wglCreateContext(hDC);
wglMakeCurrent(hDC, hRC);

ShowWindow(hWnd, nCmdShow);

while(GetMessage(&msg, hWnd, 0, 0)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}

wglMakeCurrent(NULL, NULL);
ReleaseDC(hDC, hWnd);
wglDeleteContext(hRC);
DestroyWindow(hWnd);

return msg.wParam;
}

Since this is a OpenGL tutorial and not a win32 programming tutorial I will not be going over the API calls to create, display and close a window. /P>

As you can see we did not use GLUT to create our window, instead we used windows API to create the window. The display function is where the OpenGL comes in to play, this is where the triangle is created.

Win32 Example 2 - Using the mouse

This examples allows you to move the triangle by holding down the mouse button and moving the triangle in any direction.

//mouse.cpp
/* An example of processing mouse events in an OpenGL program using
the Win32 API. */


#include <windows.h>/* must include this before GL/gl.h */
#include <GL/gl.h>/* OpenGL header file */
#include <GL/glu.h>/* OpenGL utilities header file */
#include <stdio.h>


enum {
PAN = 1,/* pan state bit */
ROTATE,/* rotate state bits */
ZOOM/* zoom state bit */
};


HDC hDC;/* device context */
HPALETTE hPalette = 0;/* custom palette (if needed) */
GLfloat trans[3];/* current translation */
GLfloat rot[2];/* current rotation */


static void update(int state, int ox, int nx, int oy, int ny)
{
int dx = ox - nx;
int dy = ny - oy;

switch(state) {
case PAN:
trans[0] -= dx / 100.0f;
trans[1] -= dy / 100.0f;
break;
case ROTATE:
rot[0] += (dy * 180.0f) / 500.0f;
rot[1] -= (dx * 180.0f) / 500.0f;
#define clamp(x) x = x > 360.0f ? x-360.0f : x < -360.0f ? x+=360.0f : x
clamp(rot[0]);
clamp(rot[1]);
break;
case ZOOM:
trans[2] -= (dx+dy) / 100.0f;
break;
}
}


void
init()
{
glEnable(GL_DEPTH_TEST);
}

void
reshape(int width, int height)
{
glViewport(0, 0, width, height);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(60.0, (float)width/height, 0.001, 100.0);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glTranslatef(0.0f, 0.0f, -3.0f);
}

void
display()
{
/* rotate a triangle around */
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glPushMatrix();
glTranslatef(trans[0], trans[1], trans[2]);
glRotatef(rot[0], 1.0f, 0.0f, 0.0f);
glRotatef(rot[1], 0.0f, 1.0f, 0.0f);
glBegin(GL_TRIANGLES);

#define TOP glIndexi(1); glColor3f(1.0f, 0.0f, 0.0f); glVertex3i(0, 1, 0)
#define FR glIndexi(2); glColor3f(0.0f, 1.0f, 0.0f); glVertex3i(1, -1, 1)
#define FL glIndexi(3); glColor3f(0.0f, 0.0f, 1.0f); glVertex3i(-1, -1, 1)
#define BR glIndexi(3); glColor3f(0.0f, 0.0f, 1.0f); glVertex3i(1, -1, -1)
#define BL glIndexi(2); glColor3f(0.0f, 1.0f, 0.0f); glVertex3i(-1, -1, -1)

TOP; FL; FR;
TOP; FR; BR;
TOP; BR; BL;
TOP; BL; FL;
FR; FL; BL;
BL; BR; FR;

glEnd();
glPopMatrix();
glFlush();
SwapBuffers(hDC);/* nop if singlebuffered */
}


LONG WINAPI
WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
static PAINTSTRUCT ps;
static GLboolean left = GL_FALSE;/* left button currently down? */
static GLboolean right = GL_FALSE;/* right button currently down? */
static GLuint state = 0;/* mouse state flag */
static int omx, omy, mx, my;

switch(uMsg) {
case WM_PAINT:
display();
BeginPaint(hWnd, &ps);
EndPaint(hWnd, &ps);
return 0;

case WM_SIZE:
reshape(LOWORD(lParam), HIWORD(lParam));
PostMessage(hWnd, WM_PAINT, 0, 0);
return 0;

case WM_CHAR:
switch (wParam) {
case 27:/* ESC key */
PostQuitMessage(0);
break;
}
return 0;

case WM_LBUTTONDOWN:
case WM_RBUTTONDOWN:
/* if we don't set the capture we won't get mouse move
messages when the mouse moves outside the window. */
SetCapture(hWnd);
mx = LOWORD(lParam);
my = HIWORD(lParam);
if (uMsg == WM_LBUTTONDOWN)
state |= PAN;
if (uMsg == WM_RBUTTONDOWN)
state |= ROTATE;
return 0;

case WM_LBUTTONUP:
case WM_RBUTTONUP:
/* remember to release the capture when we are finished. */
ReleaseCapture();
state = 0;
return 0;

case WM_MOUSEMOVE:
if (state) {
omx = mx;
omy = my;
mx = LOWORD(lParam);
my = HIWORD(lParam);
/* Win32 is pretty braindead about the x, y position that
it returns when the mouse is off the left or top edge
of the window (due to them being unsigned). therefore,
roll the Win32's 0..2^16 pointer co-ord range to the
more amenable (and useful) 0..+/-2^15. */
if(mx & 1 << 15) mx -= (1 << 16);
if(my & 1 << 15) my -= (1 << 16);
update(state, omx, mx, omy, my);
PostMessage(hWnd, WM_PAINT, 0, 0);
}
return 0;

case WM_PALETTECHANGED:
if (hWnd == (HWND)wParam)
break;
/* fall through to WM_QUERYNEWPALETTE */

case WM_QUERYNEWPALETTE:
if (hPalette) {
UnrealizeObject(hPalette);
SelectPalette(hDC, hPalette, FALSE);
RealizePalette(hDC);
return TRUE;
}
return FALSE;

case WM_CLOSE:
PostQuitMessage(0);
return 0;
}

return DefWindowProc(hWnd, uMsg, wParam, lParam);
}

HWND
CreateOpenGLWindow(char* title, int x, int y, int width, int height,
BYTE type, DWORD flags)
{
int n, pf;
HWND hWnd;
WNDCLASS wc;
LOGPALETTE* lpPal;
PIXELFORMATDESCRIPTOR pfd;
static HINSTANCE hInstance = 0;

/* only register the window class once - use hInstance as a flag. */
if (!hInstance) {
hInstance = GetModuleHandle(NULL);
wc.style = CS_OWNDC;
wc.lpfnWndProc = (WNDPROC)WindowProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hInstance;
wc.hIcon = LoadIcon(NULL, IDI_WINLOGO);
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = NULL;
wc.lpszMenuName = NULL;
wc.lpszClassName = "OpenGL";

if (!RegisterClass(&wc)) {
MessageBox(NULL, "RegisterClass() failed: "
"Cannot register window class.", "Error", MB_OK);
return NULL;
}
}

hWnd = CreateWindow("OpenGL", title, WS_OVERLAPPEDWINDOW |
WS_CLIPSIBLINGS | WS_CLIPCHILDREN,
x, y, width, height, NULL, NULL, hInstance, NULL);

if (hWnd == NULL) {
MessageBox(NULL, "CreateWindow() failed: Cannot create a window.",
"Error", MB_OK);
return NULL;
}

hDC = GetDC(hWnd);

/* there is no guarantee that the contents of the stack that become
the pfd are zeroed, therefore _make sure_ to clear these bits. */
memset(&pfd, 0, sizeof(pfd));
pfd.nSize = sizeof(pfd);
pfd.nVersion = 1;
pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | flags;
pfd.iPixelType = type;
pfd.cDepthBits = 32;
pfd.cColorBits = 32;

pf = ChoosePixelFormat(hDC, &pfd);
if (pf == 0) {
MessageBox(NULL, "ChoosePixelFormat() failed: "
"Cannot find a suitable pixel format.", "Error", MB_OK);
return 0;
}

if (SetPixelFormat(hDC, pf, &pfd) == FALSE) {
MessageBox(NULL, "SetPixelFormat() failed: "
"Cannot set format specified.", "Error", MB_OK);
return 0;
}

DescribePixelFormat(hDC, pf, sizeof(PIXELFORMATDESCRIPTOR), &pfd);

if (pfd.dwFlags & PFD_NEED_PALETTE ||
pfd.iPixelType == PFD_TYPE_COLORINDEX) {

n = 1 << pfd.cColorBits;
if (n > 256) n = 256;

lpPal = (LOGPALETTE*)malloc(sizeof(LOGPALETTE) +
sizeof(PALETTEENTRY) * n);
memset(lpPal, 0, sizeof(LOGPALETTE) + sizeof(PALETTEENTRY) * n);
lpPal->palVersion = 0x300;
lpPal->palNumEntries = n;

GetSystemPaletteEntries(hDC, 0, n, &lpPal->palPalEntry[0]);

/* if the pixel type is RGBA, then we want to make an RGB ramp,
otherwise (color index) set individual colors. */
if (pfd.iPixelType == PFD_TYPE_RGBA) {
int redMask = (1 << pfd.cRedBits) - 1;
int greenMask = (1 << pfd.cGreenBits) - 1;
int blueMask = (1 << pfd.cBlueBits) - 1;
int i;

/* fill in the entries with an RGB color ramp. */
for (i = 0; i < n; ++i) {
lpPal->palPalEntry[i].peRed =
(((i >> pfd.cRedShift) & redMask) * 255) / redMask;
lpPal->palPalEntry[i].peGreen =
(((i >> pfd.cGreenShift) & greenMask) * 255) / greenMask;
lpPal->palPalEntry[i].peBlue =
(((i >> pfd.cBlueShift) & blueMask) * 255) / blueMask;
lpPal->palPalEntry[i].peFlags = 0;
}
} else {
lpPal->palPalEntry[0].peRed = 0;
lpPal->palPalEntry[0].peGreen = 0;
lpPal->palPalEntry[0].peBlue = 0;
lpPal->palPalEntry[0].peFlags = PC_NOCOLLAPSE;
lpPal->palPalEntry[1].peRed = 255;
lpPal->palPalEntry[1].peGreen = 0;
lpPal->palPalEntry[1].peBlue = 0;
lpPal->palPalEntry[1].peFlags = PC_NOCOLLAPSE;
lpPal->palPalEntry[2].peRed = 0;
lpPal->palPalEntry[2].peGreen = 255;
lpPal->palPalEntry[2].peBlue = 0;
lpPal->palPalEntry[2].peFlags = PC_NOCOLLAPSE;
lpPal->palPalEntry[3].peRed = 0;
lpPal->palPalEntry[3].peGreen = 0;
lpPal->palPalEntry[3].peBlue = 255;
lpPal->palPalEntry[3].peFlags = PC_NOCOLLAPSE;
}

hPalette = CreatePalette(lpPal);
if (hPalette) {
SelectPalette(hDC, hPalette, FALSE);
RealizePalette(hDC);
}

free(lpPal);
}

ReleaseDC(hDC, hWnd);

return hWnd;
}

int APIENTRY
WinMain(HINSTANCE hCurrentInst, HINSTANCE hPreviousInst,
LPSTR lpszCmdLine, int nCmdShow)
{
HGLRC hRC;/* opengl context */
HWND hWnd;/* window */
MSG msg;/* message */
DWORD buffer = PFD_DOUBLEBUFFER;/* buffering type */
BYTE color = PFD_TYPE_RGBA;/* color type */

if (strstr(lpszCmdLine, "-sb")) {
buffer = 0;
}
if (strstr(lpszCmdLine, "-ci")) {
color = PFD_TYPE_COLORINDEX;
}
if (strstr(lpszCmdLine, "-h")) {
MessageBox(NULL, "mouse [-ci] [-sb]\n"
" -sb single buffered\n"
" -ci color index\n",
"Usage help", MB_ICONINFORMATION);
exit(0);
}

hWnd = CreateOpenGLWindow("mouse", 0, 0, 256, 256, color, buffer);
if (hWnd == NULL)
exit(1);

hDC = GetDC(hWnd);
hRC = wglCreateContext(hDC);
wglMakeCurrent(hDC, hRC);

init();

ShowWindow(hWnd, nCmdShow);

while(GetMessage(&msg, hWnd, 0, 0)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}

wglMakeCurrent(NULL, NULL);
ReleaseDC(hDC, hWnd);
wglDeleteContext(hRC);
DestroyWindow(hWnd);
if (hPalette)
DeleteObject(hPalette);

return msg.wParam;
}

 

You can download the win32 tutorial to get the 2 examples of using win32 with OpenGL here. One thing you might have noticed is how GLUT hide a lot of code from you. Take a look at the code that created a basic window. The GLUT example required about 26 lines of code while the win32 version required over 100 lines of code. You can see why some people like using libraries like MFC and in this case GLUT to create windows applications. But it does come at a price, the size of the files are larger and some say slower.

You can get the tutorial that has the two examples that I have posted here as well as several other examples.

Other examples

http://www.sgi.com/software/opengl/advanced97/programs/programs.html
http://www.dev-gallery.com/programming/opengl/main_opengl.htm

OpenGL and MFC

Instead of cutting and pasting code here for this portion of OpenGL w/MFC, I have decided to provide links to sample code as well as tutorials. One thing you should be aware of when compiling these samples, since they are MFC application you still have to add the opengl32.lib and glu32.lib to your linker. But under the General tab in the project settings you must select "Use MFC in a Shared DLL".

Simple MFC OpenGL tutorial - I downloaded this file and compiled it using VC++ 5, although the tutorial was written using VC6++. Other then a warning everthing else went on as planed. I did how ever make a couple changes.

1. I removed the time.h file and removed all reference to in the smotri.cpp file. By doing this it will case the default name of the window to be displayed.

OpneGL and MFC Part 2

Graphics Programming Using OpenGL and MFC - Whitepaper - This article goes over the most commonly used concepts and techniques in OpenGL Programming. If you do not want to read the article online you can download it in either a doc or pdf file.

Michael Wilber's COS452 MFC / OpenGL Help - This site has several samples of using OpenGL and MFC, however I didn't get a chance to test them to see if there were any errors in the code so you can test them at your own risk.

http://www.codeproject.com/opengl/mfchittest.asp

OpenGL and glxCtl

Most of the publicly availabe OpenGL samples and tutorial materials make use of Mark Kilgard's GLUT library, but the Win32 version of GLUT 3.6 is not fully compatible with Visual Basic. You can instead download 'glxCtl', a generic OpenGL ActiveX control written in VB5. The control handles the setup of the OpenGL window and fires various events. The glxCtl is structured so that GLUT samples can be easily ported to Visual Basic. It includes VB versions of the GLUT shape routines (Solidxxx, Wirexxx) and a port of the GLE Extrusion library. It also provides at least minimal support for palettes, bitmaps and rgb image files. And unlike OGL this ActiveX control is free!

You can get instruction on how to install and use the control here. I downloaded and tested the control and had no problems. I also tested the samples using VB5 and VB6. Just note that if you are using VB5 you have to remove the BEGIN/END lines and everything in between that are located in the class modules. One more thing, the BEGIN is missing in all these examples so you will see the code below instead.

MultiUse = -1  'True
  Persistable = 0  'NotPersistable
  DataBindingBehavior = 0  'vbNone
  DataSourceBehavior = 0   'vbNone
  MTSTransactionMode = 0   'NotAnMTSObject
End

I tested all the examples located the site below other then changing the  reference directory I had no problems. The example was compiled on a WinNT machine so the reference is pointing to a WinNT directory. You can change this manually by using notepad to open the ProjectX file and change the following.

Change from

Reference=*\G{00020430-0000-0000-C000-000000000046}#2.0#0#D:\WINNT\System32\stdole2.tlb#OLE Automation
Reference=*\G{03644881-8010-11D1-95AA-000000000000}#1.1#0#X:\WINNT\System32\vbogl.tlb#VB OpenGL API 1.2 (ANSI)

Change to

Reference=*\G{00020430-0000-0000-C000-000000000046}#2.0#0#C:\Windows\System\stdole2.tlb#OLE Automation
Reference=*\G{03644881-8010-11D1-95AA-000000000000}#1.1#0#C:\Windows\System\vbogl.tlb#VB OpenGL API 1.2 (ANSI)

http://is6.pacific.net.hk/~edx/glxctl.htm

VBOpenGL Type Library 1.2

If you don't want to go the way of the ActiveX control then you can download and use the VBOpenGL type library. The type library includes declarations for GLUT 3.6. You can for example call glutWireSphere and VB will load glut and you will get a wire sphere. However since it is a library you will have to include it if you distribute your application.

I downloaded the library and tested it, it's very easy to install, just extract the vbogl.tlb and you can either put it in your windows system directory or in the same directory as your project.

I downloaded and tested all the examples on the site below and other then one example (MemDC) there were no problems. By the way the Trackball example is really kewl!

MemDC Project

If you get the following message:

ProjectZ.vbp contains invalid key retained - continue loading

Go to the directory where the project files are located. Hold your mouse over the ProjectZ.vbp file and hold the shift key down while right clicking the mouse. Then select open with and select notepad. You should see the two lines of code below change it accordingly. Basically it's telling you it can't find the type libraries in the directories specified.

Of course you wont get this message if you are using WinNT and both libraries are located in the listed directories.


Change from

Reference=*\G{00020430-0000-0000-C000-000000000046}#2.0#0#D:\WINNT\System32\stdole2.tlb#OLE Automation
Reference=*\G{03644881-8010-11D1-95AA-000000000000}#1.1#0#X:\WINNT\System32\vbogl.tlb#VB OpenGL API 1.2 (ANSI)

Change to

Reference=*\G{00020430-0000-0000-C000-000000000046}#2.0#0#C:\Windows\System\stdole2.tlb#OLE Automation
Reference=*\G{03644881-8010-11D1-95AA-000000000000}#1.1#0#C:\Windows\System\vbogl.tlb#VB OpenGL API 1.2 (ANSI)

More VB and OpenGL

If you haven't done so already check out the "Programming OpenGL with Visual Basic" web site. You will find plenty of examples as well as tutorials on OpenGL with VB, using eighter using the glxCtr or the vbogl type library. You will find links to other sites that provide information on using VB with OpenGL.

Programming OpenGL w/VB
http://is6.pacific.net.hk/~edx/contents.htm

More sites on OpenGL and VB

http://www.relia.net/~davepamn/colorcube.html

This concludes the VB protion of the tutorial.

OpenGL and Java

When it comes to OpenGL for java I found many different implementations, however I only got a couple of them to work. So I will sum up this OpenGL tutorial with our look at two implementations of Java binding for OpenGL, JSparrow and JPot.

JSparrow

You should know right off the bat that this verson of JSparrow is a trial version, if you wish to use it commerically you will have to contact the company. You will be presented with a license agreement when you download the software. JSparrow can be used on Windows 95/98/NT 4.0/2000, Solaris, Linux, IRIX and Mac OS systems. I found JSparrow very easy to install and use, you can get the software at the link below along with instructions on how to install the software.

JSparrow - http://home.att.ne.jp/red/aruga/jsparrow/

JSparrow Overview

Don't forget to read the Overview (see link below). It explains how it supports, GL, GLU and  GLUT libraries a long with sample code.

http://home.att.ne.jp/red/aruga/jsparrow/overview.html

JPot

That old saying, "Saved the best for last" definitely applies here. Had I evaluated JPot first I would have introduced it first rather then last. The reason, if you really want to understand the code behind OpenGL and GLUT then download this software and go over the tutorial that comes with it. Believe me, not only will you get a better understanding of the code, it actually demonstrates it for you. You are presented with two windows the right side of the window has the code the left side has the actual rendering of that code. So you can see the effect any change you make to the code immediately, once you hit the execute button.

Installing JPot was easy download the jpot.zip file and the trigger.exe file. Create a directory and unzip the jpot.zip file to that directory. Put the trigger.exe file in the Windows directory, this assumes that you have windows in your path statement.

To run the tutorial I created a bat file and put it on my desk to make it easier to access the tutorial. To create a bat file open notepad and copy and past the code below, then click save as "jpot.bat" with the quotes and save it to your desktop.

CD C:\jPot\
java JPot

This assumes that you have installed the jPot software package to your C: dirive.

JPot - http://www.cs.uwm.edu/~grafix2/

While downloading the software take a look around the site, you can get screen shots of the tutorial, instructions on how to use and install the software. And if that was not enough all the samples in the tutorial are also available in HTML format (under the HTML directory) so you can veiw the code.

Other OpenGL ports to Java

Like I stated earlier I found several ports of OpenGL to Java packages, however since I could get them to work I can't really tell you if they are any good or not. But if you wish to give them a try here you go.

GL4Java - http://www.jausoft.com/gl4java.html
Jun for Java - http://www.sra.co.jp/people/nisinaka/Jun4Java/index-e.html
Jogl - http://copa.pajato.com/jogl/

This concludes OpenGL for Java.

Final Words and Resources

I hope you have enjoyed our look at OpenGL. If you were wondering what you can use OpenGL for think game programming. If you were able to check out any of the site you wll see code example that use OpenGL for gamming.

I will leave you with a couple of sites that have other links and resources on OpenGL.

Resources

OpenGL Programming Guide

OpenGL FAQ and Troubleshooting Guide

SGI OpenGL FAQ

 

 

 

Copyright© 2001 Marietta Crockett
Disclaimer