VOICE Home Page: http://www.os2voice.org |
January 2005
Newsletter Index
|
By Per Johansson © January 2005 |
OpenGL is a visual programming environment for anything from pretty screen savers to simulating machines. With OpenGL you can run existing programs and also create your own. This article is about how to make OpenGL programs with our most current C++ compiler, Innotek GCC 3.2.2. It's not an introduction about OpenGL itself, rather about how you can use code samples and available tools to make OpenGL programs.
I'll use these tools to get started. OS/2 Warp 4 comes with some support for OpenGL, but the default version is 1.0. If I remember correctly, that version was left out of eComStation. I use version 1.1 for this article. This is the latest (last?) version for OS/2, but it's enough for this purpose. For newer development have a look at MesaGL (see below).
In eComStation 1.1 you can install the OpenGL 1.1 runtime (latest filedate 1997-10-06) from the Applications CD. The installation consists of some DLL files that are copied to your X:\OS2\DLL directory.
The OS/2 Developer's Toolkit version 4.52, filedate 2001-10-04, ships with eComStation 1.1. It can be installed from CD #2, "Developer software." It contains the libraries glut.lib, libaux.lib and opengl.lib. It also contains source code and compiled programs. Unfortunately, all this stuff is OpenGL 1.0 and it won't work with the OpenGL 1.1 runtime. You can still use the source code recompiling it with the OpenGL 1.1 libraries. Furthermore, the Toolkit is made for IBM Visual Age C++ version 3 which means that you sometimes have modify the code to make it compile with GCC.
The 1.1 version of the OpenGL API (latest filedate 1997-10-06) is available from the Hobbes archive. Either opengl.zip, the original one from IBM, or opengl_gold_110.wpi that contains some modifications for the Watcom compiler, for instance. In any case, one header file, glut.h, needs to be changed to compile with GCC. In fact, I have seen a slightly newer official glut.h modified in the same way as I did, so the modifications seem OK to do. glut.h provides, for instance, functionality to manage windows so you don't have to do any PM programming.
To include the directory F:\oglgold\include instead of F:\oglgold\include\gl I changed the following lines:
#include <gl.h> #include <glu.h>
to:
#include <GL/gl.h> #include <GL/glu.h>
I also changed 20 function parameters, removing one APIENTRY
(defined as _System
,
finally expanding to __attribute__((__system__)))
, to avoid the compiler error: "invalid type
modifier within pointer declarator". I don't know what the problem is, but my programs work fine without
this modifier.
extern void APIENTRY glutDisplayFunc (void (* APIENTRY)(void));
to:
extern void APIENTRY glutDisplayFunc (void (*)(void));
The corrected glut.h is available from here.
It's available from Innotek. I have used beta 4 CSD 1. It comes with an installer.
This is the linker that is used by default by GCC 3.2.2. I tried in vain to use the older alternative, IBM Linker 4.0 (or LINK386) that comes with OS/2, eComStation and the toolkit. I also tried the IBM C/C++ 3.6.5 linker. None of them worked, at least not in C++ mode. IBM Linker 5.0 (filedate 2003-10-07) is not easy to find; I got it from the Warpzilla build site. Installation is easy. Just unzip the file, and add its bin directory to your PATH and LIBPATH.
When studying OpenGL programming, we used the book Computer Programming using Open GL, 2nd edition, by Francis S. Hill, ISBN 0-02-254856-8. The book contains many program samples that are available from its website. Here's the first program, FIG2_10.CPP, with my modifications:
/* Removed #include <windows.h> Removed #include <GL/Gl.h> since it's already included from glut.h Changed #include <gl/glut.h> to #include <GL/glut.h> for Unix compatibility Changed main return from void to int for ISO C/C++ compliance (an explicit return statement is not needed in main) */ /* #include <windows.h> // use as needed for your system #include <gl/Gl.h> #include <gl/glut.h> */ #include <GL/glut.h> //<<<<<<<<<<<<<<<<<<<<<<< myInit >>>>>>>>>>>>>>>>>>>> void myInit(void) { glClearColor(1.0,1.0,1.0,0.0); // set white background color glColor3f(0.0f, 0.0f, 0.0f); // set the drawing color glPointSize(4.0); // a dot is 4 by 4 pixels glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluOrtho2D(0.0, 640.0, 0.0, 480.0); } //<<<<<<<<<<<<<<<<<<<<<<<< myDisplay >>>>>>>>>>>>>>>>> void myDisplay(void) { glClear(GL_COLOR_BUFFER_BIT); // clear the screen glBegin(GL_POINTS); glVertex2i(100, 50); // draw three points glVertex2i(100, 130); glVertex2i(150, 130); glEnd(); glFlush(); // send all output to display } //<<<<<<<<<<<<<<<<<<<<<<<< main >>>>>>>>>>>>>>>>>>>>>> int main(int argc, char** argv) { glutInit(&argc, argv); // initialize the toolkit glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB); // set display mode glutInitWindowSize(640,480); // set window size glutInitWindowPosition(100, 150); // set window position on screen glutCreateWindow("my first attempt"); // open the screen window glutDisplayFunc(myDisplay); // register redraw function myInit(); glutMainLoop(); // go into a perpetual loop }
To compile:
set path=F:\ILINK50\bin;%path% set beginlibpath=F:\ILINK50\bin g++ -Wall -ansi -pedantic -DOS2=1 -D__IBMC__=1 fig2_10.cpp -I\oglgold\INCLUDE -lglut -lopengl -L/oglgold/lib -Zomf -Zlinker /PM:PM
Run with the command fig2_10. You'll see a window with three dots.
This is somewhat more advanced. It shows as (unrealistic) solar system with a sun and three planets rotating around it at different speeds. The viewpoint is placed in angle from the rotating plane so the orbits look elliptical. Perspective is used so the planets' sizes vary with distance. The planets are illuminated from the sun with some ambient lightning so you can see their dark sides too.
#include <GL/glut.h> #include <cstdlib> const GLfloat light_pos[] = {0, 0, 0, 1} , light_ambient[] = {0.1, 0.1, 0.1, 1} , light_diffuse[] = {1, 1, 1, 1} , light_specular[] = {1, 1, 1, 1} ; static int iteration = 0; static GLint slices = 30 , stacks = 30 ; void myCreateObjects(int iteration) { GLfloat white[] = {1, 1, 1, 1}, red[] = {1, 0, 0, 1}, green[] = {0, 1, 0, 1}, blue[] = {0, 1, 1, 1}, spec_exp = 100; glPushAttrib(GL_LIGHTING_BIT); glDisable(GL_LIGHTING); glColor3ub(255, 255, 0); glutSolidSphere(5, slices, stacks); glPopAttrib(); glMaterialfv(GL_FRONT, GL_AMBIENT, white); glMaterialfv(GL_FRONT, GL_SPECULAR, white); glMaterialf(GL_FRONT, GL_SHININESS, spec_exp); for (int i(1); i <=3; ++i) { glPushMatrix(); glRotatef((iteration) * 3/i, 0, 1, 0); glTranslatef(i * 10, 0, 0); switch (i) { case 1: glMaterialfv(GL_FRONT, GL_DIFFUSE, red) ; break ; case 2: glMaterialfv(GL_FRONT, GL_DIFFUSE, green) ; break ; case 3: glMaterialfv(GL_FRONT, GL_DIFFUSE, blue) ; break ; default: glMaterialfv(GL_FRONT, GL_DIFFUSE, white) ; } glutSolidSphere(2, slices, stacks); glPopMatrix(); } } void myKeyHandler(unsigned char key, int x, int y) { //While mouse over this window if (key == 'q') { exit(0); } } void myDisplay() { } void myReshape(int w, int h) { GLint border = 10 ; GLint size_of_curve ; GLint low_left_x, low_left_y ; if (w > h) { if (h < 2 * border) { border = 0 ; } /* endif */ size_of_curve = h - 2 * border ; low_left_x = static_cast<GLint>(0.5 * (w - size_of_curve)) ; low_left_y = border ; } else { if (w < 2 * border) { border = 0 ; } /* endif */ size_of_curve = w - 2 * border ; low_left_x = border ; low_left_y = static_cast<GLint>(0.5 * (h - size_of_curve)) ; } /* endif */ glViewport(low_left_x, low_left_y, size_of_curve, size_of_curve) ; } void myMenuHandler(int id) { if (id == 1) { slices = 4 ; stacks = 4 ; } else { if (id == 2) { slices = 30 ; stacks = 30 ; } else { if (id == 3) { exit(0); } else { } /* endif */ } /* endif */ } /* endif */ } void myIdle() { glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); myCreateObjects(++iteration); glFlush(); glutSwapBuffers(); glutPostRedisplay(); } void myInit() { GLdouble aspect = 1; glClearColor(0.0, 0.0, 0.2, 0.0); glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluPerspective(45, aspect, 50, -50); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); gluLookAt(0, 20, 80, 0, 0, 0, 0, 1, 0); glLightfv(GL_LIGHT0, GL_AMBIENT, light_ambient); glLightfv(GL_LIGHT0, GL_DIFFUSE, light_diffuse); glLightfv(GL_LIGHT0, GL_SPECULAR, light_specular); glEnable(GL_LIGHTING); glEnable(GL_LIGHT0); glLightfv(GL_LIGHT0, GL_POSITION, light_pos); glShadeModel(GL_SMOOTH); glEnable(GL_DEPTH_TEST); } int main(int argc, char** argv) { glutInit(&argc, argv); glutInitDisplayMode(GLUT_RGB | GLUT_DEPTH | GLUT_DOUBLE); glutInitWindowSize(640, 480); glutInitWindowPosition(100, 150); glutCreateWindow("Solar System"); glutKeyboardFunc(myKeyHandler); glutDisplayFunc(myDisplay); glutReshapeFunc(myReshape); glutCreateMenu(myMenuHandler); glutAddMenuEntry("Fast", 1); glutAddMenuEntry("Slow", 2); glutAddMenuEntry("Quit", 3); glutAttachMenu(GLUT_RIGHT_BUTTON); glutIdleFunc(myIdle); myInit(); glutMainLoop(); }
To compile:
g++ -ansi -pedantic -DOS2=1 -D__IBMC__=1 solar.cpp -I\oglgold\INCLUDE -lglut -lopengl -L/oglgold/lib -Zomf -Zlinker /PM:PM
There are OpenGL samples in the directory \OS2TK45\samples\opengl. Most of them use the deprecated
libaux library, but there are two GLUT programs, atlantis and test7 in the
glutdemo directory. I can compile and run them by changing the OpenGL #include
as shown above,
although test7 does not run correctly - I haven't found out why yet.
I had a hard time getting started with OpenGL since I wanted to do it with GCC. Perhaps this article will help other aspiring programmers. It shows what you need to do to make simple code examples compile and run with the Innotek GCC compiler.
References:
|
Feature Index
editor@os2voice.org
< Previous Page | Newsletter Index | Next Page >
VOICE Home Page: http://www.os2voice.org