home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
OS/2 Shareware BBS: 36 Tips
/
36-Tips.zip
/
mjk_tips.zip
/
mjk_tips.INF
(
.txt
)
Wrap
OS/2 Help File
|
1997-05-30
|
588KB
|
15,612 lines
ΓòÉΓòÉΓòÉ 1. Mark Kilgard's OpenGL tips ΓòÉΓòÉΓòÉ
Introduction
As a reader of OpenGL-GameDev mailing list I found myself impressed by the
usefulness of Mark Kilgard`s OpenGL-related tips, and at last I decided to
extract them into a separate .INF book so the OpenGL-ish OS/2 community can
have them handy. So, here is it, with kind Mark's permission.
Andrew Zabolotny
ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ
Contents
ΓòÉΓòÉΓòÉ 1.1. opengl-gamedev-list.txt ΓòÉΓòÉΓòÉ
Newsgroups: comp.graphics.api.opengl,rec.games.programmer
From: tsikes@netcom.com (Terry Sikes)
Subject: OpenGL Game Development Mailing List
Organization: Netcom
Date: Fri, 11 Apr 97 10:04:12 1997
If you're interested in OpenGL Game Development, check out the
OpenGL Game Development List!
To subscribe, enter:
sub OPENGL-GAMEDEV-L My Name
in the MESSAGE BODY (NOT Subject), and mail the message to:
listserv@fatcity.com
Here's what the list is about:
The OpenGL Game Development List Charter
========================================
(This is a draft charter. Any comments or suggestions are welcome!)
Welcome to the OpenGL Game Development List!
This list is being provided as a service to the 3D game development
community to help promote OpenGL as a viable and exciting way to
program 3D entertainment titles. Discussion of game programming
techniques and issues using OpenGL is the primary goal of this list!
Since so much of the installed base consists of Intel PCs running
Win32 platforms, the emphasis will probably be on that environment and
C/C++. However, there are many other interesting platforms out there,
and any discussion relating to OpenGL programming on those platforms
is welcome! For instance, OpenGL programming in Java may well become
a hot topic soon. Another thing to keep an eye on is OpenGL support
in Apple's forthcoming Rhapsody OS.
While the emphasis of this list is on game programming, general OpenGL
programming information and examples are welcome as well. This is
intended as a resource for all levels of OpenGL programmers, from
beginner to expert. Other topics that are appropriate to the list
include OpenGL device and driver quality, OpenGL benchmarking, and
other real-world issues involved in doing OpenGL development. General
topics relating to programming 3D games are also welcome.
There are a few things that aren't desired on the list. The ongoing
religious war between OpenGL and Direct3D is best left somewhere else
(rec.games.programmer is a likely candidate ;-). Actively promoting
other APIs besides OpenGL on this list is discouraged. General
programming questions (i.e. "which is better a pointer or an array?")
are also best taken elsewhere. Some of these topics will inevitably
creep onto the list, but let's try to keep the discussion civil and
technical.
A Web site relating to this list will become available soon...stay
tuned! Among other things, it will contain a large list of OpenGL,
3D, hardware and game development links. We're also working on
providing archive space for source examples, and would like to build
up a library of freely available OpenGL source to benefit the
community served by this list. More information on that will follow.
--
Terry Sikes | Software Developer
tsikes@netcom.com | C++, Delphi, Java, Win32
finger for PGP pub key | Objective objects objectify objectivity.
My opinions - mine only! | http://members.aol.com/tsikes
ΓòÉΓòÉΓòÉ 2. Contents ΓòÉΓòÉΓòÉ
Contents
Fast OpenGL-based "in place" scale & bias technique
Rendering Fast reflections with OpenGL
Rendering a Magic Halo with OpenGL
Shadows, Reflections, Lighting, Textures. Easy with OpenGL!
Virtualized OpenGL Light Sources for Efficient Multi-Light Source
An OpenGL-based API for texture mapped text
ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ
Title page | Next
ΓòÉΓòÉΓòÉ 2.1. Fast OpenGL-based "in place" scale & bias technique ΓòÉΓòÉΓòÉ
Path: fido.asd.sgi.com!fangio.asd.sgi.com!mjk
From: mjk@fangio.asd.sgi.com (Mark Kilgard)
Newsgroups: comp.graphics.api.opengl,rec.games.programmer
Subject: Fast OpenGL-based "in place" scale & bias technique
Date: Wed, 16 Apr 97 04:29:59 1997
Organization: Silicon Graphics, Inc.
Lines: 561
Message-ID: <5j2d7n$200@fido.asd.sgi.com>
NNTP-Posting-Host: fangio.asd.sgi.com
Xref: fido.asd.sgi.com comp.graphics.api.opengl:14758 rec.games.programmer:137192
A common computer graphics and image processing operation is to scale and/or
bias components in an image. A scale & bias operation lets an application
quickly adjust the contrast and/or bightness of an image.
OpenGL's pixel path has scale & bias parameters that permit an application to
scale & bias drawn, copied, or read back pixels rectangles as well as textures
during download. See glPixelTransfer.
It is often useful to do an "in place" scale & bias of an image already
rendered in the framebuffer. This can be useful to perform a scale & bias
*after* texture filtering (OpenGL's pixel path scale & bias is before texture
filtering). Post-texture filtering scale & bias is often needed by volume
rendering and image processing applications. A post-texture filtering scale &
bias can also be used by mainstream 3D applications to easily change the
contrast & brightness of textured geometry without having to re-download (and
re-filter) the texture. For example, a texture mapped spaceship might brighten
briefly when it absorbs power from a fuel cell.
A straightforward means to implement an "in place" scale & bias is with an "in
place" glCopyPixels to scale & bias the designated pixels. This ends up being
rather expensive however since many low-end OpenGL implementations do not fully
optimize this path and it involves streaming pixels out of the framebuffer to
then be immediately written back into the framebuffer. This degree of data
movement is expensive.
An alternative approach is to use OpenGL's blending capabilities to perform the
"in place" scale & bias as blended rendering. Many low-end hardware
accelerators fully implement OpenGL's blending modes in hardware.
Here's a simple example. Say you want to scale & bias a rectangular region of
the frame buffer. The desired scale factor is 0.7 and the desired bias factor
is 0.1. This can be done like this:
glBlendFunc(GL_ONE, GL_SRC_ALPHA);
glColor4f(0.1, 0.1, 0.1, 0.7);
glRect(x, y, x + width, y + height);
This ends up computing:
REDnew = 0.1 * 1 + 0.7 * REDprevious
GREENnew = 0.1 * 1 + 0.7 * GREENprevious
BLUEnew = 0.1 * 1 + 0.7 * BLUEprevious
This turns out to perform exactly the intended "in place" scale & bias
operation. The expense is no more than rendering a blended rectangle,
substantailly cheaper than a glCopyPixels. On an O2, this blending approach can
be 4 to 25 times faster depending on how many pixels are affected and the
particular scale & bias parameters.
Notice that you can actually scale & bias an arbitrary region in the frame
buffer, not simply a rectangular region with this technique by drawing
triangles instead of a single rectangle. OpenGL stencil can make sure you don't
scale & bias a particular pixel multiple times.
This blending approach becomes more complicated when the scale factor exceeds
1.0, but this can be handled with log2(n) extra passes where n is the integer
portion of the scale factor. Another problem is how to handle a negative bias.
An EXT OpenGL extension called the "blend subtract" extension makes it possible
to efficiently handle the negative bias case. Machines like SGI's O2
workstation implement the "blend subtract" extension in hardware making a
negative bias just as fast as a positive bias.
Below is a complete working GLUT-based OpenGL program that uses a fully
developed approach to perform a fast "in place" scale & bias operation. The
example uses texture mapping so that you can appreciate the advantage of
post-filtered scale & bias.
On a machine such as O2 and even a substantially faster machine such as an
InfiniteReality, this blending technique provides a completely hardware
accelerated means to scale & bias an image in place and is substantially faster
than using glCopyPixels.
I hope this technique is useful to you. If nothing else, I hope it shows the
power of OpenGL as a vocabulary for expressing graphics operations in a fast
hardware acceleratable manner.
- Mark
ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ
Source code | Title page | Contents | Next
ΓòÉΓòÉΓòÉ 2.1.1. InPlaceScaleAndBias.c ΓòÉΓòÉΓòÉ
/* Copyright (c) Mark J. Kilgard, 1997. */
/* This program is freely distributable without licensing fees and is
provided without guarantee or warrantee expressed or implied. This
program is -not- in the public domain. */
/* X compile line: cc -o scalebias scalebias.c -ltiff -lglut -lGLU -lGL -lXmu -lXext -lX11 -lm */
/* This program requires Sam Leffler's libtiff library and GLUT. */
/* scalebias demonstrates how an "in place" scale & bias of pixels in the
frame buffer can often be accomplished faster with OpenGL blending
extensions instead of using the naive glCopyPixels with glPixelTransfer
used to do the scale and bias.
The blending approach requires the "blend subtract" EXT extension in
order to perform negative biases. You could use this approach without
the "blend subtract" extension if you never need to do negative
biases.
NOTE: This blending approach does not allow negative scales. The
blending approach also fails if the partial scaling or biasing results
leave the 0.0 to 1.0 range (example, scale=5.47, bias=-1.2).
This technique can be valuable when you want to perform post-texture
filtering scaling and biasing (say for volume rendering or image processing),
but your hardware lacks texture lookup tables.
To give you an idea of the speed advantage of this "in place" blending
technique for doing scales and biases, on an SGI O2, this program
runs 8 to 40 times faster with a greater than 1.0 scaling factor when
using the blending mode instead of using glCopyPixels. The performance
improvement depends on the number of pixels scaled or biased. */
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <GL/glut.h>
#include <tiffio.h> /* Sam Leffler's libtiff library. */
TIFFRGBAImage img;
uint32 *raster, *texture;
size_t npixels;
int imgwidth, imgheight;
int tw, th;
int hasABGR = 0, hasBlendSubtract = 0;
int doubleBuffer = 1;
char *filename = NULL;
int ax = 10, ay = -10;
int luminance = 0;
int useBlend = 1;
int timing = 0;
int height;
GLfloat scale = 1.0, bias = 0.0, zoom = 1.0;
void
reshape(int w, int h)
{
glViewport(0, 0, w, h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluOrtho2D(0, w, 0, h);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
height = h;
}
void
drawImage(void)
{
glPushMatrix();
glTranslatef(ax, -ay + imgheight * zoom, 0);
glScalef(zoom * imgwidth, zoom * imgheight, 1);
glBegin(GL_QUADS);
glTexCoord2i(0, 0);
glVertex2i(0, 0);
glTexCoord2i(1, 0);
glVertex2i(1, 0);
glTexCoord2i(1, -1);
glVertex2i(1, -1);
glTexCoord2i(0, -1);
glVertex2i(0, -1);
glEnd();
glPopMatrix();
}
void
display(void)
{
int start, end;
/* Clear the color buffer. */
glClear(GL_COLOR_BUFFER_BIT);
glColor3f(1.0, 1.0, 1.0); /* Modulate texture with white. */
glEnable(GL_TEXTURE_2D);
drawImage();
if (timing) {
/* Avoid timing the clear and original draw image speed. */
glFinish();
start = glutGet(GLUT_ELAPSED_TIME);
}
/* Scale and bias via . */
if (bias != 0.0 || scale != 1.0) {
glDisable(GL_TEXTURE_2D);
/* Other things you might want to make sure are disabled. */
/* glDisable(GL_LIGHTING); */
/* glDisable(GL_DEPTH_TEST); */
if (useBlend && hasBlendSubtract) {
/* NOTE: The blending approach does not allow negative
scales. The blending approach also fails if the
partial scaling or biasing results leave the 0.0 to
1.0 range (example, scale=5.47, bias=-1.2). */
glEnable(GL_BLEND);
if (scale > 1.0) {
float remainingScale;
remainingScale = scale;
#ifdef GL_EXT_blend_subtract
glBlendEquationEXT(GL_FUNC_ADD_EXT);
#endif
glBlendFunc(GL_DST_COLOR, GL_ONE);
if (remainingScale > 2.0) {
/* Clever cascading approach. Example: if the
scaling factor was 9.5, do 3 "doubling" blends
(8x), then scale by the remaining 1.1875. */
glColor4f(1, 1, 1, 1);
while (remainingScale > 2.0) {
drawImage();
remainingScale /= 2.0;
}
}
glColor4f(remainingScale - 1,
remainingScale - 1, remainingScale - 1, 1);
drawImage();
glBlendFunc(GL_ONE, GL_ONE);
if (bias != 0) {
if (bias > 0) {
glColor4f(bias, bias, bias, 0.0);
} else {
#ifdef GL_EXT_blend_subtract
glBlendEquationEXT(GL_FUNC_REVERSE_SUBTRACT_EXT);
#endif
glColor4f(-bias, -bias, -bias, 0.0);
}
drawImage();
}
} else {
if (bias > 0) {
glBlendEquationEXT(GL_FUNC_ADD_EXT);
glColor4f(bias, bias, bias, scale);
} else {
#ifdef GL_EXT_blend_subtract
glBlendEquationEXT(GL_FUNC_REVERSE_SUBTRACT_EXT);
#endif
glColor4f(-bias, -bias, -bias, scale);
}
glBlendFunc(GL_ONE, GL_SRC_ALPHA);
drawImage();
}
glDisable(GL_BLEND);
} else {
glPixelTransferf(GL_RED_SCALE, scale);
glPixelTransferf(GL_GREEN_SCALE, scale);
glPixelTransferf(GL_BLUE_SCALE, scale);
glPixelTransferf(GL_RED_BIAS, bias);
glPixelTransferf(GL_GREEN_BIAS, bias);
glPixelTransferf(GL_BLUE_BIAS, bias);
glRasterPos2i(0, 0);
glBitmap(0, 0, 0, 0, ax, -ay, NULL);
glCopyPixels(ax, -ay,
ceilf(imgwidth * zoom), ceilf(imgheight * zoom), GL_COLOR);
glPixelTransferf(GL_RED_SCALE, 1.0);
glPixelTransferf(GL_GREEN_SCALE, 1.0);
glPixelTransferf(GL_BLUE_SCALE, 1.0);
glPixelTransferf(GL_RED_BIAS, 0.0);
glPixelTransferf(GL_GREEN_BIAS, 0.0);
glPixelTransferf(GL_BLUE_BIAS, 0.0);
}
}
if (timing) {
glFinish();
end = glutGet(GLUT_ELAPSED_TIME);
printf("time = %d milliseconds\n", end - start);
}
/* Swap the buffers if necessary. */
if (doubleBuffer) {
glutSwapBuffers();
} else {
glFlush();
}
}
static int moving = 0, ox, oy;
void
mouse(int button, int state, int x, int y)
{
if (button == GLUT_LEFT_BUTTON) {
if (state == GLUT_DOWN) {
/* Left mouse button press. Update last seen mouse
position. And set "moving" true since button is
pressed. */
ox = x;
oy = y;
moving = 1;
} else {
/* Left mouse button released; unset "moving" since
button no longer pressed. */
moving = 0;
}
}
}
void
motion(int x, int y)
{
/* If there is mouse motion with the left button held down. */
if (moving) {
/* Figure out offset from the last mouse position seen. */
ax += (x - ox);
ay += (y - oy);
/* Request a window redraw. */
glutPostRedisplay();
/* Update last seen mouse position. */
ox = x;
oy = y;
}
}
void
updateTitle(void)
{
char title[200];
sprintf(title, "Scale (%.2f) & Bias (%.1f) via %s", scale, bias,
useBlend ? "Blend" : "Copy");
glutSetWindowTitle(title);
}
void
option(int value)
{
switch (value) {
case 6:
bias += 0.1;
break;
case 7:
bias -= 0.1;
break;
case 8:
scale *= 1.1;
break;
case 9:
scale *= 0.9;
break;
case 10:
scale = 1.0;
bias = 0.0;
break;
case 11:
if (hasBlendSubtract) {
useBlend = 1 - useBlend;
}
break;
case 12:
zoom += 0.2;
break;
case 13:
zoom -= 0.2;
break;
case 14:
timing = 1 - timing;
break;
case 666:
exit(0);
break;
}
updateTitle();
glutPostRedisplay();
}
void
special(int key, int x, int y)
{
switch (key) {
case GLUT_KEY_UP:
option(6);
break;
case GLUT_KEY_DOWN:
option(7);
break;
case GLUT_KEY_LEFT:
option(9);
break;
case GLUT_KEY_RIGHT:
option(8);
break;
case GLUT_KEY_HOME:
option(10);
break;
case GLUT_KEY_INSERT:
option(11);
break;
case GLUT_KEY_PAGE_UP:
option(12);
break;
case GLUT_KEY_PAGE_DOWN:
option(13);
break;
}
}
int
main(int argc, char **argv)
{
TIFF *tif;
char emsg[1024];
int i;
glutInit(&argc, argv);
for (i = 1; i < argc; i++) {
if (!strcmp(argv[i], "-sb")) {
doubleBuffer = 0;
} else {
filename = argv[i];
}
}
if (filename == NULL) {
fprintf(stderr, "usage: scalebias [GLUT-options] [-sb] TIFF-file\n");
exit(1);
}
tif = TIFFOpen(filename, "r");
if (tif == NULL) {
fprintf(stderr, "Problem showing %s\n", filename);
exit(1);
}
if (TIFFRGBAImageBegin(&img, tif, 0, emsg)) {
npixels = img.width * img.height;
raster = (uint32 *) _TIFFmalloc(npixels * sizeof(uint32));
if (raster != NULL) {
if (TIFFRGBAImageGet(&img, raster, img.width, img.height) == 0) {
TIFFError(filename, emsg);
exit(1);
}
}
TIFFRGBAImageEnd(&img);
} else {
TIFFError(filename, emsg);
exit(1);
}
if (doubleBuffer) {
glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE);
} else {
glutInitDisplayMode(GLUT_RGB | GLUT_SINGLE);
}
imgwidth = img.width;
imgheight = img.height;
glutInitWindowSize(imgwidth * 1.5, imgheight * 1.5);
glutCreateWindow("");
glutReshapeFunc(reshape);
glutDisplayFunc(display);
glutMouseFunc(mouse);
glutMotionFunc(motion);
glutSpecialFunc(special);
#ifdef GL_EXT_abgr
if (glutExtensionSupported("GL_EXT_abgr")) {
hasABGR = 1;
}
#endif
#ifdef GL_EXT_blend_subtract
if (glutExtensionSupported("GL_EXT_blend_subtract")) {
hasBlendSubtract = 1;
}
#endif
if (!hasBlendSubtract) {
printf("\nThis program needs the blend subtract extension for\n");
printf("fast blending-base in-place scaling & biasing. Since\n");
printf("the extension is not available, using the slower\n");
printf("glCopyPixels approach.\n\n");
useBlend = 0;
}
/* If cannot directly display ABGR format, we need to reverse
the component ordering in each pixel. :-( */
if (!hasABGR) {
int i;
for (i = 0; i < npixels; i++) {
register unsigned char *cp = (unsigned char *) &raster[i];
int t;
t = cp[3];
cp[3] = cp[0];
cp[0] = t;
t = cp[2];
cp[2] = cp[1];
cp[1] = t;
}
}
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
/* Linear sampling within a mipmap level. */
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
GL_LINEAR_MIPMAP_NEAREST);
/* A TIFF file could be any size; OpenGL textures are allowed
to have a width and height that is a power of two (32, 64,
128, etc.). To maximize the use of available texture
memory, we scale the image to gluScaleImage to the next
larger power of 2 width or height dimension (not exceeding
512, don't want to use too much texture memory!). This
rescaling can result in a bit of image bluring because of
the resampling done by gluScaleImage. An alternative would
be to change the texture coordinates to only use a portion
texture area. */
tw = 1 << (int) ceilf(logf(img.width) / log(2.0));
th = 1 << (int) ceilf(logf(img.height) / log(2.0));
if (tw > 512)
tw = 512;
if (th > 512)
th = 512;
texture = (uint32 *) malloc(sizeof(GLubyte) * 4 * tw * th);
gluScaleImage(hasABGR ? GL_ABGR_EXT : GL_RGBA,
img.width, img.height, GL_UNSIGNED_BYTE, raster,
tw, th, GL_UNSIGNED_BYTE, texture);
/* Build mipmaps for the texture image. Since we are not
scaling the image (we easily could by calling glScalef),
creating mipmaps is not really useful, but it is done just
to show how easily creating mipmaps is. */
gluBuild2DMipmaps(GL_TEXTURE_2D, 4, tw, th,
hasABGR ? GL_ABGR_EXT : GL_RGBA, GL_UNSIGNED_BYTE,
texture);
glutCreateMenu(option);
glutAddMenuEntry("Increase bias (Up)", 6);
glutAddMenuEntry("Decrease bias (Down)", 7);
glutAddMenuEntry("Increase scale (Right)", 8);
glutAddMenuEntry("Decrease scale (Left)", 9);
glutAddMenuEntry("Reset scale & bias (Home)", 10);
if (hasBlendSubtract) {
glutAddMenuEntry("Toggle blend/copy (Insert)", 11);
}
glutAddMenuEntry("Zoom up (PageUp)", 12);
glutAddMenuEntry("Zoom down (PageDown)", 13);
glutAddMenuEntry("Toggle timing", 14);
glutAddMenuEntry("Quit", 666);
glutAttachMenu(GLUT_RIGHT_BUTTON);
/* Use a gray background so TIFF images with black
backgrounds will show against textiff's background. */
glClearColor(0.2, 0.2, 0.2, 1.0);
updateTitle();
glutMainLoop();
return 0; /* ANSI C requires main to return int. */
}
ΓòÉΓòÉΓòÉ 2.2. Rendering Fast reflections with OpenGL ΓòÉΓòÉΓòÉ
From: mjk@fangio.asd.sgi.com (Mark Kilgard)
Path: fangio.asd.sgi.com!mjk
Newsgroups: comp.graphics.api.opengl,rec.games.programmer,alt.3d
Organization: Silicon Graphics, Inc.
Subject: Rendering Fast reflections with OpenGL
3D programmers,
The real world has reflections. It would be nice if interactive 3D graphics
programs could capture the extra realism added by reflections. It turns out
this is fairly easy to do.
For example, in a 3D "fighting" game it would be cool to have two ninjas
fighting on a reflective floor so that each fighter's reflection could be seen
in the floor. Adding reflections can help the viewer better understand the
position of reflected objects (for example, the height of a ninja's jump is
easier to appreciate when there is a reflection).
OpenGL has all the features needed to render fast high-quality reflections on
planar surfaces. Artifact-free planar reflections require 3D transformations,
blending, and stenciling. (While Direct3D Immediate mode supports 3D
transformations and blending, Direct3D lacks OpenGL's stenciling functionality
that also you to accomplish good clean reflections.)
At the end of this posting is a complete OpenGL program demonstrating how to
accomplish fast artifact-free reflections. This technique can be readily
adapted to other OpenGL-based 3D games and applications. First, I'll briefly
describe the technique.
The first thing to appreciate is that a reflection on a planar surface is
nothing more than correctly projecting (er, reflecting) the object through the
plane of the reflecting surface. That sounds hard, but it is surprisingly easy.
Say you had an object positioned just above the Y=0 plane. The object is drawn
by a routine drawNinja. In OpenGL, to draw the object *and* its reflection, you
could just do the following:
glPushMatrix();
glScalef(1, -1, 1); /* "reflect" across Y=0 plane. */
drawNinja();
glPopMatrix();
drawNinja();
Wow, that was simple. But typically, the object is being reflected in some
surface that is not fully reflective like a marble floor.
Say we had a routine drawFloor that could draw the floor as a big rectangle in
the Y=0 plane. We could blend the floor with the reflection like this:
glPushMatrix();
glScalef(1.0, -1.0, 1.0);
drawNinja();
glPopMatrix();
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glColor4f(0.7, 0.0, 0.0, 0.40); /* 40% dark red floor color */
drawFloor();
glDisable(GL_BLEND);
drawNinja();
All we did was draw the floor after the reflected ninja and enable blending.
The floor is specified to be 40% the color of the floor and 60% the color of
the reflection. Pretty cool. Reflections are easy with OpenGL.
Here's an image showing the complete example program below with what we've
managed so far. Check out:
Ok, so it's a dinosaur and not a ninja. Still, the dinosausr has a very nice
reflection in the floor. But now check out this picture (from a slightly lower
viewing angle):
Gulp. You can actually *see* what we did. You can see how the dinosaur has
really just been drawn twice, once flipped around through the Y=0 plane! This
is like a magician giving away the trick. The reflection should only be
reflected where there is floor. Otherwise, we've introduced an unfortunate
visual artifact.
How can we fix this problem? We could hack around the solution by clearing back
to black the area under the floor (not a good general solution) or just limit
the possible views so that the viewer never gets to see "beyond the floor"
(again not very general). Well, if we were using Direct3D immediate mode, we'd
have to resort to such hacks. Fortunately, OpenGL is more powerful than
Direct3D.
With OpenGL stenciling, you can "pre-draw" the floor into the stencil buffer
without updating the color or depth buffers. Then when you go to draw the
reflection, you just only allow the reflection to update pixels marked as
belonging to the floor's stencil value. The floor can then be any complex (but
coplanar) polygon and the reflection only shows up in the floor. Here's the
OpenGL for this:
/* Don't update color or depth. */
glDisable(GL_DEPTH_TEST);
glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
/* Draw 1 into the stencil buffer. */
glEnable(GL_STENCIL_TEST);
glStencilOp(GL_REPLACE, GL_REPLACE, GL_REPLACE);
glStencilFunc(GL_ALWAYS, 1, 0xffffffff);
/* Now drawing the floor just tags the floor pixels
as stencil value 1. */
drawFloor();
/* Re-enable update of color and depth. */
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
glEnable(GL_DEPTH_TEST);
/* Now, only render where stencil is set to 1. */
glStencilFunc(GL_EQUAL, 1, 0xffffffff); /* draw if stencil ==1 */
glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
/* Draw reflected ninja, but only where floor is. */
glPushMatrix();
glScalef(1.0, -1.0, 1.0);
drawNinja();
glPopMatrix();
glDisable(GL_STENCIL_TEST);
[ ... continue on as above drawing the blended floor, then the
actual ninja ... ]
While this seems like a lot more OpenGL commands, these extra commands are
actually just quickly reconfiguring OpenGL state. They aren't doing anything
that expensive.
So how does our example program look with this stencil technique? Take a look:
Notice that the reflection is only where the floor surface is now. We've use
OpenGL to cleanly remove an otherwise quite unsatisfactory visual artifact. And
we've done it in a way that is completely hardware acceleratable.
In an API like Direct3D Immediate Mode, there's not even an option to support
stencil buffering. Without stenciling, fast planar reflections are
substantially harder to do cleanly. Also, since stencil buffering is easy to
support in fast hardware, good OpenGL hardware can do what is described above
with stenciling very fast.
Now it's your turn. Get the OpenGL Utility Toolkit (GLUT) and compile the code
below and try out reflections. You can use popup menu to toggle the use of
stencil. You can also disable the light sources in the scene; notice the
lighting works as you would expect even in the reflection.
For information about getting GLUT for free see:
http://reality.sgi.com/mjk_asd/glut3/glut3.html
I hope this helps; happy reflecting.
(BTW, OpenGL Quake fans should recognize that John Carmack uses exactly the
technique described here to implement the cool reflections enablable in OpenGL
Quake.)
- Mark
ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ
Source code | Title page | Contents | Next
ΓòÉΓòÉΓòÉ 2.2.1. Reflect.c ΓòÉΓòÉΓòÉ
/* Copyright (c) Mark J. Kilgard, 1994, 1997. */
/* This program is freely distributable without licensing fees
and is provided without guarantee or warrantee expressed or
implied. This program is -not- in the public domain. */
/* Very simple example of how to achieve reflections on a flat
surface using OpenGL blending. The example has a mode using
OpenGL stenciling to avoid drawing the reflection not on the top of the
floor. Initially, stenciling is not used so if you look (by holding
down the left mouse button and moving) at the dinosaur from "below"
the floor, you'll see a bogus dinosaur and appreciate how the basic
technique works. Enable stenciling with the popup menu and the
bogus dinosaur goes away! Also, notice that OpenGL lighting works
correctly with reflections. */
/* Check out the comments in the "redraw" routine to see how the
reflection blending and surface stenciling is done. */
/* This program is derived from glutdino.c */
/* Compile: cc -o reflectdino reflectdino.c -lglut -lGL -lGLU -lXmu -lXext -lX11 -lm */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h> /* for cos(), sin(), and sqrt() */
#include <GL/glut.h>
typedef enum {
RESERVED, BODY_SIDE, BODY_EDGE, BODY_WHOLE, ARM_SIDE, ARM_EDGE, ARM_WHOLE,
LEG_SIDE, LEG_EDGE, LEG_WHOLE, EYE_SIDE, EYE_EDGE, EYE_WHOLE
} displayLists;
GLfloat angle = -150; /* in degrees */
GLfloat angle2 = 30; /* in degrees */
GLboolean doubleBuffer = GL_TRUE, iconic = GL_FALSE, keepAspect = GL_FALSE;
int moving, startx, starty;
int W = 300, H = 300;
int useStencil = 0; /* Initially, allow the artifacts. */
GLdouble bodyWidth = 2.0;
float jump = 0.0;
/* *INDENT-OFF* */
GLfloat body[][2] = { {0, 3}, {1, 1}, {5, 1}, {8, 4}, {10, 4}, {11, 5},
{11, 11.5}, {13, 12}, {13, 13}, {10, 13.5}, {13, 14}, {13, 15}, {11, 16},
{8, 16}, {7, 15}, {7, 13}, {8, 12}, {7, 11}, {6, 6}, {4, 3}, {3, 2},
{1, 2} };
GLfloat arm[][2] = { {8, 10}, {9, 9}, {10, 9}, {13, 8}, {14, 9}, {16, 9},
{15, 9.5}, {16, 10}, {15, 10}, {15.5, 11}, {14.5, 10}, {14, 11}, {14, 10},
{13, 9}, {11, 11}, {9, 11} };
GLfloat leg[][2] = { {8, 6}, {8, 4}, {9, 3}, {9, 2}, {8, 1}, {8, 0.5}, {9, 0},
{12, 0}, {10, 1}, {10, 2}, {12, 4}, {11, 6}, {10, 7}, {9, 7} };
GLfloat eye[][2] = { {8.75, 15}, {9, 14.7}, {9.6, 14.7}, {10.1, 15},
{9.6, 15.25}, {9, 15.25} };
GLfloat lightZeroPosition[] = {10.0, 4.0, 10.0, 1.0};
GLfloat lightZeroColor[] = {0.8, 1.0, 0.8, 1.0}; /* green-tinted */
GLfloat lightOnePosition[] = {-1.0, -2.0, 1.0, 0.0};
GLfloat lightOneColor[] = {0.6, 0.3, 0.2, 1.0}; /* red-tinted */
GLfloat skinColor[] = {0.1, 1.0, 0.1, 1.0}, eyeColor[] = {1.0, 0.2, 0.2, 1.0};
/* *INDENT-ON* */
void
extrudeSolidFromPolygon(GLfloat data[][2], unsigned int dataSize,
GLdouble thickness, GLuint side, GLuint edge, GLuint whole)
{
static GLUtriangulatorObj *tobj = NULL;
GLdouble vertex[3], dx, dy, len;
int i;
int count = dataSize / (2 * sizeof(GLfloat));
if (tobj == NULL) {
tobj = gluNewTess(); /* create and initialize a GLU
polygon * * tesselation object */
gluTessCallback(tobj, GLU_BEGIN, glBegin);
gluTessCallback(tobj, GLU_VERTEX, glVertex2fv); /* semi-tricky */
gluTessCallback(tobj, GLU_END, glEnd);
}
glNewList(side, GL_COMPILE);
glShadeModel(GL_SMOOTH); /* smooth minimizes seeing
tessellation */
gluBeginPolygon(tobj);
for (i = 0; i < count; i++) {
vertex[0] = data[i][0];
vertex[1] = data[i][1];
vertex[2] = 0;
gluTessVertex(tobj, vertex, data[i]);
}
gluEndPolygon(tobj);
glEndList();
glNewList(edge, GL_COMPILE);
glShadeModel(GL_FLAT); /* flat shade keeps angular hands
from being "smoothed" */
glBegin(GL_QUAD_STRIP);
for (i = 0; i <= count; i++) {
/* mod function handles closing the edge */
glVertex3f(data[i % count][0], data[i % count][1], 0.0);
glVertex3f(data[i % count][0], data[i % count][1], thickness);
/* Calculate a unit normal by dividing by Euclidean
distance. We * could be lazy and use
glEnable(GL_NORMALIZE) so we could pass in * arbitrary
normals for a very slight performance hit. */
dx = data[(i + 1) % count][1] - data[i % count][1];
dy = data[i % count][0] - data[(i + 1) % count][0];
len = sqrt(dx * dx + dy * dy);
glNormal3f(dx / len, dy / len, 0.0);
}
glEnd();
glEndList();
glNewList(whole, GL_COMPILE);
glFrontFace(GL_CW);
glCallList(edge);
glNormal3f(0.0, 0.0, -1.0); /* constant normal for side */
glCallList(side);
glPushMatrix();
glTranslatef(0.0, 0.0, thickness);
glFrontFace(GL_CCW);
glNormal3f(0.0, 0.0, 1.0); /* opposite normal for other side */
glCallList(side);
glPopMatrix();
glEndList();
}
void
makeDinosaur(void)
{
GLfloat bodyWidth = 3.0;
extrudeSolidFromPolygon(body, sizeof(body), bodyWidth,
BODY_SIDE, BODY_EDGE, BODY_WHOLE);
extrudeSolidFromPolygon(arm, sizeof(arm), bodyWidth / 4,
ARM_SIDE, ARM_EDGE, ARM_WHOLE);
extrudeSolidFromPolygon(leg, sizeof(leg), bodyWidth / 2,
LEG_SIDE, LEG_EDGE, LEG_WHOLE);
extrudeSolidFromPolygon(eye, sizeof(eye), bodyWidth + 0.2,
EYE_SIDE, EYE_EDGE, EYE_WHOLE);
}
void
drawDinosaur(void)
{
glPushMatrix();
glTranslatef(0.0, jump, 0.0);
glMaterialfv(GL_FRONT, GL_DIFFUSE, skinColor);
glCallList(BODY_WHOLE);
glPushMatrix();
glTranslatef(0.0, 0.0, bodyWidth);
glCallList(ARM_WHOLE);
glCallList(LEG_WHOLE);
glTranslatef(0.0, 0.0, -bodyWidth - bodyWidth / 4);
glCallList(ARM_WHOLE);
glTranslatef(0.0, 0.0, -bodyWidth / 4);
glCallList(LEG_WHOLE);
glTranslatef(0.0, 0.0, bodyWidth / 2 - 0.1);
glMaterialfv(GL_FRONT, GL_DIFFUSE, eyeColor);
glCallList(EYE_WHOLE);
glPopMatrix();
glPopMatrix();
}
void
drawFloor(void)
{
glDisable(GL_LIGHTING);
glBegin(GL_QUADS);
glVertex3f(-18.0, 0.0, 27.0);
glVertex3f(27.0, 0.0, 27.0);
glVertex3f(27.0, 0.0, -18.0);
glVertex3f(-18.0, 0.0, -18.0);
glEnd();
glEnable(GL_LIGHTING);
}
void
redraw(void)
{
if (useStencil) {
/* Clear; default stencil clears to zero. */
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
} else {
/* Not using stencil; just clear color and depth. */
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
}
glPushMatrix();
/* Perform scene rotations based on user mouse input. */
glRotatef(angle2, 1.0, 0.0, 0.0);
glRotatef(angle, 0.0, 1.0, 0.0);
/* Translate the dinosaur to be at (0,0,0). */
glTranslatef(-8, -8, -bodyWidth / 2);
if (useStencil) {
/* We can eliminate the visual "artifact" of seeing the "flipped"
dinosaur underneath the floor by using stencil. The idea is
draw the floor without color or depth update but so that
a stencil value of one is where the floor will be. Later when
rendering the dinosaur reflection, we will only update pixels
with a stencil value of 1 to make sure the reflection only
lives on the floor, not below the floor. */
/* Don't update color or depth. */
glDisable(GL_DEPTH_TEST);
glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
/* Draw 1 into the stencil buffer. */
glEnable(GL_STENCIL_TEST);
glStencilOp(GL_REPLACE, GL_REPLACE, GL_REPLACE);
glStencilFunc(GL_ALWAYS, 1, 0xffffffff);
/* Now render floor; floor pixels just get their stencil set to 1. */
drawFloor();
/* Re-enable update of color and depth. */
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
glEnable(GL_DEPTH_TEST);
/* Now, only render where stencil is set to 1. */
glStencilFunc(GL_EQUAL, 1, 0xffffffff); /* draw if ==1 */
glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
}
glPushMatrix();
/* The critical reflection step: Reflect dinosaur through the floor
(the Y=0 plane) to make a relection. */
glScalef(1.0, -1.0, 1.0);
/* XXX Ugh, unfortunately the back face culling reverses when we reflect
the dinosaur. Easy solution is just disable back face culling for
rendering the reflection. Also, the normals for lighting get screwed
up by the scale; enabled normalize to ensure normals are still
properly normalized despite the scaling. We could have fixed the
dinosaur rendering code, but this is more expedient. */
glDisable(GL_CULL_FACE);
glEnable(GL_NORMALIZE);
/* Draw the reflected dinosaur. */
drawDinosaur();
/* Disable noramlize again and re-enable back face culling. */
glDisable(GL_NORMALIZE);
glEnable(GL_CULL_FACE);
glPopMatrix();
if (useStencil) {
/* Don't want to be using stenciling for drawing the actual dinosaur
(not its reflection) and the floor. */
glDisable(GL_STENCIL_TEST);
}
/* Back face culling will get used to only draw either the top or the
bottom floor. This let's us get a floor with two distinct
appearances. The top floor surface is reflective and kind of red.
The bottom floor surface is not reflective and blue. */
/* Draw "top" of floor. Use blending to blend in reflection. */
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glColor4f(0.7, 0.0, 0.0, 0.3);
drawFloor();
glDisable(GL_BLEND);
/* Draw "bottom" of floor in blue. */
glFrontFace(GL_CW); /* Switch face orientation. */
glColor4f(0.1, 0.1, 0.7, 1.0);
drawFloor();
glFrontFace(GL_CCW);
/* Draw "actual" dinosaur, not its reflection. */
drawDinosaur();
glPopMatrix();
glutSwapBuffers();
}
/* ARGSUSED2 */
void
mouse(int button, int state, int x, int y)
{
if (button == GLUT_LEFT_BUTTON && state == GLUT_DOWN) {
moving = 1;
startx = x;
starty = y;
}
if (button == GLUT_LEFT_BUTTON && state == GLUT_UP) {
moving = 0;
}
}
/* ARGSUSED1 */
void
motion(int x, int y)
{
if (moving) {
angle = angle + (x - startx);
angle2 = angle2 + (y - starty);
startx = x;
starty = y;
glutPostRedisplay();
}
}
GLboolean lightZeroSwitch = GL_TRUE, lightOneSwitch = GL_TRUE;
void
controlLights(int value)
{
switch (value) {
case 1:
lightZeroSwitch = !lightZeroSwitch;
if (lightZeroSwitch) {
glEnable(GL_LIGHT0);
} else {
glDisable(GL_LIGHT0);
}
break;
case 2:
lightOneSwitch = !lightOneSwitch;
if (lightOneSwitch) {
glEnable(GL_LIGHT1);
} else {
glDisable(GL_LIGHT1);
}
break;
case 3:
useStencil = 1 - useStencil;
break;
}
glutPostRedisplay();
}
void
idle(void)
{
static float time;
time = glutGet(GLUT_ELAPSED_TIME) / 500.0;
jump = 3.0 * fabs(sin(time));
glutPostRedisplay();
}
void
visible(int vis)
{
if (vis == GLUT_VISIBLE)
glutIdleFunc(idle);
else
glutIdleFunc(NULL);
}
int
main(int argc, char **argv)
{
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH | GLUT_STENCIL);
glutCreateWindow("Leapin' Lizards");
glutDisplayFunc(redraw);
glutMouseFunc(mouse);
glutMotionFunc(motion);
glutVisibilityFunc(visible);
glutCreateMenu(controlLights);
glutAddMenuEntry("Toggle right light", 1);
glutAddMenuEntry("Toggle left light", 2);
glutAddMenuEntry("Toggle stenciling out reflection artifacts", 3);
glutAttachMenu(GLUT_RIGHT_BUTTON);
makeDinosaur();
glEnable(GL_CULL_FACE);
glEnable(GL_DEPTH_TEST);
glEnable(GL_LIGHTING);
glMatrixMode(GL_PROJECTION);
gluPerspective( /* field of view in degree */ 40.0,
/* aspect ratio */ 1.0,
/* Z near */ 1.0, /* Z far */ 80.0);
glMatrixMode(GL_MODELVIEW);
gluLookAt(0.0, 0.0, 40.0, /* eye is at (0,0,30) */
0.0, 0.0, 0.0, /* center is at (0,0,0) */
0.0, 1.0, 0.); /* up is in postivie Y direction */
glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, 1);
glLightfv(GL_LIGHT0, GL_POSITION, lightZeroPosition);
glLightfv(GL_LIGHT0, GL_DIFFUSE, lightZeroColor);
glLightf(GL_LIGHT0, GL_CONSTANT_ATTENUATION, 0.1);
glLightf(GL_LIGHT0, GL_LINEAR_ATTENUATION, 0.05);
glLightfv(GL_LIGHT1, GL_POSITION, lightOnePosition);
glLightfv(GL_LIGHT1, GL_DIFFUSE, lightOneColor);
glEnable(GL_LIGHT0);
glEnable(GL_LIGHT1);
glutMainLoop();
return 0; /* ANSI C requires main to return int. */
}
ΓòÉΓòÉΓòÉ 2.3. Rendering a Magic Halo with OpenGL ΓòÉΓòÉΓòÉ
Rendering a Magic Halo with OpenGL
A technique often used in cartoon animation is adding a subtle halo around a
character to indicate (depending on the color and nature of the halo) if the
character is happy, magicaly transformed, innocent, lovable, or even evil (in
the case of a shadowy halo). For example, Walt Disney's cartoon animation often
use halos to convey subtle storytelling cues to the child in all of us.
3D games can benefit from adding similar halo effects as part of their game
play. For example, a halo might surround a 3D character when the character
becomes shielded or otherwise invincible. A briefly pulsing halo could indicate
the character's health or other power has been recharged. Different halo colors
can indicate different kinds of changes.
OpenGL provides rendering capabilities that enable real-time halo effects
around 3D objects within your game scene. The approach is straightforward, and
you can combine the halo effect with other OpenGL rendering techniques such as
real-time shadows and reflections. At the end of this discussion, the complete
source code for the program pictured in the various snapshots is made
available.
Here's is an example of a very simple halo generated around a sphere:
Notice that the scene also includes reflections of both the sphere and the post
along with shadows as well. The golden halo surrounding the sphere nice blends
with post, floor, and background as expected. An animated "recharging" effect
is accomplished by quickly growing and reducing the halo size. The program
picture above does this when you hit the space bar.
ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ
Here is a short outline of the steps to generate the halo effect pictured
above:
1. Before clearing the screen, pick a unique stencil buffer bit and force
OpenGL to set the bit to one during a stencil buffer clear. For example,
if you chose bit 2 (i.e., 0x4), you could call:
glClearStencil(0x4);
If you plan to halo multiple objects, give them each a distinct bit.
Objects can share a stencil bit if you know the objects will not overlap
in the framebuffer or should be haloed together.
2. Now be sure to clear the stencil buffer in addition to any other color
and ancillary buffers. For example:
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT |
GL_STENCIL_BUFFER_BIT);
3. Render the scene normally. This may include reflections, texturing,
shadows, lighting, or other real-time OpenGL rendering effects. The one
additional step is to render any haloed objects with the object's
corresponding stencil bit set.
For example, when rendering the sphere, first call:
glEnable(GL_STENCIL_TEST);
glStencilFunc(GL_ALWAYS, 0x0, 0x4);
glStencilMask(0x4);
glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);
This tags the sphere with stencil bit 2 (i.e., 1<<2). Remember to disable
stencil testing if no longer needed when done rendering the sphere.
4. Once the scene is rendered, go back and add the halo. Configure OpenGL to
draw once and only once to stencil value not tagged with stencil the
haloed object's unique stencil bit. For example:
glDisable(GL_LIGHTING);
glEnable(GL_STENCIL_TEST);
glStencilFunc(GL_EQUAL, 0x4, 0x4);
glStencilMask(0x4);
glStencilOp(GL_KEEP, GL_KEEP, GL_INVERT);
Also disable texturing if used when rendering the object.
5. Now, decide if you want the halo blended with the scenery behind this
halo (this generally looks better), or if you want faster performance or
lack good blending hardware, you can settle for a solid, non-blended
halo.
First, consider how to render a blended halo:
glEnable(GL_BLEND);
glColor4f(0.8, 0.8, 0.0, 0.3); /* 30% sorta yellow. */
A non-blended halo is almost identical, except you don't enable blending
and you set a color without a semi-opaque alpha value. For example:
glDisable(GL_BLEND);
glColor3f(0.5, 0.5, 0.0); /* Half yellow. */
6. Now, translate the modelview matrix so that the halo will be draw exactly
on top of the object to be haloed. The halo works best if the object is
fairly convex; a sphere is ideal, but other objects work reasonably well.
The object should modeled so its centroid (center) is at the modeling
coordinate system origin. For example, a sphere should be centered around
(0,0,0). Then scale the object slightly larger and render the object. For
example:
haloScale = 1.1; /* 10% larger for halo. */
glPushMatrix();
glScalef(haloScale, haloScale, haloScale);
drawModel();
glPopMatrix();
The code fragment above does not show the modeling commands required to
first place the sphere in its originally rendered location in world
coordinates.
The key observation is that now we draw the object again, except scaled
slightly larger and we have setup stenciling to not render pixels
originally updated by the object and we update the stencil buffer during
rendering to not "double render" a pixel twice when blending the halo
(the GL_INVERT parameter to glStencilOp in Step 4 could be changed to
GL_KEEP for slightly more efficiency if a non-blended halo is rendered).
The result is a nice yellowish halo around the object. Depth buffering is
left enabled so the halo is properly rendered relative to other opaque
objects in the scene (it can be obscured by close objects and it
obscures, optionally with blending, further away objects).
7. If we had multiple halos in the scene, you should sort the objects by
depth and render the haloes in back to front order so that the blending
works ok.
Remember to restore any modes such as blending, lighting, stencil, or
texturing as necessary when done rendering the halos.
ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ
Here are a few more scenes from the demonstration program to show you various
haloed objects:
Notice that the dinosaur model is not very convex and the halo does not evenly
surround the object. You can improve the halo effect in these cases by haloing
the different pieces that make up the dinosaur with distinct scaling. For
example, halo the head, then each arm, then each leg, then the main body. The
example adds texture to the floor. Notice you still see through the halo to
see the textured floor surface as you would expect. Also notice that the post
is in front of the halo so it does not get blended with the halo (unlike the
previous image where the post was behind the halo).
The following scene uses a non-alpha blended halo which is slightly faster to
render:
Notice that the halo still looks like a halo, but you are not able to see the
post through the halo on the hands nor can you see the pattern on the floor.
The critical rendering features that this halo effect relies on is OpenGL's
stenciling capability. Most other low-level 3D APIs such as Microsoft's
proprietary Direct3D completely lack support for stenciling. It is instructive
to see what the halo effect would look like if we just did the blending but
didn't enable stencil testing while rendering the halo effect:
The left scene is rendered without any stenciling to avoid haloing the object
itself; the right scene is rendered according to the stencil-based algorithm
described above so that the haloed object itself is not covered by the halo.
The right image has the more pleasing and convincing halo.
ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ
The halo effects described here have obvious applications for 3D games. While
it is difficult to demonstrate with images on a static web page, "pulsing" a
halo effect around an object gives a convincing "transformation" or
"recharging" effect.
Object haloing can also be useful in applications other than games. For
example, sometimes a CAD or modeling program wants to highlight a particular
object in the scene without obscuring the object itself. A halo effect can be
perfect for this.
And as Walt Disney realized a halo is a powerful cue for the viewer to
understand that something is unique or special about the object being
rendered, a subtle halo around an 3D cartoon character animated in real-time
can add an extra level of expressiveness enabling creative storytellers to
overcome some of the jagged, sterile appearance of typical real-time computer
graphics scenes.
The complete demonstration program follows, or down load halomagic.c directly.
Mesa users are warned that Mesa 2.2 requires a Mesa 2.2 patch in able to
successfully run this program.
- Mark Kilgard (mjk@sgi.com)
ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ
Source code | Title page | Contents | Next
ΓòÉΓòÉΓòÉ 2.3.1. halomagic.c ΓòÉΓòÉΓòÉ
/* Copyright (c) Mark J. Kilgard, 1994, 1997. */
/* This program is freely distributable without licensing fees
and is provided without guarantee or warrantee expressed or
implied. This program is -not- in the public domain. */
/* dinoshade.c with an added "magic halo" effect when you hit the
space bar. You can use an overlaid or blended halo (blending is
slower). */
/* Example for PC game developers to show how to *combine* texturing,
reflections, and projected shadows all in real-time with OpenGL.
Robust reflections use stenciling. Robust projected shadows
use both stenciling and polygon offset. PC game programmers
should realize that neither stenciling nor polygon offset are
supported by Direct3D, so these real-time rendering algorithms
are only really viable with OpenGL.
The program has modes for disabling the stenciling and polygon
offset uses. It is worth running this example with these features
toggled off so you can see the sort of artifacts that result.
Notice that the floor texturing, reflections, and shadowing
all co-exist properly. */
/* When you run this program: Left mouse button controls the
view. Middle mouse button controls light position (left &
right rotates light around dino; up & down moves light
position up and down). Right mouse button pops up menu. */
/* Check out the comments in the "redraw" routine to see how the
reflection blending and surface stenciling is done. You can
also see in "redraw" how the projected shadows are rendered,
including the use of stenciling and polygon offset. */
/* This program is derived from glutdino.c */
/* Compile: cc -o halomagic halomagic.c -lglut -lGLU -lGL -lXmu -lXext -lX11 -lm */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h> /* for cos(), sin(), and sqrt() */
#include <GL/glut.h> /* OpenGL Utility Toolkit header */
/* Some <math.h> files do not define M_PI... */
#ifndef M_PI
#define M_PI 3.14159265
#endif
/* Variable controlling various rendering modes. */
static int stencilReflection = 1, stencilShadow = 1, offsetShadow = 1;
static int renderShadow = 0, renderDinosaur = 1, renderReflection = 0;
static int linearFiltering = 0, useMipmaps = 0, useTexture = 0;
static int reportSpeed = 0;
static int animation = 0;
static GLboolean lightSwitch = GL_TRUE;
static int directionalLight = 1;
static int forceExtension = 0;
static int haloMagic = 0, blendedHalo = 0;
static GLfloat haloScale = 1.0, haloTime = 0.0;
/* Time varying or user-controled variables. */
static float jump = 0.0;
static float lightAngle = 0.0, lightHeight = 20;
GLfloat angle = -150; /* in degrees */
GLfloat angle2 = 30; /* in degrees */
int moving, startx, starty;
int lightMoving = 0, lightStartX, lightStartY;
enum {
MISSING, EXTENSION, ONE_DOT_ONE
};
int polygonOffsetVersion;
static GLdouble bodyWidth = 3.0;
/* *INDENT-OFF* */
static GLfloat body[][2] = { {0, 3}, {1, 1}, {5, 1}, {8, 4}, {10, 4}, {11, 5},
{11, 11.5}, {13, 12}, {13, 13}, {10, 13.5}, {13, 14}, {13, 15}, {11, 16},
{8, 16}, {7, 15}, {7, 13}, {8, 12}, {7, 11}, {6, 6}, {4, 3}, {3, 2},
{1, 2} };
static GLfloat arm[][2] = { {8, 10}, {9, 9}, {10, 9}, {13, 8}, {14, 9}, {16, 9},
{15, 9.5}, {16, 10}, {15, 10}, {15.5, 11}, {14.5, 10}, {14, 11}, {14, 10},
{13, 9}, {11, 11}, {9, 11} };
static GLfloat leg[][2] = { {8, 6}, {8, 4}, {9, 3}, {9, 2}, {8, 1}, {8, 0.5}, {9, 0},
{12, 0}, {10, 1}, {10, 2}, {12, 4}, {11, 6}, {10, 7}, {9, 7} };
static GLfloat eye[][2] = { {8.75, 15}, {9, 14.7}, {9.6, 14.7}, {10.1, 15},
{9.6, 15.25}, {9, 15.25} };
static GLfloat lightPosition[4];
static GLfloat lightColor[] = {0.8, 1.0, 0.8, 1.0}; /* green-tinted */
static GLfloat skinColor[] = {0.1, 1.0, 0.1, 1.0}, eyeColor[] = {1.0, 0.2, 0.2, 1.0};
/* *INDENT-ON* */
/* Nice floor texture tiling pattern. */
static char *circles[] = {
"....xxxx........",
"..xxxxxxxx......",
".xxxxxxxxxx.....",
".xxx....xxx.....",
"xxx......xxx....",
"xxx......xxx....",
"xxx......xxx....",
"xxx......xxx....",
".xxx....xxx.....",
".xxxxxxxxxx.....",
"..xxxxxxxx......",
"....xxxx........",
"................",
"................",
"................",
"................",
};
static void
makeFloorTexture(void)
{
GLubyte floorTexture[16][16][3];
GLubyte *loc;
int s, t;
/* Setup RGB image for the texture. */
loc = (GLubyte*) floorTexture;
for (t = 0; t < 16; t++) {
for (s = 0; s < 16; s++) {
if (circles[t][s] == 'x') {
/* Nice blue. */
loc[0] = 0x1f;
loc[1] = 0x1f;
loc[2] = 0x8f;
} else {
/* Light gray. */
loc[0] = 0xca;
loc[1] = 0xca;
loc[2] = 0xca;
}
loc += 3;
}
}
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
if (useMipmaps) {
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
GL_LINEAR_MIPMAP_LINEAR);
gluBuild2DMipmaps(GL_TEXTURE_2D, 3, 16, 16,
GL_RGB, GL_UNSIGNED_BYTE, floorTexture);
} else {
if (linearFiltering) {
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
} else {
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
}
glTexImage2D(GL_TEXTURE_2D, 0, 3, 16, 16, 0,
GL_RGB, GL_UNSIGNED_BYTE, floorTexture);
}
}
enum {
X, Y, Z, W
};
enum {
A, B, C, D
};
/* Create a matrix that will project the desired shadow. */
void
shadowMatrix(GLfloat shadowMat[4][4],
GLfloat groundplane[4],
GLfloat lightpos[4])
{
GLfloat dot;
/* Find dot product between light position vector and ground plane normal. */
dot = groundplane[X] * lightpos[X] +
groundplane[Y] * lightpos[Y] +
groundplane[Z] * lightpos[Z] +
groundplane[W] * lightpos[W];
shadowMat[0][0] = dot - lightpos[X] * groundplane[X];
shadowMat[1][0] = 0.f - lightpos[X] * groundplane[Y];
shadowMat[2][0] = 0.f - lightpos[X] * groundplane[Z];
shadowMat[3][0] = 0.f - lightpos[X] * groundplane[W];
shadowMat[X][1] = 0.f - lightpos[Y] * groundplane[X];
shadowMat[1][1] = dot - lightpos[Y] * groundplane[Y];
shadowMat[2][1] = 0.f - lightpos[Y] * groundplane[Z];
shadowMat[3][1] = 0.f - lightpos[Y] * groundplane[W];
shadowMat[X][2] = 0.f - lightpos[Z] * groundplane[X];
shadowMat[1][2] = 0.f - lightpos[Z] * groundplane[Y];
shadowMat[2][2] = dot - lightpos[Z] * groundplane[Z];
shadowMat[3][2] = 0.f - lightpos[Z] * groundplane[W];
shadowMat[X][3] = 0.f - lightpos[W] * groundplane[X];
shadowMat[1][3] = 0.f - lightpos[W] * groundplane[Y];
shadowMat[2][3] = 0.f - lightpos[W] * groundplane[Z];
shadowMat[3][3] = dot - lightpos[W] * groundplane[W];
}
/* Find the plane equation given 3 points. */
void
findPlane(GLfloat plane[4],
GLfloat v0[3], GLfloat v1[3], GLfloat v2[3])
{
GLfloat vec0[3], vec1[3];
/* Need 2 vectors to find cross product. */
vec0[X] = v1[X] - v0[X];
vec0[Y] = v1[Y] - v0[Y];
vec0[Z] = v1[Z] - v0[Z];
vec1[X] = v2[X] - v0[X];
vec1[Y] = v2[Y] - v0[Y];
vec1[Z] = v2[Z] - v0[Z];
/* find cross product to get A, B, and C of plane equation */
plane[A] = vec0[Y] * vec1[Z] - vec0[Z] * vec1[Y];
plane[B] = -(vec0[X] * vec1[Z] - vec0[Z] * vec1[X]);
plane[C] = vec0[X] * vec1[Y] - vec0[Y] * vec1[X];
plane[D] = -(plane[A] * v0[X] + plane[B] * v0[Y] + plane[C] * v0[Z]);
}
void
extrudeSolidFromPolygon(GLfloat data[][2], unsigned int dataSize,
GLdouble thickness, GLuint side, GLuint edge, GLuint whole)
{
static GLUtriangulatorObj *tobj = NULL;
GLdouble vertex[3], dx, dy, len;
int i;
int count = dataSize / (2 * sizeof(GLfloat));
if (tobj == NULL) {
tobj = gluNewTess(); /* create and initialize a GLU
polygon * * tesselation object */
gluTessCallback(tobj, GLU_BEGIN, glBegin);
gluTessCallback(tobj, GLU_VERTEX, glVertex2fv); /* semi-tricky */
gluTessCallback(tobj, GLU_END, glEnd);
}
glNewList(side, GL_COMPILE);
glShadeModel(GL_SMOOTH); /* smooth minimizes seeing
tessellation */
gluBeginPolygon(tobj);
for (i = 0; i < count; i++) {
vertex[0] = data[i][0];
vertex[1] = data[i][1];
vertex[2] = 0;
gluTessVertex(tobj, vertex, data[i]);
}
gluEndPolygon(tobj);
glEndList();
glNewList(edge, GL_COMPILE);
glShadeModel(GL_FLAT); /* flat shade keeps angular hands
from being "smoothed" */
glBegin(GL_QUAD_STRIP);
for (i = 0; i <= count; i++) {
/* mod function handles closing the edge */
glVertex3f(data[i % count][0], data[i % count][1], 0.0);
glVertex3f(data[i % count][0], data[i % count][1], thickness);
/* Calculate a unit normal by dividing by Euclidean
distance. We * could be lazy and use
glEnable(GL_NORMALIZE) so we could pass in * arbitrary
normals for a very slight performance hit. */
dx = data[(i + 1) % count][1] - data[i % count][1];
dy = data[i % count][0] - data[(i + 1) % count][0];
len = sqrt(dx * dx + dy * dy);
glNormal3f(dx / len, dy / len, 0.0);
}
glEnd();
glEndList();
glNewList(whole, GL_COMPILE);
glFrontFace(GL_CW);
glCallList(edge);
glNormal3f(0.0, 0.0, -1.0); /* constant normal for side */
glCallList(side);
glPushMatrix();
glTranslatef(0.0, 0.0, thickness);
glFrontFace(GL_CCW);
glNormal3f(0.0, 0.0, 1.0); /* opposite normal for other side */
glCallList(side);
glPopMatrix();
glEndList();
}
/* Enumerants for refering to display lists. */
typedef enum {
RESERVED, BODY_SIDE, BODY_EDGE, BODY_WHOLE, ARM_SIDE, ARM_EDGE, ARM_WHOLE,
LEG_SIDE, LEG_EDGE, LEG_WHOLE, EYE_SIDE, EYE_EDGE, EYE_WHOLE
} displayLists;
static void
makeDinosaur(void)
{
extrudeSolidFromPolygon(body, sizeof(body), bodyWidth,
BODY_SIDE, BODY_EDGE, BODY_WHOLE);
extrudeSolidFromPolygon(arm, sizeof(arm), bodyWidth / 4,
ARM_SIDE, ARM_EDGE, ARM_WHOLE);
extrudeSolidFromPolygon(leg, sizeof(leg), bodyWidth / 2,
LEG_SIDE, LEG_EDGE, LEG_WHOLE);
extrudeSolidFromPolygon(eye, sizeof(eye), bodyWidth + 0.2,
EYE_SIDE, EYE_EDGE, EYE_WHOLE);
}
static void
drawDinosaur(void)
{
glPushMatrix();
/* Translate the dinosaur to be at (0,8,0). */
glTranslatef(-8, -8, -bodyWidth / 2);
glTranslatef(0.0, jump, 0.0);
glMaterialfv(GL_FRONT, GL_DIFFUSE, skinColor);
glCallList(BODY_WHOLE);
glTranslatef(0.0, 0.0, bodyWidth);
glCallList(ARM_WHOLE);
glCallList(LEG_WHOLE);
glTranslatef(0.0, 0.0, -bodyWidth - bodyWidth / 4);
glCallList(ARM_WHOLE);
glTranslatef(0.0, 0.0, -bodyWidth / 4);
glCallList(LEG_WHOLE);
glTranslatef(0.0, 0.0, bodyWidth / 2 - 0.1);
glMaterialfv(GL_FRONT, GL_DIFFUSE, eyeColor);
glCallList(EYE_WHOLE);
glPopMatrix();
}
enum {
MOD_DINO, MOD_SPHERE, MOD_CUBE, MOD_ICO
};
static int currentModel = MOD_DINO;
static GLfloat blueMaterial[] = {0.0, 0.2, 1.0, 1.0},
redMaterial[] = {0.6, 0.1, 0.0, 1.0},
purpleMaterial[] = {0.3, 0.0, 0.3, 1.0},
greenMaterial[] = {1.0, 0.2, 0.0, 1.0};
static void
drawModel(void)
{
switch(currentModel) {
case MOD_DINO:
drawDinosaur();
break;
case MOD_SPHERE:
glMaterialfv(GL_FRONT, GL_DIFFUSE, blueMaterial);
glutSolidSphere(6.0, 15, 15);
break;
case MOD_CUBE:
glMaterialfv(GL_FRONT, GL_DIFFUSE, redMaterial);
glutSolidCube(6.0);
break;
case MOD_ICO:
glMaterialfv(GL_FRONT, GL_DIFFUSE, purpleMaterial);
glPushMatrix();
glEnable(GL_NORMALIZE);
glScalef(7.0, 7.0, 7.0);
glutSolidIcosahedron();
glDisable(GL_NORMALIZE);
glPopMatrix();
break;
}
}
static void
drawBox(GLfloat xsize, GLfloat ysize, GLfloat zsize)
{
static GLfloat n[6][3] =
{
{-1.0, 0.0, 0.0},
{0.0, 1.0, 0.0},
{1.0, 0.0, 0.0},
{0.0, -1.0, 0.0},
{0.0, 0.0, 1.0},
{0.0, 0.0, -1.0}
};
static GLint faces[6][4] =
{
{0, 1, 2, 3},
{3, 2, 6, 7},
{7, 6, 5, 4},
{4, 5, 1, 0},
{5, 6, 2, 1},
{7, 4, 0, 3}
};
GLfloat v[8][3];
GLint i;
v[0][0] = v[1][0] = v[2][0] = v[3][0] = -xsize / 2;
v[4][0] = v[5][0] = v[6][0] = v[7][0] = xsize / 2;
v[0][1] = v[1][1] = v[4][1] = v[5][1] = -ysize / 2;
v[2][1] = v[3][1] = v[6][1] = v[7][1] = ysize / 2;
v[0][2] = v[3][2] = v[4][2] = v[7][2] = -zsize / 2;
v[1][2] = v[2][2] = v[5][2] = v[6][2] = zsize / 2;
for (i = 0; i < 6; i++) {
glBegin(GL_QUADS);
glNormal3fv(&n[i][0]);
glVertex3fv(&v[faces[i][0]][0]);
glVertex3fv(&v[faces[i][1]][0]);
glVertex3fv(&v[faces[i][2]][0]);
glVertex3fv(&v[faces[i][3]][0]);
glEnd();
}
}
static void
drawPillar(void)
{
glEnable(GL_NORMALIZE);
glMaterialfv(GL_FRONT, GL_DIFFUSE, greenMaterial);
glPushMatrix();
glTranslatef(8.0, 4.01, 8.0);
drawBox(2.0, 8.0, 2.0);
glutSolidCube(2.0);
glPopMatrix();
glDisable(GL_NORMALIZE);
}
static GLfloat floorVertices[4][3] = {
{ -20.0, 0.0, 20.0 },
{ 20.0, 0.0, 20.0 },
{ 20.0, 0.0, -20.0 },
{ -20.0, 0.0, -20.0 },
};
/* Draw a floor (possibly textured). */
static void
drawFloor(void)
{
glDisable(GL_LIGHTING);
if (useTexture) {
glEnable(GL_TEXTURE_2D);
}
glBegin(GL_QUADS);
glTexCoord2f(0.0, 0.0);
glVertex3fv(floorVertices[0]);
glTexCoord2f(0.0, 16.0);
glVertex3fv(floorVertices[1]);
glTexCoord2f(16.0, 16.0);
glVertex3fv(floorVertices[2]);
glTexCoord2f(16.0, 0.0);
glVertex3fv(floorVertices[3]);
glEnd();
if (useTexture) {
glDisable(GL_TEXTURE_2D);
}
glEnable(GL_LIGHTING);
}
static GLfloat floorPlane[4];
static GLfloat floorShadow[4][4];
static void
redraw(void)
{
int start, end;
if (reportSpeed) {
start = glutGet(GLUT_ELAPSED_TIME);
}
/* Clear; default stencil clears to zero. */
if ((stencilReflection && renderReflection) || (stencilShadow && renderShadow) || (haloScale > 1.0)) {
glStencilMask(0xffffffff);
glClearStencil(0x4);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
} else {
/* Avoid clearing stencil when not using it. */
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
}
/* Reposition the light source. */
lightPosition[0] = 15*cos(lightAngle);
lightPosition[1] = lightHeight;
lightPosition[2] = 15*sin(lightAngle);
if (directionalLight) {
lightPosition[3] = 0.0;
} else {
lightPosition[3] = 1.0;
}
shadowMatrix(floorShadow, floorPlane, lightPosition);
glPushMatrix();
/* Perform scene rotations based on user mouse input. */
glRotatef(angle2, 1.0, 0.0, 0.0);
glRotatef(angle, 0.0, 1.0, 0.0);
/* Tell GL new light source position. */
glLightfv(GL_LIGHT0, GL_POSITION, lightPosition);
if (renderReflection) {
if (stencilReflection) {
/* We can eliminate the visual "artifact" of seeing the "flipped"
model underneath the floor by using stencil. The idea is
draw the floor without color or depth update but so that
a stencil value of one is where the floor will be. Later when
rendering the model reflection, we will only update pixels
with a stencil value of 1 to make sure the reflection only
lives on the floor, not below the floor. */
/* Don't update color or depth. */
glDisable(GL_DEPTH_TEST);
glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
/* Draw 1 into the stencil buffer. */
glEnable(GL_STENCIL_TEST);
glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);
glStencilFunc(GL_ALWAYS, 1, 0x1);
glStencilMask(0x1);
/* Now render floor; floor pixels just get their stencil set to 1. */
drawFloor();
/* Re-enable update of color and depth. */
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
glEnable(GL_DEPTH_TEST);
/* Now, only render where stencil is set to 1. */
glStencilFunc(GL_EQUAL, 1, 0x1); /* draw if ==1 */
glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
}
glPushMatrix();
/* The critical reflection step: Reflect 3D model through the floor
(the Y=0 plane) to make a relection. */
glScalef(1.0, -1.0, 1.0);
/* Reflect the light position. */
glLightfv(GL_LIGHT0, GL_POSITION, lightPosition);
/* To avoid our normals getting reversed and hence botched lighting
on the reflection, turn on normalize. */
glEnable(GL_NORMALIZE);
glCullFace(GL_FRONT);
/* Draw the reflected model. */
glPushMatrix();
glTranslatef(0, 8.01, 0);
drawModel();
glPopMatrix();
drawPillar();
/* Disable noramlize again and re-enable back face culling. */
glDisable(GL_NORMALIZE);
glCullFace(GL_BACK);
glPopMatrix();
/* Switch back to the unreflected light position. */
glLightfv(GL_LIGHT0, GL_POSITION, lightPosition);
if (stencilReflection) {
glDisable(GL_STENCIL_TEST);
}
}
/* Back face culling will get used to only draw either the top or the
bottom floor. This let's us get a floor with two distinct
appearances. The top floor surface is reflective and kind of red.
The bottom floor surface is not reflective and blue. */
/* Draw "bottom" of floor in blue. */
glFrontFace(GL_CW); /* Switch face orientation. */
glColor4f(0.1, 0.1, 0.7, 1.0);
drawFloor();
glFrontFace(GL_CCW);
if (renderShadow && stencilShadow) {
/* Draw the floor with stencil value 2. This helps us only
draw the shadow once per floor pixel (and only on the
floor pixels). */
glEnable(GL_STENCIL_TEST);
glStencilFunc(GL_ALWAYS, 0x2, 0x2);
glStencilMask(0x2);
glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);
}
/* Draw "top" of floor. Use blending to blend in reflection. */
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glColor4f(1.0, 1.0, 1.0, 0.3);
drawFloor();
glDisable(GL_BLEND);
if (renderShadow && stencilShadow) {
glDisable(GL_STENCIL_TEST);
}
if (renderDinosaur) {
drawPillar();
if (haloScale > 1.0) {
/* If halo effect is enabled, draw the model with its stencil set to 6
(arbitary value); later, we'll make sure not to update pixels tagged
as 6. */
glEnable(GL_STENCIL_TEST);
glStencilFunc(GL_ALWAYS, 0x0, 0x4);
glStencilMask(0x4);
glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);
}
/* Draw "actual" dinosaur (or other model), not its reflection. */
glPushMatrix();
glTranslatef(0, 8.01, 0);
drawModel();
glPopMatrix();
}
/* Begin shadow render. */
if (renderShadow) {
/* Render the projected shadow. */
if (stencilShadow) {
/* Now, only render where stencil is set above 5 (ie, 6 where
the top floor is). Update stencil with 2 where the shadow
gets drawn so we don't redraw (and accidently reblend) the
shadow). */
glEnable(GL_STENCIL_TEST);
glStencilFunc(GL_NOTEQUAL, 0x0, 0x2);
glStencilMask(0x2);
glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);
}
/* To eliminate depth buffer artifacts, we use polygon offset
to raise the depth of the projected shadow slightly so
that it does not depth buffer alias with the floor. */
if (offsetShadow) {
switch (polygonOffsetVersion) {
case EXTENSION:
#ifdef GL_EXT_polygon_offset
glEnable(GL_POLYGON_OFFSET_EXT);
break;
#endif
#ifdef GL_VERSION_1_1
case ONE_DOT_ONE:
glEnable(GL_POLYGON_OFFSET_FILL);
break;
#endif
case MISSING:
/* Oh well. */
break;
}
}
/* Render 50% black shadow color on top of whatever the
floor appareance is. */
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glDisable(GL_LIGHTING); /* Force the 50% black. */
glColor4f(0.0, 0.0, 0.0, 0.5);
glPushMatrix();
/* Project the shadow. */
glMultMatrixf((GLfloat *) floorShadow);
glPushMatrix();
glTranslatef(0, 8.01, 0);
drawModel();
glPopMatrix();
drawPillar();
glPopMatrix();
glDisable(GL_BLEND);
glEnable(GL_LIGHTING);
if (offsetShadow) {
switch (polygonOffsetVersion) {
#ifdef GL_EXT_polygon_offset
case EXTENSION:
glDisable(GL_POLYGON_OFFSET_EXT);
break;
#endif
#ifdef GL_VERSION_1_1
case ONE_DOT_ONE:
glDisable(GL_POLYGON_OFFSET_FILL);
break;
#endif
case MISSING:
/* Oh well. */
break;
}
}
if (stencilShadow) {
glDisable(GL_STENCIL_TEST);
}
} /* End shadow render. */
/* Begin light source location render. */
glPushMatrix();
glDisable(GL_LIGHTING);
glColor3f(1.0, 1.0, 0.0);
if (directionalLight) {
/* Draw an arrowhead. */
glDisable(GL_CULL_FACE);
glTranslatef(lightPosition[0], lightPosition[1], lightPosition[2]);
glRotatef(lightAngle * -180.0 / M_PI, 0, 1, 0);
glRotatef(atan(lightHeight/12) * 180.0 / M_PI, 0, 0, 1);
glBegin(GL_TRIANGLE_FAN);
glVertex3f(0, 0, 0);
glVertex3f(2, 1, 1);
glVertex3f(2, -1, 1);
glVertex3f(2, -1, -1);
glVertex3f(2, 1, -1);
glVertex3f(2, 1, 1);
glEnd();
/* Draw a white line from light direction. */
glColor3f(1.0, 1.0, 1.0);
glBegin(GL_LINES);
glVertex3f(0.1, 0, 0);
glVertex3f(5, 0, 0);
glEnd();
glEnable(GL_CULL_FACE);
} else {
/* Draw a yellow ball at the light source. */
glTranslatef(lightPosition[0], lightPosition[1], lightPosition[2]);
glutSolidSphere(1.0, 5, 5);
}
glEnable(GL_LIGHTING);
glPopMatrix();
/* End light source location render. */
/* Add a halo effect around the 3D model. */
if (haloScale > 1.0) {
glDisable(GL_LIGHTING);
if (blendedHalo) {
/* If we are doing a nice blended halo, enable blending and
make sure we only blend a halo pixel once and that we do
not draw to pixels tagged as 6 (where the model is). */
glEnable(GL_BLEND);
glEnable(GL_STENCIL_TEST);
glColor4f(0.8, 0.8, 0.0, 0.3); /* 30% sorta yellow. */
glStencilFunc(GL_EQUAL, 0x4, 0x4);
glStencilMask(0x4);
glStencilOp(GL_KEEP, GL_KEEP, GL_INVERT);
} else {
/* Be cheap; no blending. Just draw yellow halo but not updating
pixels where the model is. We don't update stencil at all. */
glDisable(GL_BLEND);
glEnable(GL_STENCIL_TEST);
glColor3f(0.5, 0.5, 0.0); /* Half yellow. */
glStencilFunc(GL_EQUAL, 0x4, 0x4);
glStencilMask(0x4);
glStencilOp(GL_KEEP, GL_KEEP, GL_INVERT);
}
glPushMatrix();
glTranslatef(0, 8.01, 0);
glScalef(haloScale, haloScale, haloScale);
drawModel();
glPopMatrix();
if (blendedHalo) {
glDisable(GL_BLEND);
}
glDisable(GL_STENCIL_TEST);
glEnable(GL_LIGHTING);
}
/* End halo effect render. */
glPopMatrix();
if (reportSpeed) {
glFinish();
end = glutGet(GLUT_ELAPSED_TIME);
printf("Speed %.3g frames/sec (%d ms)\n", 1000.0/(end-start), end-start);
}
glutSwapBuffers();
}
/* ARGSUSED2 */
static void
mouse(int button, int state, int x, int y)
{
if (button == GLUT_LEFT_BUTTON) {
if (state == GLUT_DOWN) {
moving = 1;
startx = x;
starty = y;
}
if (state == GLUT_UP) {
moving = 0;
}
}
if (button == GLUT_MIDDLE_BUTTON) {
if (state == GLUT_DOWN) {
lightMoving = 1;
lightStartX = x;
lightStartY = y;
}
if (state == GLUT_UP) {
lightMoving = 0;
}
}
}
/* ARGSUSED1 */
static void
motion(int x, int y)
{
if (moving) {
angle = angle + (x - startx);
angle2 = angle2 + (y - starty);
startx = x;
starty = y;
glutPostRedisplay();
}
if (lightMoving) {
lightAngle += (x - lightStartX)/40.0;
lightHeight += (lightStartY - y)/20.0;
lightStartX = x;
lightStartY = y;
glutPostRedisplay();
}
}
static const float maxHalo[] = { 0.2, 0.35, 0.3, 0.5 };
/* Advance time varying state when idle callback registered. */
static void
idle(void)
{
static float time = 0.0;
if (animation) {
time = glutGet(GLUT_ELAPSED_TIME) / 500.0;
jump = 4.0 * fabs(sin(time)*0.8);
if (!lightMoving) {
lightAngle += 0.03;
}
}
if (haloMagic) {
haloTime += 0.1;
haloScale = 1.0 + maxHalo[currentModel] * sin(haloTime);
if (haloScale <= 1.0) {
haloMagic = 0;
if (!animation) {
glutIdleFunc(NULL);
}
}
}
glutPostRedisplay();
}
enum {
M_NONE, M_BLENDED_HALO, M_SHOW_HALO, M_SWITCH_MODEL, M_MOTION, M_LIGHT,
M_TEXTURE, M_SHADOWS, M_REFLECTION, M_DINOSAUR,
M_STENCIL_REFLECTION, M_STENCIL_SHADOW, M_OFFSET_SHADOW,
M_POSITIONAL, M_DIRECTIONAL, M_PERFORMANCE
};
static void
controlLights(int value)
{
switch (value) {
case M_NONE:
return;
case M_SWITCH_MODEL:
currentModel = (currentModel + 1) % 4;
break;
case M_SHOW_HALO:
haloScale = 1.0 + maxHalo[currentModel];
break;
case M_BLENDED_HALO:
blendedHalo = 1 - blendedHalo;
break;
case M_MOTION:
animation = 1 - animation;
if (animation || haloMagic) {
glutIdleFunc(idle);
} else {
glutIdleFunc(NULL);
}
break;
case M_LIGHT:
lightSwitch = !lightSwitch;
if (lightSwitch) {
glEnable(GL_LIGHT0);
} else {
glDisable(GL_LIGHT0);
}
break;
case M_TEXTURE:
useTexture = !useTexture;
break;
case M_SHADOWS:
renderShadow = 1 - renderShadow;
break;
case M_REFLECTION:
renderReflection = 1 - renderReflection;
break;
case M_DINOSAUR:
renderDinosaur = 1 - renderDinosaur;
break;
case M_STENCIL_REFLECTION:
stencilReflection = 1 - stencilReflection;
break;
case M_STENCIL_SHADOW:
stencilShadow = 1 - stencilShadow;
break;
case M_OFFSET_SHADOW:
offsetShadow = 1 - offsetShadow;
break;
case M_POSITIONAL:
directionalLight = 0;
break;
case M_DIRECTIONAL:
directionalLight = 1;
break;
case M_PERFORMANCE:
reportSpeed = 1 - reportSpeed;
break;
}
glutPostRedisplay();
}
/* When not visible, stop animating. Restart when visible again. */
static void
visible(int vis)
{
if (vis == GLUT_VISIBLE) {
if (animation || haloMagic)
glutIdleFunc(idle);
} else {
if (!animation && !haloMagic)
glutIdleFunc(NULL);
}
}
/* Press any key to redraw; good when motion stopped and
performance reporting on. */
/* ARGSUSED */
static void
key(unsigned char c, int x, int y)
{
if (c == 27) {
exit(0); /* IRIS GLism, Escape quits. */
}
if (c == ' ') {
haloMagic = 1;
haloTime = 0.0;
glutIdleFunc(idle);
}
glutPostRedisplay();
}
/* Press any key to redraw; good when motion stopped and
performance reporting on. */
/* ARGSUSED */
static void
special(int k, int x, int y)
{
glutPostRedisplay();
}
static int
supportsOneDotOne(void)
{
const char *version;
int major, minor;
version = (char *) glGetString(GL_VERSION);
if (sscanf(version, "%d.%d", &major, &minor) == 2)
return major >= 1 && minor >= 1;
return 0; /* OpenGL version string malformed! */
}
int
main(int argc, char **argv)
{
int i;
glutInit(&argc, argv);
for (i=1; i<argc; i++) {
if (!strcmp("-linear", argv[i])) {
linearFiltering = 1;
} else if (!strcmp("-mipmap", argv[i])) {
useMipmaps = 1;
} else if (!strcmp("-ext", argv[i])) {
forceExtension = 1;
}
}
glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH | GLUT_STENCIL | GLUT_MULTISAMPLE);
#if 1
/* In GLUT 4.0, you'll be able to do this an be sure to
get 2 bits of stencil if the machine has it for you. */
glutInitDisplayString("samples stencil>=3 rgb double depth");
#endif
glutCreateWindow("OpenGL Halo Magic (hit Space)");
if (glutGet(GLUT_WINDOW_STENCIL_SIZE) < 3) {
printf("halomagic: Sorry, I need at least 3 bits of stencil.\n");
exit(1);
}
/* Register GLUT callbacks. */
glutDisplayFunc(redraw);
glutMouseFunc(mouse);
glutMotionFunc(motion);
glutVisibilityFunc(visible);
glutKeyboardFunc(key);
glutSpecialFunc(special);
glutCreateMenu(controlLights);
glutAddMenuEntry("Toggle halo blending", M_BLENDED_HALO);
glutAddMenuEntry("Show halo", M_SHOW_HALO);
glutAddMenuEntry("Switch model", M_SWITCH_MODEL);
glutAddMenuEntry("Toggle motion", M_MOTION);
glutAddMenuEntry("-----------------------", M_NONE);
glutAddMenuEntry("Toggle light", M_LIGHT);
glutAddMenuEntry("Toggle texture", M_TEXTURE);
glutAddMenuEntry("Toggle shadows", M_SHADOWS);
glutAddMenuEntry("Toggle reflection", M_REFLECTION);
glutAddMenuEntry("Toggle object", M_DINOSAUR);
glutAddMenuEntry("-----------------------", M_NONE);
glutAddMenuEntry("Toggle reflection stenciling", M_STENCIL_REFLECTION);
glutAddMenuEntry("Toggle shadow stenciling", M_STENCIL_SHADOW);
glutAddMenuEntry("Toggle shadow offset", M_OFFSET_SHADOW);
glutAddMenuEntry("----------------------", M_NONE);
glutAddMenuEntry("Positional light", M_POSITIONAL);
glutAddMenuEntry("Directional light", M_DIRECTIONAL);
glutAddMenuEntry("-----------------------", M_NONE);
glutAddMenuEntry("Toggle performance", M_PERFORMANCE);
glutAttachMenu(GLUT_RIGHT_BUTTON);
makeDinosaur();
#ifdef GL_VERSION_1_1
if (supportsOneDotOne() && !forceExtension) {
polygonOffsetVersion = ONE_DOT_ONE;
glPolygonOffset(-2.0, -1.0);
} else
#endif
{
#ifdef GL_EXT_polygon_offset
/* check for the polygon offset extension */
if (glutExtensionSupported("GL_EXT_polygon_offset")) {
polygonOffsetVersion = EXTENSION;
glPolygonOffsetEXT(-0.1, -0.002);
} else
#endif
{
polygonOffsetVersion = MISSING;
printf("\ndinoshine: Missing polygon offset.\n");
printf(" Expect shadow depth aliasing artifacts.\n\n");
}
}
glEnable(GL_CULL_FACE);
glEnable(GL_DEPTH_TEST);
glLineWidth(3.0);
glMatrixMode(GL_PROJECTION);
gluPerspective( /* field of view in degree */ 40.0,
/* aspect ratio */ 1.0,
/* Z near */ 20.0, /* Z far */ 100.0);
glMatrixMode(GL_MODELVIEW);
gluLookAt(0.0, 8.0, 60.0, /* eye is at (0,0,30) */
0.0, 8.0, 0.0, /* center is at (0,0,0) */
0.0, 1.0, 0.); /* up is in postivie Y direction */
glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, 1);
glLightfv(GL_LIGHT0, GL_DIFFUSE, lightColor);
glLightf(GL_LIGHT0, GL_CONSTANT_ATTENUATION, 0.1);
glLightf(GL_LIGHT0, GL_LINEAR_ATTENUATION, 0.05);
glEnable(GL_LIGHT0);
glEnable(GL_LIGHTING);
makeFloorTexture();
/* Setup floor plane for projected shadow calculations. */
findPlane(floorPlane, floorVertices[1], floorVertices[2], floorVertices[3]);
glutMainLoop();
return 0; /* ANSI C requires main to return int. */
}
ΓòÉΓòÉΓòÉ 2.4. Shadows, Reflections, Lighting, Textures. Easy with OpenGL! ΓòÉΓòÉΓòÉ
Shadows, Reflections, Lighting, Textures. Easy with OpenGL!
Below are several screen snapshots from an OpenGL program demonstrating
shadows, reflections, lighting, and texturing. The point is to show that OpenGL
provides all the rendering functionality needed to combine texturing,
lighting, reflections, and shadows all in a single scene.
The complete source code for the program is provided so that you can study how
easy it is to generate extremely realistic real-time scenes with OpenGL.
A secondary purpose of these images is to point out limitations in Microsoft's
Direct3D API. Unfortunately, Direct3D represents a significant step backwards
for realistic, real-time rendering. Direct3D lacks both the stenciling and
polygon offset capabilities needed to render the scenes as shown below. On the
other hand, OpenGL 1.1 provides these features on all implementations. The
program below with all its combined techniques can run on any OpenGL 1.1
implementation.
While Direct3D claims to be good for games, in fact, Direct3D does not have
adequate rendering support for fast reflections and shadows. Indeed, an OpenGL
game developer can develop a richer experience than can a Direct3D game
developer. Also consider that:
OpenGL is a better documented API.
OpenGL is also a cleaner API and much easier to learn and program.
OpenGL has the best demonstrated 3D performance for any API.
Microsoft's Direct3D group is already planning a major API change called
DirectPrimitive (to make its API more OpenGL-like) that will leave any
existing investment in learning Direct3D immediate mode largely obsolete.
SGI is now providing a free software OpenGL implementation called Cosmo
OpenGL that is tuned specifically for 3D games to give better performance
than Microsoft's OpenGL 1.1 and Direct3D implementation even with no
special 3D hardware.
OpenGL has a conformance suite to validate that OpenGL implementions
correctly implement OpenGL. Direct3D has no conformance suite; indeed,
its feature set can vary from driver to driver creating a testing
nightmare for the game developers.
PC 3D hardware vendors are now realizing the tremendous limitations to
Direct3D. The leaders in PC 3D hardware either have OpenGL drivers
available already or are releasing them as soon as possible. 3Dfx,
3Dlabs, Dynamic Pictures, Intergraph, and others are all supporting
OpenGL today.
Microsoft is the only vendors that controls Direct3D. OpenGL on the other
hand is an open standard jointly maintained by Intel, Microsoft, DEC,
IBM, Evans & Sutherland, HP, Silicon Graphics, Sun, and Intergraph - all
the leaders in 3D graphics on OpenGL's Architectural Review Board. OpenGL
has an open extension mechanism allowing vendors to add new extensions
such as 3D texture mapping, convolutions, better blending modes,
multisample antialiasing. All these features are now available as OpenGL
extensions. On the other hand, Microsoft has no mechanism for hardware
vendors to release new extensions. OpenGL is a far more innovative API.
ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ
On with the images. . .
This first image shows a 3D dinosaur (uh, sorry it looks so lame). The yellow
spot indicates the light source's direction heading towards the origin (the
light is infinitely far away in these snapshots). Notice that the light also
casts a shadow on the texture mapped ground. Notice the shadow correctly
overlays the ground. Also notice the correct reflection on the floor.
I should stress that this is an interactive program. You can change the view
and move the light source with the mouse. The dinosaur is animated and
repeatedly jumps up and down. The shadow and reflection both correctly follow
the dinosaur's jumping. Since the source code for the program can be found
below, I encourage you to compile the program and run it.
ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ
The next image shows the light behind the dinosaur and lower to the ground.
Notice that the shadow projects out further. You can also see how both the
reflection, the textured floor, and the shadow all interact correctly at the
dinosaur's foot.
ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ
The image below is actually showing what the scene would look like if the
program didn't use OpenGL's stencil buffer facility. Stencil buffering is a
capability that Direct3D completely lacks so the artifacts below would afflict
a Direct3D program.
Notice how the dinosaur reflection is not correctly terminated at the edge of
the floor. Indeed, you can see how the reflection is really a blended
re-rendering of the dinosaur (geometrically) reflected through the plane of
the floor. However, you don't want the dinosaur to appear in pixels that do
not actually belong to the floor. OpenGL's general stenciling capability makes
it easy to only draw the reflected dinosaur on floor pixels.
You can see a second artifact in the dinosaur's shadow. Notice how some areas
of the shadow appear darker than other areas. This is because the dinosaur's
shoulder gets drawn by multiple pixels when projected onto the floor. This
causes duplicate shadow blends. Notice that the previous two images have no
such artifacts. OpenGL stenciling can be used to ensure that a shadow pixel is
only blended once with the floor. Again, Direct3D would suffer from the
shadowing artifacts below since Direct3D completely lacks stenciling support.
OpenGL stenciling has a straightforward hardware implementation so stenciling
programs can run very fast on good hardware. Notice that stenciling is used to
eliminate both the reflection and shadow artifacts; actually, stencil has lots
more uses.
ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ
The image below has a different artifact due to depth buffer aliasing when the
shadow blends with the floor. The dark shadow area and the floor lie in almost
the same plane so some polygons in the shadow appear, while others do not.
This is a classic depth buffer problem. OpenGL 1.1 provides a robust solution
to this problem with its polygon offset functionality. This feature of OpenGL
lets you bias depth values so that coplanar polygons are correctly layered.
The two images above use polygon offset to slightly lift the shadow's depth
values to eliminate the artifacts shown below. Since Direct3D has no
equivalent capability, Direct3D projected blended shadows would suffer the
artifact demonstrated below.
Actually, the image below is using stenciling. If both stenciling and polygon
offset were unavailable (as in Direct3D), these two scenes would look far
worse.
There are ways to "hack" around Direct3D's lack of stenciling and polygon
offset. In general, these hacks force you to give up something like blended
shadows or reflections or texturing in combination or add constraints on how
the scene can be viewed.
ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ
If you are wondering how general these techniques are, I assure you all the
techniques demonstrated can be effectively combined. The images above are
simple so you can see the interactions easily and so I can provide you the
complete source code. With more work, multiple reflecting objects (including
multiple reflections), multiple shadows, and more textures are all possible.
If you want to see an even richer demonstration of these techniques, check out
the OpenGL-rendered (in real-time!) QuickTime movie below. Notice at the end
of the movie that you can see the ceiling fan reflected in the floor that is
reflected in the mirror (multiple reflections!):
The Smoke & Mirrors QuickTime Movie
If you are a game developer and you are exploring your options for 3D APIs,
please seriously consider the issues. Game developers that settle for Direct3D
are very likely to find their games are inferior to the more realistic games
written with fast, portable OpenGL.
If you have not seen John Carmark's treatise on OpenGL vs Direct3D, I
recommend that you read it. Id Software has already ported Quake to OpenGL;
based on the problems with Direct3D cited in Carmack's treatise, Id Software
intends no Direct3D port. You will also probably benefit from reading SGI's
OpenGL Perspective on Direct3D. If you aren't thinking about these issues, I
assure you that your competitors are.
To compile the code below on Windows 95, you will need either Microsoft's
OpenGL 1.1 DLL or SGI's Cosmo OpenGL DLL. You will also need the Win32 version
of the OpenGL Utility Toolkit (GLUT). You can also get the full GLUT source
code distribution for more OpenGL sample code. (By the way, this code is
portable and works on Unix workstations.)
Click here to see dinoshade.c.
- Mark Kilgard (mjk@sgi.com)
ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ
Source code | Title page | Contents | Next
ΓòÉΓòÉΓòÉ 2.4.1. dinoshade.c ΓòÉΓòÉΓòÉ
/* Copyright (c) Mark J. Kilgard, 1994, 1997. */
/* This program is freely distributable without licensing fees
and is provided without guarantee or warrantee expressed or
implied. This program is -not- in the public domain. */
/* Example for PC game developers to show how to *combine* texturing,
reflections, and projected shadows all in real-time with OpenGL.
Robust reflections use stenciling. Robust projected shadows
use both stenciling and polygon offset. PC game programmers
should realize that neither stenciling nor polygon offset are
supported by Direct3D, so these real-time rendering algorithms
are only really viable with OpenGL.
The program has modes for disabling the stenciling and polygon
offset uses. It is worth running this example with these features
toggled off so you can see the sort of artifacts that result.
Notice that the floor texturing, reflections, and shadowing
all co-exist properly. */
/* When you run this program: Left mouse button controls the
view. Middle mouse button controls light position (left &
right rotates light around dino; up & down moves light
position up and down). Right mouse button pops up menu. */
/* Check out the comments in the "redraw" routine to see how the
reflection blending and surface stenciling is done. You can
also see in "redraw" how the projected shadows are rendered,
including the use of stenciling and polygon offset. */
/* This program is derived from glutdino.c */
/* Compile: cc -o dinoshade dinoshade.c -lglut -lGLU -lGL -lXmu -lXext -lX11 -lm */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h> /* for cos(), sin(), and sqrt() */
#include <GL/glut.h> /* OpenGL Utility Toolkit header */
/* Some <math.h> files do not define M_PI... */
#ifndef M_PI
#define M_PI 3.14159265
#endif
/* Variable controlling various rendering modes. */
static int stencilReflection = 1, stencilShadow = 1, offsetShadow = 1;
static int renderShadow = 1, renderDinosaur = 1, renderReflection = 1;
static int linearFiltering = 0, useMipmaps = 0, useTexture = 1;
static int reportSpeed = 0;
static int animation = 1;
static GLboolean lightSwitch = GL_TRUE;
static int directionalLight = 1;
static int forceExtension = 0;
/* Time varying or user-controled variables. */
static float jump = 0.0;
static float lightAngle = 0.0, lightHeight = 20;
GLfloat angle = -150; /* in degrees */
GLfloat angle2 = 30; /* in degrees */
int moving, startx, starty;
int lightMoving = 0, lightStartX, lightStartY;
enum {
MISSING, EXTENSION, ONE_DOT_ONE
};
int polygonOffsetVersion;
static GLdouble bodyWidth = 3.0;
/* *INDENT-OFF* */
static GLfloat body[][2] = { {0, 3}, {1, 1}, {5, 1}, {8, 4}, {10, 4}, {11, 5},
{11, 11.5}, {13, 12}, {13, 13}, {10, 13.5}, {13, 14}, {13, 15}, {11, 16},
{8, 16}, {7, 15}, {7, 13}, {8, 12}, {7, 11}, {6, 6}, {4, 3}, {3, 2},
{1, 2} };
static GLfloat arm[][2] = { {8, 10}, {9, 9}, {10, 9}, {13, 8}, {14, 9}, {16, 9},
{15, 9.5}, {16, 10}, {15, 10}, {15.5, 11}, {14.5, 10}, {14, 11}, {14, 10},
{13, 9}, {11, 11}, {9, 11} };
static GLfloat leg[][2] = { {8, 6}, {8, 4}, {9, 3}, {9, 2}, {8, 1}, {8, 0.5}, {9, 0},
{12, 0}, {10, 1}, {10, 2}, {12, 4}, {11, 6}, {10, 7}, {9, 7} };
static GLfloat eye[][2] = { {8.75, 15}, {9, 14.7}, {9.6, 14.7}, {10.1, 15},
{9.6, 15.25}, {9, 15.25} };
static GLfloat lightPosition[4];
static GLfloat lightColor[] = {0.8, 1.0, 0.8, 1.0}; /* green-tinted */
static GLfloat skinColor[] = {0.1, 1.0, 0.1, 1.0}, eyeColor[] = {1.0, 0.2, 0.2, 1.0};
/* *INDENT-ON* */
/* Nice floor texture tiling pattern. */
static char *circles[] = {
"....xxxx........",
"..xxxxxxxx......",
".xxxxxxxxxx.....",
".xxx....xxx.....",
"xxx......xxx....",
"xxx......xxx....",
"xxx......xxx....",
"xxx......xxx....",
".xxx....xxx.....",
".xxxxxxxxxx.....",
"..xxxxxxxx......",
"....xxxx........",
"................",
"................",
"................",
"................",
};
static void
makeFloorTexture(void)
{
GLubyte floorTexture[16][16][3];
GLubyte *loc;
int s, t;
/* Setup RGB image for the texture. */
loc = (GLubyte*) floorTexture;
for (t = 0; t < 16; t++) {
for (s = 0; s < 16; s++) {
if (circles[t][s] == 'x') {
/* Nice green. */
loc[0] = 0x1f;
loc[1] = 0x8f;
loc[2] = 0x1f;
} else {
/* Light gray. */
loc[0] = 0xaa;
loc[1] = 0xaa;
loc[2] = 0xaa;
}
loc += 3;
}
}
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
if (useMipmaps) {
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
GL_LINEAR_MIPMAP_LINEAR);
gluBuild2DMipmaps(GL_TEXTURE_2D, 3, 16, 16,
GL_RGB, GL_UNSIGNED_BYTE, floorTexture);
} else {
if (linearFiltering) {
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
} else {
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
}
glTexImage2D(GL_TEXTURE_2D, 0, 3, 16, 16, 0,
GL_RGB, GL_UNSIGNED_BYTE, floorTexture);
}
}
enum {
X, Y, Z, W
};
enum {
A, B, C, D
};
/* Create a matrix that will project the desired shadow. */
void
shadowMatrix(GLfloat shadowMat[4][4],
GLfloat groundplane[4],
GLfloat lightpos[4])
{
GLfloat dot;
/* Find dot product between light position vector and ground plane normal. */
dot = groundplane[X] * lightpos[X] +
groundplane[Y] * lightpos[Y] +
groundplane[Z] * lightpos[Z] +
groundplane[W] * lightpos[W];
shadowMat[0][0] = dot - lightpos[X] * groundplane[X];
shadowMat[1][0] = 0.f - lightpos[X] * groundplane[Y];
shadowMat[2][0] = 0.f - lightpos[X] * groundplane[Z];
shadowMat[3][0] = 0.f - lightpos[X] * groundplane[W];
shadowMat[X][1] = 0.f - lightpos[Y] * groundplane[X];
shadowMat[1][1] = dot - lightpos[Y] * groundplane[Y];
shadowMat[2][1] = 0.f - lightpos[Y] * groundplane[Z];
shadowMat[3][1] = 0.f - lightpos[Y] * groundplane[W];
shadowMat[X][2] = 0.f - lightpos[Z] * groundplane[X];
shadowMat[1][2] = 0.f - lightpos[Z] * groundplane[Y];
shadowMat[2][2] = dot - lightpos[Z] * groundplane[Z];
shadowMat[3][2] = 0.f - lightpos[Z] * groundplane[W];
shadowMat[X][3] = 0.f - lightpos[W] * groundplane[X];
shadowMat[1][3] = 0.f - lightpos[W] * groundplane[Y];
shadowMat[2][3] = 0.f - lightpos[W] * groundplane[Z];
shadowMat[3][3] = dot - lightpos[W] * groundplane[W];
}
/* Find the plane equation given 3 points. */
void
findPlane(GLfloat plane[4],
GLfloat v0[3], GLfloat v1[3], GLfloat v2[3])
{
GLfloat vec0[3], vec1[3];
/* Need 2 vectors to find cross product. */
vec0[X] = v1[X] - v0[X];
vec0[Y] = v1[Y] - v0[Y];
vec0[Z] = v1[Z] - v0[Z];
vec1[X] = v2[X] - v0[X];
vec1[Y] = v2[Y] - v0[Y];
vec1[Z] = v2[Z] - v0[Z];
/* find cross product to get A, B, and C of plane equation */
plane[A] = vec0[Y] * vec1[Z] - vec0[Z] * vec1[Y];
plane[B] = -(vec0[X] * vec1[Z] - vec0[Z] * vec1[X]);
plane[C] = vec0[X] * vec1[Y] - vec0[Y] * vec1[X];
plane[D] = -(plane[A] * v0[X] + plane[B] * v0[Y] + plane[C] * v0[Z]);
}
void
extrudeSolidFromPolygon(GLfloat data[][2], unsigned int dataSize,
GLdouble thickness, GLuint side, GLuint edge, GLuint whole)
{
static GLUtriangulatorObj *tobj = NULL;
GLdouble vertex[3], dx, dy, len;
int i;
int count = dataSize / (2 * sizeof(GLfloat));
if (tobj == NULL) {
tobj = gluNewTess(); /* create and initialize a GLU
polygon * * tesselation object */
gluTessCallback(tobj, GLU_BEGIN, glBegin);
gluTessCallback(tobj, GLU_VERTEX, glVertex2fv); /* semi-tricky */
gluTessCallback(tobj, GLU_END, glEnd);
}
glNewList(side, GL_COMPILE);
glShadeModel(GL_SMOOTH); /* smooth minimizes seeing
tessellation */
gluBeginPolygon(tobj);
for (i = 0; i < count; i++) {
vertex[0] = data[i][0];
vertex[1] = data[i][1];
vertex[2] = 0;
gluTessVertex(tobj, vertex, data[i]);
}
gluEndPolygon(tobj);
glEndList();
glNewList(edge, GL_COMPILE);
glShadeModel(GL_FLAT); /* flat shade keeps angular hands
from being "smoothed" */
glBegin(GL_QUAD_STRIP);
for (i = 0; i <= count; i++) {
/* mod function handles closing the edge */
glVertex3f(data[i % count][0], data[i % count][1], 0.0);
glVertex3f(data[i % count][0], data[i % count][1], thickness);
/* Calculate a unit normal by dividing by Euclidean
distance. We * could be lazy and use
glEnable(GL_NORMALIZE) so we could pass in * arbitrary
normals for a very slight performance hit. */
dx = data[(i + 1) % count][1] - data[i % count][1];
dy = data[i % count][0] - data[(i + 1) % count][0];
len = sqrt(dx * dx + dy * dy);
glNormal3f(dx / len, dy / len, 0.0);
}
glEnd();
glEndList();
glNewList(whole, GL_COMPILE);
glFrontFace(GL_CW);
glCallList(edge);
glNormal3f(0.0, 0.0, -1.0); /* constant normal for side */
glCallList(side);
glPushMatrix();
glTranslatef(0.0, 0.0, thickness);
glFrontFace(GL_CCW);
glNormal3f(0.0, 0.0, 1.0); /* opposite normal for other side */
glCallList(side);
glPopMatrix();
glEndList();
}
/* Enumerants for refering to display lists. */
typedef enum {
RESERVED, BODY_SIDE, BODY_EDGE, BODY_WHOLE, ARM_SIDE, ARM_EDGE, ARM_WHOLE,
LEG_SIDE, LEG_EDGE, LEG_WHOLE, EYE_SIDE, EYE_EDGE, EYE_WHOLE
} displayLists;
static void
makeDinosaur(void)
{
extrudeSolidFromPolygon(body, sizeof(body), bodyWidth,
BODY_SIDE, BODY_EDGE, BODY_WHOLE);
extrudeSolidFromPolygon(arm, sizeof(arm), bodyWidth / 4,
ARM_SIDE, ARM_EDGE, ARM_WHOLE);
extrudeSolidFromPolygon(leg, sizeof(leg), bodyWidth / 2,
LEG_SIDE, LEG_EDGE, LEG_WHOLE);
extrudeSolidFromPolygon(eye, sizeof(eye), bodyWidth + 0.2,
EYE_SIDE, EYE_EDGE, EYE_WHOLE);
}
static void
drawDinosaur(void)
{
glPushMatrix();
/* Translate the dinosaur to be at (0,8,0). */
glTranslatef(-8, 0, -bodyWidth / 2);
glTranslatef(0.0, jump, 0.0);
glMaterialfv(GL_FRONT, GL_DIFFUSE, skinColor);
glCallList(BODY_WHOLE);
#if 0
glPushMatrix();
#endif
glTranslatef(0.0, 0.0, bodyWidth);
glCallList(ARM_WHOLE);
glCallList(LEG_WHOLE);
glTranslatef(0.0, 0.0, -bodyWidth - bodyWidth / 4);
glCallList(ARM_WHOLE);
glTranslatef(0.0, 0.0, -bodyWidth / 4);
glCallList(LEG_WHOLE);
glTranslatef(0.0, 0.0, bodyWidth / 2 - 0.1);
glMaterialfv(GL_FRONT, GL_DIFFUSE, eyeColor);
glCallList(EYE_WHOLE);
#if 0
glPopMatrix();
#endif
glPopMatrix();
}
static GLfloat floorVertices[4][3] = {
{ -20.0, 0.0, 20.0 },
{ 20.0, 0.0, 20.0 },
{ 20.0, 0.0, -20.0 },
{ -20.0, 0.0, -20.0 },
};
/* Draw a floor (possibly textured). */
static void
drawFloor(void)
{
glDisable(GL_LIGHTING);
if (useTexture) {
glEnable(GL_TEXTURE_2D);
}
glBegin(GL_QUADS);
glTexCoord2f(0.0, 0.0);
glVertex3fv(floorVertices[0]);
glTexCoord2f(0.0, 16.0);
glVertex3fv(floorVertices[1]);
glTexCoord2f(16.0, 16.0);
glVertex3fv(floorVertices[2]);
glTexCoord2f(16.0, 0.0);
glVertex3fv(floorVertices[3]);
glEnd();
if (useTexture) {
glDisable(GL_TEXTURE_2D);
}
glEnable(GL_LIGHTING);
}
static GLfloat floorPlane[4];
static GLfloat floorShadow[4][4];
static void
redraw(void)
{
int start, end;
if (reportSpeed) {
start = glutGet(GLUT_ELAPSED_TIME);
}
/* Clear; default stencil clears to zero. */
if ((stencilReflection && renderReflection) || (stencilShadow && renderShadow)) {
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
} else {
/* Avoid clearing stencil when not using it. */
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
}
/* Reposition the light source. */
lightPosition[0] = 12*cos(lightAngle);
lightPosition[1] = lightHeight;
lightPosition[2] = 12*sin(lightAngle);
if (directionalLight) {
lightPosition[3] = 0.0;
} else {
lightPosition[3] = 1.0;
}
shadowMatrix(floorShadow, floorPlane, lightPosition);
glPushMatrix();
/* Perform scene rotations based on user mouse input. */
glRotatef(angle2, 1.0, 0.0, 0.0);
glRotatef(angle, 0.0, 1.0, 0.0);
/* Tell GL new light source position. */
glLightfv(GL_LIGHT0, GL_POSITION, lightPosition);
if (renderReflection) {
if (stencilReflection) {
/* We can eliminate the visual "artifact" of seeing the "flipped"
dinosaur underneath the floor by using stencil. The idea is
draw the floor without color or depth update but so that
a stencil value of one is where the floor will be. Later when
rendering the dinosaur reflection, we will only update pixels
with a stencil value of 1 to make sure the reflection only
lives on the floor, not below the floor. */
/* Don't update color or depth. */
glDisable(GL_DEPTH_TEST);
glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
/* Draw 1 into the stencil buffer. */
glEnable(GL_STENCIL_TEST);
glStencilOp(GL_REPLACE, GL_REPLACE, GL_REPLACE);
glStencilFunc(GL_ALWAYS, 1, 0xffffffff);
/* Now render floor; floor pixels just get their stencil set to 1. */
drawFloor();
/* Re-enable update of color and depth. */
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
glEnable(GL_DEPTH_TEST);
/* Now, only render where stencil is set to 1. */
glStencilFunc(GL_EQUAL, 1, 0xffffffff); /* draw if ==1 */
glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
}
glPushMatrix();
/* The critical reflection step: Reflect dinosaur through the floor
(the Y=0 plane) to make a relection. */
glScalef(1.0, -1.0, 1.0);
/* Reflect the light position. */
glLightfv(GL_LIGHT0, GL_POSITION, lightPosition);
/* To avoid our normals getting reversed and hence botched lighting
on the reflection, turn on normalize. */
glEnable(GL_NORMALIZE);
glCullFace(GL_FRONT);
/* Draw the reflected dinosaur. */
drawDinosaur();
/* Disable noramlize again and re-enable back face culling. */
glDisable(GL_NORMALIZE);
glCullFace(GL_BACK);
glPopMatrix();
/* Switch back to the unreflected light position. */
glLightfv(GL_LIGHT0, GL_POSITION, lightPosition);
if (stencilReflection) {
glDisable(GL_STENCIL_TEST);
}
}
/* Back face culling will get used to only draw either the top or the
bottom floor. This let's us get a floor with two distinct
appearances. The top floor surface is reflective and kind of red.
The bottom floor surface is not reflective and blue. */
/* Draw "bottom" of floor in blue. */
glFrontFace(GL_CW); /* Switch face orientation. */
glColor4f(0.1, 0.1, 0.7, 1.0);
drawFloor();
glFrontFace(GL_CCW);
if (renderShadow) {
if (stencilShadow) {
/* Draw the floor with stencil value 3. This helps us only
draw the shadow once per floor pixel (and only on the
floor pixels). */
glEnable(GL_STENCIL_TEST);
glStencilFunc(GL_ALWAYS, 3, 0xffffffff);
glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);
}
}
/* Draw "top" of floor. Use blending to blend in reflection. */
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glColor4f(0.7, 0.0, 0.0, 0.3);
glColor4f(1.0, 1.0, 1.0, 0.3);
drawFloor();
glDisable(GL_BLEND);
if (renderDinosaur) {
/* Draw "actual" dinosaur, not its reflection. */
drawDinosaur();
}
if (renderShadow) {
/* Render the projected shadow. */
if (stencilShadow) {
/* Now, only render where stencil is set above 2 (ie, 3 where
the top floor is). Update stencil with 2 where the shadow
gets drawn so we don't redraw (and accidently reblend) the
shadow). */
glStencilFunc(GL_LESS, 2, 0xffffffff); /* draw if ==1 */
glStencilOp(GL_REPLACE, GL_REPLACE, GL_REPLACE);
}
/* To eliminate depth buffer artifacts, we use polygon offset
to raise the depth of the projected shadow slightly so
that it does not depth buffer alias with the floor. */
if (offsetShadow) {
switch (polygonOffsetVersion) {
case EXTENSION:
#ifdef GL_EXT_polygon_offset
glEnable(GL_POLYGON_OFFSET_EXT);
break;
#endif
#ifdef GL_VERSION_1_1
case ONE_DOT_ONE:
glEnable(GL_POLYGON_OFFSET_FILL);
break;
#endif
case MISSING:
/* Oh well. */
break;
}
}
/* Render 50% black shadow color on top of whatever the
floor appareance is. */
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glDisable(GL_LIGHTING); /* Force the 50% black. */
glColor4f(0.0, 0.0, 0.0, 0.5);
glPushMatrix();
/* Project the shadow. */
glMultMatrixf((GLfloat *) floorShadow);
drawDinosaur();
glPopMatrix();
glDisable(GL_BLEND);
glEnable(GL_LIGHTING);
if (offsetShadow) {
switch (polygonOffsetVersion) {
#ifdef GL_EXT_polygon_offset
case EXTENSION:
glDisable(GL_POLYGON_OFFSET_EXT);
break;
#endif
#ifdef GL_VERSION_1_1
case ONE_DOT_ONE:
glDisable(GL_POLYGON_OFFSET_FILL);
break;
#endif
case MISSING:
/* Oh well. */
break;
}
}
if (stencilShadow) {
glDisable(GL_STENCIL_TEST);
}
}
glPushMatrix();
glDisable(GL_LIGHTING);
glColor3f(1.0, 1.0, 0.0);
if (directionalLight) {
/* Draw an arrowhead. */
glDisable(GL_CULL_FACE);
glTranslatef(lightPosition[0], lightPosition[1], lightPosition[2]);
glRotatef(lightAngle * -180.0 / M_PI, 0, 1, 0);
glRotatef(atan(lightHeight/12) * 180.0 / M_PI, 0, 0, 1);
glBegin(GL_TRIANGLE_FAN);
glVertex3f(0, 0, 0);
glVertex3f(2, 1, 1);
glVertex3f(2, -1, 1);
glVertex3f(2, -1, -1);
glVertex3f(2, 1, -1);
glVertex3f(2, 1, 1);
glEnd();
/* Draw a white line from light direction. */
glColor3f(1.0, 1.0, 1.0);
glBegin(GL_LINES);
glVertex3f(0, 0, 0);
glVertex3f(5, 0, 0);
glEnd();
glEnable(GL_CULL_FACE);
} else {
/* Draw a yellow ball at the light source. */
glTranslatef(lightPosition[0], lightPosition[1], lightPosition[2]);
glutSolidSphere(1.0, 5, 5);
}
glEnable(GL_LIGHTING);
glPopMatrix();
glPopMatrix();
if (reportSpeed) {
glFinish();
end = glutGet(GLUT_ELAPSED_TIME);
printf("Speed %.3g frames/sec (%d ms)\n", 1000.0/(end-start), end-start);
}
glutSwapBuffers();
}
/* ARGSUSED2 */
static void
mouse(int button, int state, int x, int y)
{
if (button == GLUT_LEFT_BUTTON) {
if (state == GLUT_DOWN) {
moving = 1;
startx = x;
starty = y;
}
if (state == GLUT_UP) {
moving = 0;
}
}
if (button == GLUT_MIDDLE_BUTTON) {
if (state == GLUT_DOWN) {
lightMoving = 1;
lightStartX = x;
lightStartY = y;
}
if (state == GLUT_UP) {
lightMoving = 0;
}
}
}
/* ARGSUSED1 */
static void
motion(int x, int y)
{
if (moving) {
angle = angle + (x - startx);
angle2 = angle2 + (y - starty);
startx = x;
starty = y;
glutPostRedisplay();
}
if (lightMoving) {
lightAngle += (x - lightStartX)/40.0;
lightHeight += (lightStartY - y)/20.0;
lightStartX = x;
lightStartY = y;
glutPostRedisplay();
}
}
/* Advance time varying state when idle callback registered. */
static void
idle(void)
{
static float time = 0.0;
time = glutGet(GLUT_ELAPSED_TIME) / 500.0;
jump = 4.0 * fabs(sin(time)*0.5);
if (!lightMoving) {
lightAngle += 0.03;
}
glutPostRedisplay();
}
enum {
M_NONE, M_MOTION, M_LIGHT, M_TEXTURE, M_SHADOWS, M_REFLECTION, M_DINOSAUR,
M_STENCIL_REFLECTION, M_STENCIL_SHADOW, M_OFFSET_SHADOW,
M_POSITIONAL, M_DIRECTIONAL, M_PERFORMANCE
};
static void
controlLights(int value)
{
switch (value) {
case M_NONE:
return;
case M_MOTION:
animation = 1 - animation;
if (animation) {
glutIdleFunc(idle);
} else {
glutIdleFunc(NULL);
}
break;
case M_LIGHT:
lightSwitch = !lightSwitch;
if (lightSwitch) {
glEnable(GL_LIGHT0);
} else {
glDisable(GL_LIGHT0);
}
break;
case M_TEXTURE:
useTexture = !useTexture;
break;
case M_SHADOWS:
renderShadow = 1 - renderShadow;
break;
case M_REFLECTION:
renderReflection = 1 - renderReflection;
break;
case M_DINOSAUR:
renderDinosaur = 1 - renderDinosaur;
break;
case M_STENCIL_REFLECTION:
stencilReflection = 1 - stencilReflection;
break;
case M_STENCIL_SHADOW:
stencilShadow = 1 - stencilShadow;
break;
case M_OFFSET_SHADOW:
offsetShadow = 1 - offsetShadow;
break;
case M_POSITIONAL:
directionalLight = 0;
break;
case M_DIRECTIONAL:
directionalLight = 1;
break;
case M_PERFORMANCE:
reportSpeed = 1 - reportSpeed;
break;
}
glutPostRedisplay();
}
/* When not visible, stop animating. Restart when visible again. */
static void
visible(int vis)
{
if (vis == GLUT_VISIBLE) {
if (animation)
glutIdleFunc(idle);
} else {
if (!animation)
glutIdleFunc(NULL);
}
}
/* Press any key to redraw; good when motion stopped and
performance reporting on. */
/* ARGSUSED */
static void
key(unsigned char c, int x, int y)
{
if (c == 27) {
exit(0); /* IRIS GLism, Escape quits. */
}
glutPostRedisplay();
}
/* Press any key to redraw; good when motion stopped and
performance reporting on. */
/* ARGSUSED */
static void
special(int k, int x, int y)
{
glutPostRedisplay();
}
static int
supportsOneDotOne(void)
{
const char *version;
int major, minor;
version = (char *) glGetString(GL_VERSION);
if (sscanf(version, "%d.%d", &major, &minor) == 2)
return major >= 1 && minor >= 1;
return 0; /* OpenGL version string malformed! */
}
int
main(int argc, char **argv)
{
int i;
glutInit(&argc, argv);
for (i=1; i<argc; i++) {
if (!strcmp("-linear", argv[i])) {
linearFiltering = 1;
} else if (!strcmp("-mipmap", argv[i])) {
useMipmaps = 1;
} else if (!strcmp("-ext", argv[i])) {
forceExtension = 1;
}
}
glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH | GLUT_STENCIL | GLUT_MULTISAMPLE);
#if 0
/* In GLUT 4.0, you'll be able to do this an be sure to
get 2 bits of stencil if the machine has it for you. */
glutInitDisplayString("samples stencil>=2 rgb double depth");
#endif
glutCreateWindow("Shadowy Leapin' Lizards");
if (glutGet(GLUT_WINDOW_STENCIL_SIZE) <= 1) {
printf("dinoshade: Sorry, I need at least 2 bits of stencil.\n");
exit(1);
}
/* Register GLUT callbacks. */
glutDisplayFunc(redraw);
glutMouseFunc(mouse);
glutMotionFunc(motion);
glutVisibilityFunc(visible);
glutKeyboardFunc(key);
glutSpecialFunc(special);
glutCreateMenu(controlLights);
glutAddMenuEntry("Toggle motion", M_MOTION);
glutAddMenuEntry("-----------------------", M_NONE);
glutAddMenuEntry("Toggle light", M_LIGHT);
glutAddMenuEntry("Toggle texture", M_TEXTURE);
glutAddMenuEntry("Toggle shadows", M_SHADOWS);
glutAddMenuEntry("Toggle reflection", M_REFLECTION);
glutAddMenuEntry("Toggle dinosaur", M_DINOSAUR);
glutAddMenuEntry("-----------------------", M_NONE);
glutAddMenuEntry("Toggle reflection stenciling", M_STENCIL_REFLECTION);
glutAddMenuEntry("Toggle shadow stenciling", M_STENCIL_SHADOW);
glutAddMenuEntry("Toggle shadow offset", M_OFFSET_SHADOW);
glutAddMenuEntry("----------------------", M_NONE);
glutAddMenuEntry("Positional light", M_POSITIONAL);
glutAddMenuEntry("Directional light", M_DIRECTIONAL);
glutAddMenuEntry("-----------------------", M_NONE);
glutAddMenuEntry("Toggle performance", M_PERFORMANCE);
glutAttachMenu(GLUT_RIGHT_BUTTON);
makeDinosaur();
#ifdef GL_VERSION_1_1
if (supportsOneDotOne() && !forceExtension) {
polygonOffsetVersion = ONE_DOT_ONE;
glPolygonOffset(-2.0, -1.0);
} else
#endif
{
#ifdef GL_EXT_polygon_offset
/* check for the polygon offset extension */
if (glutExtensionSupported("GL_EXT_polygon_offset")) {
polygonOffsetVersion = EXTENSION;
glPolygonOffsetEXT(-0.1, -0.002);
} else
#endif
{
polygonOffsetVersion = MISSING;
printf("\ndinoshine: Missing polygon offset.\n");
printf(" Expect shadow depth aliasing artifacts.\n\n");
}
}
glEnable(GL_CULL_FACE);
glEnable(GL_DEPTH_TEST);
glEnable(GL_TEXTURE_2D);
glLineWidth(3.0);
glMatrixMode(GL_PROJECTION);
gluPerspective( /* field of view in degree */ 40.0,
/* aspect ratio */ 1.0,
/* Z near */ 20.0, /* Z far */ 100.0);
glMatrixMode(GL_MODELVIEW);
gluLookAt(0.0, 8.0, 60.0, /* eye is at (0,0,30) */
0.0, 8.0, 0.0, /* center is at (0,0,0) */
0.0, 1.0, 0.); /* up is in postivie Y direction */
glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, 1);
glLightfv(GL_LIGHT0, GL_DIFFUSE, lightColor);
glLightf(GL_LIGHT0, GL_CONSTANT_ATTENUATION, 0.1);
glLightf(GL_LIGHT0, GL_LINEAR_ATTENUATION, 0.05);
glEnable(GL_LIGHT0);
glEnable(GL_LIGHTING);
makeFloorTexture();
/* Setup floor plane for projected shadow calculations. */
findPlane(floorPlane, floorVertices[1], floorVertices[2], floorVertices[3]);
glutMainLoop();
return 0; /* ANSI C requires main to return int. */
}
ΓòÉΓòÉΓòÉ 2.5. Virtualized OpenGL Light Sources for Efficient Multi-Light Source Lighting ΓòÉΓòÉΓòÉ
Virtualized OpenGL Light Sources for Efficient Multi-Light Source Lighting
Recent discussion of the OPENGL-GAMEDEV mailing list have explored how to
support numerous (more than 8) light sources at once with an OpenGL rendered
scene. For example, consider a hallway in a Quake-style dungeon where candles
or torches illumate dynamic objects in the corridor. The candles/torches can be
be modeled as positional, attentuated OpenGL light sources.
The problem is that most OpenGL implementations only support the minimum
required number of light sources. Minimum required number of light sources is
eight (8). Note: OpenGL implementations are free to support an arbitary number
of light sources, but to make hardware accelerated lighting tractable, OpenGL
only mandates that at least 8 light sources.
Even if there were an arbitary number of OpenGL light sources and available,
the performance implications of a dozen or more OpenGL light sources enabled
throughout the scene is likely to be prohibitive, particularly considering that
far away lights may add an extremely insignificant or even no lighting
contribution to many objects in the scene.
A couple of solutions were proposed on the mailing list:
Instead of using OpenGL's lighting model, calculate your own lighting
effects and simply use glColor3f to assign the application-computed lit
color.
Application-computing lighting has the advantage of allowing arbitary
lighting effects and potentially more efficient lighting calculations. It
has the disadvantage of not utilizing graphics hardware that accelerates
lighting calculations using the graphics hardware.
Use textured lightmaps (a la Quake) to generate convincing static
lighting pattersn on walls and other surfaces. For example, the lighting
pattern of candles in a hallway could be generated with a texture of each
candle's localized light pattern.
Lightmaps have the advantage of permitting convincing lighting effects
that mimic radiosity solutions and largely avoid transform costs for
lighting (instead, lightmaps stress texture mapping and blending).
Lightmaps have the disadvantage of being fairly static (often
pre-computed) so they do not easily handle lighting situations involving
dynamic objects.
Use OpenGL light sources, but do per-object calculations to determine
which light sources will most affect the overall lit appearance of each
lit object. Dynamically configure and enable the appropriate light
sources before rendering each lit object. For example, in the hallway of
candles, only the candles nearest a particular object should affect the
object significantly because candles are dim. This approach is called
virtualized light sources because a potentially large number of scene
light sources are mapped dynamically to OpenGL's limited number of
(potentially hardware accelerated) OpenGL light sources.
Virtualized light sources has the advantage of leveraging OpenGL's
hardware acceleration for per-vertex lighting calculations and using
OpenGL's easy-to-use API. The technique can also improve overall lighting
performance by disabling light sources with insignificant contributions
to an object's coloration. Virtualized light sources have the
disadvantage of introducing overhead due to lighting state changes and
may not be able to completely handle (rare?) situations where more than 8
light sources (or whatever higher limit exists) are truly needed to
correctly capture an intricate lighting effect.
The remainder of this article describes the last approach in more detail
including the presentation of screen snapshots and sample source code to
demonstrate the technique.
First, a few words about OpenGL's lighting model. Light is a complicated
phenomenon. OpenGL's lighting model is designed for real-time interaction;
OpenGL's lighting model only attempts to capture some of the simplest lighting
surface effects such as diffuse and specular interactions. OpenGL's lighting
model does not handle complicated effects such as shadows, reflections,
refraction, or occlusion of light (relativistic and quantum light
interfactions are similarly ignored). If you want to implement effects such as
reflections and shadows with OpenGL, you can with more sophisticated rendering
techniques beyond those supported by OpenGL's lighting model. What OpenGL does
model is per-vertex interactions involving only the surface material and a set
of light sources. In practice, this is enough to achieve some pretty nice
effects at interactive rates.
In practice, you can think of OpenGL's lighting model as really a bunch of
equations that compute an RGB color value at each vertex. Indeed, if you want
to really understand OpenGL's lighting model, see the explanation of OpenGL's
lighting operation in the OpenGL 1.1 specification.
The fact that OpenGL's lighting equations are explicit makes it
straightforward for applications to quickly and robustly approximate the
contributions of various light sources in the scene more or less the same way
that OpenGL. This lets the application virtualize its light sources. Some
other 3D graphics APIs such as Direct3D do not specify the lighting equations
the API uses in enough detail to pre-compute lighting effects reliably (in the
case of Direct3D, the API lacks both a rigorous specification and a standard
conformance suite to enforce a uniform behavior; OpenGL has both).
Before we get much further describing the approach, let's take a look at a
screen snapshot from the multilight.c example (the full workign source code is
available; the program uses the OpenGL Utility Toolkit for portability):
So what is the image showing? The sphere in the scene wanders among the two
rows of light sources (indicated by each of the small color spheres). Think of
the two rows as light sources as candles in a hallway if you want (use your
imagination). Notice that most of the light sources are numbered. The closer
(less distant from the sphere) light sources have smaller numbers (the blue
"0" light source is the closest; light sources "7" and "4" are actually hidden
behind the sphere). The distant light sources (what would be "8" and beyond)
are simply not enabled. Because of the way these light sources attenuate over
distances, the distable light sources wouldn't change the sphere's appearance
even if they were enablable.
Indeed, look at the following snapshot of bascially the same scene:
What's the difference? If you notice, light sources "7", "6", "5", and "4" are
gray, not white. This indicates that these light sources are disabled. Note
that the sphere's lighting looks basically the same; this is because
previously listed 4 light sources really aren't affecting the coloration of
the sphere in any significant way (yet even so, when enabled, they generally
still slow down your rendering!). The point is that if we are clever about
know how light sources contribute to the scene, we can get the same scene
appearance with less lighting overhead.
The idea is that if light sources are localized (technically, if the light
sources are positional and attenuated), it makes sense to not enable light
sources that are too dim to contribute to the lighting of an object. The more
light sources in your scene, the truer this becomes because all those extra
light sources would probably suck performance without significantly improving
your 3D scene.
When you run the multilight example (I encourage you to compile it and try it
out), you'll notice that as the sphere wanders among the light sources, the
distances between the sphere and the light sources changes. The program
automatically updates what light sources are active. You'll see that the
numbers change as the sphere's location changes. The un-numbered and
high-numbered light sources are always the ones most distant (that is, likely
to not affect the sphere's coloration much).
Think about the light sources labelled "4" and "7" in the snapshots above.
These lights are not going to affect the sphere from the view shown because
they "behind" the sphere. Their diffuse contribution to the sphere's lighting
is nil for all of the sphere we can see from this view. This is true even
though these light sources are fairly close to the sphere. Our distance-based
determination of how "bright" or "dim" a light source is may not be the best
determination of what light sources should be enabled or not.
Lambert's Law (explained in Section 6.3.2 of Ed Angel's OpenGL textbook)
models the way diffuse reflections occur. Basically, Lambert's Law explains
that the diffuse light bouncing off a diffuse surface is proprotional to the
cosine of the angle between the normal of the surface and the direction of the
light source. A more sophisticated determination of which diffuse light
sources affect a diffuse object should use Lambert's Law, not simply rely on
distance. The multilight example implements such a scheme. See the snapshot
below:
In this version, the picture looks about the same, but light sources behind
the sphere are no longer in the "top 8" light sources affecting the object.
The Lambertian-based approach does a better job determining what light sources
are really going to contribute to the lighting of the sphere based on not just
their distance from the sphere, but also the nature of diffuse reflections
from the surface.
A better determination of which lights are most important to the object's
lighting is important because it means that in more complicated situations
where lots of lights matter, the determination doesn't needlessly enable light
source just because they are close. Fewer enabled light sources = improved
performance.
Here's the same scene from a different viewpoint positioned so that the blue
light marked "0" above is actually behind the sphere now:
Notice that the blue light source that was "0" in the scene before is now not
even enabled; and the right light source now marked "0" was not even enabled
before. This makes sense because of how diffuse reflection works. Unlike the
distance-based approach, as the view changes, so will what light sources
contribute more to the object's lighting.
One caveat is that to quickly approximate diffuse reflection to determine
which light sources are most significant, multilight makes an assumption that
the "normal" of the sphere directly faces us. That's approximately true for
most of the sphere that is facing us; it is not really true for the sides of
the sphere that are still visible to us.
So how does this work in practice? Generally, for the scene in movelight
(admittedly contructed to demonstrate this point), generally only about 4
light sources really significantly contribute to the scene. By enabling only
the four most significant light sources (instead of all eight), movelight can
render frames 33% faster on a 200 Mhz Indigo2 XL (lighting calculations are
done on the main CPU, not off-loaded to dedicated graphics hardware on this
machine) compared to naively enabling 8 light sources (presumably if the full
12 light sources in the scene could be enabled, it would be even slower). The
point is that virtualized light sources can permit faster rendering at
basically the same visual quality as naively an OpenGL light source per light
source in your scene.
You can download or read the multilight.c source code.
If you want to find more information about using OpenGL for sophisticated
rendering effects, check out these other OpenGL rendering techniques.
- Mark Kilgard (mjk@sgi.com)
ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ
Source code | Title page | Contents | Next
ΓòÉΓòÉΓòÉ 2.5.1. multilight.c ΓòÉΓòÉΓòÉ
/* Copyright (c) Mark J. Kilgard, 1997. */
/* This program is freely distributable without licensing fees and is
provided without guarantee or warrantee expressed or implied. This
program is -not- in the public domain. */
/* This program demonstrates virtualization of OpenGL's lights. The idea is
that if an object is lit by many lights, it is computationally more
efficient to calculate the approximate lighting contribution of the
various lights per-object and only enable the "brightest" lights while
rendering the object. This also lets you render scenes with more lights
than the OpenGL implementation light (usually 8). Two approaches are
used: The "distance-based" approach only enables the 8 closest lights
based purely on distance. The "Lambertian-based" approach accounts for
diffuse lighting contributions and approximates the diffuse contribution. */
#include <math.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <GL/glut.h>
/* Some <math.h> files do not define M_PI... */
#ifndef M_PI
#define M_PI 3.14159265
#endif
#define MIN_VALUE(a,b) (((a)<(b))?(a):(b))
#define MAX_VALUE(a,b) (((a)>(b))?(a):(b))
enum {
DL_LIGHT_SPHERE = 1,
DL_BIG_SPHERE = 2,
DL_ICO = 3
};
enum {
M_SPHERE, M_ICO, M_LABELS, M_LINEAR, M_QUAD, M_REPORT_SIG,
M_LAMBERTIAN, M_DISTANCE, M_TIME
};
typedef struct _LightInfo {
GLfloat xyz[4];
GLfloat *rgb;
int enable;
} LightInfo;
typedef struct _LightBrightness {
int num;
GLfloat brightness;
} LightBrightness;
static int animation = 1;
static int labelLights = 1;
static int reportLightSignificance = 0;
static int brightnessModel = M_LAMBERTIAN;
static int numActiveLights;
static int timeFrames = 0;
static int singleBuffer = 0;
/* *INDENT-OFF* */
static GLfloat modelAmb[4] = {0.1, 0.1, 0.1, 1.0};
static GLfloat matAmb[4] = {0.2, 0.2, 0.2, 1.0};
static GLfloat matDiff[4] = {0.8, 0.8, 0.8, 1.0};
static GLfloat matSpec[4] = {0.4, 0.4, 0.4, 1.0};
static GLfloat matEmission[4] = {0.0, 0.0, 0.0, 1.0};
GLfloat red[] = {1.0, 0.0, 0.0, 1.0};
GLfloat green[] = {0.0, 1.0, 0.0, 1.0};
GLfloat blue[] = {0.0, 0.0, 1.0, 1.0};
GLfloat yellow[] = {1.0, 1.0, 0.0, 1.0};
GLfloat magenta[] = {1.0, 0.0, 1.0, 1.0};
GLfloat white[] = {1.0, 1.0, 1.0, 1.0};
GLfloat dim[] = {0.5, 0.5, 0.5, 1.0};
LightInfo linfo[] = {
{ {-4.0, 0.0, -10.0, 1.0}, yellow},
{ {4.0, 0.0, -10.0, 1.0}, green},
{ {-4.0, 0.0, -6.0, 1.0}, red},
{ {4.0, 0.0, -6.0, 1.0}, blue},
{ {-4.0, 0.0, -2.0, 1.0}, green},
{ {4.0, 0.0, -2.0, 1.0}, yellow},
{ {-4.0, 0.0, 2.0, 1.0}, blue},
{ {4.0, 0.0, 2.0, 1.0}, red},
{ {-4.0, 0.0, 6.0, 1.0}, yellow},
{ {4.0, 0.0, 6.0, 1.0}, green},
{ {-4.0, 0.0, 10.0, 1.0}, red},
{ {4.0, 0.0, 10.0, 1.0}, blue},
};
int lightState[8] = {1, 1, 1, 1, 1, 1, 1, 1};
/* *INDENT-ON* */
#define MAX_LIGHTS (sizeof(linfo)/sizeof(linfo[0]))
int moving = 0, begin;
GLfloat angle = 0.0;
int object = M_SPHERE;
int attenuation = M_QUAD;
GLfloat t = 0.0;
void
initLight(int num)
{
glLightf(GL_LIGHT0 + num, GL_CONSTANT_ATTENUATION, 0.0);
if (attenuation == M_LINEAR) {
glLightf(GL_LIGHT0 + num, GL_LINEAR_ATTENUATION, 0.4);
glLightf(GL_LIGHT0 + num, GL_QUADRATIC_ATTENUATION, 0.0);
} else {
glLightf(GL_LIGHT0 + num, GL_LINEAR_ATTENUATION, 0.0);
glLightf(GL_LIGHT0 + num, GL_QUADRATIC_ATTENUATION, 0.1);
}
glLightfv(GL_LIGHT0 + num, GL_SPECULAR, dim);
}
/* Draw a sphere the same color as the light at the light position so it is
easy to tell where the positional light sources are. */
void
drawLight(LightInfo * info)
{
glPushMatrix();
glTranslatef(info->xyz[0], info->xyz[1], info->xyz[2]);
glColor3fv(info->rgb);
glCallList(DL_LIGHT_SPHERE);
glPopMatrix();
}
/* Place the light's OpenGL light number next to the light's sphere. To
ensure a readable number with good contrast, a black version of the number
is drawn shifted a pixel to the left and right of the actual white number.
*/
void
labelLight(LightInfo * info, int num)
{
GLubyte nothin = 0;
void *font = GLUT_BITMAP_HELVETICA_18;
int width = glutBitmapWidth(font, '0' + num);
glPushMatrix();
glColor3f(0.0, 0.0, 0.0);
glRasterPos3f(info->xyz[0], info->xyz[1], info->xyz[2]);
glBitmap(1, 1, 0, 0, 4, 5, ¬hin);
glutBitmapCharacter(font, '0' + num);
glBitmap(1, 1, 0, 0, 2 - width, 0, ¬hin);
glutBitmapCharacter(font, '0' + num);
if (lightState[num]) {
glColor3fv(white);
} else {
/* Draw disabled lights dimmer. */
glColor3fv(dim);
}
glRasterPos3f(info->xyz[0], info->xyz[1], info->xyz[2]);
glBitmap(1, 1, 0, 0, 5, 5, ¬hin);
glutBitmapCharacter(font, '0' + num);
glPopMatrix();
}
/* Comparison routine used by qsort. */
int
lightBrightnessCompare(const void *a, const void *b)
{
LightBrightness *ld1 = (LightBrightness *) a;
LightBrightness *ld2 = (LightBrightness *) b;
GLfloat diff;
/* The brighter lights get sorted close to top of the list. */
diff = ld2->brightness - ld1->brightness;
if (diff > 0)
return 1;
if (diff < 0)
return -1;
return 0;
}
void
display(void)
{
int i;
GLfloat x, y, z;
LightBrightness ld[MAX_LIGHTS];
int start, end;
if (timeFrames) {
start = glutGet(GLUT_ELAPSED_TIME);
}
x = cos(t * 12.3) * 2.0;
y = 0.0;
z = sin(t) * 7.0;
for (i = 0; i < MAX_LIGHTS; i++) {
GLfloat dx, dy, dz;
GLfloat quadraticAttenuation;
/* Calculate object to light position vector. */
dx = (linfo[i].xyz[0] - x);
dy = (linfo[i].xyz[1] - y);
dz = (linfo[i].xyz[2] - z);
quadraticAttenuation = dx * dx + dy * dy + dz * dz;
if (brightnessModel == M_LAMBERTIAN) {
/* Lambertian surface-based brightness determination. */
GLfloat ex, ey, ez;
GLfloat nx, ny, nz;
GLfloat distance;
GLfloat diffuseReflection;
/* Determine eye point location (remember we can rotate by angle). */
ex = 16.0 * sin(angle * M_PI / 180.0);
ey = 1.0;
ez = 16.0 * -cos(angle * M_PI / 180.0);
/* Calculated normalized object to eye position direction (nx,ny,nz). */
nx = (ex - x);
ny = (ey - y);
nz = (ez - z);
distance = sqrt(nx * nx + ny * ny + nz * nz);
nx = nx / distance;
ny = ny / distance;
nz = nz / distance;
/* True distance needed, take square root. */
distance = sqrt(quadraticAttenuation);
/* Calculate normalized object to light postition direction (dx,dy,dz).
*/
dx = dx / distance;
dy = dy / distance;
dz = dz / distance;
/* Dot product of object->eye and object->light source directions.
OpenGL's lighting equations actually force the diffuse contribution
to be zero if the dot product is less than zero. For our purposes,
that's too strict since we are approximating the entire object with
a single object-to-eye normal. */
diffuseReflection = nx * dx + ny * dy + nz * dz;
if (attenuation == M_QUAD) {
/* Attenuate based on square of distance. */
ld[i].brightness = diffuseReflection / quadraticAttenuation;
} else {
/* Attenuate based on linear distance. */
ld[i].brightness = diffuseReflection / distance;
}
} else {
/* Distance-based brightness determination. */
/* In theory, we are really determining brightness based on just the
linear distance of the light source, but since we are just doing
comparisons, there is no reason to waste time doing a square root. */
/* Negation makes sure closer distances are "bigger" than further
distances for sorting. */
ld[i].brightness = -quadraticAttenuation;
}
ld[i].num = i;
}
/* Sort the lights so that the "brightest" are listed first. We really
want to just determine the first numActiveLights so a full sort is
overkill. */
qsort(ld, MAX_LIGHTS, sizeof(ld[0]), lightBrightnessCompare);
if (reportLightSignificance) {
printf("\n");
for (i = 0; i < MAX_LIGHTS; i++) {
printf("%d: dist = %g\n", ld[i].num, ld[i].brightness);
}
}
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glPushMatrix();
glRotatef(angle, 0.0, 1.0, 0.0);
glDisable(GL_LIGHTING);
for (i = 0; i < MAX_LIGHTS; i++) {
drawLight(&linfo[i]);
}
/* After sorting, the first numActiveLights (ie, <8) light sources are the
light sources with the biggest contribution to the object's lighting.
Assign these "virtual lights of significance" to OpenGL's actual
available light sources. */
glEnable(GL_LIGHTING);
for (i = 0; i < numActiveLights; i++) {
if (lightState[i]) {
int num = ld[i].num;
glLightfv(GL_LIGHT0 + i, GL_POSITION, linfo[num].xyz);
glLightfv(GL_LIGHT0 + i, GL_DIFFUSE, linfo[num].rgb);
glEnable(GL_LIGHT0 + i);
} else {
glDisable(GL_LIGHT0 + i);
}
}
glPushMatrix();
glTranslatef(x, y, z);
switch (object) {
case M_SPHERE:
glCallList(DL_BIG_SPHERE);
break;
case M_ICO:
glCallList(DL_ICO);
break;
}
glPopMatrix();
if (labelLights) {
glDisable(GL_DEPTH_TEST);
glDisable(GL_LIGHTING);
for (i = 0; i < numActiveLights; i++) {
labelLight(&linfo[ld[i].num], i);
}
glEnable(GL_DEPTH_TEST);
}
glPopMatrix();
if (timeFrames) {
glFinish();
end = glutGet(GLUT_ELAPSED_TIME);
printf("Speed %.3g frames/sec (%d ms)\n",
1000.0 / (end - start), end - start);
}
if (!singleBuffer) {
glutSwapBuffers();
}
}
void
idle(void)
{
t += 0.005;
glutPostRedisplay();
}
/* When not visible, stop animating. Restart when visible again. */
static void
visible(int vis)
{
if (vis == GLUT_VISIBLE) {
if (animation)
glutIdleFunc(idle);
} else {
if (!animation)
glutIdleFunc(NULL);
}
}
/* Press any key to redraw; good when motion stopped and performance
reporting on. */
/* ARGSUSED */
static void
key(unsigned char c, int x, int y)
{
int i;
switch (c) {
case 27:
exit(0); /* IRIS GLism, Escape quits. */
break;
case ' ':
animation = 1 - animation;
if (animation)
glutIdleFunc(idle);
else
glutIdleFunc(NULL);
break;
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
lightState[c - '0'] = 1 - lightState[c - '0'];
break;
case 13:
for (i = 0; i < numActiveLights; i++) {
lightState[i] = 1;
}
break;
}
glutPostRedisplay();
}
/* ARGSUSED3 */
void
mouse(int button, int state, int x, int y)
{
if (button == GLUT_LEFT_BUTTON && state == GLUT_DOWN) {
moving = 1;
begin = x;
}
if (button == GLUT_LEFT_BUTTON && state == GLUT_UP) {
moving = 0;
}
}
/* ARGSUSED1 */
void
motion(int x, int y)
{
if (moving) {
angle = angle + (x - begin);
begin = x;
glutPostRedisplay();
}
}
void
menu(int value)
{
int i;
switch (value) {
case M_SPHERE:
object = M_SPHERE;
break;
case M_ICO:
object = M_ICO;
break;
case M_LABELS:
labelLights = 1 - labelLights;
break;
case M_LINEAR:
case M_QUAD:
attenuation = value;
for (i = 0; i < numActiveLights; i++) {
initLight(i);
}
break;
case M_REPORT_SIG:
reportLightSignificance = 1 - reportLightSignificance;
break;
case M_LAMBERTIAN:
brightnessModel = M_LAMBERTIAN;
glutSetWindowTitle("multilight (Lambertian-based)");
break;
case M_DISTANCE:
brightnessModel = M_DISTANCE;
glutSetWindowTitle("multilight (Distance-based)");
break;
case M_TIME:
timeFrames = 1 - timeFrames;
break;
case 666:
exit(0);
}
glutPostRedisplay();
}
int
main(int argc, char **argv)
{
int i;
glutInitWindowSize(400, 200);
glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH | GLUT_MULTISAMPLE);
glutInit(&argc, argv);
for (i = 1; i < argc; i++) {
if (!strcmp("-sb", argv[i])) {
glutInitDisplayMode(GLUT_RGB | GLUT_DEPTH | GLUT_MULTISAMPLE);
singleBuffer = 1;
}
}
glutCreateWindow("multilight");
glClearColor(0.0, 0.0, 0.0, 0.0);
glMatrixMode(GL_PROJECTION);
gluPerspective(50.0, 2.0, 0.1, 100.0);
glMatrixMode(GL_MODELVIEW);
gluLookAt(
0.0, 1.0, -16.0,
0.0, 0.0, 0.0,
0.0, 1.0, 0.);
numActiveLights = MIN_VALUE(MAX_LIGHTS, 8);
for (i = 0; i < numActiveLights; i++) {
initLight(i);
}
glLightModelfv(GL_LIGHT_MODEL_AMBIENT, modelAmb);
glLightModelf(GL_LIGHT_MODEL_LOCAL_VIEWER, GL_TRUE);
glLightModelf(GL_LIGHT_MODEL_TWO_SIDE, GL_FALSE);
glEnable(GL_CULL_FACE);
glEnable(GL_DEPTH_TEST);
glMaterialfv(GL_FRONT, GL_AMBIENT, matAmb);
glMaterialfv(GL_FRONT, GL_DIFFUSE, matDiff);
glMaterialfv(GL_FRONT, GL_SPECULAR, matSpec);
glMaterialfv(GL_FRONT, GL_EMISSION, matEmission);
glMaterialf(GL_FRONT, GL_SHININESS, 10.0);
glNewList(DL_LIGHT_SPHERE, GL_COMPILE);
glutSolidSphere(0.2, 4, 4);
glEndList();
glNewList(DL_BIG_SPHERE, GL_COMPILE);
glutSolidSphere(1.5, 20, 20);
glEndList();
glNewList(DL_ICO, GL_COMPILE);
glutSolidIcosahedron();
glEndList();
glutDisplayFunc(display);
glutVisibilityFunc(visible);
glutKeyboardFunc(key);
glutMouseFunc(mouse);
glutMotionFunc(motion);
glutCreateMenu(menu);
glutAddMenuEntry("Sphere", M_SPHERE);
glutAddMenuEntry("Icosahedron", M_ICO);
glutAddMenuEntry("Linear attenuation", M_LINEAR);
glutAddMenuEntry("Quadratic attenuation", M_QUAD);
glutAddMenuEntry("Toggle Light Number Labels", M_LABELS);
glutAddMenuEntry("Report Light Significance", M_REPORT_SIG);
glutAddMenuEntry("Lambertian-based Significance", M_LAMBERTIAN);
glutAddMenuEntry("Distance-based Significance", M_DISTANCE);
glutAddMenuEntry("Time Frames", M_TIME);
glutAddMenuEntry("Quit", 666);
glutAttachMenu(GLUT_RIGHT_BUTTON);
glutMainLoop();
return 0; /* ANSI C requires main to return int. */
}
ΓòÉΓòÉΓòÉ 2.6. An OpenGL-based API for texture mapped text ΓòÉΓòÉΓòÉ
A Simple OpenGL-based API for Texture Mapped Text
Look around you. Most of the human-made surfaces around you probably have
writing on them. Written text is pervasive in our world. Many 3D games and
other 3D applications suffer from the lack of readable text within the 3D
scenes they render.
Text in scenes adds a real-world richness. Particularly in 3D games, text can
convey immersive information. For example, the proverbial writing on the wall
may really say "Death lies beyond this corner." The game player will probably
do well to take the clue.
So how does a 3D programmer add text into 3D scenes? Good 3D text rendering
must be fast but also flexible so that it can be projected, scaled, and rotated
as required. This sounds like a job for texture mapping, particularly when
accelerated by 3D graphics hardware. As we will see, it is.
Basics of Texture Mapping Text
Texture mapping is well suited for rendering text because textures can be
rendered quickly with current 3D hardware and even via clever programming of
today's fast CPUs. Textures can be stretched. rotated, scaled, and even
projected (assuming the texture mapping is perspective correct) so that texture
mapped text looks reasonable in 3D scenes. Other text rendering techniques are
drawing bitmaps, rendering characters as connected lines (stroke fonts), or
rendering as polygons (outline fonts). Bitmaps are fast but do not rotate,
scale, or project well. Stroke and outline fonts tend to render slowly (more
transformation overhead) and are somewhat hard to adapt to the varying levels
of detail in 3D scenes.
A naive approach would treat every word or phrase written on every single
surface as a distinct texture. This would let you add text to your scene, but
it is expensive because of the amount of texture images that would be required
for lots of text. Additionally, the text would be static. If the only text in
your scene is only a couple objects like traffic signs (Stop, Yield, etc.),
static textures with text may be fine, but the real world has a lot more
variety. A static textures containing text do not handle situations like
chalkboards (dynamic text) or books (lots and lots of text).
From a graphics standpoint, if you think about what text is, text consists of
sequences of letters (or characters or glyphs) decalled on a surface. Instead
of treating every instance of text as a separate texture, what if we could
render text from a set of characters. In 2D graphics, you are used to having a
font (or character set) from which you render text. Imagine the same thing in
3D.
Again, there is a naive approach to avoid. Say we created a texture for each
glyph in a font. That would work, but that would be a lot of textures. Plus,
texture mapping hardware generally adds a cost to switching textures. If you
switch textures too fast, you are probably wasting performance. Instead, let's
keep all the glyphs in a font (or at least all the ones we plan on actually
using) in a single texture. Then, when we render different characters in a line
of text, we just change our texture coordinates to match where that character
resides in our single texture map. Does this really work? Yes.
An Example
Here is an example (the full source code for this example and the texture data
are available on-line, see below):
Notice that the text is rotated, projected, differently scaled, decalled on a
3D surface, and color is varied across the text reading "3D". It looks pretty
nice. A bonus is that all the rendering operations for texture mapped text are
accelerated by good OpenGL hardware.
The scene above is all drawn with a single texture. So what does the texture
map look like? Check it out:
Notice that you can find all the glyphs in the 3D scene within the texture
image (that shouldn't be too surprising).
A two questions are worth answering. The first question is about the background
color. The second question is about the foreground color.
About the Background Color
First, what about the background color? In the texture, the background color is
black, but there is no black in the text or on the cube. What happened? Well,
the texture isn't really a simple black & white texture. The texture actually
uses OpenGL's GL_INTENSITY texture format. The GL_INTENSITY format has both
luminance (grayness) and alpha (transparency) information, but the luminance
and alpha values at every texel are the same. This texture format turns out to
be ideal for texture mapped text.
GL_INTENSITY textures do not take up much space compared to other texture
formats. That's good since it leaves more texture memory for other fonts and
other color textures. We don't want to waste valuable texture memory if we can
avoid it.
So white areas of the texture have a luminance value of 1.0 (white) and an
alpha value of 1.0 (fully opaque, not transparent); the black areas have a
luminance value of 0.0 (black) and an alpha value 0.0 (fully transparent). The
alpha component lets us do two nice things: first, with OpenGL alpha testing,
we can avoid drawing pixels below a certain threshold. You can't tell in the
scene above because alpha testing is enabled, but each character is really a
single 3D rectangle. Alpha testing only allows the glyph pixels to get updated.
Let me show you what I mean. The scene below is almost the same as the one
above, except I've disabled alpha testing so you can see the actual textured
rectangles that are being drawn:
Maybe now this wondering about the background makes more sense! Of course, you
already know the answer now. Alpha testing has eliminated every texture pixel
with an alpha of less than 0.5. That means all the background texels get
discarded so that you don't see any ugly black in the correct initial version
of the scene.
We can actually do a little better than that. We can use alpha blending to
actually blend the texels in with the underlying surface (the green cube). But
the alpha component in the texture was 1.0 for the foreground of each
character? Why would we want to blend then when basic blending with an alpha of
1.0 is just a replace? Well, if we use improved texture filtering (say
GL_LINEAR or better), the texture filtering will give us alpha values between
1.0 and 0.0 so blending makes sense. Let's see a magnified view of the scene
with high-quality texture filtering and alpha blending enabled:
Wow, the edges of the text actually look nicely antialiased! By combining
several OpenGL features (alpha blending, alpha testing, intensity textures, and
high-quality texture filtering), we can get very nice looking 3D text.
As an aside, consider if we tried the above in Direct3D. Uh, wouldn't really
work that well. Why? First off, as best as I can tell (the documentation is so
poor), Direct3D does not support an intensity texture format. If that is indeed
true (I believe it is), you'll end up using way more texture memory than an
OpenGL 1.1 program would. Indeed, I believe Direct3D only supports RGB and RGBA
textures according to the documentation I have. Since texture mapped text must
have an alpha component (the A), the texture would be FOUR times bigger than
what we really need if we use OpenGL's GL_INTENSITY. That's bad, particularly
on consumer 3D graphics hardware cards were texture memory is a very limited
resource. And Microsoft claims Direct3D is good for low-end 3D games on
inexpensive hardware! Also, the alpha testing and alpha blending capabilities
we use (alpha testing is vital!) may not be supported on all Direct3D
implementations. If a card doesn't have alpha testing, users of your game or 3D
application with that card will be mighty unhappy (either they get slow
performance or bad artifacts). You'll have to probe Direct3D's poorly defined
capability bits to figure out if you can use alpha testing or not (see
dwAlphaCmpCaps). If this sounds like a criticism of Direct3D, it is (though a
purely technical one).
About the Foreground Color
Second, the foreground color for the text is blue, not white like in the
texture shown above. How did that happen? Be happy it's not white because you
probably don't want just pure white text everywhere. It happens that OpenGL
allows the current color (post-lighting) to be modulated with the texture
color. So in the scene above, the blue letters are drawn with the current color
set to (0.2, 0.2, 0.9) RGB (nice blue). This color vector gets multiplied
(modulated) by the texel color (post-texture filtering). This means the 1.0
luminance values end up with the same blue color. With high-quality texture
filtering enabled, you'll actually get less blue around the edges of characters
which is good for the antialiasing shown above.
Also, if you look at the letters "3D" on the left side of the first scene,
you'll actually see the color smoothly varying from red at the top to blue at
the bottom. This nice effect falls out by just specifying red at the top
vertices of each glyph textured rectangle and blue at the bottom vertices of
the rectangles. OpenGL's smooth shading takes care of interpolating (easing
between) the two colors. It adds a nice effect.
One important issue is avoiding depth buffer artifacts when decalling glyphs
onto a surface. If you are not careful, the plane of the surface and the plane
of the glyph will have nearly identical depth buffer values and they will
"fight" so that the glyphs will only appear some of the time. The solution is
to use OpenGL's polygon offset functionality to "lift" the glyph slightly above
the surface in depth buffer precision. Here is what can happen without polygon
offset:
The previous example images all are use polygon offset to lift the textured
glyphs off the surface to avoid the sort of depth buffer precision artifacts
shown in the above image.
What about Direct3D? Again, Direct3D is not be up to the task. You'd have the
query Direct3D's dwTextureBlendCaps capability bits to see if
D3DPTBLENDCAPS_MODULATE was supported. What if this capability is not
supported? Then kiss fast modulation of your textured text color goodbye. The
polygon offset capability of OpenGL 1.1 is not even supported by Direct3D. You
might be able to avoid the decalling artifacts by offsetting the textured
glyphs in object space, but that can introduce other artifacts.
Making 3D Texture Mapped Text Easy with a Simple OpenGL-based API
So the above pictures and images sound promising. But isn't texture mapping
hard and how exactly would you manage to construct a texture image like the one
shown above? Do not worry. The explanation that follows shows you both how to
use texture mapped fonts with OpenGL and how to generate font texture images
for your applications. All the source code for the API shown and example
programs described here are available for free.
So how does the program pictured above render texture mapped fonts? It uses a
very simple API that I developed. The API lets you load a texture font file (a
.txf file) and then start rendering textured fonts with it. All the routines in
the API begin with txf (for TeXtured Font).
Start at the beginning. Here's how your would load a texture font file:
TexFont *txf;
txf = txfLoadFont("rockfont.txf");
if (txf == NULL) {
fprintf(stderr, "Problem loading %s, %s\n",
filename, txfErrorString());
exit(1);
}
Pretty easy. What does that do? It opens and loads the texture font (shown
above). The texture font includes both the texture image and (very
importantly) all the texture coordinates for the glyphs contained in the
texture image. Obviously, we'll need to be able to tell where the various
glyphs are within the texture when assigning texture coordinates for the
textured glyphs we draw later.
Now, you actually need to establish the texture for the font. This involves
setting up a texture object (or a display list for OpenGL 1.0 without the
texture object extension) containing the font's texture image. Make sure you
are current to an OpenGL rendering context and then call:
txfEstablishTexture(txf, 0, GL_TRUE);
This routine tells OpenGL to make a texture object and let OpenGL assign the
texture object number (what the zero means) and create mipmaps to allow
higher-quality texture filtering (what GL_TRUE means). You could specify the
specific texture object number by passing a positive integer to
txfEstablishTexture instead of zero. You could save a bit of texture memory
(25%) by not creating mipmaps and specifying GL_FALSE.
Now, setup some OpenGL state and you'll be ready to render with textured text:
glEnable(GL_TEXTURE_2D);
glAlphaFunc(GL_GEQUAL, 0.0625);
glEnable(GL_ALPHA_TEST);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glEnable(GL_POLYGON_OFFSET);
glPolygonOffset(0.0, -3);
That enabled 2D texture mapping, enables alpha testing to drop fragments that
are fairly close to a 0.0 alpha value, enables blending for nice edges. We
could skip the blending for better performance, but not get the nice edges.
Now, figure out how long the string you want to render is. Say you want to
render the string "OpenGL" (a good choice since all the letters are in the
rockfont.txf texture image) on a 5 by 5 unit square centered at the origin of
our modeling coordinate system. We want to know the length so that we can scale
to text to fit in our 3D scene correctly. Figure the "OpenGL" text metrics like
this:
int width, ascent, descent;
text = "OpenGL";
txfGetStringMetrics(txf, text, strlen(text),
&width, &ascent, &descent);
The width is 351 units (the ascent above the baseline is 75 units, the descent
below the baseline is 32 units). This means to perfectly fit the text on the 5
by 5 unit square, we'll need to scale the text by 5/351 before rendering and
then translate it over 2.5 units (after the scaling). That is easy with
OpenGL's modeling matrix manipulation routines:
glMatrixMode(GL_MODELVIEW);
glTranslatef(-2.5, 0.0, 0.0);
glScalef(5.0/width, 5.0/width, 5.0/width);
Now, we just render the texture mapped text:
txfRenderString(txf, "OpenGL", strlen("OpenGL");
Pretty easy. The fancy effects like making a circle from the words "OpenGL
OpenGL" is not much harder. You just do a slight rotate with glRotatef after
rendering each character. A routine called txfRenderFancyString lets you embed
"escape" sequences in strings to control character coloration effects like the
smooth shading in the word "3D" in the images above.
Show Me the Source Code!
The TXF texture mapped font API is implemented by texfont.c; the API uses the
TexFont.h header file.
The program shown above is txfdemo.c; a simpler TXF program showing rotating
text is simpletxf.c. The program to show the complete glyph set texture image
for a .txf file is showtxf.c. Check out the source code.
You'll want a few TXF texture font files. I'll supply a few .txf files that
you can download: rockfont.txf, curlfont.txf , default.txf, haeberli.txf and
sorority.txf (be sure to download these to a file; you can't view them with
your browser; use Shift-LeftClick in Netscape to download). Each font is just
over 8 kilobytes. Below is what the sorority.txf font (designed by Paul
Haeberli of SGI) looks like:
Notice that this font has a lot more useful characters that the rockfont.txf
font. Of course, the glyphs in the font are at a lower resolution.
Generating Your Own Textured Font Files
If you use TXF for a limited set of glyphs (say just the capital letters and
numbers), you can generate your own .txf files for just the characters your
application needs. Since your 3D game or other 3D application may have fairly
limited text rendering requirements and use a small set of glyphs, you can
generate a .txf file with the characters at higher resolutions. Obviously, the
characters in Paul's Sorority font shown above won't look very good if they get
heavily scaled up. More resolution in the texture image would help.
So how can you generate your own .txf files? Use the gentexfont utility. This
X11-based utility lets you read glyphs from fonts available on any standard X
server and combine them together into a texture image. This image and the
associated glyph metrics are then written out in a .txf file that you can then
load and use with the TXF API described and supplied above.
Here is the source code for gentexfont.c. While the program is X-based (I am
not a Windows programmer, sorry), I'm sure someone could convert the program to
convert standard Microsoft Windows fonts into .txf files. It doesn't matter how
you generate the .txf files though. You can use .txf files generated by the
X-based gentexfont program on Windows machines.
Here's an example of the command used to generate the sorority.txf file:
gentexfont \
-fn '-sgi-sorority-medium-r-normal--40-*-*-*-p-*--ascii' \
-file sorority.txf \
-glist \
'`"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMN\
OPQRSTUVWXYZ01234567890 \!@#$$%^&*()-=+/,.<>;:~{}[]' \
-bitmap \
-w 256 \
-h 256 \
-gap 3
The font is specific to SGI X servers, so don't expect to find the sorority
font on non-SGI X servers. The -fn option names the X font to capture. The
-file option says what filename to save the .txf file as. The -glist option
lists all the glyphs you want captured (you can duplicate characters on the
lists; be sure to include space). The -bitmap option says to save in the
compact bitmap format (instead of -byte). The -w and -h options specify the
width and height of the texture image. The -gap option specifies the gap in
texels between each glyph in the texture image.
A little advice. You can generally fit an entire character set in a 256 by 256
texture. (32 kilobytes in OpenGL's 4-bit per pixel GL_INTENSITY4 internal
texture format). You can try cramming glyphs into 128 by 128 textures, but
you'll probably have to leave out characters to get things to fit (or be at a
tiny glyph resolution). Increasing the texel gap beyond 1 is worthwhile if you
plan on using mipmapping with your fonts (see the next section).
Room for Improvement
In the digital image processing world, a texture containing text glyphs would
be said to have "high frequency" data. That means good texture filtering for
fonts is hard. For fonts to be readable, people like them to be very sharp
(high contrast). This raises issues for texture sampling and filtering. In
general, things work pretty well, but you should be aware that textured fonts
can look pixelized when highly scaled. A GL_LINEAR magnify texture filter can
help a little bit, but it may make the edges of characters look a little blurry
and they will still look pixelized at high enough resolutions. You can play
with the "Filtering" pop-up submenu in txfdemo to see how different filtering
options affect text sharpness, bluriness, and in the end, readability.
Mipmapping of glyph texture images can be particularly troublesome. To
construct the smaller levels of detail, you have to decimate the larger levels
of details. The problem is that with conventional texture filtering, texels
from one glyph can "bleed" into another glyph as you decimate. You could avoid
some of the problem by implementing a fancy mipmap filter that is more "aware"
of glyph boundaries, but eventually you get down to a 1 by 1 level of detail
and all the glyphs bleed into a single pixel (even before that, things are
pretty bad). In general, when glyphs start to use the smaller levels of detail
when mipmapping, the text probably isn't going to be readable no matter what so
you don't need to be overly concerned. You can help things by adding a larger
texel gap with the -gap option to gentexfont but this steals some space that
could have been used for more glyphs (you make the tradeoff).
Better texture filtering (anisotropic filtering) could provide better quality
for very "edge on" text (like words written on a road far in the distance
viewed by a driver), but it is generally slower and more expensive than
conventional mipmapped filtering. Almost no current 3D graphics hardware for
PCs and workstations does anisotropic filtering. For most games and other 3D
applications, most text that needs reading is generally viewed reasonably
straight on. Even with better filtering, "edge on" text can still be hard to
read.
Conclusions
I hope that you find this discussion and the associated source code
interesting. Texture mapped fonts can add a whole new level of realism to 3D
games and other applications. Unfortunately, Microsoft's self-proclaimed
"consumer 3D" API is actually quite poor at rendering with the techniques
described. Direct3D lacks an intensity texture format; lacks guaranteed alpha
testing, alpha blending and texture modulation; and lacks OpenGL's polygon
offset functionality - all needed for good text texture mapping. On the other
hand, OpenGL 1.1 is extremely well suited for fast, reasonable quality texture
mapped fonts. Happy font rendering.
Mark Kilgard (mjk@sgi.com)
Silicon Graphics
ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ
Title page | Contents
ΓòÉΓòÉΓòÉ 2.6.1. texfont.c ΓòÉΓòÉΓòÉ
/* Copyright (c) Mark J. Kilgard, 1997. */
/* This program is freely distributable without licensing fees and is
provided without guarantee or warrantee expressed or implied. This
program is -not- in the public domain. */
#include <assert.h>
#include <ctype.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <GL/glu.h>
#include "TexFont.h"
#if 0
/* Uncomment to debug various scenarios. */
#undef GL_VERSION_1_1
#undef GL_EXT_texture_object
#undef GL_EXT_texture
#endif
#ifndef GL_VERSION_1_1
#if defined(GL_EXT_texture_object) && defined(GL_EXT_texture)
#define glGenTextures glGenTexturesEXT
#define glBindTexture glBindTextureEXT
#ifndef GL_INTENSITY4
#define GL_INTENSITY4 GL_INTENSITY4_EXT
#endif
int useLuminanceAlpha = 0;
#else
#define USE_DISPLAY_LISTS
/* Intensity texture format not in OpenGL 1.0; added by the EXT_texture
extension and now part of OpenGL 1.1. */
int useLuminanceAlpha = 1;
#endif
#else
int useLuminanceAlpha = 0;
#endif
/* byte swap a 32-bit value */
#define SWAPL(x, n) { \
n = ((char *) (x))[0];\
((char *) (x))[0] = ((char *) (x))[3];\
((char *) (x))[3] = n;\
n = ((char *) (x))[1];\
((char *) (x))[1] = ((char *) (x))[2];\
((char *) (x))[2] = n; }
/* byte swap a short */
#define SWAPS(x, n) { \
n = ((char *) (x))[0];\
((char *) (x))[0] = ((char *) (x))[1];\
((char *) (x))[1] = n; }
static TexGlyphVertexInfo *
getTCVI(TexFont * txf, int c)
{
TexGlyphVertexInfo *tgvi;
/* Automatically substitute uppercase letters with lowercase if not
uppercase available (and vice versa). */
if ((c >= txf->min_glyph) && (c < txf->min_glyph + txf->range)) {
tgvi = txf->lut[c - txf->min_glyph];
if (tgvi) {
return tgvi;
}
if (islower(c)) {
c = toupper(c);
if ((c >= txf->min_glyph) && (c < txf->min_glyph + txf->range)) {
return txf->lut[c - txf->min_glyph];
}
}
if (isupper(c)) {
c = tolower(c);
if ((c >= txf->min_glyph) && (c < txf->min_glyph + txf->range)) {
return txf->lut[c - txf->min_glyph];
}
}
}
fprintf(stderr, "texfont: tried to access unavailable font character \"%c\" (%d)\n",
isprint(c) ? c : ' ', c);
abort();
/* NOTREACHED */
}
static char *lastError;
char *
txfErrorString(void)
{
return lastError;
}
TexFont *
txfLoadFont(char *filename)
{
TexFont *txf;
FILE *file;
GLfloat w, h, xstep, ystep;
char fileid[4], tmp;
unsigned char *texbitmap;
int min_glyph, max_glyph;
int endianness, swap, format, stride, width, height;
int i, j, got;
txf = NULL;
file = fopen(filename, "rb");
if (file == NULL) {
lastError = "file open failed.";
goto error;
}
txf = (TexFont *) malloc(sizeof(TexFont));
if (txf == NULL) {
lastError = "out of memory.";
goto error;
}
/* For easy cleanup in error case. */
txf->tgi = NULL;
txf->tgvi = NULL;
txf->lut = NULL;
txf->teximage = NULL;
got = fread(fileid, 1, 4, file);
if (got != 4 || strncmp(fileid, "\377txf", 4)) {
lastError = "not a texture font file.";
goto error;
}
assert(sizeof(int) == 4); /* Ensure external file format size. */
got = fread(&endianness, sizeof(int), 1, file);
if (got == 1 && endianness == 0x12345678) {
swap = 0;
} else if (got == 1 && endianness == 0x78563412) {
swap = 1;
} else {
lastError = "not a texture font file.";
goto error;
}
#define EXPECT(n) if (got != n) { lastError = "premature end of file."; goto error; }
got = fread(&format, sizeof(int), 1, file);
EXPECT(1);
got = fread(&txf->tex_width, sizeof(int), 1, file);
EXPECT(1);
got = fread(&txf->tex_height, sizeof(int), 1, file);
EXPECT(1);
got = fread(&txf->max_ascent, sizeof(int), 1, file);
EXPECT(1);
got = fread(&txf->max_descent, sizeof(int), 1, file);
EXPECT(1);
got = fread(&txf->num_glyphs, sizeof(int), 1, file);
EXPECT(1);
if (swap) {
SWAPL(&format, tmp);
SWAPL(&txf->tex_width, tmp);
SWAPL(&txf->tex_height, tmp);
SWAPL(&txf->max_ascent, tmp);
SWAPL(&txf->max_descent, tmp);
SWAPL(&txf->num_glyphs, tmp);
}
txf->tgi = (TexGlyphInfo *) malloc(txf->num_glyphs * sizeof(TexGlyphInfo));
if (txf->tgi == NULL) {
lastError = "out of memory.";
goto error;
}
assert(sizeof(TexGlyphInfo) == 12); /* Ensure external file format size. */
got = fread(txf->tgi, sizeof(TexGlyphInfo), txf->num_glyphs, file);
EXPECT(txf->num_glyphs);
if (swap) {
for (i = 0; i < txf->num_glyphs; i++) {
SWAPS(&txf->tgi[i].c, tmp);
SWAPS(&txf->tgi[i].x, tmp);
SWAPS(&txf->tgi[i].y, tmp);
}
}
txf->tgvi = (TexGlyphVertexInfo *)
malloc(txf->num_glyphs * sizeof(TexGlyphVertexInfo));
if (txf->tgvi == NULL) {
lastError = "out of memory.";
goto error;
}
w = txf->tex_width;
h = txf->tex_height;
xstep = 0.5 / w;
ystep = 0.5 / h;
for (i = 0; i < txf->num_glyphs; i++) {
TexGlyphInfo *tgi;
tgi = &txf->tgi[i];
txf->tgvi[i].t0[0] = tgi->x / w + xstep;
txf->tgvi[i].t0[1] = tgi->y / h + ystep;
txf->tgvi[i].v0[0] = tgi->xoffset;
txf->tgvi[i].v0[1] = tgi->yoffset;
txf->tgvi[i].t1[0] = (tgi->x + tgi->width) / w + xstep;
txf->tgvi[i].t1[1] = tgi->y / h + ystep;
txf->tgvi[i].v1[0] = tgi->xoffset + tgi->width;
txf->tgvi[i].v1[1] = tgi->yoffset;
txf->tgvi[i].t2[0] = (tgi->x + tgi->width) / w + xstep;
txf->tgvi[i].t2[1] = (tgi->y + tgi->height) / h + ystep;
txf->tgvi[i].v2[0] = tgi->xoffset + tgi->width;
txf->tgvi[i].v2[1] = tgi->yoffset + tgi->height;
txf->tgvi[i].t3[0] = tgi->x / w + xstep;
txf->tgvi[i].t3[1] = (tgi->y + tgi->height) / h + ystep;
txf->tgvi[i].v3[0] = tgi->xoffset;
txf->tgvi[i].v3[1] = tgi->yoffset + tgi->height;
txf->tgvi[i].advance = tgi->advance;
}
min_glyph = txf->tgi[0].c;
max_glyph = txf->tgi[0].c;
for (i = 1; i < txf->num_glyphs; i++) {
if (txf->tgi[i].c < min_glyph) {
min_glyph = txf->tgi[i].c;
}
if (txf->tgi[i].c > max_glyph) {
max_glyph = txf->tgi[i].c;
}
}
txf->min_glyph = min_glyph;
txf->range = max_glyph - min_glyph + 1;
txf->lut = (TexGlyphVertexInfo **)
calloc(txf->range, sizeof(TexGlyphVertexInfo *));
if (txf->lut == NULL) {
lastError = "out of memory.";
goto error;
}
for (i = 0; i < txf->num_glyphs; i++) {
txf->lut[txf->tgi[i].c - txf->min_glyph] = &txf->tgvi[i];
}
switch (format) {
case TXF_FORMAT_BYTE:
if (useLuminanceAlpha) {
unsigned char *orig;
orig = (unsigned char *) malloc(txf->tex_width * txf->tex_height);
if (orig == NULL) {
lastError = "out of memory.";
goto error;
}
got = fread(orig, 1, txf->tex_width * txf->tex_height, file);
EXPECT(txf->tex_width * txf->tex_height);
txf->teximage = (unsigned char *)
malloc(2 * txf->tex_width * txf->tex_height);
if (txf->teximage == NULL) {
lastError = "out of memory.";
goto error;
}
for (i = 0; i < txf->tex_width * txf->tex_height; i++) {
txf->teximage[i * 2] = orig[i];
txf->teximage[i * 2 + 1] = orig[i];
}
free(orig);
} else {
txf->teximage = (unsigned char *)
malloc(txf->tex_width * txf->tex_height);
if (txf->teximage == NULL) {
lastError = "out of memory.";
goto error;
}
got = fread(txf->teximage, 1, txf->tex_width * txf->tex_height, file);
EXPECT(txf->tex_width * txf->tex_height);
}
break;
case TXF_FORMAT_BITMAP:
width = txf->tex_width;
height = txf->tex_height;
stride = (width + 7) >> 3;
texbitmap = (unsigned char *) malloc(stride * height);
if (texbitmap == NULL) {
lastError = "out of memory.";
goto error;
}
got = fread(texbitmap, 1, stride * height, file);
EXPECT(stride * height);
if (useLuminanceAlpha) {
txf->teximage = (unsigned char *) calloc(width * height * 2, 1);
if (txf->teximage == NULL) {
lastError = "out of memory.";
goto error;
}
for (i = 0; i < height; i++) {
for (j = 0; j < width; j++) {
if (texbitmap[i * stride + (j >> 3)] & (1 << (j & 7))) {
txf->teximage[(i * width + j) * 2] = 255;
txf->teximage[(i * width + j) * 2 + 1] = 255;
}
}
}
} else {
txf->teximage = (unsigned char *) calloc(width * height, 1);
if (txf->teximage == NULL) {
lastError = "out of memory.";
goto error;
}
for (i = 0; i < height; i++) {
for (j = 0; j < width; j++) {
if (texbitmap[i * stride + (j >> 3)] & (1 << (j & 7))) {
txf->teximage[i * width + j] = 255;
}
}
}
}
free(texbitmap);
break;
}
fclose(file);
return txf;
error:
if (txf) {
if (txf->tgi)
free(txf->tgi);
if (txf->tgvi)
free(txf->tgvi);
if (txf->lut)
free(txf->lut);
if (txf->teximage)
free(txf->teximage);
free(txf);
}
if (file)
fclose(file);
return NULL;
}
GLuint
txfEstablishTexture(
TexFont * txf,
GLuint texobj,
GLboolean setupMipmaps)
{
if (txf->texobj == 0) {
if (texobj == 0) {
#if !defined(USE_DISPLAY_LISTS)
glGenTextures(1, &txf->texobj);
#else
txf->texobj = glGenLists(1);
#endif
} else {
txf->texobj = texobj;
}
}
#if !defined(USE_DISPLAY_LISTS)
glBindTexture(GL_TEXTURE_2D, txf->texobj);
#else
glNewList(txf->texobj, GL_COMPILE);
#endif
#if 1
/* XXX Indigo2 IMPACT in IRIX 5.3 and 6.2 does not support the GL_INTENSITY
internal texture format. Sigh. Win32 non-GLX users should disable this
code. */
if (useLuminanceAlpha == 0) {
char *vendor, *renderer, *version;
renderer = (char *) glGetString(GL_RENDERER);
vendor = (char *) glGetString(GL_VENDOR);
if (!strcmp(vendor, "SGI") && !strncmp(renderer, "IMPACT", 6)) {
version = (char *) glGetString(GL_VERSION);
if (!strcmp(version, "1.0 Irix 6.2") ||
!strcmp(version, "1.0 Irix 5.3")) {
unsigned char *latex;
int width = txf->tex_width;
int height = txf->tex_height;
int i;
useLuminanceAlpha = 1;
latex = (unsigned char *) calloc(width * height * 2, 1);
/* XXX unprotected alloc. */
for (i = 0; i < height * width; i++) {
latex[i * 2] = txf->teximage[i];
latex[i * 2 + 1] = txf->teximage[i];
}
free(txf->teximage);
txf->teximage = latex;
}
}
}
#endif
if (useLuminanceAlpha) {
if (setupMipmaps) {
gluBuild2DMipmaps(GL_TEXTURE_2D, GL_LUMINANCE_ALPHA,
txf->tex_width, txf->tex_height,
GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, txf->teximage);
} else {
glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE_ALPHA,
txf->tex_width, txf->tex_height, 0,
GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, txf->teximage);
}
} else {
#if defined(GL_VERSION_1_1) || defined(GL_EXT_texture)
/* Use GL_INTENSITY4 as internal texture format since we want to use as
little texture memory as possible. */
if (setupMipmaps) {
gluBuild2DMipmaps(GL_TEXTURE_2D, GL_INTENSITY4,
txf->tex_width, txf->tex_height,
GL_LUMINANCE, GL_UNSIGNED_BYTE, txf->teximage);
} else {
glTexImage2D(GL_TEXTURE_2D, 0, GL_INTENSITY4,
txf->tex_width, txf->tex_height, 0,
GL_LUMINANCE, GL_UNSIGNED_BYTE, txf->teximage);
}
#else
abort(); /* Should not get here without EXT_texture or OpenGL
1.1. */
#endif
}
#if defined(USE_DISPLAY_LISTS)
glEndList();
glCallList(txf->texobj);
#endif
return txf->texobj;
}
void
txfBindFontTexture(
TexFont * txf)
{
#if !defined(USE_DISPLAY_LISTS)
glBindTexture(GL_TEXTURE_2D, txf->texobj);
#else
glCallList(txf->texobj);
#endif
}
void
txfUnloadFont(
TexFont * txf)
{
if (txf->teximage) {
free(txf->teximage);
}
free(txf->tgi);
free(txf->tgvi);
free(txf->lut);
free(txf);
}
void
txfGetStringMetrics(
TexFont * txf,
char *string,
int len,
int *width,
int *max_ascent,
int *max_descent)
{
TexGlyphVertexInfo *tgvi;
int w, i;
w = 0;
for (i = 0; i < len; i++) {
if (string[i] == 27) {
switch (string[i + 1]) {
case 'M':
i += 4;
break;
case 'T':
i += 7;
break;
case 'L':
i += 7;
break;
case 'F':
i += 13;
break;
}
} else {
tgvi = getTCVI(txf, string[i]);
w += tgvi->advance;
}
}
*width = w;
*max_ascent = txf->max_ascent;
*max_descent = txf->max_descent;
}
void
txfRenderGlyph(TexFont * txf, int c)
{
TexGlyphVertexInfo *tgvi;
tgvi = getTCVI(txf, c);
glBegin(GL_QUADS);
glTexCoord2fv(tgvi->t0);
glVertex2sv(tgvi->v0);
glTexCoord2fv(tgvi->t1);
glVertex2sv(tgvi->v1);
glTexCoord2fv(tgvi->t2);
glVertex2sv(tgvi->v2);
glTexCoord2fv(tgvi->t3);
glVertex2sv(tgvi->v3);
glEnd();
glTranslatef(tgvi->advance, 0.0, 0.0);
}
void
txfRenderString(
TexFont * txf,
char *string,
int len)
{
int i;
for (i = 0; i < len; i++) {
txfRenderGlyph(txf, string[i]);
}
}
enum {
MONO, TOP_BOTTOM, LEFT_RIGHT, FOUR
};
void
txfRenderFancyString(
TexFont * txf,
char *string,
int len)
{
TexGlyphVertexInfo *tgvi;
GLubyte c[4][3];
int mode = MONO;
int i;
for (i = 0; i < len; i++) {
if (string[i] == 27) {
switch (string[i + 1]) {
case 'M':
mode = MONO;
glColor3ubv((GLubyte *) & string[i + 2]);
i += 4;
break;
case 'T':
mode = TOP_BOTTOM;
memcpy(c, &string[i + 2], 6);
i += 7;
break;
case 'L':
mode = LEFT_RIGHT;
memcpy(c, &string[i + 2], 6);
i += 7;
break;
case 'F':
mode = FOUR;
memcpy(c, &string[i + 2], 12);
i += 13;
break;
}
} else {
switch (mode) {
case MONO:
txfRenderGlyph(txf, string[i]);
break;
case TOP_BOTTOM:
tgvi = getTCVI(txf, string[i]);
glBegin(GL_QUADS);
glColor3ubv(c[0]);
glTexCoord2fv(tgvi->t0);
glVertex2sv(tgvi->v0);
glTexCoord2fv(tgvi->t1);
glVertex2sv(tgvi->v1);
glColor3ubv(c[1]);
glTexCoord2fv(tgvi->t2);
glVertex2sv(tgvi->v2);
glTexCoord2fv(tgvi->t3);
glVertex2sv(tgvi->v3);
glEnd();
glTranslatef(tgvi->advance, 0.0, 0.0);
break;
case LEFT_RIGHT:
tgvi = getTCVI(txf, string[i]);
glBegin(GL_QUADS);
glColor3ubv(c[0]);
glTexCoord2fv(tgvi->t0);
glVertex2sv(tgvi->v0);
glColor3ubv(c[1]);
glTexCoord2fv(tgvi->t1);
glVertex2sv(tgvi->v1);
glColor3ubv(c[1]);
glTexCoord2fv(tgvi->t2);
glVertex2sv(tgvi->v2);
glColor3ubv(c[0]);
glTexCoord2fv(tgvi->t3);
glVertex2sv(tgvi->v3);
glEnd();
glTranslatef(tgvi->advance, 0.0, 0.0);
break;
case FOUR:
tgvi = getTCVI(txf, string[i]);
glBegin(GL_QUADS);
glColor3ubv(c[0]);
glTexCoord2fv(tgvi->t0);
glVertex2sv(tgvi->v0);
glColor3ubv(c[1]);
glTexCoord2fv(tgvi->t1);
glVertex2sv(tgvi->v1);
glColor3ubv(c[2]);
glTexCoord2fv(tgvi->t2);
glVertex2sv(tgvi->v2);
glColor3ubv(c[3]);
glTexCoord2fv(tgvi->t3);
glVertex2sv(tgvi->v3);
glEnd();
glTranslatef(tgvi->advance, 0.0, 0.0);
break;
}
}
}
}
int
txfInFont(TexFont * txf, int c)
{
TexGlyphVertexInfo *tgvi;
/* NOTE: No uppercase/lowercase substituion. */
if ((c >= txf->min_glyph) && (c < txf->min_glyph + txf->range)) {
if (txf->lut[c - txf->min_glyph]) {
return 1;
}
}
return 0;
}
ΓòÉΓòÉΓòÉ 2.6.2. TexFont.h ΓòÉΓòÉΓòÉ
/* Copyright (c) Mark J. Kilgard, 1997. */
/* This program is freely distributable without licensing fees and is
provided without guarantee or warrantee expressed or implied. This
program is -not- in the public domain. */
#ifndef __TEXFONT_H__
#define __TEXFONT_H__
#include <GL/gl.h>
#define TXF_FORMAT_BYTE 0
#define TXF_FORMAT_BITMAP 1
typedef struct {
unsigned short c; /* Potentially support 16-bit glyphs. */
unsigned char width;
unsigned char height;
signed char xoffset;
signed char yoffset;
signed char advance;
char dummy; /* Space holder for alignment reasons. */
short x;
short y;
} TexGlyphInfo;
typedef struct {
GLfloat t0[2];
GLshort v0[2];
GLfloat t1[2];
GLshort v1[2];
GLfloat t2[2];
GLshort v2[2];
GLfloat t3[2];
GLshort v3[2];
GLfloat advance;
} TexGlyphVertexInfo;
typedef struct {
GLuint texobj;
int tex_width;
int tex_height;
int max_ascent;
int max_descent;
int num_glyphs;
int min_glyph;
int range;
unsigned char *teximage;
TexGlyphInfo *tgi;
TexGlyphVertexInfo *tgvi;
TexGlyphVertexInfo **lut;
} TexFont;
extern char *txfErrorString(void);
extern TexFont *txfLoadFont(
char *filename);
extern void txfUnloadFont(
TexFont * txf);
extern GLuint txfEstablishTexture(
TexFont * txf,
GLuint texobj,
GLboolean setupMipmaps);
extern void txfBindFontTexture(
TexFont * txf);
extern void txfGetStringMetrics(
TexFont * txf,
char *string,
int len,
int *width,
int *max_ascent,
int *max_descent);
extern void txfRenderGlyph(
TexFont * txf,
int c);
extern void txfRenderString(
TexFont * txf,
char *string,
int len);
extern void txfRenderFancyString(
TexFont * txf,
char *string,
int len);
#endif /* __TEXFONT_H__ */
ΓòÉΓòÉΓòÉ 2.6.3. txfdemo.c ΓòÉΓòÉΓòÉ
/* Copyright (c) Mark J. Kilgard, 1997. */
/* This program is freely distributable without licensing fees and is
provided without guarantee or warrantee expressed or implied. This
program is -not- in the public domain. */
/* X compile line: cc -o txfdemo txfdemo.c -lglut -lGLU -lGL -lXmu -lXext -lX11 -lm */
#include <math.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <GL/glut.h>
#include "TexFont.h"
/* Uncomment to debug various scenarios. */
#if 0
#undef GL_VERSION_1_1
#undef GL_EXT_polygon_offset
#endif
#ifndef GL_VERSION_1_1
#ifdef GL_EXT_polygon_offset
#define GL_POLYGON_OFFSET GL_POLYGON_OFFSET_EXT
#define glPolygonOffset(s,b) glPolygonOffsetEXT(s,b*0.001);
#else
/* Gag. No polygon offset? Artifacts will exist. */
#define glPolygonOffset(s,b) /* nothing */
#endif
#endif
#ifndef M_PI
#define M_PI 3.14159265358979323846
#endif
static int doubleBuffer = 1;
static char *filename = "rockfont.txf";
static GLfloat angle = 20;
static TexFont *txf;
static int usePolygonOffset = 1;
static int animation = 1;
void
idle(void)
{
angle += 4;
glutPostRedisplay();
}
void
visible(int vis)
{
if (vis == GLUT_VISIBLE) {
if (animation) {
glutIdleFunc(idle);
}
} else {
glutIdleFunc(NULL);
}
}
void
cubeSide(void)
{
glDisable(GL_TEXTURE_2D);
glDisable(GL_BLEND);
glDisable(GL_ALPHA_TEST);
glColor3f(0.3, 0.7, 0.3);
glRectf(-1.0, -1.0, 1.0, 1.0);
}
int alphaMode;
void
alphaModeSet(void)
{
switch (alphaMode) {
case GL_ALPHA_TEST:
glDisable(GL_BLEND);
glEnable(GL_ALPHA_TEST);
glAlphaFunc(GL_GEQUAL, 0.5);
break;
case GL_BLEND:
glDisable(GL_ALPHA_TEST);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
break;
case GL_ALPHA_TEST + GL_BLEND:
glEnable(GL_ALPHA_TEST);
glAlphaFunc(GL_GEQUAL, 0.0625);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
break;
case GL_NONE:
glDisable(GL_ALPHA_TEST);
glDisable(GL_BLEND);
break;
}
}
void
cubeSideWithOpenGLcircle(void)
{
int w, ow, a, d;
char *text;
int len;
int i;
GLfloat flen;
cubeSide();
glPushMatrix();
alphaModeSet();
glEnable(GL_TEXTURE_2D);
if (usePolygonOffset) {
#if defined(GL_EXT_polygon_offset) || defined(GL_VERSION_1_1)
glEnable(GL_POLYGON_OFFSET_EXT);
glPolygonOffset(0.0, -3);
#endif
}
glColor3f(0.2, 0.2, 0.9);
txfGetStringMetrics(txf, "OpenGL", 6, &w, &a, &d);
text = "OpenGL OpenGL ";
len = strlen(text);
txfGetStringMetrics(txf, text, len, &w, &a, &d);
txfGetStringMetrics(txf, "O", 1, &ow, &a, &d);
glScalef(5.6/w, 5.6/w, 5.6/w);
flen = len;
glTranslatef(-ow/2.0, -w/(M_PI*2.0), 0.0);
for (i=0; i<len; i++) {
if (text[i] == 'L' && usePolygonOffset) {
/* Hack. The "L" in OpenGL slightly overlaps the "G". Slightly
raise the "L" so that it will overlap the "G" in the depth
buffer to avoid a double blend.. */
glPolygonOffset(0.0, -4);
txfRenderGlyph(txf, text[i]);
glPolygonOffset(0.0, -3);
} else {
txfRenderGlyph(txf, text[i]);
}
glRotatef(360.0/flen, 0, 0, 1);
}
if (usePolygonOffset) {
#if defined(GL_EXT_polygon_offset) || defined(GL_VERSION_1_1)
glDisable(GL_POLYGON_OFFSET_EXT);
#endif
}
glPopMatrix();
}
void
cubeSideWithText(char *text, int len)
{
int w, a, d;
cubeSide();
glPushMatrix();
glEnable(GL_TEXTURE_2D);
alphaModeSet();
if (usePolygonOffset) {
#if defined(GL_EXT_polygon_offset) || defined(GL_VERSION_1_1)
glEnable(GL_POLYGON_OFFSET_EXT);
glPolygonOffset(0.0, -3);
#endif
}
glColor3f(0.2, 0.2, 0.9);
txfGetStringMetrics(txf, text, len, &w, &a, &d);
glScalef(1.8/w, 1.8/w, 1.8/w);
glTranslatef(-w/2.0, d-(a+d)/2.0, 0.0);
txfRenderFancyString(txf, text, len);
if (usePolygonOffset) {
#if defined(GL_EXT_polygon_offset) || defined(GL_VERSION_1_1)
glDisable(GL_POLYGON_OFFSET_EXT);
#endif
}
glPopMatrix();
}
void
display(void)
{
char *str;
/* Clear the color buffer. */
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glPushMatrix();
glRotatef(-angle, 0, 1, 0);
glPushMatrix();
glTranslatef(0.0, 0.0, 1.0);
cubeSideWithOpenGLcircle();
glPopMatrix();
glPushMatrix();
glRotatef(90.0, 0, 1, 0);
glTranslatef(0.0, 0.0, 1.0);
str = "MAkes";
cubeSideWithText(str, strlen(str));
glPopMatrix();
glPushMatrix();
glRotatef(180.0, 0, 1, 0);
glTranslatef(0.0, 0.0, 1.0);
str = "Text";
cubeSideWithText(str, strlen(str));
glPopMatrix();
glPushMatrix();
glRotatef(270.0, 0, 1, 0);
glTranslatef(0.0, 0.0, 1.0);
str = "\033T\377\000\000\000\000\3773D";
cubeSideWithText(str, 10);
glPopMatrix();
glPopMatrix();
/* Swap the buffers if necessary. */
if (doubleBuffer) {
glutSwapBuffers();
}
}
int savex;
/* ARGSUSED23 */
void
mouse(int button, int state, int x, int y)
{
if (button == GLUT_LEFT_BUTTON) {
if (state == GLUT_DOWN) {
glutIdleFunc(NULL);
savex = x;
} else {
if (animation)
glutIdleFunc(idle);
}
}
}
/* ARGSUSED1 */
void
motion(int x, int y)
{
angle += (savex - x);
savex = x;
glutPostRedisplay();
}
int minifyMenu;
void
minifySelect(int value)
{
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, value);
glutPostRedisplay();
}
int alphaMenu;
void
alphaSelect(int value)
{
alphaMode = value;
glutPostRedisplay();
}
int polygonOffsetMenu;
void
polygonOffsetSelect(int value)
{
usePolygonOffset = value;
glutPostRedisplay();
}
int animationMenu;
void
animationSelect(int value)
{
animation = value;
if (animation) {
glutIdleFunc(idle);
} else {
glutIdleFunc(NULL);
}
}
/* ARGSUSED1 */
void
keyboard(unsigned char c, int x, int y)
{
switch(c) {
case 27:
exit(0);
break;
case ' ':
animation = 1 - animation;
if (animation) {
glutIdleFunc(idle);
} else {
glutIdleFunc(NULL);
}
break;
}
}
void
mainSelect(int value)
{
if (value == 666) {
exit(0);
}
}
int
main(int argc, char **argv)
{
int i;
glutInit(&argc, argv);
for (i = 1; i < argc; i++) {
if (!strcmp(argv[i], "-sb")) {
doubleBuffer = 0;
} else {
filename = argv[i];
}
}
if (filename == NULL) {
fprintf(stderr, "usage: txfdemo [GLUT-options] [-sb] txf-file\n");
exit(1);
}
txf = txfLoadFont(filename);
if (txf == NULL) {
fprintf(stderr, "Problem loading %s, %s\n", filename, txfErrorString());
exit(1);
}
if (doubleBuffer) {
glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH | GLUT_MULTISAMPLE);
} else {
glutInitDisplayMode(GLUT_RGB | GLUT_SINGLE | GLUT_DEPTH | GLUT_MULTISAMPLE);
}
glutInitWindowSize(300, 300);
glutCreateWindow("txfdemo");
glutDisplayFunc(display);
glutMouseFunc(mouse);
glutMotionFunc(motion);
glutKeyboardFunc(keyboard);
glutVisibilityFunc(visible);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(60.0, 1.0, 0.1, 20.0);
glMatrixMode(GL_MODELVIEW);
gluLookAt(0.0, 0.0, 4.0,
0.0, 0.0, 0.0,
0.0, 1.0, 0.0);
/* Use a gray background so the teximage with black backgrounds will show
against showtxf's background. */
glClearColor(0.0, 0.0, 0.0, 0.0);
glEnable(GL_DEPTH_TEST);
glEnable(GL_CULL_FACE);
alphaSelect(GL_ALPHA_TEST);
minifySelect(GL_NEAREST);
txfEstablishTexture(txf, 1, GL_TRUE);
minifyMenu = glutCreateMenu(minifySelect);
glutAddMenuEntry("Nearest", GL_NEAREST);
glutAddMenuEntry("Linear", GL_LINEAR);
glutAddMenuEntry("Nearest mipmap nearest", GL_NEAREST_MIPMAP_NEAREST);
glutAddMenuEntry("Linear mipmap nearest", GL_LINEAR_MIPMAP_NEAREST);
glutAddMenuEntry("Nearest mipmap linear", GL_NEAREST_MIPMAP_LINEAR);
glutAddMenuEntry("Linear mipmap linear", GL_LINEAR_MIPMAP_LINEAR);
alphaMenu = glutCreateMenu(alphaSelect);
glutAddMenuEntry("Alpha testing", GL_ALPHA_TEST);
glutAddMenuEntry("Alpha blending", GL_BLEND);
glutAddMenuEntry("Both", GL_ALPHA_TEST + GL_BLEND);
glutAddMenuEntry("Nothing", GL_NONE);
polygonOffsetMenu = glutCreateMenu(polygonOffsetSelect);
glutAddMenuEntry("Enable", 1);
glutAddMenuEntry("Disable", 0);
animationMenu = glutCreateMenu(animationSelect);
glutAddMenuEntry("Start", 1);
glutAddMenuEntry("Stop", 0);
glutCreateMenu(mainSelect);
glutAddSubMenu("Filtering", minifyMenu);
glutAddSubMenu("Alpha", alphaMenu);
glutAddSubMenu("Polygon Offset", polygonOffsetMenu);
glutAddSubMenu("Animation", animationMenu);
glutAddMenuEntry("Quit", 666);
glutAttachMenu(GLUT_RIGHT_BUTTON);
#if !defined(GL_EXT_polygon_offset) && !defined(GL_VERSION_1_1)
fprintf(stderr, "Warning: polygon offset not available; artifacts will results.\n");
#endif
glutMainLoop();
return 0; /* ANSI C requires main to return int. */
}
ΓòÉΓòÉΓòÉ 2.6.4. simpletxf.c ΓòÉΓòÉΓòÉ
/* Copyright (c) Mark J. Kilgard, 1997. */
/* This program is freely distributable without licensing fees and is
provided without guarantee or warrantee expressed or implied. This
program is -not- in the public domain. */
/* X compile line: cc -o simpletxf simpletxf.c texfont.c -lglut -lGLU -lGL -lXmu -lXext -lX11 -lm */
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <GL/glut.h>
#include "TexFont.h"
int doubleBuffer = 1;
char *filename = "default.txf";
TexFont *txf;
GLfloat angle = 20;
void
idle(void)
{
angle += 4;
glutPostRedisplay();
}
void
visible(int vis)
{
if (vis == GLUT_VISIBLE)
glutIdleFunc(idle);
else
glutIdleFunc(NULL);
}
void
display(void)
{
char *str;
/* Clear the color buffer. */
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glPushMatrix();
glRotatef(angle, 0, 0, 1);
glTranslatef(-2.0, 0.0, 0.0);
glScalef(1 / 60.0, 1 / 60.0, 1 / 60.0);
glPushMatrix();
glColor3f(0.0, 0.0, 1.0);
str = "OpenGL is";
txfRenderString(txf, str, strlen(str));
glPopMatrix();
glPushMatrix();
glColor3f(1.0, 0.0, 0.0);
glTranslatef(0.0, -60.0, 0.0);
str = "the best.";
txfRenderString(txf, str, strlen(str));
glPopMatrix();
glPopMatrix();
/* Swap the buffers if necessary. */
if (doubleBuffer) {
glutSwapBuffers();
}
}
int minifyMenu;
void
minifySelect(int value)
{
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, value);
glutPostRedisplay();
}
int alphaMenu;
void
alphaSelect(int value)
{
switch (value) {
case GL_ALPHA_TEST:
glDisable(GL_BLEND);
glEnable(GL_ALPHA_TEST);
glAlphaFunc(GL_GEQUAL, 0.5);
break;
case GL_BLEND:
glDisable(GL_ALPHA_TEST);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
break;
case GL_NONE:
glDisable(GL_ALPHA_TEST);
glDisable(GL_BLEND);
break;
}
}
void
mainSelect(int value)
{
if (value == 666) {
exit(0);
}
}
int
main(int argc, char **argv)
{
int i;
glutInit(&argc, argv);
for (i = 1; i < argc; i++) {
if (!strcmp(argv[i], "-sb")) {
doubleBuffer = 0;
} else {
filename = argv[i];
}
}
if (filename == NULL) {
fprintf(stderr, "usage: show [GLUT-options] [-sb] txf-file\n");
exit(1);
}
txf = txfLoadFont(filename);
if (txf == NULL) {
fprintf(stderr, "Problem loading %s\n", filename);
exit(1);
}
if (doubleBuffer) {
glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH);
} else {
glutInitDisplayMode(GLUT_RGB | GLUT_SINGLE | GLUT_DEPTH);
}
glutInitWindowSize(300, 300);
glutCreateWindow("texfont");
glutDisplayFunc(display);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(60.0, 1.0, 0.1, 20.0);
glMatrixMode(GL_MODELVIEW);
gluLookAt(0.0, 0.0, 5.0,
0.0, 0.0, 0.0,
0.0, 1.0, 0.0);
glEnable(GL_TEXTURE_2D);
glEnable(GL_DEPTH_TEST);
alphaSelect(GL_ALPHA_TEST);
minifySelect(GL_NEAREST);
txfEstablishTexture(txf, 0, GL_TRUE);
glutVisibilityFunc(visible);
minifyMenu = glutCreateMenu(minifySelect);
glutAddMenuEntry("Nearest", GL_NEAREST);
glutAddMenuEntry("Linear", GL_LINEAR);
glutAddMenuEntry("Nearest mipmap nearest", GL_NEAREST_MIPMAP_NEAREST);
glutAddMenuEntry("Linear mipmap nearest", GL_LINEAR_MIPMAP_NEAREST);
glutAddMenuEntry("Nearest mipmap linear", GL_NEAREST_MIPMAP_LINEAR);
glutAddMenuEntry("Linear mipmap linear", GL_LINEAR_MIPMAP_LINEAR);
alphaMenu = glutCreateMenu(alphaSelect);
glutAddMenuEntry("Alpha testing", GL_ALPHA_TEST);
glutAddMenuEntry("Alpha blending", GL_BLEND);
glutAddMenuEntry("Nothing", GL_NONE);
glutCreateMenu(mainSelect);
glutAddSubMenu("Filtering", minifyMenu);
glutAddSubMenu("Alpha", alphaMenu);
glutAddMenuEntry("Quit", 666);
glutAttachMenu(GLUT_RIGHT_BUTTON);
glutMainLoop();
return 0; /* ANSI C requires main to return int. */
}
ΓòÉΓòÉΓòÉ 2.6.5. showtxf.c ΓòÉΓòÉΓòÉ
/* Copyright (c) Mark J. Kilgard, 1997. */
/* This program is freely distributable without licensing fees and is
provided without guarantee or warrantee expressed or implied. This
program is -not- in the public domain. */
/* X compile line: cc -o showtxf showtxf.c texfont.c -lglut -lGLU -lGL -lXmu -lXext -lX11 -lm */
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <GL/glut.h>
#include "TexFont.h"
unsigned char *raster;
int imgwidth, imgheight;
int max_ascent, max_descent;
int len;
int ax = 0, ay = 0;
int doubleBuffer = 1, verbose = 0;
char *filename = "default.txf";
TexFont *txf;
/* If resize is called, enable drawing into the full screen area
(glViewport). Then setup the modelview and projection matrices to map 2D
x,y coodinates directly onto pixels in the window (lower left origin).
Then set the raster position (where the image would be drawn) to be offset
from the upper left corner, and then offset by the current offset (using a
null glBitmap). */
void
reshape(int w, int h)
{
glViewport(0, 0, w, h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluOrtho2D(0, w, 0, h);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glTranslatef(0, h - imgheight, 0);
glRasterPos2i(0, 0);
glBitmap(0, 0, 0, 0, ax, -ay, NULL);
}
void
display(void)
{
/* Clear the color buffer. */
glClear(GL_COLOR_BUFFER_BIT);
/* Re-blit the image. */
glDrawPixels(imgwidth, imgheight,
GL_LUMINANCE, GL_UNSIGNED_BYTE,
txf->teximage);
/* Swap the buffers if necessary. */
if (doubleBuffer) {
glutSwapBuffers();
}
}
static int moving = 0, ox, oy;
void
mouse(int button, int state, int x, int y)
{
if (button == GLUT_LEFT_BUTTON) {
if (state == GLUT_DOWN) {
/* Left mouse button press. Update last seen mouse position. And set
"moving" true since button is pressed. */
ox = x;
oy = y;
moving = 1;
} else {
/* Left mouse button released; unset "moving" since button no longer
pressed. */
moving = 0;
}
}
}
void
motion(int x, int y)
{
/* If there is mouse motion with the left button held down... */
if (moving) {
/* Figure out the offset from the last mouse position seen. */
ax += (x - ox);
ay += (y - oy);
/* Offset the raster position based on the just calculated mouse position
delta. Use a null glBitmap call to offset the raster position in
window coordinates. */
glBitmap(0, 0, 0, 0, x - ox, oy - y, NULL);
/* Request a window redraw. */
glutPostRedisplay();
/* Update last seen mouse position. */
ox = x;
oy = y;
}
}
int
main(int argc, char **argv)
{
int i;
glutInit(&argc, argv);
for (i = 1; i < argc; i++) {
if (!strcmp(argv[i], "-sb")) {
doubleBuffer = 0;
} else if (!strcmp(argv[i], "-v")) {
verbose = 1;
} else {
filename = argv[i];
}
}
if (filename == NULL) {
fprintf(stderr, "usage: showtxf [GLUT-options] [-sb] [-v] txf-file\n");
exit(1);
}
txf = txfLoadFont(filename);
if (txf == NULL) {
fprintf(stderr, "Problem loading %s\n", filename);
exit(1);
}
imgwidth = txf->tex_width;
imgheight = txf->tex_height;
if (doubleBuffer) {
glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE);
} else {
glutInitDisplayMode(GLUT_RGB | GLUT_SINGLE);
}
glutInitWindowSize(imgwidth, imgheight);
glutCreateWindow(filename);
glutReshapeFunc(reshape);
glutDisplayFunc(display);
glutMouseFunc(mouse);
glutMotionFunc(motion);
/* Use a gray background so teximage with black backgrounds will show
against showtxf's background. */
glClearColor(0.2, 0.2, 0.2, 1.0);
glutMainLoop();
return 0; /* ANSI C requires main to return int. */
}
ΓòÉΓòÉΓòÉ 2.6.6. gentexfont.c ΓòÉΓòÉΓòÉ
/* Copyright (c) Mark J. Kilgard, 1997. */
/* This program is freely distributable without licensing fees and is
provided without guarantee or warrantee expressed or implied. This
program is -not- in the public domain. */
/* X compile line: cc -o gentexfont gentexfont.c -lX11 */
#include <assert.h>
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <math.h>
#include "TexFont.h"
typedef struct {
short width;
short height;
short xoffset;
short yoffset;
short advance;
unsigned char *bitmap;
} PerGlyphInfo, *PerGlyphInfoPtr;
typedef struct {
int min_char;
int max_char;
int max_ascent;
int max_descent;
PerGlyphInfo glyph[1];
} FontInfo, *FontInfoPtr;
Display *dpy;
FontInfoPtr fontinfo;
int format = TXF_FORMAT_BITMAP;
int gap = 1;
/* #define REPORT_GLYPHS */
#ifdef REPORT_GLYPHS
#define DEBUG_GLYPH4(msg,a,b,c,d) printf(msg,a,b,c,d)
#define DEBUG_GLYPH(msg) printf(msg)
#else
#define DEBUG_GLYPH4(msg,a,b,c,d) { /* nothing */ }
#define DEBUG_GLYPH(msg) { /* nothing */ }
#endif
#define MAX_GLYPHS_PER_GRAB 512 /* this is big enough for 2^9 glyph
character sets */
FontInfoPtr
SuckGlyphsFromServer(Display * dpy, Font font)
{
Pixmap offscreen;
XFontStruct *fontinfo;
XImage *image;
GC xgc;
XGCValues values;
int numchars;
int width, height, pixwidth;
int i, j;
XCharStruct *charinfo;
XChar2b character;
unsigned char *bitmapData;
int x, y;
int spanLength;
int charWidth, charHeight, maxSpanLength;
int grabList[MAX_GLYPHS_PER_GRAB];
int glyphsPerGrab = MAX_GLYPHS_PER_GRAB;
int numToGrab, thisglyph;
FontInfoPtr myfontinfo;
fontinfo = XQueryFont(dpy, font);
if (!fontinfo)
return NULL;
numchars = fontinfo->max_char_or_byte2 - fontinfo->min_char_or_byte2 + 1;
if (numchars < 1)
return NULL;
myfontinfo = (FontInfoPtr) malloc(sizeof(FontInfo) + (numchars - 1) * sizeof(PerGlyphInfo));
if (!myfontinfo)
return NULL;
myfontinfo->min_char = fontinfo->min_char_or_byte2;
myfontinfo->max_char = fontinfo->max_char_or_byte2;
myfontinfo->max_ascent = fontinfo->max_bounds.ascent;
myfontinfo->max_descent = fontinfo->max_bounds.descent;
width = fontinfo->max_bounds.rbearing - fontinfo->min_bounds.lbearing;
height = fontinfo->max_bounds.ascent + fontinfo->max_bounds.descent;
maxSpanLength = (width + 7) / 8;
/* Be careful determining the width of the pixmap; the X protocol allows
pixmaps of width 2^16-1 (unsigned short size) but drawing coordinates
max out at 2^15-1 (signed short size). If the width is too large, we
need to limit the glyphs per grab. */
if ((glyphsPerGrab * 8 * maxSpanLength) >= (1 << 15)) {
glyphsPerGrab = (1 << 15) / (8 * maxSpanLength);
}
pixwidth = glyphsPerGrab * 8 * maxSpanLength;
offscreen = XCreatePixmap(dpy, RootWindow(dpy, DefaultScreen(dpy)),
pixwidth, height, 1);
values.font = font;
values.background = 0;
values.foreground = 0;
xgc = XCreateGC(dpy, offscreen, GCFont | GCBackground | GCForeground, &values);
XFillRectangle(dpy, offscreen, xgc, 0, 0, 8 * maxSpanLength * glyphsPerGrab, height);
XSetForeground(dpy, xgc, 1);
numToGrab = 0;
if (fontinfo->per_char == NULL) {
charinfo = &(fontinfo->min_bounds);
charWidth = charinfo->rbearing - charinfo->lbearing;
charHeight = charinfo->ascent + charinfo->descent;
spanLength = (charWidth + 7) / 8;
}
for (i = 0; i < numchars; i++) {
if (fontinfo->per_char != NULL) {
charinfo = &(fontinfo->per_char[i]);
charWidth = charinfo->rbearing - charinfo->lbearing;
charHeight = charinfo->ascent + charinfo->descent;
if (charWidth == 0 || charHeight == 0) {
/* Still must move raster pos even if empty character */
myfontinfo->glyph[i].width = 0;
myfontinfo->glyph[i].height = 0;
myfontinfo->glyph[i].xoffset = 0;
myfontinfo->glyph[i].yoffset = 0;
myfontinfo->glyph[i].advance = charinfo->width;
myfontinfo->glyph[i].bitmap = NULL;
goto PossiblyDoGrab;
}
}
grabList[numToGrab] = i;
/* XXX is this right for large fonts? */
character.byte2 = (i + fontinfo->min_char_or_byte2) & 255;
character.byte1 = (i + fontinfo->min_char_or_byte2) >> 8;
/* XXX we could use XDrawImageString16 which would also paint the backing
rectangle but X server bugs in some scalable font rasterizers makes it
more effective to do XFillRectangles to clear the pixmap and
XDrawImage16 for the text. */
XDrawString16(dpy, offscreen, xgc,
-charinfo->lbearing + 8 * maxSpanLength * numToGrab,
charinfo->ascent, &character, 1);
numToGrab++;
PossiblyDoGrab:
if (numToGrab >= glyphsPerGrab || i == numchars - 1) {
image = XGetImage(dpy, offscreen,
0, 0, pixwidth, height, 1, XYPixmap);
for (j = 0; j < numToGrab; j++) {
thisglyph = grabList[j];
if (fontinfo->per_char != NULL) {
charinfo = &(fontinfo->per_char[thisglyph]);
charWidth = charinfo->rbearing - charinfo->lbearing;
charHeight = charinfo->ascent + charinfo->descent;
spanLength = (charWidth + 7) / 8;
}
bitmapData = calloc(height * spanLength, sizeof(char));
if (!bitmapData)
goto FreeFontAndReturn;
DEBUG_GLYPH4("index %d, glyph %d (%d by %d)\n",
j, thisglyph + fontinfo->min_char_or_byte2, charWidth, charHeight);
for (y = 0; y < charHeight; y++) {
for (x = 0; x < charWidth; x++) {
/* XXX The algorithm used to suck across the font ensures that
each glyph begins on a byte boundary. In theory this would
make it convienent to copy the glyph into a byte oriented
bitmap. We actually use the XGetPixel function to extract
each pixel from the image which is not that efficient. We
could either do tighter packing in the pixmap or more
efficient extraction from the image. Oh well. */
if (XGetPixel(image, j * maxSpanLength * 8 + x, charHeight - 1 - y)) {
DEBUG_GLYPH("x");
bitmapData[y * spanLength + x / 8] |= (1 << (x & 7));
} else {
DEBUG_GLYPH(" ");
}
}
DEBUG_GLYPH("\n");
}
myfontinfo->glyph[thisglyph].width = charWidth;
myfontinfo->glyph[thisglyph].height = charHeight;
myfontinfo->glyph[thisglyph].xoffset = charinfo->lbearing;
myfontinfo->glyph[thisglyph].yoffset = -charinfo->descent;
myfontinfo->glyph[thisglyph].advance = charinfo->width;
myfontinfo->glyph[thisglyph].bitmap = bitmapData;
}
XDestroyImage(image);
numToGrab = 0;
/* do we need to clear the offscreen pixmap to get more? */
if (i < numchars - 1) {
XSetForeground(dpy, xgc, 0);
XFillRectangle(dpy, offscreen, xgc, 0, 0, 8 * maxSpanLength * glyphsPerGrab, height);
XSetForeground(dpy, xgc, 1);
}
}
}
XFreeGC(dpy, xgc);
XFreePixmap(dpy, offscreen);
return myfontinfo;
FreeFontAndReturn:
XDestroyImage(image);
XFreeGC(dpy, xgc);
XFreePixmap(dpy, offscreen);
for (j = i - 1; j >= 0; j--) {
if (myfontinfo->glyph[j].bitmap)
free(myfontinfo->glyph[j].bitmap);
}
free(myfontinfo);
return NULL;
}
void
printGlyph(FontInfoPtr font, int c)
{
PerGlyphInfoPtr glyph;
unsigned char *bitmapData;
int width, height, spanLength;
int x, y;
if (c < font->min_char || c > font->max_char) {
printf("out of range glyph\n");
return;
}
glyph = &font->glyph[c - font->min_char];
bitmapData = glyph->bitmap;
if (bitmapData) {
width = glyph->width;
spanLength = (width + 7) / 8;
height = glyph->height;
for (y = 0; y < height; y++) {
for (x = 0; x < width; x++) {
if (bitmapData[y * spanLength + x / 8] & (1 << (x & 7))) {
putchar('X');
} else {
putchar('.');
}
}
putchar('\n');
}
}
}
void
getMetric(FontInfoPtr font, int c, TexGlyphInfo * tgi)
{
PerGlyphInfoPtr glyph;
unsigned char *bitmapData;
tgi->c = c;
if (c < font->min_char || c > font->max_char) {
tgi->width = 0;
tgi->height = 0;
tgi->xoffset = 0;
tgi->yoffset = 0;
tgi->dummy = 0;
tgi->advance = 0;
return;
}
glyph = &font->glyph[c - font->min_char];
bitmapData = glyph->bitmap;
if (bitmapData) {
tgi->width = glyph->width;
tgi->height = glyph->height;
tgi->xoffset = glyph->xoffset;
tgi->yoffset = glyph->yoffset;
} else {
tgi->width = 0;
tgi->height = 0;
tgi->xoffset = 0;
tgi->yoffset = 0;
}
tgi->dummy = 0;
tgi->advance = glyph->advance;
}
int
glyphCompare(const void *a, const void *b)
{
unsigned char *c1 = (unsigned char *) a;
unsigned char *c2 = (unsigned char *) b;
TexGlyphInfo tgi1;
TexGlyphInfo tgi2;
getMetric(fontinfo, *c1, &tgi1);
getMetric(fontinfo, *c2, &tgi2);
return tgi2.height - tgi1.height;
}
int
getFontel(unsigned char *bitmapData, int spanLength, int i, int j)
{
return bitmapData[i * spanLength + j / 8] & (1 << (j & 7)) ? 255 : 0;
}
void
placeGlyph(FontInfoPtr font, int c, unsigned char *texarea, int stride, int x, int y)
{
PerGlyphInfoPtr glyph;
unsigned char *bitmapData;
int width, height, spanLength;
int i, j;
if (c < font->min_char || c > font->max_char) {
printf("out of range glyph\n");
return;
}
glyph = &font->glyph[c - font->min_char];
bitmapData = glyph->bitmap;
if (bitmapData) {
width = glyph->width;
spanLength = (width + 7) / 8;
height = glyph->height;
for (i = 0; i < height; i++) {
for (j = 0; j < width; j++) {
texarea[stride * (y + i) + x + j] =
getFontel(bitmapData, spanLength, i, j);
}
}
}
}
char *
nodupstring(char *s)
{
int len, i, p;
char *new;
len = strlen(s);
new = (char *) calloc(len + 1, 1);
p = 0;
for (i = 0; i < len; i++) {
if (!strchr(new, s[i])) {
new[p] = s[i];
p++;
}
}
new = realloc(new, p + 1);
return new;
}
void
main(int argc, char *argv[])
{
int texw, texh;
unsigned char *texarea, *texbitmap;
FILE *file;
int len, stride;
unsigned char *glist;
int width, height;
int px, py, maxheight;
TexGlyphInfo tgi;
int usageError = 0;
char *fontname, *filename;
XFontStruct *xfont;
int endianness;
int i, j;
texw = texh = 256;
glist = " ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890abcdefghijmklmnopqrstuvwxyz?.;,!*:\"/+@#$%^&()";
fontname = "-adobe-courier-bold-r-normal--46-*-100-100-m-*-iso8859-1";
filename = "default.txf";
for (i = 1; i < argc; i++) {
if (!strcmp(argv[i], "-w")) {
i++;
texw = atoi(argv[i]);
} else if (!strcmp(argv[i], "-h")) {
i++;
texh = atoi(argv[i]);
} else if (!strcmp(argv[i], "-gap")) {
i++;
gap = atoi(argv[i]);
} else if (!strcmp(argv[i], "-byte")) {
format = TXF_FORMAT_BYTE;
break;
} else if (!strcmp(argv[i], "-bitmap")) {
format = TXF_FORMAT_BITMAP;
} else if (!strcmp(argv[i], "-glist")) {
i++;
glist = (unsigned char *) argv[i];
} else if (!strcmp(argv[i], "-fn")) {
i++;
fontname = argv[i];
} else if (!strcmp(argv[i], "-file")) {
i++;
filename = argv[i];
} else {
usageError = 1;
}
}
if (usageError) {
putchar('\n');
printf("usage: texfontgen [options] txf-file\n");
printf(" -w # textureWidth (def=%d)\n", texw);
printf(" -h # textureHeight (def=%d)\n", texh);
printf(" -gap # gap between glyphs (def=%d)\n", gap);
printf(" -bitmap use a bitmap encoding (default)\n", gap);
printf(" -byte use a byte encoding (less compact)\n", gap);
printf(" -glist ABC glyph list (def=%s)\n", glist);
printf(" -fn name X font name (def=%s)\n", fontname);
printf(" -file name output file for textured font (def=%s)\n", fontname);
putchar('\n');
exit(1);
}
texarea = calloc(texw * texh, sizeof(unsigned char));
glist = (unsigned char *) nodupstring((char *) glist);
dpy = XOpenDisplay(NULL);
if (!dpy) {
printf("could not open display\n");
exit(1);
}
/* find an OpenGL-capable RGB visual with depth buffer */
xfont = XLoadQueryFont(dpy, fontname);
if (!xfont) {
printf("could not get load X font: %s\n", fontname);
exit(1);
}
fontinfo = SuckGlyphsFromServer(dpy, xfont->fid);
if (!fontinfo) {
printf("could not get font glyphs\n");
exit(1);
}
len = strlen((char *) glist);
qsort(glist, len, sizeof(unsigned char), glyphCompare);
file = fopen(filename, "wb");
fwrite("\377txf", 1, 4, file);
endianness = 0x12345678;
assert(sizeof(int) == 4); /* Ensure external file format size. */
fwrite(&endianness, sizeof(int), 1, file);
fwrite(&format, sizeof(int), 1, file);
fwrite(&texw, sizeof(int), 1, file);
fwrite(&texh, sizeof(int), 1, file);
fwrite(&fontinfo->max_ascent, sizeof(int), 1, file);
fwrite(&fontinfo->max_descent, sizeof(int), 1, file);
fwrite(&len, sizeof(int), 1, file);
px = gap;
py = gap;
maxheight = 0;
for (i = 0; i < len; i++) {
if (glist[i] != 0) { /* If not already processed... */
/* Try to find a character from the glist that will fit on the
remaining space on the current row. */
int foundWidthFit = 0;
int c;
getMetric(fontinfo, glist[i], &tgi);
width = tgi.width;
height = tgi.height;
if (height > 0 && width > 0) {
for (j = i; j < len;) {
if (height > 0 && width > 0) {
if (px + width + gap < texw) {
foundWidthFit = 1;
if (j != i) {
i--; /* Step back so i loop increment leaves us at same character. */
}
break;
}
}
j++;
getMetric(fontinfo, glist[j], &tgi);
width = tgi.width;
height = tgi.height;
}
/* If a fit was found, use that character; otherwise, advance a line
in the texture. */
if (foundWidthFit) {
if (height > maxheight) {
maxheight = height;
}
c = j;
} else {
getMetric(fontinfo, glist[i], &tgi);
width = tgi.width;
height = tgi.height;
py += maxheight + gap;
px = gap;
maxheight = height;
if (py + height + gap >= texh) {
printf("Overflowed texture space.\n");
exit(1);
}
c = i;
}
/* Place the glyph in the texture image. */
placeGlyph(fontinfo, glist[c], texarea, texw, px, py);
/* Assign glyph's texture coordinate. */
tgi.x = px;
tgi.y = py;
/* Advance by glyph width, remaining in the current line. */
px += width + gap;
} else {
/* No texture image; assign invalid bogus texture coordinates. */
tgi.x = -1;
tgi.y = -1;
}
glist[c] = 0; /* Mark processed; don't process again. */
assert(sizeof(tgi) == 12); /* Ensure external file format size. */
fwrite(&tgi, sizeof(tgi), 1, file);
}
}
switch (format) {
case TXF_FORMAT_BYTE:
fwrite(texarea, texw * texh, 1, file);
break;
case TXF_FORMAT_BITMAP:
stride = (texw + 7) >> 3;
texbitmap = (unsigned char *) calloc(stride * texh, 1);
for (i = 0; i < texh; i++) {
for (j = 0; j < texw; j++) {
if (texarea[i * texw + j] >= 128) {
texbitmap[i * stride + (j >> 3)] |= 1 << (j & 7);
}
}
}
fwrite(texbitmap, stride * texh, 1, file);
free(texbitmap);
break;
default:
printf("Unknown texture font format.\n");
exit(1);
}
free(texarea);
fclose(file);
}
ΓòÉΓòÉΓòÉ 3. GLUT 3.3 now available! ΓòÉΓòÉΓòÉ
GLUT 3.3 now available!
Contents
About GLUT . . .
About the GLUT source code distribution
Pre-compiled instable images for SGI users
GLUT for Microsoft Windows 95 & NT users
Available GLUT Documentation
What did GLUT 3.0 add?
What did GLUT 3.1 add?
What did GLUT 3.2 add?
What did GLUT 3.3 add?
Frequently Asked Questions
Contributions Accepted (not money)
Reporting Bugs
About GLUT . . .
GLUT (pronounced like the glut in gluttony) is the OpenGL Utility Toolkit, a
window system independent toolkit for writing OpenGL programs. It implements a
simple windowing application programming interface (API) for OpenGL. GLUT
makes it considerably easier to learn about and explore OpenGL programming.
GLUT is designed for constructing small to medium sized OpenGL programs. While
GLUT is well-suited to learning OpenGL and developing simple OpenGL
applications, GLUT is not a full-featured toolkit so large applications
requiring sophisticated user interfaces are better off using native window
system toolkits like Motif. GLUT is simple, easy, and small. My intent is to
keep GLUT that way.
The GLUT library supports the following functionality:
Multiple windows for OpenGL rendering.
Callback driven event processing.
An `idle' routine and timers.
Utility routines to generate various solid and wire frame objects.
Support for bitmap and stroke fonts.
Miscellaneous window management functions.
The GLUT library has both C, C++ (same as C), and FORTRAN programming
bindings. The GLUT source code distribution is portable to nearly all OpenGL
implementations for the X Window System. GLUT also works well with Brian
Paul's Mesa, a freely available implementation of the OpenGL API.
Because GLUT is window system independent (as much as possible), GLUT can be
implemented for window systems other than X. Implementations of GLUT for OS/2,
NT & Windows 95, and the Mac have ben implemented, but these implementations
are not part of the official GLUT source code distrbution.
The current version of the GLUT API is 3. The current source code distribution
is GLUT 3.2.
About the GLUT source code distribution
GLUT is distributed in source code form. The programs and associated files
contained in the distrbution were developed by Mark J. Kilgard (unless
otherwise noted). The programs are not in the public domain, but they are
freely distributable without licensing fees. These programs are provided
without gurantee or warrantee expressed or implied.
Download the GLUT 3.3 source distribution by downloading this (shift Left in
Netscape).
Since the data files for some of the new advanced GLUT examples are large,
they are contained in a separate distribution.
Down load the GLUT 3.3 image datafile distribution (not required; 1.6
megabytes).
You can also download GLUT from the University of North Carolina, Chapel
Hill's SunSITE archive by either FTP or HTTP:
http://sunsite.unc.edu/pub/packages/development/graphics/glut/
ftp://sunsite.unc.edu/pub/packages/development/graphics/glut/
Pre-compiled installable images for SGI users
For SGI users that want to save the hassle of compiling GLUT 3.3 by hand, you
can download installable images for GLUT 3.3. Image images include:
glut_dev.doc.intro - PostScript introduction to programming with GLUT
3.2.
glut_dev.doc.spec - PostScript specification for the GLUT API, version 3.
glut_dev.man.glut - Unix man pages for the GLUT programming interface
glut_dev.src.samples - Source code for selected GLUT examples.
glut_dev.src.inventor - Source cofr for Inventor GLUT examples.
glut_dev.sw.demos - Pre-compiled GLUT demos.
glut_dev.sw.dev - The GLUT 3.2 development environment.
glut_dev.sw.fortran - GLUT FORTRAN bindings.
glut_dev.sw32.dev - For IRIX 6.x users, N32 version of GLUT library.
glut_dev.sw32.fortran - N32 version of GLUT FORTRAN bindings.
glut_dev.sw64.dev - For 64-bit IRIX 6.x users, 64-bit version of GLUT
library.
glut_dev.sw64.fortran - 64-bit version of GLUT FORTRAN bindings.
The GLUT 3.3 images work with IRIX 5.3, IRIX 6.1, IRIX 6.2, IRIX 6.3, and IRIX
6.4. The installable images make it easy to install, upgrade, and remove GLUT.
This is particularly true if you want N32 or 64-bit versions of GLUT. The N32
version refers to the new N32 object format that results in better performance
from MIPS's current R4400, R8000, and R10000 processors. N32 is supported in
IRIX 6.1 and later IRIX releases. The glut_dev.sw32.dev system is now marked
for install by default since N32 is the default object format in IRIX 6.4.
The images are distributed as a tar file. You can either untar the file, or
run tardist on the tar file to automatically start SGI's Software Manager
(swmgr). Otherwise, you can run inst or swmgr on the untar'ed files.
Download the GLUT 3.3 installable images by downloading this (shift Left in
Netscape).
If your browser is configured to use tardist, try clicking the above link to
start swmgr automatically. Note that not all the GLUT example source code in
the source distribution is included with the GLUT images.
GLUT for Microsoft Windows 95 & NT users
Nate Robbins and Paul Mayfield with help from Layne Christensen have
implemented a version of GLUT for Windows 95 & NT. Here's a link to their GLUT
for Windows info..
Available GLUT Documentation
The OpenGL Utility Toolkit (GLUT) Programming Interface, API version 3
specifies all the routines in the GLUT API and how they operate. This document
is available in both HTML and PostScript formats. There were no revisions for
GLUT 3.2.
There is also a column on GLUT published in The X Journal available in
PostScript. Unfortunately, The X Journal is no longer published, but back
issues contain various other OpenGL columns using OpenGL with GLUT.
GLUT is fully described in my book Programming OpenGL for the X Window System
(Addison-Wesley, ISBN 0-201-48359-9). Consult this book for a full tutorial on
GLUT.
What did GLUT 3.0 add?
GLUT 3.0 involves an update to the GLUT API to version 3 so the GLUT library
has new routines included in it implementing new functionality. There are also
bug fixes, better support for IRIX 6.x's 64-bit and N32 object formats, and
more sample programs.
The important new API additions are support for overlays, determining font
character widths, new bitmap fonts, returning held down modifiers for mouse
and keyboard events, and full screen windows.
What did GLUT 3.1 add?
There are a few minor bug fixes in the library. Various build problems on
various built platforms have been resolved. GLUT 3.1 should build much cleanly
on HP/UX, AIX, Linux, Solaris, and SunOS platforms now (cross finger). There
are also a few more example programs. See the CHANGES file for details.
What did GLUT 3.2 add?
GLUT 3.2 fixed a few more minor bugs in the library. Mesa users will benefit
from a hack to speed double-buffered damage regeneration. Man pages for the
complete GLUT API are now included. The tests are expanded. New examples from
Mesa distribution (converted to use GLUT) and advanced OpenGL programs from
the Advanced OpenGL Rendering SIGGRAPH '96 class are now included. See the
CHANGES file for details.
What did GLUT 3.3 add?
GLUT 3.3 is more portable; nearly all compiler warning are resolved. Lots of
new GLUT-based OpenGL examples have been added or improved. Some new API has
been added that will be codified with the GLUT 4 API revision. For example, an
API for using InfiniteReality's dynamic video resize (DVR) capability is
included. Also, a better way of getting window status is supported. There were
some bug in the GLUT library itself that are now fixed. Some the warning or
error messages weren't quite right. glutFullScreen before a window is first
displayed now ensures that the window need not be positioned by the user. See
the CHANGES file for details.
Frequently Asked Questions
I've collected a page of GLUT frequently asked questions that I expect about
GLUT 3.3.
Contributions Accepted
No, not money. If you have benefited from using GLUT and have developed a cool
GLUT program that you would like included with a future GLUT source code
distribution, feel free to notify me by email about including it.
Reporting Bugs
Please send email to Mark Kilgard at mjk@sgi.com to report bugs or problems
with GLUT.
(I make no promises to fix bugs quickly or even at all, though I usually do.)
- Mark
ΓòÉΓòÉΓòÉ 3.1. Frequently Asked GLUT Questions ΓòÉΓòÉΓòÉ
Frequently Asked GLUT Questions
Here are few questions I expect to be frequently asked about GLUT 3.3. First,
here are tag-line summaries of the question subject matter.
1. Problems building GLUT.
2. More GUI features.
3. New with GLUT 3.0.
4. GLUT for NT.
5. GLUT for OS/2.
6. GLUT for Power Mcintosh.
7. GLUT 3.0 incompatibilities.
8. GLUT and Motif.
9. aux conversion to GLUT.
10. SGI N32 and 64-bit support.
11. FORTRAN and GLUT.
12. Sophisticated input devices.
13. GLUT and Open Inventor.
14. GLUT, Sun, and Overlays.
15. The GLUT stroke font.
16. My upcoming book.
17. GLUT and Microsoft portability.
18. GLUT and networking.
19. Asking GLUT questions.
20. Free OpenGL.
21. GLUT overlay example code.
22. BadMatch errors running GLUT programs.
23. New with GLUT 3.1.
24. Shared libraries for Linux
25. New in GLUT 3.2.
26. GLUT API man pages.
27. Fast window repair for Mesa.
28. Advanced GLUT example .rgb image files.
29. IRIX 6.3 and 6.4 fast atoms support issues for older IRIX releases.
30. GLUT for the Power Macintosh.
ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ
Q1: I've tried to use the "mkmkfiles.imake" script to generate Makefiles so I
can build GLUT, but it doesn't seem to work.
A1: While Imakefiles are supposted to be system independent (hence the "I"),
the commands to translate Imakefiles into Makefiles varies from system to
system. The X Consortium provides a command called "xmkmf", but vendors do not
put this command in a consistent place. The "mkmkfiles.imake" script tries its
best to generate Makefiles, but may get confused by different vendors
configurations that I am not aware of.
It is also possible the imake configuration files (typically located at
/usr/lib/X11/config) are buggy or from a very old version of X.
SGI users can benefit from using the "mkmkfile.sgi" script that uses SGI's
parallel make, though "mkmkfiles.imake" should work too.
ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ
Q2: GLUT needs improved menus, dialog boxes, scrollbars, text entry fields,
etc. to be useful to me?
A2: GLUT does not pretend to be a full-featured graphical user interface
toolkit.
You _could_ write these sorts of GUI objects using GLUT and OpenGL if you
needed to. The other alternative is to use Motif or whatever full featured
toolkit you have.
ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ
Q3: What new things are in GLUT 3.0?
A3: See README.glut3 or read The OpenGL Utility (GLUT) Programming Interface
document.
ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ
Q4: Is there a version of GLUT for Windows NT or Windows 95.
A4: Nate Robins and Layne Christensen at Evans & Sutherland has been working
on a freely distributable version of GLUT for Windows 95 and NT. His efforts
are directed at porting GLUT 2.3; work on GLUT 3.0 is in progress.
ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ
Q5: Is there a version of GLUT for OS/2?
A5: Yes. I believe a version based on GLUT 2.x is distributed on an OS/2
OpenGL developer's CD-ROM.
ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ
Q6: Is there a version of GLUT for the Power Mcintosh?
A6: Was told by Template Graphics that an incomplete version of GLUT had been
developed for their OpenGL product for the Power Mcintosh. I am not sure if it
was ever completed or made available.
ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ
Q7: I'm hesitant about upgrading to GLUT 3.0 since I've got things working
will with GLUT 2.3. Is the transition painful?
A7: I do not believe so. There are two changes worth noting that _may_ affect
programs you have written.
First, you need a display callback registered before your display your windows
on the screen. It did not make sense for this to not be true. In all
likeihood, this should not affect your GLUT programs if they written well.
Second, you can no longer change, create, or destroy menus while pop-up menus
are in use. Before, you could do this, but it meant a menu might be changed
while in use. It was near impossible to describe what should happen in the
case of menus being changed while in use that was likely to be portable to the
way other window systems handled menus, so I made the practice illegal.
You can register a menu status callback to know when menus become used and
unused to avoid changing menus while they are in use.
For more details about what has changed, see the CHANGES file.
ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ
Q8: So how do I use GLUT and Motif together?
A8: You don't. To make GLUT simple and easy-to-program, GLUT supplies its own
event processing loop. This makes it nearly impossible to combine GLUT and
Motif. If you want Motif, you probably want a full-featured toolkit, and you
ship skip GLUT and implement your application directly in Motif.
ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ
Q9: I have a bunch of simpe OpenGL programs using the aux toolkit descibed in
the OpenGL Programming Guide (the "red" book). Is there an easy way to convert
them to GLUT?
A9: In the progs/redbook directory, there is a script named aux2glut.sed It
will give you a good start at converting simple aux calls to their GLUT
equivalents. It is a good start, but you'll still have to hand edit some
things.
Here's a usage example:
sed -f aux2glut.sed < aux_prog. > glut_prog.c
ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ
Q10: I have IRIX 6.2 (or 6.1) and I'd like to write GLUT programs run in true
64-bit and/or benefit from the recent, faster MIPS processors. How do I build
GLUT to support these newer application binary interfaces (ABIs)?
A10: See README.irix6
ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ
Q11: I'd like to write FORTRAN programs using GLUT and OpenGL. How do I use
GLUT with FORTRAN?
A11: GLUT does have a FORTRAN language binding.
For instructions for building a binding library for Silicon Graphics
workstations, see README.fortran
If you want to use GLUT and OpenGL or Mesa on with Fortran on non-SGI systems,
I recommend that you check, William Mitchell's f90gl home page.
ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ
Q12: I'd like to use the sophisticated input devices that GLUT supports. What
should I know about this?
A12: GLUT uses the X Input extension to talk to these devices. Because the X
Input extension gives a framework for supporting input devices, but does not
manadate how particular devices are supported, it is possible that each vendor
supports the same input devices differently.
GLUT as implemented supports SGI's means of advertising the tablet, dial &
button box, and Spaceball devices. I am not sure how other vendors support
these devices. For the details of SGI's support for these devices, see
README.xinput Since there is no benefit in each vendor supporting these same
devices in a different an incompatible way, I encourage other vendors to
implement their devices in this same manner.
ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ
Q13: Can I use GLUT and Open Inventor?
A13: Yes. See the README.inventor file. Also, some source code examples can be
found at progs/inventor
Because the Open Inventor development enviornment is not supported on all
systems, the Inventor example programs are not built by default, and the
Makefile there only support SGI systems.
ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ
Q14: I have Sun workstation, and it is supposed to support overlays. So why
does GLUT not use them?
A14: GLUT uses the SERVER_OVERLAY_VISUALS convention that advertises overlay
visuals. Most major workstation vendors support this convention (DEC, HP, IBM,
SGI), but Sun does not.
ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ
Q15: The stroke font used for GLUT looks familar. Where did it come from?
A15: The data for the "stroke roman" font is lifted from the X11R5 PEX sample
implementation.
ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ
Q16: I read in the NOTICE file that you are writing a book on programming
OpenGL for the X Window System. When will it be available?
A16: At SIGGRAPH '96 or possibly before that.
ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ
Q17: You mention an unnamed bu "very large window system software vendor" as
the reason portable GLUT programs should not directly include <GL/gl.h> and
<GL/glu.h> directly. What's the vendor and what are the details?
A17: Microsoft. It's version of <GL/gl.h> requires <windows.h> to be included
before <GL/gl.h> can be included because of Microsoft function declaration
conventions. Sigh.
ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ
Q18: I want my GLUT program to read and send information over a socket to some
other program. How do I do this in in GLUT?
A18: You can not do it currently. I am considering such support for a possible
GLUT 4.0. I'd like to have a portable solution.
What you'd like is a callback that would tell you when a socket is ready for
reading and writing. I'm hoping to find a way to support this in an operating
system independent manner. Does anyone know of a good portable interface for
networked bytestream connections?
For now, you've got the source code to GLUT and you could hack it into GLUT
for whatever particular interface your operating system provides.
ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ
Q19: Where's the best place to ask questions about GLUT or OpenGL? Can I just
email them to you?
A19: While I may try to return email if I have time, the best place is the
comp.graphics.api.opengl newsgroup. This gives a lot more people a chance to
answer your question and you'll probably get an answer much faster than
sending me email. Plus, I may not know the answer though someone on the "net"
may know it.
ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ
Q20: My workstation doesn't have OpenGL. Where can I get a free copy to use
with GLUT?
A20: OpenGL is licensed by Silicon Graphics and is not available as "free" or
"public domain" software, but workstation vendors typically bundle OpenGL
software with their workstation. However, there is a package called Mesa
written by Brian Paul at the University of Wisconsin that implements the
OpenGL API. (To be branded as "OpenGL", an implementation must be licensed and
pass the Architectural Review Board's conformance suite, so Mesa is not an
official "OpenGL" implementation.) Mesa does work with GLUT.
ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ
Q21: I hear GLUT 3.0 has overlay support. Where is an example?
A21: Look at progs/examples/zoomdino.c for an example of using overlays for
rubber-banding and display of a help message, both in the overlays. Also,
test/over_test.c exercises all of the overlay routines.
ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ
Q22: I get BadMatch X protocol errors when I run GLUT programs. What gives?
A22: There is a bug in the Solaris 2.4 and 2.5 implementation of
XmuLookupStandardColormap. When you compile GLUT on Solaris 2.4 or 2.5, please
apply the following patch and compile with -DSOLARIS_2_4_BUG to workaround the
problem. To do this, edit the glut/lib/glut/Makefile and add
-DSOLARIS_2_4_BUG to the CFLAGS macro. See the comment in the patch below.
This code is already in GLUT 3.1 and later.
*** glut_win.c Wed Apr 24 14:06:08 1996
--- glut_win.c.bad Wed Apr 24 14:03:58 1996
***************
*** 398,414 ****
case TrueColor:
case DirectColor:
*colormap = NULL; /* NULL if RGBA */
- #ifndef SOLARIS_2_4_BUG
- /* Solaris 2.4 has a bug in its XmuLookupStandardColormap
- implementation. Please compile your Solaris 2.4 version
- of GLUT with -DSOLARIS_2_4_BUG to work around this bug.
- The symptom of the bug is that programs will get a
- BadMatch error from X_CreateWindow when creating a GLUT
- window because Solaris 2.4 creates a corrupted
- RGB_DEFAULT_MAP property. Note that this workaround
- prevents Colormap sharing between applications, perhaps
- leading unnecessary colormap installations or colormap
- flashing. */
status = XmuLookupStandardColormap(__glutDisplay,
vi->screen, vi->visualid, vi->depth, XA_RGB_DEFAULT_MAP,
/* replace */ False, /* retain */ True);
--- 398,403 ----
***************
*** 423,429 ****
return;
}
}
- #endif
/* If no standard colormap but TrueColor, just make a
private one. */
/* XXX Should do a better job of internal sharing for
--- 412,417 ----
ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ
Q23: What is new in GLUT 3.1?
A23: GLUT 3.1 is largely a maintence release. There are some new programs, a
few minor GLUT library bug fixes, but mostly GLUT 3.1 is to make sure GLUT
builds cleanly on various platforms like SunOS, HP/UX, Solaris, and Linux. See
the CHANGES file included in the distribution for more details.
ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ
Q24: How do I make Linux shared libraries for GLUT?
A24: Peter F. Martone (pmarton@mailbox.bgsu.edu) has written some instructions
for making a Linux shared library for GLUT. You can grab the instructions for
doing so from http://pizza.bgsu.edu/cgi-bin/cgiwrap/~pmarton/makeMainIndex
ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ
Q25: New in GLUT 3.2.
A25: Like GLUT 3.1, GLUT 3.2 is a maintence release. Along with bug fixes to
the core GLUT library, many new GLUT example programs have been added. The
portability of the examples has been improved so that most should build using
Windows 95 and NT. Also, GLUT API man pages are now included. See the CHANGES
file included in the distribution for more details.
ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ
Q26: GLUT API man pages.
A26: Please see the README.man file for details. The easiest way for SGI users
to get the man pages is to install the "glut_dev.man.glut" subsystem included
with the pre-compiled SGI GLUT images.
ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ
Q27: Fast window repair for Mesa.
A27: The GLX specification states that the state of a window's back color
buffer after a glXSwapBuffers is undefined. However, the freeware Mesa
implementation of the OpenGL API always leaves the back buffer with its
previous contents (ie, it simply "copies" the back buffer contents to the
front buffer).
Because Mesa lacks hardware acceleration and is often slow to redraw a window,
this presents the opportunity to speed redrawing a window damaged by window
system interactions by simply calling glXSwapBuffers again.
If you set the MESA_SWAP_HACK enviornment variable, GLUT 3.2 will try to
repair double buffered windows not otherwise needing a redisplay because of
glutPostRedisplay by calling glXSwapBuffers when Mesa is the OpenGL
implementation being used and the last display callback called
glutSwapBuffers.
In general, this means if you see MESA_SWAP_HACK when using Mesa, double
buffered GLUT programs will redraw very quickly after being damaged but still
operate well if they've been correctly written to use glutPostRedisplay to
trigger application required redraws.
I encourage all Mesa users to set the MESA_SWAP_HACK environment variable.
ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ
Q28: Advanced GLUT example .rgb image file.
A28: Yes, the image files these examples use are large and were seperated out
from the main GLUT source code distribution. Get the glut_data.tar.gz file
from where you got your GLUT distribution. Untar these data files over your
glut distribution so the "data" directory is at the same level as "progs".
Then do a "make links" in the progs/advanced directory to make symbolic links.
See the progs/advanced/README file for more details.
ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ
Q29: Why doesn't GLUT programs compiled on IRIX 6.4 or 6.3 work earlier
releases?
A29: First, SGI never guarantees that an executable built on a later IRIX
release will work on an earlier release. Sometimes it works; more often than
not it does not. GLUT takes advantage of a new X optimization in IRIX 6.3
called "fast atoms". This optimization lets X clients determine common atom
values without an X server round-trip. This helps X performance.
If you compile the GLUT library on an IRIX 6.3 or IRIX 6.4 machine, the
library will support fast atoms. This will mean that if you run executables
linked against the "fast atom enabled" version of the GLUT library, you'll get
a run-time link error saying something like:
17062:glut_example: rld: Fatal Error: attemped access to unresolvable symbol
in projtex: _XSGIFastInternAtom
Do not be alarmed. If you want, you can recompile the GLUT library with the
-DNO_FAST_ATOMS and get a version of the library that doesn't have the support
so that GLUT executables built with a library compiled without "fast atoms"
can work on earlier IRIX releases. Note that even if you do compile with
-DNO_FAST_ATOMS, there is still no guarantee that an IRIX executable compiled
on a newer release will actually work on an older release (but at least you'll
have a chance!).
Note that the precompiled images lack "fast atoms" support so they will work
fine with IRIX releases before IRIX 6.3 and 6.4.
ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ
Q30: Can I get a version of GLUT for the Power Macintosh?
A30: Probably pretty soon. Conix Graphics is working on a port of GLUT 3.2 as
of late January 1997. Try checking the Conix Graphics web site
http://www.conix3d.com for current info.
ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ
- Mark
ΓòÉΓòÉΓòÉ 3.2. mjk's Home Page ΓòÉΓòÉΓòÉ
Mark Kilgard
Technical Information
OpenGL Render Serving with GLR
Pipelined Multiprocessor Movie Compression of Hardware Rendered Scenes
OpenGL Utility Toolkit (GLUT) Specification, version 3 (PostScript)
Connectathon '96: GLX, the protocol for networked OpenGL (SGI Showcase)
Graphics Interface '95: System Support for OpenGL Direct Rendering
(PostScript)
X Tech '94: X Server Multirendering for OpenGL and PEX (PostScript)
X Tech '95: D11: a high-performance, protocol-optional,
transport-optional window system with X11 compatibility and semantics
(PostScript)
A Three Color Cursor for Silicon Graphics Workstations
Gateway to OpenGL Info
Book Information
Info on Programming OpenGL for the X Window System
SIGGRAPH '96 Course Info
OpenGL and Window System Integration
Software Distributions (by ftp)
Getting the GLUT 3.3 software distribution
The X Journal OpenGL sample program from "OpenGL and X" series
Stuff about me
Where I grew up.
Went to Rice University.
Advanced Systems Division Silicon Graphics Computer Systems Inc. Mailstop
8U-590 2011 N. Shoreline Blvd. P.O. Box 7311 Mountain View, CA 94039-7311
Phone: (415) 390-2028 Email: mjk@sgi.com
ΓòÉΓòÉΓòÉ 4. Gateway to OpenGL Info ΓòÉΓòÉΓòÉ
Gateway to OpenGL Info
This page contains collects links to various sources of information on OpenGL,
the fastest and most widely available programming interface for 3D and imaging.
The topics and links are in no particular order.
OpenGL Overviews
OpenGL for the X Window System
OpenGL Tutorials
OpenGL Utility Toolkit (GLUT)
Mesa 3D Graphics Library (freeware OpenGL-like implementation)
OpenGL for Windows NT
OpenGL Implementation Information
OpenGL with Fortran
Silicon Graphics OpenGL Documentation
Books on OpenGL
Free OpenGL-related Software
OpenGL Benchmarks
Graphics Hardware Designed for OpenGL
Higher-level OpenGL libraries
OpenGL for OS/2
OpenGL for NeXTStep
OpenGL for Macintosh
OpenGL for BeOS
OpenGL Personalities
OpenGL for Linux
OpenGL SIGGRAPH '96 Courses
OpenGL Architectural Review Board
Vendor support for OpenGL
Publically Available OpenGL-based applications
Courses using OpenGL
OpenGL-based Rendering Techniques
Gaming with OpenGL
OpenGL in Japan
Random OpenGL Related Links
OpenGL Overviews
The OpenGL Graphics Interface (PostScript)
The Design of the OpenGL Graphics Interface (PostScript)
The OpenGL Graphics System: A Specification,Version 1.1 (PostScript)
The OpenGL Graphics System Utility Library (the GLU 1.2 spec) in
PostScript
OpenGL WWW Center
OpenGL - The Integration of Windowing and 3D Graphics
Hypertext OpenGL manual pages
Notes on the new polygon tessellator in GLU version 1.2
Objective X: An Overview of OpenGL
OpenGL: The Leading Visual Programming Interface
Glossary of Graphics Terms
About OpenGL Extensions
An Introduction to OpenGL
An OpenGL Perspective on Direct3D
Using OpenGL to Create 2D and 3D Graphics
Byte Magazine: OpenGL's Command Structure
Analysis of PEX 5.1 and OpenGL 1.0
John Carmack's .plan comparing OpenGL vs. Direct3D
PC Webopaedia entry for OpenGL
Hypertext OpenGL Frequently Asked Questions
How OpenGL differs from IRIS GL
Microsoft documentation: OpenGL Utility Library
Microsoft documentation: Introduction to OpenGL
OpenGL for the X Window System
GLX 1.2 Specification in HTML
OpenGL & X: An Introduction
OpenGL & X: Using OpenGL with Xlib
OpenGL & X: Integrating OpenGL with Motif
Programming with OpenGL
Overlay-extended Motif-based OpenGL Widget
Hints on using OpenGL
OpenGL Tutorials
OpenGL: from the EXTensions to the SOLutions
HP's Volume Rendering Technique Comparison: Raycasting vs. 3D Texture
Mapping
Brian Paul's OpenGL Portability Notes
Brian Paul's Using OpenGL Extensions
Using Sam Leffler's libtiff with OpenGL and GLUT
OpenGL Utility Toolkit (GLUT)
Getting the GLUT 3.3 software distribution
OpenGL Utility Toolkit (GLUT) Specification, version 3 (PostScript)
Frequently Asked GLUT Questions
GLUT 3.3 for Windows NT & Windows 95
GLUT 3.3 for Windows NT & Windows 95 (Europe mirror)
GLUT 3.2 for Windows NT (old version)
GLUT 3.3 ftp location
GLUT 3.3 for Windows 95 & NT libraries compiled for Borland
Debian Download of pre-compiled GLUT library for Linux
Debian Download of GLUT examples programs and documentation for Linux
Mesa 3D Graphics Library (freeware OpenGL-like implementation)
The Mesa 3-D graphics library
Mesa Frequently Asked Questions
Mesa User's Guide
Mesa for the Amiga
Linux Mesa hardware support for 3DLab's GLINT chips
MESA Mailing List Archive
Adding GLX extension to XFree86 using Mesa 2.0
More about adding GLX to XFree86 with Mesa
Accelerating Mesa with a 3D Graphics Card
Tree: Java interface for Mesa 3D graphics
OpenGL for Windows 95 and NT
Windows NT OpenGL: Getting Started
OpenGL I: Quick Start
OpenGL II: Windows Palettes in RGBA Mode
OpenGL III: Building an OpenGL C++ Class
OpenGL IV: Color Index Mode
OpenGL V: Translating Windows DIBs
OpenGL VI: Rendering on DIBs with PFD_DRAW_TO_BITMAP
OpenGL VII: Scratching the Surface of Texture Mapping
Using OpenGL in Visual C++ Version 4.x
OpenGL for Windows NT Workstation
OpenGL Demo Software for Windows NT
Update on Cosmo OpenGL
OpenGL/Win32 Q&A
Win32 OpenGL Examples
The OpenGL SuperBible Sampler
NewMedia: Reviews of Windows NT OpenGL Cards
Download OpenGL DLLs for Windows 95 from Microsoft
Download SGI's Cosmo OpenGL DLLs for Windows 95
Cosmo OpenGL Beta 2 Release Notes
Microsoft's OpenGL Support
Microsoft documentation: Introduction to Porting to OpenGL for Windows NT
and Windows 95
Microsoft documentations: OpenGL on Windows NT and Windows 95
OpenGL Programming with 3dfx's Voodoo Graphics
SciTech's Full Screen OpenGL demos
OpenGL Implementation Information
Graphics Interface '95: System Support for OpenGL Direct Rendering
(PostScript)
X Tech '94: X Server Multirendering for OpenGL and PEX (PostScript)
Connectathon '96: GLX, the protocol for networked OpenGL (SGI Showcase)
Software OpenGL: Architecture and Implementation
Pixel-Planes issues considering the implementation of OpenGL
Solaris OpenGL 1.0 Implementation and Performance Guide
Intergraph's MicroStation OpenGL Engine (MOGLE)
HP's Volume Rendering Extensions for OpenGL
The OpenGL Stream Codec: A Specification
The OpenGL Character Renderer: A Specification
Mesa Implementation Notes
An Overview of Microsoft's OpenGL Driver Models
Solaris OpenGL Architecture
The Design and Analysis of a Cache Architecture for Texture Mapping
OpenGL with Fortran
f90gl: Fortran Interface for Mesa and GLUT
Silicon Graphics OpenGL Documentation
OpenGL on Silicon Graphics Systems (IRIX 6.4 version)
The OpenGL Porting Guide (IRIX 6.4 version)
Cosmo OpenGL User Guide (Beta 2/97)
Books on OpenGL
The OpenGL Programming Guide, Second Edition
OpenGL Programming Guide (2nd ed) Errata
OpenGL Reference Manual, 2nd edition
Addison-Wesley's OpenGL Technical Library
Programming OpenGL for the X Window System: table of contents
3D Graphics Programming with OpenGL
OpenGL SuperBible
Programming OpenGL for Windows 95 and Windows NT
Interactive Computer Graphics A Top-Down Approach with OpenGL (college
textbook)
Ordering Sun OpenGL Software Manuals
Free OpenGL-related Software
OpenGL Interface for Modula-3
An Unofficial port of OpenGL to Java
OpenGL Perl Module
TIGER 1.2 (Tcl based Interpretative Graphics EnviRonment) using OpenGL
Forms Library, a graphical user interface toolkit for X (has OpenGL
canvas)
Togl - a Tk OpenGL widget
TkSM - an OpenGL based 3D modeling extension for Tcl/Tk
AutoDesk DXF file format renderer using OpenGL
The Visualization Toolkit
Source code and executable for Quake database walk-through using OpenGL
PyOpenGL: The Python Tk-OpenGL Module
TRAWN: Tron-like cycle game for SGIs
Matumot's OpenGL Paradise (includes fonts and Windows example code)
A free, partial Open Inventor Implementation: Apprentice
repGL: an IRIS GL to OpenGL porting library
Files in GEO format, together with OpenGL geo viewer
OpenGL-based Hierarchical Modeling and Animation System
OpenGL Benchmarks
OpenGL Performance Characterization Project
What's This Thing Called "Viewperf"?
Download the Viewperf Benchmark
Preliminary GLperf Benchmark Info
OpenGL Performance Characterization (dated info)
viewperf's Advanced Visualizer Viewset (AWadvs-01)
viewperf's CDRS Viewset (CDRS-03)
viewperf's Data Explorer Viewset (DX-02)
viewperf's Design Review Viewset
viewperf's Lightscape Viewset (LIGHT-01)
SGI's overview of the viewperf benchmark
Graphics Hardware Designed for OpenGL
GLINT Delta 3D Geometry Pipeline Processor
GLINT 300SX Overview
GLINT based Graphics Boards
Silicon Graphics Onyx InfiniteReality and RealityEngine
Silicon Graphics Indigo2 IMPACT
IBM POWER GXT 1000
IBM Freedom Series 6000
IBM POWER GXT500 and GXT500D Graphics Accelerators
DEC PowerStorm Family of Graphics Accelerators
Freedom Series from Evans & Sutherland for Alpha Systems
Intergraph GLZ Series of OpenGL Graphics Accelerators
Evans & Sutherland Freedom Series Whitepaper
Sun SPARCstation 20 with Freedom Series
S-MOS Systems 3D geometry accelerator
AccelGraphics OpenGL 3D Graphics Accelerators for Windows NT
ELSA Gloria 3D accelerator
ELSA GLoria-M, GLoria-L
PC 3D Graphics Accelerators FAQ
Mitsubishi Intros New 3D-RAM Product
Dynamic Pictures Oxygen 3D Graphics Accelerator Family
Digital Design & Technology Blending ASIC
Digital's PowerStore OpenGL hardware for Unix and Windows NT
Lockheed Martin: Real 3D R3D/100 chipset
Evans & Sutherland: Univeral 3D Architecture for NT
SGI InfiniteReality Graphics - Power Through Complexity
3Dlabs: Permedia and GLINT Delta - New Generation Silicon for 3D Graphics
S3: ViRGE/VX
Leadtek: WinFast 3D L2200
Leadtek: WinFast 3D L2500 (Glint 500TX)
MicroStep: AGC-GL300 / AGC-GL300 Pro
MicroSetp: AGC-GL500 Pro
TriTech Microelectronics: Pyramid3D
3Dlabs: GLINT Gamma 3D
Higher-level OpenGL libraries
OpenGL Optimizer for CAD applications
OpenGL Optimizer Frequently Asked Questions
CAD/CAM/CAE Graphics Standards Consortium (CGSC) standardization effort
for OpenGL Optimizer
OpenGL Optimizer offered as CAD rendering API
IRIS Performer visual simulation toolkit
IRIS Performer Frequently Asked Questions
Open Inventor object-oriented 3D toolkit
Open Inventor Frequently Asked Questions
Open Inventor for Windows 95 and NT
Apprentice: An Open Inventor freeware clone
NeTpower's Open Inventor Toolkit for Microsoft Windows
ImageVision image processing toolkit
ImageVision Frequently Asked Questions
OpenGL for OS/2
The OpenGL on OS/2 API
OpenGL For OS/2 Developer Mailing List
1995 ColoradOS/2 OpenGL presentations
Latest OS/2 OpenGL binaries for Intel x86-based PCs
OpenGL for NeXTStep
GNU 3DKit: OpenGL and 3DKit
OpenGL for Macintosh
Conix Graphics OpenGL for the Macintosh
OpenGL for BeOS
Be Computer reports they have licensed OpenGL
OpenGL Personalities
Brian Paul (Mesa implementor)
Mark Kilgard (OpenGL for X author)
Nate Robins (Windows GLUT co-implementor)
Robert Doyle
Mason Woo (OpenGL Programming Guide coauthor)
Philip Winston's Graphics Page
Professor Edward S. Angel (OpenGL graphics textbook author)
Richard Wright (OpenGL Super Bible coauthor)
Brian Hook
OpenGL for Linux
Metro Link's for Linux
Common Questions about OpenGL for Linux from Portable Graphics
Features of AcceleratedX OpenGL for Linux ELF
OpenGL SIGGRAPH '96 Courses
Programming with OpenGL: An Introduction
Programming with OpenGL: Advanced Rendering
OpenGL and Window System Integration
OpenGL Architectural Review Board
Minutes of the 22 August 1994 OpenGL Advisory Forum
Notes from the 26 February 1996 OpenGL Architectural Review Board Meeting
Notes from the 14 May 1996 OpenGL Architectural Review Board Meeting
Notes from the 20 August 1996 OpenGL Architectural Review Board Meeting
Old Architectural Review Board Meeting Notes
HP Joins OpenGL Architectural Review Board (ARB)
Bylaws of the OpenGL Architecture Review Board
Vendor Support for OpenGL
OpenGL Adopted by SunSoft
Common Questions About OpenGL for HP from Portable Graphics
HP and Portable Graphics Announce Accelerated OpenGL for HP Workstations
Template Graphics OpenGL Implementations
SunSoft, NCD, & HP Adopt OpenGL
SunSoft's native OpenGL 3D graphics product
Sun's Questions Answered about OpenGL 1.0
Solaris OpenGL 1.0 Implementation and Performance Guide
Solaris OpenGL╨╛ Ultra Creator3D Edition
Sun Ships Native OpenGL for UltraSPARC Workstations
OpenGL & Open Inventor for HP 9000 Available
CAD/CAM Leaders Define OpenGL-based API Standard
NEC adopts OpenGL-based GLINT chips for new NT Workstations
Available OpenGL-based Software
OpenSpace, a distributed discrete-event modeling and simulation package
Vis5D, a system for interactive visualization of large 5-D gridded data
sets
NBody Granitational Simulation for Windows NT/95 using OpenGL
Softoholic OGL ActiveX Control
AVS 5.3 (Data Visualization)
AVS/Express 3.0 Visualization Edition
AVS/Express 3.0 Developer Edition
Dropit 1.1 (A blockout clone.)
GMV (General Mesh Viewer)
RAD: A Radiosity Program
VRweb Home Page (VRML browser with source code)
View3D (Motif/OpenGL viewer widget)
CAVE (CAVE Automatic Virtual Environment) User's Guide
OpenGL extensions to AL, the Animation Language
i3D: A High Speed 3D Web Browser
Sculptor NT: Free Form Modeling for Windows
WarpSpace: O2/2 VRML browser
WebLab Viewer: PC-based molecular viewer
MOLMOL: MOLecule analysis and MOLecule display
Solaris OpenGL╨╛ 1.0 Application Partners
3D Spectral Viewer for NT
Computer Graphics World: Microsoft Softimage on NT
DIR3D, an OpenGL-based 3D file manager for Windows 95 & NT
CAVE User's Guide for OpenGL-based fully immersive virtual reality
PoVSB, a Windows 95/NT based modeler for the Persistence of Vision
Raytracer
Courses using OpenGL
UCLA: Graphics Programming with OpenGL
The Michael Zyda Image Synthesis in OpenGL Consulting Course
The Michael Zyda Beginning Computer Graphics with OpenGL & Motif
Consulting Course
Carleton College: Computer Graphics
Technion: Computer Graphics
Rensselaer Polytechnic Institute: Advanced Computer Graphics and Data
Visualization
Boston University, Introduction to Computer Graphics
Boston University, Graduate Introduction to Computer Graphics (CS 680)
University of Texas: Computer Graphics
University of New Mexico: Computer Graphics (CS/EECE 433)
Royal Melbourne Institute of Technology, Interactive 3D Graphics (CS545)
Royal Melbourne Institute of Technology, Interactive 3D Graphics and
Animation (CS493)
University of Hong Kong, Computer Graphics (CS381)
Stanford University, Introduction to Computer Graphics (CS 248)
University of Wisconsin Oshkosh, Computer Graphics(34-371)
University of Toronto, Computer Graphics (CSC 418/2504)
University of Toronto, Current Ideas and Techniques in Computer Graphics
(SCI 199)
Wake Forest University, Introduction to Computer Graphics (CSC323)
University of Maryland Baltimore County, Graphical User Interface
Programming (CMSC 491A/691A)
University of Houston, Interactive Computer Graphics (CS 4370)
University of Waterloo, Introduction to Computer Graphics (CS488/688)
University of Calgary, Computer Graphics 453
Georgia Tech, Advanced Computer Graphics (CS4391)
Harvey Mudd College, Computer Graphics (CS 155)
Technion User Support Group, The OpenGL graphic system
Foothill College, Computer Graphics Programming 1 (CIS 53A)
Silicon Graphics, OpenGL Programming 1
Silicon Graphics, OpenGL Programming 2
Caltech, Computer Graphics Laboratory (CS 174)
Columbia University, Computer Graphics (CS W4160y)
Santa Clara University, Computer Graphics I (COEN 290)
UCLA: 3D graphics Programming (X499.91)
California State University, Chico (CSCI-231)
Gaming with OpenGL
Andy Johnson's Battalion Page (A game where a monster blows up and
destroys stuff.)
Free Rubik's Cube Game for Windows 95 & NT
OpenGL Asteriods
OpenGL Quake Unleashed
Download OpenGL Quake for Windows 95
Download SGI Port of Id Software's Quake using OpenGL
OpenGL-based Open Inventor games for SGI machines
3D Mines V1.2 for SGI using OpenGL-based Open Inventor
MutliGen's OpenGL-based GameGen II Realtime 3D authoring for
entertainment
OpenGL-based bzflag "capture the flag with virtual tanks" game
KnightCap: OpenGL-based 3D front-end to supercomputer chess
Free Flight Simulator using Cosmo OpenGL
OpenGL Game Development Mailing List
OpenGL-based Rendering Techniques
Texture Mapping in Technical, Scientific and Engineering Visualization
Interactive Volume Rendering Using Advanced Graphics Architectures
Texture Mapping as a Fundamental Drawing Primitive
Graphics Gems Source Code Archive (useful to OpenGL programmers)
Converting sets of triangles with shared edges into triangle strips
STRIPE: a software tool that converts a polygonal model into triangle
strips
Hin Jang on Tri-Linear MIP Mapping
Hin Jang on Projective Texture Mapping
Hin Jang on Perspective Projection
Alvy Smith on "Image Compositing Fundamentals"
Alvy Smith on "A Pixel is Not a Little Square"
Alvy Smith on "Alpha and the History of Digital Compositing"
Alvy Smith on " Varities of Digital Painting"
Alvy Smith on "Gamma Correction"
Journal of Graphics Tools
Fast OpenGL-based "in place" scale & bias technique
Rendering Fast reflections with OpenGL
OpenGL in Japan
Japanese OpenGL Mailing List Archive
NK-EXA's handmade "OpenGL Programming Course"
Handouts of "Practical OpenGL Programming" Series
OpenGL Frequently Asked Questions in Japanese
Random OpenGL Related Links
The Virtual Whale Project: 3D Modeling of Humpback Whales (rendered with
OpenGL)
Masayuki Matsumoto beside Kurt Akeley's Lotus (California "OpenGL"
license plate)
Paper on integrating Ray Tracingwith OpenGL (???, written in German)
Intelligraphics Device Drivers: consulting for developing OpenGL drivers
General Reality Company: OpenGL software for their 5th Glove (3D glove
device)
A Vision Application in OpenGL
OpenGL Debug Library: gldebug.h and gldebug.c
- Mark Kilgard
ΓòÉΓòÉΓòÉ 5. External links ΓòÉΓòÉΓòÉ
This chapter contains all external links referenced in this book - either link
is an Unified Resource Locator (URL) or simply to a local file which is not a
part of this book.
ΓòÉΓòÉΓòÉ 5.1. mailto:bit@freya.etu.ru ΓòÉΓòÉΓòÉ
The link you selected points to an external resource.
Click the URL below to launch IBM Web Explorer
mailto:bit@freya.etu.ru
ΓòÉΓòÉΓòÉ 5.2. http://www.digital.com:80/pub/doc/opengl/glPixelTransfer.html ΓòÉΓòÉΓòÉ
The link you selected points to an external resource.
Click the URL below to launch IBM Web Explorer
http://www.digital.com:80/pub/doc/opengl/glPixelTransfer.html
ΓòÉΓòÉΓòÉ 5.3. http://www.digital.com:80/pub/doc/opengl/glCopyPixels.html ΓòÉΓòÉΓòÉ
The link you selected points to an external resource.
Click the URL below to launch IBM Web Explorer
http://www.digital.com:80/pub/doc/opengl/glCopyPixels.html
ΓòÉΓòÉΓòÉ 5.4. http://www.sgi.com/Products/hardware/desktop/products/graphics.html ΓòÉΓòÉΓòÉ
The link you selected points to an external resource.
Click the URL below to launch IBM Web Explorer
http://www.sgi.com/Products/hardware/desktop/products/graphics.html
ΓòÉΓòÉΓòÉ 5.5. http://www.ssec.wisc.edu/~brianp/Mesa.html ΓòÉΓòÉΓòÉ
The link you selected points to an external resource.
Click the URL below to launch IBM Web Explorer
http://www.ssec.wisc.edu/~brianp/Mesa.html
ΓòÉΓòÉΓòÉ 5.6. mesa_patch.diff ΓòÉΓòÉΓòÉ
The link you selected points to an external resource.
Click the URL below to launch IBM Web Explorer
mesa_patch.diff
ΓòÉΓòÉΓòÉ 5.7. http://reality.sgi.com/mjk_asd/ ΓòÉΓòÉΓòÉ
The link you selected points to an external resource.
Click the URL below to launch IBM Web Explorer
http://reality.sgi.com/mjk_asd/
ΓòÉΓòÉΓòÉ 5.8. mailto:mjk@sgi.com ΓòÉΓòÉΓòÉ
The link you selected points to an external resource.
Click the URL below to launch IBM Web Explorer
mailto:mjk@sgi.com
ΓòÉΓòÉΓòÉ 5.9. http://www.sgi.com/Products/cosmo/opengl/download.html ΓòÉΓòÉΓòÉ
The link you selected points to an external resource.
Click the URL below to launch IBM Web Explorer
http://www.sgi.com/Products/cosmo/opengl/download.html
ΓòÉΓòÉΓòÉ 5.10. http://www.sgi.com/Technology/openGL/arb.html ΓòÉΓòÉΓòÉ
The link you selected points to an external resource.
Click the URL below to launch IBM Web Explorer
http://www.sgi.com/Technology/openGL/arb.html
ΓòÉΓòÉΓòÉ 5.11. http://reality.sgi.com/mjk_asd/smoke.qt ΓòÉΓòÉΓòÉ
The link you selected points to an external resource.
Click the URL below to launch IBM Web Explorer
http://reality.sgi.com/mjk_asd/smoke.qt
ΓòÉΓòÉΓòÉ 5.12. http://www.directx.com/carmack.htm ΓòÉΓòÉΓòÉ
The link you selected points to an external resource.
Click the URL below to launch IBM Web Explorer
http://www.directx.com/carmack.htm
ΓòÉΓòÉΓòÉ 5.13. http://www.sgi.com/Technology/openGL/direct-3d.html ΓòÉΓòÉΓòÉ
The link you selected points to an external resource.
Click the URL below to launch IBM Web Explorer
http://www.sgi.com/Technology/openGL/direct-3d.html
ΓòÉΓòÉΓòÉ 5.14. http://www.microsoft.com/kb/softlib/mslfiles/OPENGL95.EXE ΓòÉΓòÉΓòÉ
The link you selected points to an external resource.
Click the URL below to launch IBM Web Explorer
http://www.microsoft.com/kb/softlib/mslfiles/OPENGL95.EXE
ΓòÉΓòÉΓòÉ 5.15. http://www.cs.utah.edu/~narobins/glut.html ΓòÉΓòÉΓòÉ
The link you selected points to an external resource.
Click the URL below to launch IBM Web Explorer
http://www.cs.utah.edu/~narobins/glut.html
ΓòÉΓòÉΓòÉ 5.16. http://www.sgi.com/Technology/openGL/glspec1.1/node32.html ΓòÉΓòÉΓòÉ
The link you selected points to an external resource.
Click the URL below to launch IBM Web Explorer
http://www.sgi.com/Technology/openGL/glspec1.1/node32.html
ΓòÉΓòÉΓòÉ 5.17. http://www.sgi.com/Technology/openGL/glspec1.1/glspec.html ΓòÉΓòÉΓòÉ
The link you selected points to an external resource.
Click the URL below to launch IBM Web Explorer
http://www.sgi.com/Technology/openGL/glspec1.1/glspec.html
ΓòÉΓòÉΓòÉ 5.18. http://www.cs.unm.edu/~angel/ ΓòÉΓòÉΓòÉ
The link you selected points to an external resource.
Click the URL below to launch IBM Web Explorer
http://www.cs.unm.edu/~angel/
ΓòÉΓòÉΓòÉ 5.19. http://heg-school.aw.com/cseng/authors/angel/intcg/intcg.html ΓòÉΓòÉΓòÉ
The link you selected points to an external resource.
Click the URL below to launch IBM Web Explorer
http://heg-school.aw.com/cseng/authors/angel/intcg/intcg.html
ΓòÉΓòÉΓòÉ 5.20. http://reality.sgi.com/mjk_asd/tips/ ΓòÉΓòÉΓòÉ
The link you selected points to an external resource.
Click the URL below to launch IBM Web Explorer
http://reality.sgi.com/mjk_asd/tips/
ΓòÉΓòÉΓòÉ 5.21. rockfont.txf ΓòÉΓòÉΓòÉ
The link you selected points to an external resource.
Click the URL below to launch IBM Web Explorer
rockfont.txf
ΓòÉΓòÉΓòÉ 5.22. curlfont.txf ΓòÉΓòÉΓòÉ
The link you selected points to an external resource.
Click the URL below to launch IBM Web Explorer
curlfont.txf
ΓòÉΓòÉΓòÉ 5.23. default.txf ΓòÉΓòÉΓòÉ
The link you selected points to an external resource.
Click the URL below to launch IBM Web Explorer
default.txf
ΓòÉΓòÉΓòÉ 5.24. haeberli.txf ΓòÉΓòÉΓòÉ
The link you selected points to an external resource.
Click the URL below to launch IBM Web Explorer
haeberli.txf
ΓòÉΓòÉΓòÉ 5.25. sorority.txf ΓòÉΓòÉΓòÉ
The link you selected points to an external resource.
Click the URL below to launch IBM Web Explorer
sorority.txf
ΓòÉΓòÉΓòÉ 5.26. http://reality.sgi.com/paul/ ΓòÉΓòÉΓòÉ
The link you selected points to an external resource.
Click the URL below to launch IBM Web Explorer
http://reality.sgi.com/paul/
ΓòÉΓòÉΓòÉ 5.27. http://www.sgi.com/ ΓòÉΓòÉΓòÉ
The link you selected points to an external resource.
Click the URL below to launch IBM Web Explorer
http://www.sgi.com/
ΓòÉΓòÉΓòÉ 5.28. glut-3.3.tar.gz ΓòÉΓòÉΓòÉ
The link you selected points to an external resource.
Click the URL below to launch IBM Web Explorer
glut-3.3.tar.gz
ΓòÉΓòÉΓòÉ 5.29. glut_data-3.3.tar.gz ΓòÉΓòÉΓòÉ
The link you selected points to an external resource.
Click the URL below to launch IBM Web Explorer
glut_data-3.3.tar.gz
ΓòÉΓòÉΓòÉ 5.30. http://sunsite.unc.edu/pub/packages/development/graphics/glut/ ΓòÉΓòÉΓòÉ
The link you selected points to an external resource.
Click the URL below to launch IBM Web Explorer
http://sunsite.unc.edu/pub/packages/development/graphics/glut/
ΓòÉΓòÉΓòÉ 5.31. ftp://sunsite.unc.edu/pub/packages/development/graphics/glut/ ΓòÉΓòÉΓòÉ
The link you selected points to an external resource.
Click the URL below to launch IBM Web Explorer
ftp://sunsite.unc.edu/pub/packages/development/graphics/glut/
ΓòÉΓòÉΓòÉ 5.32. glut_dev.tardist ΓòÉΓòÉΓòÉ
The link you selected points to an external resource.
Click the URL below to launch IBM Web Explorer
glut_dev.tardist
ΓòÉΓòÉΓòÉ 5.33. http://www.cs.utah.edu/~narobins/opengl.html ΓòÉΓòÉΓòÉ
The link you selected points to an external resource.
Click the URL below to launch IBM Web Explorer
http://www.cs.utah.edu/~narobins/opengl.html
ΓòÉΓòÉΓòÉ 5.34. spec3.html ΓòÉΓòÉΓòÉ
The link you selected points to an external resource.
Click the URL below to launch IBM Web Explorer
spec3.html
ΓòÉΓòÉΓòÉ 5.35. glut-3.spec.ps.gz ΓòÉΓòÉΓòÉ
The link you selected points to an external resource.
Click the URL below to launch IBM Web Explorer
glut-3.spec.ps.gz
ΓòÉΓòÉΓòÉ 5.36. glut.column1.ps.gz ΓòÉΓòÉΓòÉ
The link you selected points to an external resource.
Click the URL below to launch IBM Web Explorer
glut.column1.ps.gz
ΓòÉΓòÉΓòÉ 5.37. OpenGLforX.html ΓòÉΓòÉΓòÉ
The link you selected points to an external resource.
Click the URL below to launch IBM Web Explorer
OpenGLforX.html
ΓòÉΓòÉΓòÉ 5.38. http://math.nist.gov/f90gl/ ΓòÉΓòÉΓòÉ
The link you selected points to an external resource.
Click the URL below to launch IBM Web Explorer
http://math.nist.gov/f90gl/
ΓòÉΓòÉΓòÉ 5.39. mailto:pmarton@mailbox.bgsu.edu ΓòÉΓòÉΓòÉ
The link you selected points to an external resource.
Click the URL below to launch IBM Web Explorer
mailto:pmarton@mailbox.bgsu.edu
ΓòÉΓòÉΓòÉ 5.40. http://pizza.bgsu.edu/cgi-bin/cgiwrap/~pmarton/makeMainIndex ΓòÉΓòÉΓòÉ
The link you selected points to an external resource.
Click the URL below to launch IBM Web Explorer
http://pizza.bgsu.edu/cgi-bin/cgiwrap/~pmarton/makeMainIndex
ΓòÉΓòÉΓòÉ 5.41. http://www.conix3d.com ΓòÉΓòÉΓòÉ
The link you selected points to an external resource.
Click the URL below to launch IBM Web Explorer
http://www.conix3d.com
ΓòÉΓòÉΓòÉ 5.42. onyx_on_an_indy.html ΓòÉΓòÉΓòÉ
The link you selected points to an external resource.
Click the URL below to launch IBM Web Explorer
onyx_on_an_indy.html
ΓòÉΓòÉΓòÉ 5.43. movie-generation.html ΓòÉΓòÉΓòÉ
The link you selected points to an external resource.
Click the URL below to launch IBM Web Explorer
movie-generation.html
ΓòÉΓòÉΓòÉ 5.44. spec3.html ΓòÉΓòÉΓòÉ
The link you selected points to an external resource.
Click the URL below to launch IBM Web Explorer
spec3.html
ΓòÉΓòÉΓòÉ 5.45. GLUT.spec.ps ΓòÉΓòÉΓòÉ
The link you selected points to an external resource.
Click the URL below to launch IBM Web Explorer
GLUT.spec.ps
ΓòÉΓòÉΓòÉ 5.46. GLXprotocol.ps ΓòÉΓòÉΓòÉ
The link you selected points to an external resource.
Click the URL below to launch IBM Web Explorer
GLXprotocol.ps
ΓòÉΓòÉΓòÉ 5.47. GLXprotocol.sc ΓòÉΓòÉΓòÉ
The link you selected points to an external resource.
Click the URL below to launch IBM Web Explorer
GLXprotocol.sc
ΓòÉΓòÉΓòÉ 5.48. direct.html ΓòÉΓòÉΓòÉ
The link you selected points to an external resource.
Click the URL below to launch IBM Web Explorer
direct.html
ΓòÉΓòÉΓòÉ 5.49. direct.ps ΓòÉΓòÉΓòÉ
The link you selected points to an external resource.
Click the URL below to launch IBM Web Explorer
direct.ps
ΓòÉΓòÉΓòÉ 5.50. multirender.html ΓòÉΓòÉΓòÉ
The link you selected points to an external resource.
Click the URL below to launch IBM Web Explorer
multirender.html
ΓòÉΓòÉΓòÉ 5.51. multirender.ps ΓòÉΓòÉΓòÉ
The link you selected points to an external resource.
Click the URL below to launch IBM Web Explorer
multirender.ps
ΓòÉΓòÉΓòÉ 5.52. d11.html ΓòÉΓòÉΓòÉ
The link you selected points to an external resource.
Click the URL below to launch IBM Web Explorer
d11.html
ΓòÉΓòÉΓòÉ 5.53. d11.PS ΓòÉΓòÉΓòÉ
The link you selected points to an external resource.
Click the URL below to launch IBM Web Explorer
d11.PS
ΓòÉΓòÉΓòÉ 5.54. 3color.PS ΓòÉΓòÉΓòÉ
The link you selected points to an external resource.
Click the URL below to launch IBM Web Explorer
3color.PS
ΓòÉΓòÉΓòÉ 5.55. OpenGLforX.html ΓòÉΓòÉΓòÉ
The link you selected points to an external resource.
Click the URL below to launch IBM Web Explorer
OpenGLforX.html
ΓòÉΓòÉΓòÉ 5.56. http://www.siggraph.org/conferences/siggraph96/core/conference/courses/22.html ΓòÉΓòÉΓòÉ
The link you selected points to an external resource.
Click the URL below to launch IBM Web Explorer
http://www.siggraph.org/conferences/siggraph96/core/conference/courses/22.html
ΓòÉΓòÉΓòÉ 5.57. ftp://sgigate.sgi.com/pub/opengl/xjournal ΓòÉΓòÉΓòÉ
The link you selected points to an external resource.
Click the URL below to launch IBM Web Explorer
ftp://sgigate.sgi.com/pub/opengl/xjournal
ΓòÉΓòÉΓòÉ 5.58. http://pubweb.parc.xerox.com/map/border=1/color=1/grid=0/ht=12.00/lat=29.60/lon=-95.15/mark=29.75,-95.349999999999994316,6,9/river=1/wd=180.00 ΓòÉΓòÉΓòÉ
The link you selected points to an external resource.
Click the URL below to launch IBM Web Explorer
http://pubweb.parc.xerox.com/map/border=1/color=1/grid=0/ht=12.00/lat=29.60/lon=-95.15/mark=29.75,-95.349999999999994316,6,9/river=1/wd=180.00
═══ <hidden> 6,6,9/river=1/wd=180.00Н ═══
the 12 180 00
, /01234999999999999431600
, /0122900
, /
, /01218000
, /wd
, =
, :
, to
,
,
, 60
, Click
, lon ht
, ht
, . launch
, ht
, .
, 95
, 12= external
, 00 , http=ht
, = external
, 121 12
, = ht
, =12
, = grid
, . river
, /lon
, com = 156
, . com = pubweb
,12
, belowcom lon 12 =
, com 15
, com =
, com = 0border00
, com lat1215 lat12
, com lat12
, com
, belowcom =
12Explorer ,
, parc
, selected
, 1515000
, resource mark
,
, selected
, 12=
, selected
, color lon
, pointscom link / . /
,/
,
, selected
159
, 159 mark
, 159
, 75 159
, 159 12to
, ancom lon an
,
you
, URL
, 000
, 0The00
, 01200
, 12
, 000
, - /
, 15 The 000
, 000
,
, /
, http
, lat
/com
, Explorer pubweb
, Explorermark
, selected
you
, : 60 parc
, = 75 you
, 6 75 you
, 95 75 you
, you
, you 0xerox00
,
Explorer 1
, lon
, ht
, selected to IBM
,
, 1 1 . link
, /below
, /URL http 3499999999999943161529
, 3499999999999943161529 selected
, -
, . Click
, 18012wd
, map 12
12
, 1 grid 12selected
, 1 grid border12
, 180color
, launch
, 00 wd - border 15 an0 00
, 180an1529
, 180an1529
, 34999999999999431615349999999999994316 0external 1500
, 000
, Explorer external
, 000
, 018000
, 000 /. /
,points1 the
, Explorer external below
, Explorer
, Explorer 1809
, Explorer 12
, Explorer river selected
, - 3499999999999943161529 Web
, below
, Explorer
, 1resource12 belowcolor.
, /12
, 1 grid color180
, Explorer
, 12
, you .
, link
, link
, mark pubweb
, 1
, 1 0ht00
, link
, link 0180color00
, 1 border 000
, 1 border pubweb river 000
, 1 000
, 1 09500
, 1 0an12below00
, 1 0Click180:00
, 1 pubweb 06000
, 1 000
, wd 1 0external180IBM00
, 1 0com00
, 1 0180http00
, 1 Explorer
, 1 mark 000
, 1 034999999999999431600
, 1
, 1 29 0grid00
, 1 29
, 1 75
, 1 0600
, 000
, 1 0=00
, link border 015lat00
, 1 012900
, resource /xerox 0lon map pubweb 1500
, /launch .
, to
,
, launch
, /
, 12Web
, border 1575 12Web
, /12Web border URL
, 12Web --
, link 12Web border 12
,
,
12 Web
, 1 pubweb
, mark selected
, the map
, The 000
,
, link map map
, 12
,
, / . /
,points --
, points -lon map -
, points -parc pubweb -
, points - . link -
, 9 -resource grid-
, URL
, parc 12below -- . Click
, parc
/ . /
, =
, 12mark/Web -ht-
, xerox --
, pubweb an
, 349999999999994316 180 you 000
, border 75/0com -- 00
, 06661 selected00
, - latlon 349999999999994316externalpointsIBMmap
, river Explorer349999999999994316 points 29 to 0180 the launch00
, 60 :
, http 349999999999994316 The15wd 95 The15color
12
wd ,
grid 15 180 00 349999999999994316 95 color 60 external 12 . 29 9 75 1 http com
= ,IBM- border Explorer ht 0 : 6 lat 75 an 0 Click below external 12/ 9 ,
an 60 com = 9 border / 180 95,
1 below Click 0 border 6 349999999999994316 color 15
URL URL 75-00.29,12,:
,
color : http Click an Explorer 0 349999999999994316 border,
1 com external 00 Explorer 95 9 grid 29
75/--ht,15,12/.-below-180-=-6,60
,
color : http Click an Explorer 0 349999999999994316 border,
1 com external 00 Explorer 95 9 grid 29
wd URL 75/--ht,15,12/.-below-180-=-6,60
,
color 95 http border : Explorer / 180 below,
00 com external 0 Explorer 9 75 grid 15
60.--ht,Click,1-an-349999999999994316-12-=-29,6
,
below 75 grid = 95 Click / 180 :,
1 border color 0 Click 60 6 com 15
URL URL wd wd URL 349999999999994316.--external,an,Explorer,12-ht00-9,29
,
9 180 below 75 6 : - 1 60,
/ 95 = . : 15 12 an 00
29border349999999999994316,0
,
below 60 Explorer = 9 Click / 180 :,
1 border color 00 Click 6 349999999999994316 com 15
29.--95,an,12-75external0-
,
= 349999999999994316 color 95 75 below / 15 00 an border 0 below 29 180 Click 12
6-60.:,1
- ,
Click 9 ht below : com / 29 an,
00 color Explorer 0 com 75 60 external 180
6.--grid,border,1-=-12-95-15,349999999999994316
/ ,
border 75 grid = 95 color / 180 :,
1 Click com 00 color 60 6 Explorer 15
URL wd wd wd URL 349999999999994316.--external,an,12-below-9-0,29
,
Click 60 grid an 9 com / 180 =,
1 color Explorer 00 com 6 349999999999994316 external 15
29.--:,below,12-75ht0-border,95
,
an 9 Explorer = 95 border / 29 :,
1 below Click 0 border 75 60 color 180
6.--, 12 - 00 , 349999999999994316
,
color 95 http below = Explorer 00 349999999999994316 an-
12 com external 1 Explorer 9 75 grid 29
600..ht-border-15.Click.:.180,/-6
,
Click 75 ht below = com / 180 an,
00 color Explorer 0 com 60 349999999999994316 external 15
29.--grid,9,1border - 95 - : , 12
,
below 9 grid an : Click / 180 =,
00 border color 0 Click 75 60 Explorer 15
6.--external,1,com,12-ht95-29,349999999999994316
,
color 9 http below = Explorer 0 180 an,
1 com external 00 Explorer 75 60 grid 15
6/--ht,border,12-Click-:-29,.-
, ,
color 95 http below = Explorer 0 180 an,
1 com external 00 Explorer 9 75 grid 15
60/--ht,border,12-Click-:-349999999999994316,.-29,6
,
= 75 Explorer : 9 below / 29 95,
1 an Click 00 below 60 6 color 180
349999999999994316.--com,12,border,15-external0-
,
belowIBMcombordergrid060Click -
180 external ht 15 grid an : http 6
95/..75,color-12-29.349999999999994316.1.00.=.=-9
,
below 60 external = 9 color / 180 :,
1 border com 00 color 6 349999999999994316 Explorer 15
29.--95,an,12-75grid0-Click-
,
60 15 an 6 180 9 - ,
/ 75 : . 9 12 1 = 0
349999999999994316,95
/ ,
60 180 an 6 29 9 - 1 349999999999994316,
/ 75 : . 9 15 12 = 00
0,95
. ,
60 180 an 6 29 9 - 1 349999999999994316,
/ 75 : . 9 15 12 = 00
0,95
,
60 180 an 6 29 9 - 00 349999999999994316,
/ 75 : . 9 15 12 = 0
URL 1,95
,
an 6 com : 75 border / 15 95,
00 below Click 0 border 349999999999994316 29 color 12
180.--9,=,1-60-
,
: 6 color 9 60 an / 15 75,
00 = below 0 an 349999999999994316 29 border 12
URL URL wd 180.--Click,95,1-
grid ,
= 60 color 95 75 below / 15 9-
00 an border 0 below 6 349999999999994316 Click 12
180com1,.-.-:-29
12 ,
Click 9 ht below : com / 180 an,
00 color external 0 com 75 60 grid 15
wd wd URL URL wd wd wd wd wd wd 6.--border,Explorer,12-=-95-1-349999999999994316-29-
,
Click 9 ht below : com / 180 an,
00 color external 0 com 75 60 grid 15
29.--border,Explorer,12-=-95-1-6-349999999999994316-
15 ,
9 29 below 60 349999999999994316 : - 1 6,
/ 95 = . : 180 15 an 00
launch 95 launch URL launch launch URL 12border0,75
/ ,
below 75 grid an : Click / 180 =,
00 border color 0 Click 60 6 Explorer 15
349999999999994316.--external,1,com,12-ht9-95,29
,
75 180 an 6 29 95 - 00 349999999999994316,
/ 9 : . 95 15 12 = 0
60,1
,
= 6 color 95 60 below /
75 180 an 60 349999999999994316 95 - 00 6,
/ 9 : . 95 15 12 = 0
29,1
,
an 60 com = 95 border / 12 :,
00 below Click 0 border 6 349999999999994316 color 1
29.--75,9,180-15-
,
an 6 com = 95 border / 180 :,
1 below Click 0 border 349999999999994316 29 color 15
75 - 9 . 60 , 00 , 12
,
com : http color border external 0 60 Click-
29 Explorer grid 00 external 95 9 ht 6
75/..an-1-349999999999994316.15,12.180.IBMbelow.=
,
: 60 color 95 75 an / 180 9,
00 = below 0 an 6 349999999999994316 border 15
29.--Click,12,1
,
95 60 = - 00 75,
/ : an . = 180 12 below 0
6Click349999999999994316Click-Click15,1
, ,
95 349999999999994316 border 9 60 = . 1 75-
0 : an / = 29 180 below 00
6,12-15
,
75 180 an 6 29 95 - 00 349999999999994316,
/ 9 : . 95 15 12 = 0
60,1
29 ,
9 180 below 60 29 : - 00 6,= . : 15 12 an 0
1,75,349999999999994316
,
75 180 an 60 29 95 - 00 6,
/ 9 : . 95 15 12 = 0
1,349999999999994316
,
75 180 an 60 29 95 - 00 349999999999994316,
/ 9 : . 95 15 12 = 0
1,6
, ,
75 29 an 60 349999999999994316 95 - 1 6,
/ 9 : . 95 180 15 = 00
launch launch URL 0,12
,
75 180 an 60 29 95 - 1 6,
/ 9 : . 95 15 12 = 00
0,349999999999994316
,
75 180 an 60 349999999999994316 95 - 00 6,
/ 9 : . 95 15 12 = 0
29,1
Explorer ,
75 29 an 60 349999999999994316 95 - 1 6,
/ 9 : . 95 180 15 = 00
0,12
,
75 180 an 60 29 95 - 1 6,
/ 9 : . 95 15 12 = 00
0,349999999999994316
grid ,
75 180 an 60 349999999999994316 95 - 00 6,
/ 9 : . 95 15 12 = 0
URL launch launch URL 29,1
,
com : IBM border an external 0 6 below,
1 Explorer grid 00 external 95 9 ht 349999999999994316
75/--http,Click,=-15-color-180-12-29-.,60
15 ,
below 6 external : 75 Click / 15 95,
00 border color 0 Click 349999999999994316 29 com 12
wd wd wd 180.--an,=,1-9-60-Explorer
border -
The link you selected points to an external resource.
Click the URL below to launch IBM Web Explorer
http://pubweb.parc.xerox.com/map/border=1/color=1/grid=0/ht=/ lat = 29 . 60 / lon = - 95 . 15 / mark = 29 . 75 , - 95 . 349999999999994316 , 6 , 9 / river = 1 / wd = 180 . 00
border - the 12 180 00
, /01234999999999999431600
, /0122900
, /
, /01218000
, /wd
, =
, : 15
, to
, border -
,
, 60
, Click
, lon ht
, ht
, . launch
, ht
, .
, 95
, 12= external
, border-00,http = ht
, = external
, 121 12
, = ht
, =12
, = grid
, . river
, /lon
, com=15 6
, . com = pubweb
,12
, belowcom lon 12 =
, com 15
, com =
, com = 0border00
, com lat1215 lat12
, com lat12
, com 15
, belowcom =
12border - Explorer ,
, parc
, selected
, 1515000
, resource mark
,
, selected
, 12=
, selected colorlon
, pointscom link - / . /
,/
,
, selected
159
, 159 mark
, 159
, 75 159
, 159 12to
, ancom lon an -
,
you
, URL
, 000
, 0The00
, 01200
, 12
, 000
, /
, 15 The 000
, 000
,
, /
, http
, lat
/com Explorer ,
, Explorer pubweb
, Explorer mark
, selected
you
, : 60 parc
, = 75 you
, 6 75 you
, 95 75 you
, you
, you 0xerox00
,
border - Explorer 1
, lon
, ht
, selected to IBM
,
, 1 1 . link
, /below
, /URL http 3499999999999943161529
, 3499999999999943161529 selected
, -
border -
, . Click
, 18012wd
, map 12
12
, 1 grid 12selected
, 1 grid border12
, 180color
, launch
, border-00wd-border15an 000
, 180an1529
, 180an1529
, 34999999999999431615349999999999994316 0external 1500
, 000
, Explorer external
, 000
, 000
, 000 /border - . /
,points1 the
, Explorer external below
, Explorer
, Explorer 1809
, Explorer 12
, Explorer river selected
, - 3499999999999943161529 Web
, below . 15
, Explorer
, 1 resource 12below color .
, /12
, 1 grid color180
, Explorer
, 12
, you .
, link 15
, link
, border-markpubweb
, 1
, 1 0ht00
, link
, link 0180color00
, 1 border 000
, 1 border pubweb river 000
, 0 00 - 10 00
, 1 border - 09500
, 1 0an12below00
, 1 0Click180:00
, 1 pubweb 06000
, 1 000
, wd 1 0external180IBM00
, 1 0com00
, 1 0180http00 1 Explorer
, 1 mark 000
, 1 034999999999999431600
, 1
, 1 29 0grid00
, 1 29
, 1 75
/ . 1 10 6 00
, border - 000
, 1 0=00
, link border 015lat00
, 1 012900
, resource /xerox 0lon map pubweb 1500
, /launch .
, to
,
, border - launch
, /
, 12Web
, border 1575 12Web
, /12Web border URL
, 12Web --
, link 12Web border 12
,
,
border - 12 Web
, 1 pubweb
, mark selected
, the map
, The 000
,
, link map map
, 12
,
, - / . /
,points --
, points -lon map -
, points -parc pubweb -
, points - . link -
, 9 -resource grid-
, URL
, parc 12below -- . Click 15
, parc
border - / . /
, =
, 12mark/Web -ht-
, xerox --
, pubweb an
, 349999999999994316 180 you 000
, border 75/0com -- 00 , 0 6 6 6 1selected 00
, lat lon349999999999994316 external points IBM map
, river Explorer349999999999994316 points 29 to 0180 the launch00
, 60 :
, http 349999999999994316 The15wd 95 The15color
12
wd ,
grid 15 180 00 349999999999994316 95 color 60 external 12 . 29 9 75 1 http com
= ,IBM- border Explorer ht 0 : 6 lat 75 an 0 Click below external 12/ 9 ,
60com=9border/18095 ,
1 below Click 0 border 6 349999999999994316 color 15
75-00.29,12,:
,
color : http Click an Explorer 0 349999999999994316 border,
1 com external 00 Explorer 95 9 grid 29
75/--ht,15,12/.-below-180-=-6,60
,
color : http Click an Explorer 0 349999999999994316 border,
1 com external 00 Explorer 95 9 grid 29
URL launch launch wd wd URL URL Web wd wd wd border - wd URL 75/--ht,15,12/.-below-180-=-6,60
,
color 95 http border : Explorer / 180 below,
00 com external 0 Explorer 9 75 grid 15
60.--ht,Click,1-an-349999999999994316-12-=-29,6
,
below 75 grid = 95 Click / ,
1 border color 0 Click 60 6 com 15
349999999999994316.--external,an,Explorer,12-ht00-9,29
,
9 180 below 75 6 : - 1 60,
/ 95 = . : 15 12 an 00
29border349999999999994316,0
,
below 60 Explorer = 9 Click / 180 :,
1 border color 00 Click 6 349999999999994316 com 15
29 . - - 95 , an , 12 - 75 external 0 -
,
= 349999999999994316 color 95 75 below / 15 9border-00anborder0below29180Click12
6-60.:,1
- ,
Click 9 ht below : com / 29 an,
00 color Explorer 0 com 75 60 external 180
6.--grid,border,1-=-12-95-15,349999999999994316
/ ,
border 75 grid = 95 color / ,
1 Click com 00 color 60 6 Explorer 15
349999999999994316.--external,an,12-below-9-0,29
,
Click 60 grid an 9 com / 180 =,
1 color Explorer 00 com 6 349999999999994316 external 15
29.--:,below,12-75ht0-border,95
,
an 9 Explorer = 95 border / 29 :,
1 below Click 0 border 75 60 color 180
URL launch launch wd wd URL URL wd URL 6.--comborder-,12-00,349999999999994316
,
color 95 http below = Explorer 00 349999999999994316 an-
12 com external 1 Explorer 9 75 grid 29
600..ht-border-15.Click.:.180,/-6
,
Click 75 ht below = com / 180 an,
00 color Explorer 0 com 60 349999999999994316 external 15
wd wd wd wd URL 29.--grid,9,1-border-border-95-:,12
,
below 9 grid an : Click / 180 =,
00 border color 0 Click 75 60 Explorer 15
6.--external,1,com,12-ht95-29,349999999999994316
,
color 9 http below = Explorer 0 180 an,
1 com external 00 Explorer 75 60 grid 15
wd xerox URL xerox wd you URL 6/--ht,border,12-Click-:-29,.-95border-
, ,
color 95 http below = Explorer 0 180 an,
1 com external 00 Explorer 9 75 grid 15
60/--ht,border,12-Click-:-349999999999994316,.-29,6
,
= 75 Explorer : 9 below / 29 95,
1 an Click 00 below 60 6 color 180
wd wd 349999999999994316.--com,12,border,15-external0-
,
border-below IBM com border grid 0 60 Click-
180 external ht 15 grid an : http 6
95/..75,color-12-29.349999999999994316.1.00.=.=-9
,
below 60 external = 9 color / 180 :,
1 border com 00 color 6 349999999999994316 Explorer 15
29.--95,an,12-75grid0-Click-
,
60 15 an 6 180 9 - 00 border - ,
/ 75 : . 9 12 1 = 0
349999999999994316,95
/ ,
60 180 an 6 29 9 - 1 349999999999994316,
/ 75 : . 9 15 12 = 00
0,95
. ,
60 180 an 6 29 9 - 1 349999999999994316,
/ 75 : . 9 15 12 = 00
0,95
,
external 0 60 180an6299-00349999999999994316 ,
/ 75 : . 9 15 12 = 0
1,95
,
an 6 com : 75 border / 15 95,
00 below Click 0 border 349999999999994316 29 color 12
180.--9,=,1-60-
,
: 60 an / 15 75,
00 = below 0 an 349999999999994316 29 border 12
180.--Click,95,1-
grid ,
= 60 color 95 75 below / 15 9-
00 an border 0 below 6 349999999999994316 Click 12
180com1,.-.-:-29
12 ,
Click 9htbelow:com/180an ,
00 color external 0 com 75 60 grid 15
6.--border,Explorer,12-=-95-1-349999999999994316-29-
,
Click 9 ht below : com / 180 an,
00 color external 0 com 75 60 grid 15
29.--border,Explorer,12-=-95-1-6-349999999999994316. 15
15 ,
9 29 below 60 349999999999994316 : - 1 6,
/ 95 = . : 180 15 an 00
border - launch 95 launch URL launch launch URL 12border0,75
/ ,
below 75 grid an : Click / 180 =,
00 border color 0 Click 60 6 Explorer 15
349999999999994316.--external,1,com,12-ht9-95,29
,
75 180 an 6 29 95 - 00 349999999999994316,
/ 9 : . 95 15 12 = 0
75 180 an 60 349999999999994316 95 - 00 6,
/ 9 : . 95 15 12 = 0
29,1
,
an 60 com = 95 border / 12 :,
00 below Click 0 border 6 349999999999994316 color 1
29.--75,9,180-15-
,
an 6 com = 95 border / 180 :,
1 below Click 0 border 349999999999994316 29 color 15
75 - 9 . 60 , 00 , 12
,
com : http color border external 0 60 Click-
29 Explorer grid 00 external 95 9 ht 6
75/..an-1-349999999999994316.15,12.180.IBMbelow.=
,
: 60 color 95 75 an / 180 9,
00 = below 0 an 6 349999999999994316 border 15
29.--Click,12,1
,
95 60 = - 00 75,
/ : an . = 180 12 below 0
6Click349999999999994316Click-Click15,1
, ,
95 349999999999994316 border 9 60 = . 1 75-
0 : an / = 29 180 below 00
6,12-15
,
75 180 an 6 29 95 - 00 349999999999994316,
/ 9 : . 95 15 12 = 0
60,1
29 ,
9 180 below 60 29 : - 00 6,= . : 15 12 an 0
1,75,349999999999994316
,
75 180 an 60 29 95 - 00 6,
/ 9 : . 95 15 12 = 0
1,349999999999994316
,
75 180 an 60 29 95 - 00 349999999999994316,
/ 9 : . 95 15 12 = 0
1,6
, ,
75 29 an 60 349999999999994316 95 - 1 6,
/ 9 : . 95 180 15 = 00
launch launch URL 0,12
,
75 180 an 60 29 95 - 1 6,
/ 9 : . 95 15 12 = 00
0,349999999999994316
,
75 180 an 60 349999999999994316 95 - 00 6,
/ 9 : . 95 15 12 = 0
29,1
Explorer ,
75 29 an 60 349999999999994316 95 - 1 6,
/ 9 : . 95 180 15 = 00
0,12
,
75 180 an 60 29 95 - 1 6,
/ 9 : . 95 15 12 = 00
0,349999999999994316
grid ,
75 180 an 60 349999999999994316 95 - 00 6,
/ 9 : . 95 15 12 = 0
URL launch launch URL 29,1
,
com : IBM border an external 0 6 below,
1 Explorer grid 00 external 95 9 ht 349999999999994316
75/--http,Click,=-15-color-180-12-29-.,60
15 ,
below 6 external : 75 Click / 15 95,
00 border color 0 Click 349999999999994316 29 com 12
wd wd wd 180.--an,=,1-9-60-Explorer
border -
The link you selected points to an external resource.
Click the URL below to launch IBM Web Explorer
http://pubweb.parc.xerox.com/map/border=1/color=1/grid=0/ht=/ lat = 29 . 60 / lon = - 95 . 15 / mark = 29 . 75 , - 95 . 349999999999994316 , 6 , 9 / river = 1 / wd = 180 . 00
border - the 12 180 00
, /01234999999999999431600
, /0122900
, /
, /01218000
, /wd
, =
, : 15
, to
, border -
,
, 60
, Click
, lon ht
, ht
, . launch
, ht
, .
, 95
, 12= external
, border-00,http = ht
, = external
, 121 12
, = ht
, =12
, = grid
, . river
, /lon
, com=15 6
, . com = pubweb
,12
, belowcom lon 12 =
, com 15
, com =
, com = 0border00
, com lat1215 lat12
, com lat12
, com 15
, belowcom =
12border - Explorer ,
, parc
, selected
, 1515000
, resource mark
,
, selected
, 12=
, selected colorlon
, pointscom link - / . /
,/
,
, selected
159
, 159 mark
, 159
, 75 159
, 159 12to
, ancom lon an -
,
you
, URL
, 000
, 0The00
, 01200
, 12
, 000
, /
, 15 The 000
, 000
,
, /
, http
, lat
/com Explorer ,
, Explorer pubweb
, Explorer mark
, selected
you
, : 60 parc
, = 75 you
, 6 75 you
, 95 75 you
, you
, you 0xerox00
,
border - Explorer 1
, lon
, ht
, selected to IBM
,
, 1 1 . link
, /below
, /URL http 3499999999999943161529
, 3499999999999943161529 selected
, -
border -
, . Click
, 18012wd
, map 12
12
, 1 grid 12selected
, 1 grid border12
, 180color
, launch
, border-00wd-border15an 000
, 180an1529
, 180an1529
, 34999999999999431615349999999999994316 0external 1500
, 000
, Explorer external
, 000
, 000
, 000 /border - . /
,points1 the
, Explorer external below
, Explorer
, Explorer 1809
, Explorer 12
, Explorer river selected
, - 3499999999999943161529 Web
, below . 15
, Explorer
, 1 resource 12below color .
, /12
, 1 grid color180
, Explorer
, 12
, you .
, link 15
, link
, border-markpubweb
, 1
, 1 0ht00
, link
, link 0180color00
, 1 border 000
, 1 border pubweb river 000
, 0 00 - 10 00
, 1 border - 09500
, 1 0an12below00
, 1 0Click180:00
, 1 pubweb 06000
, 1 000
, wd 1 0external180IBM00
, 1 0com00
, 1 0180http00 1 Explorer
, 1 mark 000
, 1 034999999999999431600
, 1
, 1 29 0grid00
, 1 29
, 1 75
/ . 1 10 6 00
, border - 000
, 1 0=00
, link border 015lat00
, 1 012900
, resource /xerox 0lon map pubweb 1500
, /launch .
, to
,
, border - launch
, /
, 12Web
, border 1575 12Web
, /12Web border URL
, 12Web --
, link 12Web border 12
,
,
border - 12 Web
, 1 pubweb
, mark selected
, the map
, The 000
,
, link map map
, 12
,
, - / . /
,points --
, points -lon map -
, points -parc pubweb -
, points - . link -
, 9 -resource grid-
, URL
, parc 12below -- . Click 15
, parc
border - / . /
, =
, 12mark/Web -ht-
, xerox --
, pubweb an
, 349999999999994316 180 you 000
, border 75/0com -- 00
═══ <hidden> /opengl.html5Р ═══
, 0 6 6 6 1selected 00
, lat lon349999999999994316 external points IBM map
, river Explorer349999999999994316 points 29 to 0180 the launch00
, 60 :
, http 349999999999994316 The15wd 95 The15color
12
wd ,
grid 15 180 00 349999999999994316 95 color 60 external 12 . 29 9 75 1 http com
= ,IBM- border Explorer ht 0 : 6 lat 75 an 0 Click below external 12/ 9 ,
60com=9border/18095 ,
1 below Click 0 border 6 349999999999994316 color 15
75-00.29,12,:
,
color : http Click an Explorer 0 349999999999994316 border,
1 com external 00 Explorer 95 9 grid 29
75/--ht,15,12/.-below-180-=-6,60
,
color : http Click an Explorer 0 349999999999994316 border,
1 com external 00 Explorer 95 9 grid 29
URL launch launch wd wd URL URL Web wd wd wd border - wd URL 75/--ht,15,12/.-below-180-=-6,60
,
color 95 http border : Explorer / 180 below,
00 com external 0 Explorer 9 75 grid 15
60.--ht,Click,1-an-349999999999994316-12-=-29,6
,
below 75 grid = 95 Click / ,
1 border color 0 Click 60 6 com 15
349999999999994316.--external,an,Explorer,12-ht00-9,29
,
9 180 below 75 6 : - 1 60,
/ 95 = . : 15 12 an 00
29border349999999999994316,0
,
below 60 Explorer = 9 Click / 180 :,
1 border color 00 Click 6 349999999999994316 com 15
29 . - - 95 , an , 12 - 75 external 0 -
,
= 349999999999994316 color 95 75 below / 15 9border-00anborder0below29180Click12
6-60.:,1
- ,
Click 9 ht below : com / 29 an,
00 color Explorer 0 com 75 60 external 180
6.--grid,border,1-=-12-95-15,349999999999994316
/ ,
border 75 grid = 95 color / ,
1 Click com 00 color 60 6 Explorer 15
349999999999994316.--external,an,12-below-9-0,29
,
Click 60 grid an 9 com / 180 =,
1 color Explorer 00 com 6 349999999999994316 external 15
29.--:,below,12-75ht0-border,95
,
an 9 Explorer = 95 border / 29 :,
1 below Click 0 border 75 60 color 180
URL launch launch wd wd URL URL wd URL 6.--comborder-,12-00,349999999999994316
,
color 95 http below = Explorer 00 349999999999994316 an-
12 com external 1 Explorer 9 75 grid 29
600..ht-border-15.Click.:.180,/-6
,
Click 75 ht below = com / 180 an,
00 color Explorer 0 com 60 349999999999994316 external 15
wd wd wd wd URL 29.--grid,9,1-border-border-95-:,12
,
below 9 grid an : Click / 180 =,
00 border color 0 Click 75 60 Explorer 15
6.--external,1,com,12-ht95-29,349999999999994316
,
color 9 http below = Explorer 0 180 an,
1 com external 00 Explorer 75 60 grid 15
wd xerox URL xerox wd you URL 6/--ht,border,12-Click-:-29,.-95border-
, ,
color 95 http below = Explorer 0 180 an,
1 com external 00 Explorer 9 75 grid 15
60/--ht,border,12-Click-:-349999999999994316,.-29,6
,
= 75 Explorer : 9 below / 29 95,
1 an Click 00 below 60 6 color 180
wd wd 349999999999994316.--com,12,border,15-external0-
,
border-below IBM com border grid 0 60 Click-
180 external ht 15 grid an : http 6
95/..75,color-12-29.349999999999994316.1.00.=.=-9
,
below 60 external = 9 color / 180 :,
1 border com 00 color 6 349999999999994316 Explorer 15
29.--95,an,12-75grid0-Click-
,
60 15 an 6 180 9 - 00 border - ,
/ 75 : . 9 12 1 = 0
349999999999994316,95
/ ,
60 180 an 6 29 9 - 1 349999999999994316,
/ 75 : . 9 15 12 = 00
0,95
. ,
60 180 an 6 29 9 - 1 349999999999994316,
/ 75 : . 9 15 12 = 00
0,95
,
external 0 60 180an6299-00349999999999994316 ,
/ 75 : . 9 15 12 = 0
1,95
,
an 6 com : 75 border / 15 95,
00 below Click 0 border 349999999999994316 29 color 12
180.--9,=,1-60-
,
: 60 an / 15 75,
00 = below 0 an 349999999999994316 29 border 12
180.--Click,95,1-
grid ,
= 60 color 95 75 below / 15 9-
00 an border 0 below 6 349999999999994316 Click 12
180com1,.-.-:-29
12 ,
Click 9htbelow:com/180an ,
00 color external 0 com 75 60 grid 15
6.--border,Explorer,12-=-95-1-349999999999994316-29-
,
Click 9 ht below : com / 180 an,
00 color external 0 com 75 60 grid 15
29.--border,Explorer,12-=-95-1-6-349999999999994316. 15
15 ,
9 29 below 60 349999999999994316 : - 1 6,
/ 95 = . : 180 15 an 00
border - launch 95 launch URL launch launch URL 12border0,75
/ ,
below 75 grid an : Click / 180 =,
00 border color 0 Click 60 6 Explorer 15
349999999999994316.--external,1,com,12-ht9-95,29
,
75 180 an 6 29 95 - 00 349999999999994316,
/ 9 : . 95 15 12 = 0
75 180 an 60 349999999999994316 95 - 00 6,
/ 9 : . 95 15 12 = 0
29,1
,
an 60 com = 95 border / 12 :,
00 below Click 0 border 6 349999999999994316 color 1
29.--75,9,180-15-
,
an 6 com = 95 border / 180 :,
1 below Click 0 border 349999999999994316 29 color 15
75 - 9 . 60 , 00 , 12
,
com : http color border external 0 60 Click-
29 Explorer grid 00 external 95 9 ht 6
75/..an-1-349999999999994316.15,12.180.IBMbelow.=
,
: 60 color 95 75 an / 180 9,
00 = below 0 an 6 349999999999994316 border 15
29.--Click,12,1
,
95 60 = - 00 75,
/ : an . = 180 12 below 0
6Click349999999999994316Click-Click15,1
, ,
95 349999999999994316 border 9 60 = . 1 75-
0 : an / = 29 180 below 00
6,12-15
,
75 180 an 6 29 95 - 00 349999999999994316,
/ 9 : . 95 15 12 = 0
60,1
29 ,
9 180 below 60 29 : - 00 6,= . : 15 12 an 0
1,75,349999999999994316
,
75 180 an 60 29 95 - 00 6,
/ 9 : . 95 15 12 = 0
1,349999999999994316
,
75 180 an 60 29 95 - 00 349999999999994316,
/ 9 : . 95 15 12 = 0
1,6
, ,
75 29 an 60 349999999999994316 95 - 1 6,
/ 9 : . 95 180 15 = 00
launch launch URL 0,12
,
75 180 an 60 29 95 - 1 6,
/ 9 : . 95 15 12 = 00
0,349999999999994316
,
75 180 an 60 349999999999994316 95 - 00 6,
/ 9 : . 95 15 12 = 0
29,1
Explorer ,
75 29 an 60 349999999999994316 95 - 1 6,
/ 9 : . 95 180 15 = 00
0,12
,
75 180 an 60 29 95 - 1 6,
/ 9 : . 95 15 12 = 00
0,349999999999994316
grid ,
75 180 an 60 349999999999994316 95 - 00 6,
/ 9 : . 95 15 12 = 0
URL launch launch URL 29,1
,
com : IBM border an external 0 6 below,
1 Explorer grid 00 external 95 9 ht 349999999999994316
75/--http,Click,=-15-color-180-12-29-.,60
15 ,
below 6 external : 75 Click / 15 95,
00 border color 0 Click 349999999999994316 29 com 12
wd wd wd 180.--an,=,1-9-60-Explorer
border -
The link you selected points to an external resource.
Click the URL below to launch IBM Web Explorer
http://pubweb.parc.xerox.com/map/border=1/color=1/grid=0/ht=/ lat = 29 . 60 / lon = - 95 . 15 / mark = 29 . 75 , - 95 . 349999999999994316 , 6 , 9 / river = 1 / wd = 180 . 00
border - the 12 180 00
, /01234999999999999431600
, /0122900
, /
, /01218000
, /wd
, =
, : 15
, to
, border -
,
, 60
, Click
, lon ht
, ht
, . launch
, ht
, .
, 95
, 12= external
, border-00,http = ht
, = external
, 121 12
, = ht
, =12
, = grid
, . river
, /lon
, com=15 6
, . com = pubweb
,12
, belowcom lon 12 =
, com 15
, com =
, com = 0border00
, com lat1215 lat12
, com lat12
, com 15
, belowcom =
12border - Explorer ,
, parc
, selected
, 1515000
, resource mark
,
, selected
, 12=
, selected colorlon
, pointscom link - / . /
,/
,
, selected
159
, 159 mark
, 159
, 75 159
, 159 12to
, ancom lon an -
,
you
, URL
, 000
, 0The00
, 01200
, 12
, 000
, /
, 15 The 000
, 000
,
, /
, http
, lat
/com Explorer ,
, Explorer pubweb
, Explorer mark
, selected
you
, : 60 parc
, = 75 you
, 6 75 you
, 95 75 you
, you
, you 0xerox00
,
border - Explorer 1
, lon
, ht
, selected to IBM
,
, 1 1 . link
, /below
, /URL http 3499999999999943161529
, 3499999999999943161529 selected
, -
border -
, . Click
, 18012wd
, map 12
12
, 1 grid 12selected
, 1 grid border12
, 180color
, launch
, border-00wd-border15an 000
, 180an1529
, 180an1529
, 34999999999999431615349999999999994316 0external 1500
, 000
, Explorer external
, 000
, 000
, 000 /border - . /
,points1 the
, Explorer external below
, Explorer
, Explorer 1809
, Explorer 12
, Explorer river selected
, - 3499999999999943161529 Web
, below . 15
, Explorer
, 1 resource 12below color .
, /12
, 1 grid color180
, Explorer
, 12
, you .
, link 15
, link
, border-markpubweb
, 1
, 1 0ht00
, link
, link 0180color00
, 1 border 000
, 1 border pubweb river 000
, 0 00 - 10 00
, 1 border - 09500
, 1 0an12below00
, 1 0Click180:00
, 1 pubweb 06000
, 1 000
, wd 1 0external180IBM00
, 1 0com00
, 1 0180http00 1 Explorer
, 1 mark 000
, 1 034999999999999431600
, 1
, 1 29 0grid00
, 1 29
, 1 75
/ . 1 10 6 00
, border - 000
, 1 0=00
, link border 015lat00
, 1 012900
, resource /xerox 0lon map pubweb 1500
, /launch .
, to
,
, border - launch
, /
, 12Web
, border 1575 12Web
, /12Web border URL
, 12Web --
, link 12Web border 12
,
,
border - 12 Web
, 1 pubweb
, mark selected
, the map
, The 000
,
, link map map
, 12
,
, - / . /
,points --
, points -lon map -
, points -parc pubweb -
, points - . link -
, 9 -resource grid-
, URL
, parc 12below -- . Click 15
, parc
border - / . /
, =
, 12mark/Web -ht-
, xerox --
, pubweb an
, 349999999999994316 180 you 000
, border 75/0com -- 00 , 0 6 6 6 1selected 00
, lat lon349999999999994316 external points IBM map
, river Explorer349999999999994316 points 29 to 0180 the launch00
, 60 :
, http 349999999999994316 The15wd 95 The15color
12
wd ,
grid 15 180 00 349999999999994316 95 color 60 external 12 . 29 9 75 1 http com
= ,IBM- border Explorer ht 0 : 6 lat 75 an 0 Click below external 12/ 9 ,
60com=9border/18095 ,
1 below Click 0 border 6 349999999999994316 color 15
75-00.29,12,:
,
color : http Click an Explorer 0 349999999999994316 border,
1 com external 00 Explorer 95 9 grid 29
75/--ht,15,12/.-below-180-=-6,60
,
color : http Click an Explorer 0 349999999999994316 border,
1 com external 00 Explorer 95 9 grid 29
URL launch launch wd wd URL URL Web wd wd wd border - wd URL 75/--ht,15,12/.-below-180-=-6,60
,
color 95 http border : Explorer / 180 below,
00 com external 0 Explorer 9 75 grid 15
60.--ht,Click,1-an-349999999999994316-12-=-29,6
,
below 75 grid = 95 Click / ,
1 border color 0 Click 60 6 com 15
349999999999994316.--external,an,Explorer,12-ht00-9,29
,
9 180 below 75 6 : - 1 60,
/ 95 = . : 15 12 an 00
29border349999999999994316,0
,
below 60 Explorer = 9 Click / 180 :,
1 border color 00 Click 6 349999999999994316 com 15
29 . - - 95 , an , 12 - 75 external 0 -
,
= 349999999999994316 color 95 75 below / 15 9border-00anborder0below29180Click12
6-60.:,1
- ,
Click 9 ht below : com / 29 an,
00 color Explorer 0 com 75 60 external 180
6.--grid,border,1-=-12-95-15,349999999999994316
/ ,
border 75 grid = 95 color / ,
1 Click com 00 color 60 6 Explorer 15
349999999999994316.--external,an,12-below-9-0,29
,
Click 60 grid an 9 com / 180 =,
1 color Explorer 00 com 6 349999999999994316 external 15
29.--:,below,12-75ht0-border,95
,
an 9 Explorer = 95 border / 29 :,
1 below Click 0 border 75 60 color 180
URL launch launch wd wd URL URL wd URL 6.--comborder-,12-00,349999999999994316
,
color 95 http below = Explorer 00 349999999999994316 an-
12 com external 1 Explorer 9 75 grid 29
600..ht-border-15.Click.:.180,/-6
,
Click 75 ht below = com / 180 an,
00 color Explorer 0 com 60 349999999999994316 external 15
wd wd wd wd URL 29.--grid,9,1-border-border-95-:,12
,
below 9 grid an : Click / 180 =,
00 border color 0 Click 75 60 Explorer 15
6.--external,1,com,12-ht95-29,349999999999994316
,
color 9 http below = Explorer 0 180 an,
1 com external 00 Explorer 75 60 grid 15
wd xerox URL xerox wd you URL 6/--ht,border,12-Click-:-29,.-95border-
, ,
color 95 http below = Explorer 0 180 an,
1 com external 00 Explorer 9 75 grid 15
60/--ht,border,12-Click-:-349999999999994316,.-29,6
,
= 75 Explorer : 9 below / 29 95,
1 an Click 00 below 60 6 color 180
wd wd 349999999999994316.--com,12,border,15-external0-
,
border-below IBM com border grid 0 60 Click-
180 external ht 15 grid an : http 6
95/..75,color-12-29.349999999999994316.1.00.=.=-9
,
below 60 external = 9 color / 180 :,
1 border com 00 color 6 349999999999994316 Explorer 15
29.--95,an,12-75grid0-Click-
,
60 15 an 6 180 9 - 00 border - ,
/ 75 : . 9 12 1 = 0
349999999999994316,95
/ ,
60 180 an 6 29 9 - 1 349999999999994316,
/ 75 : . 9 15 12 = 00
0,95
. ,
60 180 an 6 29 9 - 1 349999999999994316,
/ 75 : . 9 15 12 = 00
0,95
,
external 0 60 180an6299-00349999999999994316 ,
/ 75 : . 9 15 12 = 0
1,95
,
an 6 com : 75 border / 15 95,
00 below Click 0 border 349999999999994316 29 color 12
180.--9,=,1-60-
,
: 60 an / 15 75,
00 = below 0 an 349999999999994316 29 border 12
180.--Click,95,1-
grid ,
= 60 color 95 75 below / 15 9-
00 an border 0 below 6 349999999999994316 Click 12
180com1,.-.-:-29
12 ,
Click 9htbelow:com/180an ,
00 color external 0 com 75 60 grid 15
6.--border,Explorer,12-=-95-1-349999999999994316-29-
,
Click 9 ht below : com / 180 an,
00 color external 0 com 75 60 grid 15
29.--border,Explorer,12-=-95-1-6-349999999999994316. 15
15 ,
9 29 below 60 349999999999994316 : - 1 6,
/ 95 = . : 180 15 an 00
border - launch 95 launch URL launch launch URL 12border0,75
/ ,
below 75 grid an : Click / 180 =,
00 border color 0 Click 60 6 Explorer 15
349999999999994316.--external,1,com,12-ht9-95,29
,
75 180 an 6 29 95 - 00 349999999999994316,
/ 9 : . 95 15 12 = 0
75 180 an 60 349999999999994316 95 - 00 6,
/ 9 : . 95 15 12 = 0
29,1
,
an 60 com = 95 border / 12 :,
00 below Click 0 border 6 349999999999994316 color 1
29.--75,9,180-15-
,
an 6 com = 95 border / 180 :,
1 below Click 0 border 349999999999994316 29 color 15
75 - 9 . 60 , 00 , 12
,
com : http color border external 0 60 Click-
29 Explorer grid 00 external 95 9 ht 6
75/..an-1-349999999999994316.15,12.180.IBMbelow.=
,
: 60 color 95 75 an / 180 9,
00 = below 0 an 6 349999999999994316 border 15
29.--Click,12,1
,
95 60 = - 00 75,
/ : an . = 180 12 below 0
6Click349999999999994316Click-Click15,1
, ,
95 349999999999994316 border 9 60 = . 1 75-
0 : an / = 29 180 below 00
6,12-15
,
75 180 an 6 29 95 - 00 349999999999994316,
/ 9 : . 95 15 12 = 0
60,1
29 ,
9 180 below 60 29 : - 00 6,= . : 15 12 an 0
1,75,349999999999994316
,
75 180 an 60 29 95 - 00 6,
/ 9 : . 95 15 12 = 0
1,349999999999994316
,
75 180 an 60 29 95 - 00 349999999999994316,
/ 9 : . 95 15 12 = 0
1,6
, ,
75 29 an 60 349999999999994316 95 - 1 6,
/ 9 : . 95 180 15 = 00
launch launch URL 0,12
,
75 180 an 60 29 95 - 1 6,
/ 9 : . 95 15 12 = 00
0,349999999999994316
,
75 180 an 60 349999999999994316 95 - 00 6,
/ 9 : . 95 15 12 = 0
29,1
Explorer ,
75 29 an 60 349999999999994316 95 - 1 6,
/ 9 : . 95 180 15 = 00
0,12
,
75 180 an 60 29 95 - 1 6,
/ 9 : . 95 15 12 = 00
0,349999999999994316
grid ,
75 180 an 60 349999999999994316 95 - 00 6,
/ 9 : . 95 15 12 = 0
URL launch launch URL 29,1
,
com : IBM border an external 0 6 below,
1 Explorer grid 00 external 95 9 ht 349999999999994316
75/--http,Click,=-15-color-180-12-29-.,60
15 ,
below 6 external : 75 Click / 15 95,
00 border color 0 Click 349999999999994316 29 com 12
wd wd wd 180.--an,=,1-9-60-Explorer
border -
The link you selected points to an external resource.
Click the URL below to launch IBM Web Explorer
http://pubweb.parc.xerox.com/map/border=1/color=1/grid=0/ht=/ lat = 29 . 60 / lon = - 95 . 15 / mark = 29 . 75 , - 95 . 349999999999994316 , 6 , 9 / river = 1 / wd = 180 . 00
border - the 12 180 00
, /01234999999999999431600
, /0122900
, /
, /01218000
, /wd
, =
, :
The link you selected points to an external resource.
Click the URL below to launch IBM Web Explorer
http://www.webcity.co.jp/info/matumot/index-e.html
The link you selected points to an external resource.
Click the URL below to launch IBM Web Explorer
http://www.rice.edu/
. :
. Web/selected
. Explorerthe
. Web/Clickthe
. the
. Exploreredu Explorer
. the an
.theExplorer
. the
. :
. an
. Web / theexternal link
. : the
.Explorer
. URLExplorer the
. external
. the
. the belowWebClick
. Explorerexternal Explorer
. Exploreran : an
.Web / external
. URLthe
ExplorerWeb / .
.
.
. externalexternalbelowClick
. an : an
.
.
. Explorerthe
.
Web / you
. / an : an
.an.
.
externalrice
. externalrice
. externalrice
. resource externalrice
. externalrice Explorer: / Web /
. toto /
. : /
.
. belowClick
. belowClick
. belowExplorerClick
. Explorer .belowClick
. an
. external belowClick
.belowClick
.
. an
.
.
anWeb / .
. below Click Web /
.
.
. The points
. the resource
. link resource
an : edu selectedresource
.
. Web / belowClick
. /
Web / edu
.
.
The link you selected points to an external resource.
Click the URL below to launch IBM Web Explorer
http://www.webcity.co.jp/info/matumot/index-e.html
The link you selected points to an external resource.
Click the URL below to launch IBM Web Explorer
http://www.sgi.com/Technology/openGL/paper/opengl.html
. Explorer
Explorer
. com www Explorer
. com www TechnologyExplorer .Technology / htmlthe
.
. Technology/Click/Technologyexternalselected belowClick
. htmlselectedexternalhttp
. htmlselected
. IBMexternalIBM belowWeb externalClick
. belowClick
. URL Web
. belowClick
.com below html Technology / Click
. belowClick anTechnology / : an
.com
. URL Web sgi
.
. URL htmlopengl
. URL Explorer
. URL
. / IBMexternalhttp
.
sgi Technology / : external
. URL
. comExplorer sgithe:
. an Explorer
. comwwwhtml
. URL
. Explorer
. :
. Technology / external
.
. Technology /
. com
. combelow you Click .
. below html the Click
. comTechnologybelow Click
. comTechnologybelow Click
. / below Click / combelow Click
. comTechnology/below paper Click
. combelow selected Explorer sgi Click
. combelow The html points external
. combelow link Click
. combelow Click
. combelow Web html Click
. com Technology / belowtoClick
. combelow html ClickcomURL
. combelow Click
. below IBM Click
. com
. comhttpbelow www Click
. comhttp
. comopenGL
Technology / an : com combelow launch Click
. Technology/below Click
. combelow resource Click
. Technologybelow external Clickcom belowExploreropenglClick
. an below external Click
. an :
. Technology/
.
. Technology/
. an
. Explorer
. TechnologyexternalopenGL Explorer
. an Explorer Technology
. Explorer / /
. Explorer TechnologyExplorer
.
.
Technology/Explorer
. com
.
.
. below Click
.
.
. Explorer .
. /an:an
. / /
. / /
. / /
. /:/
. opengl/ www /
.
. Explorer sgi/ /:TheTechnology/external
═══ 5.58.0.0.0.0.0.0.1. L/paper/opengl.html5Р ═══
an
.
Technology / an : an
. resource
. Exploreran/you/
. //
.selected
. IBM html belowClick
. Technology openGLanbelowto // Click Technology / . below Click / below
launch launch launch comClick
. IBM Web
. URLIBM http belowhtml Click
. link points
. / IBMexternal paperexternal the
Explorer
.
www external html Click IBM paper the link Web Explorer : http opengl openGL
com to resource ./ Technology URL you below points launch openGL selected
below The sgi Web Exploreran opengl .
Technology/link to resource opengl paper.
com sgi The below Technology launch IBM the external
openGL/Click:http.Explorer.points
.
the points The selected URL below IBM Technology.
com to Web Click URL paper opengl www http
openGLan//you.external.Exploreran:/sgi/html/resource/launch.link
.
the points The selected URL below IBM Technology.
com to Web Click URL paper opengl www http
Technology / openGLan//you.external.Exploreran:/sgi/html/resource/launch.link
.
the paper Technology points URL an html sgi.
Click to Web below URL opengl openGL www external
link://you.The.com/selected/IBM/Explorer/resource/http.launch
.
sgi openGL www resource paper The an html Technology / .
com Technology the below The link launch
IBM://Web.selected.URL.Explorer/youClick/opengl.http
.
opengl html sgi openGL launch points / com link.
an paper resource : points external Explorer selected Click
httpTechnologyIBM.below
.
sgi link URL resource opengl The an html points.
com Technology the Click The launch IBM to external
/ http : / / paper . selected . Explorer / openGL
.
resource IBM the paper openGL sgi an external openglTechnology/ClickselectedTechnologybelowsgihttphtmlTheExplorer
launch/link:points.com
/ .
The opengl you sgi points to an http selected.
Click the URL below to openGL link Web html
launch://www.Technology.com/resource/Explorer/paper/external.IBM
an .
Technology openGL www resource paper the an html Technology / .
com The to Click the link launch URL external
IBM://Web.selected.Explorer/sgi/opengl/below.http
.
The link www selected opengl to an html resource.
com the URL Click to launch IBM Web external
http://points.sgi.Explorer/openGLyoubelow/Technology.paper
.
selected opengl URL resource paper Technology an http points.
com sgi The below Technology openGL link the html
launch://toTechnology/.Explorer/Click.IBM
.
the paper sgi resource URL Click IBM selected/
Explorer to Web com URL opengl openGL www http
linkbelow::you/Technology/external:The:points:html.an/launch
.
The openGL you sgi resource to an html selected.
Click the URL below to link IBM Web external
http://www.opengl.com/Technology/Technology/paper/points.Explorer
.
sgi opengl www selected points The an html resource.
Click Technology the below The openGL link URL external
launch://Web.com.to.Explorer/youpaper/http.IBM
.
the opengl sgi resource URL below html selected.
com to Web Click URL openGL link www external
launchan//you.Technology.Explorer/The/points/http.:/paperTechnology/
. .
the paper sgi resource URL below html selected.
com to Web Click URL opengl openGL www external
linkan//you.Technology.Explorer/The/points/IBM.:/http.launch
.
resource openGL URL points opengl sgi an http paper.
com selected The Click sgi link launch the html
IBM://to.Explorer.TechnologyWeb below /
.
Technology/sgi to Technology www below link The/
html Web you external www selected points launch
paperan::openGL.thehttp : IBM : com : Click : resource : resource / opengl
.
sgi link Web resource opengl the an html points.
com Technology to Click the launch IBM URL external
http://paper.selected.Explorer/openGLwwwbelow/The/
link external selected launch html opengl / Click Technology / .
an openGL points : opengl Explorer com resource below
IBM.paper
an .
link html selected launch http opengl / com IBM.
an openGL points : opengl external Explorer resource Click
below.paper
: .
link html selected launch http opengl / com IBM.
an openGL points : opengl external Explorer resource Click
below.paper
.
Technology/Webbelowlink html selected launch http opengl / Click IBM.
an openGL points : opengl external Explorer resource below URL Explorer
com.paper
.
launchtopointsopenGLTechnologyanexternalpaper .
Click sgi The below Technology IBM http the Explorer
html://opengl.resource.com/link/
.
points launch Technology / link selected an external openGL.
Click resource sgi below selected IBM http Technology Explorer
The link you selected points to an external resource.
Click the URL below to launch IBM Web Explorer
http://www.webcity.co.jp/info/matumot/index-e.html
The link you selected points to an external resource.
Click the URL below to launch IBM Web Explorer
http://www.sgi.com
Explorer .
www selected URL The an http to.
Click you below resource points external
link://Web..Explorer/the/sgi/com/launch/IBM/
.
www selected URL The an http to.
Click you below resource points
IBM://Web.the / sgi / com / link / launch / Web / : external
external .
selected IBM URL points launch The / com link.
an sgi the : The http external to Click
Web / sgi Web below . resource
an .
URL resource to The www an http the.
Click Web you below www points link external
launch://.com..Explorer/selected/sgi.IBM
.
resource http to link IBM sgi / Click launch.
an selected The : sgi external Explorer the below
. points.com
.
the link you sgi points URL an Explorer . /
Click to Web below URL launch IBM www com
external.:/The/resource/http
.
sgi launch Web selected link the / com resource.
an The to : the IBM http URL Click
resource http to points launch sgi / Click link.
an selected The : sgi external Explorer the below
IBM.com
.
to pointsthesgiWebanExplorerThe .
Click URL www below Web link launch you com
IBM://resource.selected.http/external/
.
to link the sgi Web an http The.
com URL www below Web launch IBM you external
/ resource points . Click . Explorer
.
The you Web below points www/
IBM Click sgi selected link
resourcean::to/com/launch:external.Explorer:http:URL:the
.
The points you sgi resource to an http selected.
Click to link launch Web external
IBM://www.Explorer.com
.
sgi IBM Web / points the / Click an The to : the http Explorer URL below
linkwwwlaunchwww/wwwexternal.com
. .
sgi launch Web selected points the : /
below The to an the IBM http URL Click
link.Explorer/external
.
resource http to link IBM sgi / Click an selected The : sgi external Explorer the below
points.com
IBM .
selected http URL points IBM The / Click link.
Web / the : The external Explorer to below
com.resource.launch
.
resource http to points IBM sgi / Click link.
an selected The : sgi external Explorer the below
com.launch
.
resource http to points IBM sgi / Click launch.
an selected The : sgi external Explorer the below
com.link
. .
resource IBM to points launch sgi / com link.
an selected The : sgi http external the Click
below . Explorer
.
resource http to points IBM sgi / com link.
an selected The : sgi external Explorer the Click
below.launch
.
resource http to points launch sgi / Click link.
an selected The : sgi external Explorer the below
IBM.com
externaltopointsIBMsgi/Clicklink .
an selected The : sgi Explorer com the below
http.launch
.
an selected The : sgi http external the Click
below.Explorer
.
resource http to points IBM sgi / com link.
an selected The : sgi external Explorer the Click
below.launch
/.launch
.
resource http to points launch sgi / Click link.
an selected The : sgi external Explorer the below
IBM . com
.
The Web to below link URL.
com Click sgi selected launch
resourcean//.www.the/external/you/http/Explorer/IBM/:.points
external .
below URL linkTheresourcewwwanexternalsgi .
Click Web you below www launch IBM Explorer
http
═══ 5.58.0.0.0.0.0.0.1.0.0.0.0.1. Т ═══
The link you selected points to an external resource.
Click the URL below to launch IBM Web Explorer
http://www.webcity.co.jp/info/matumot/index-e.html
The link you selected points to an external resource.
Click the URL below to launch IBM Web Explorer
http://www.sgi.com
an Web the com an you the com an the below an the Explorer Web / an the IBM :
points an the / sgi : external an the IBM : resource . / sgi : launch . link .
selected an the com an the http : Click
Web / Explorer http Click
. belowExplorerlaunchClick
. anbelowExplorerIBMClick
. an
. anbelow Explorer http Click
. an
. the
an : com The.
you the www URL below IBM Web/
com Click The points http
linkan:://Explorer/sgi:selected:to:resource.external/launch
Explorer
http://www.selected.com/
.
. :
an : com Web / sgi
. Explorerthe
. Web/Click.the
.
. Explorercom Explorer
. the
.the
. :
. .an
. . Web/the externallink
. : the
..Explorer
. Explorerthe
. external
. the .
. the Web Click
. Explorerexternal Explorer
. Explorer. an : an
.Web / external
. URLthe
ExplorerWeb / .
. .
. .
. externalexternalbelowClick
. . an : an
.
.
. Explorerthe
. .
Web : com you
. / an : an
.an. .
.
externalselected
. externalselected below Click com / external selected
. resource externalselected
. externalselected Explorer. : / Web /
. toto /
. . : /
com
.
. belowClick . below Click
. belowExplorerClick
. Explorer : com below Click
. an
. external belowClick . below Click
.
. an
.
.
anWeb / .
.. below Click Web /
.
.
. The points
. the resource
. link resource : an
.an:comsgi resource
.
. Web / belowClick . : external
.
you the www URL below IBM Web/
com Click The points http
linkan:://Explorer/sgi:selected:to:resource.external/launch
: .
www points to The an external the.
Click you below link launch Explorer
sgi IBM://.URL.com/Web/resource/sgi/selected.http
.
. Explorer
Explorer
. com
. com WebExplorer .
.Web / httpyou
. /
. Web/Click/Webexternalto belowClick
. httptoexternalIBM
. httpto external .
. launchexternallaunch belowexternalClick
. belowClick
.
. belowClick
.Click anWeb / : an
. com
. URL
. .
. httpselected
. Explorer
.
. / launchexternalIBM
.URL Web / : external
.
The link you selected points to an external resource.
Click the URL below to launch IBM Web Explorer
http://www.webcity.co.jp/info/matumot/index-e.html
The link you selected points to an external resource.
Click the URL below to launch IBM Web Explorer
ftp://sgigate.sgi.com/pub/opengl/doc/opengl.ps.Z
.sgigate/
. com
. com belowZClick . .
. Click / below external the Click
. com sgigate belowClick
. com sgigate belowClick
. /belowClick/com belowClick : an
.com sgigate / belowpsClick
. com belowselecteddocsgiClick
. com belowTheexternalpubClick . Explorer
. com belowlinkClick
. com belowClick
. com belowWebexternalClick
. . comsgigate/below to Clickcombelow external ClickcomURL
. com belowClick
. . belowIBMClick
an : com com
. com ftp belowyouClick
. com ftp
. com opengl
sgigate/an:combelowlaunchClick
. sgigate / belowClick
. com belowresourceClick
. sgigate belowExplorerClick
. com belowdocpointsClick
. anbelowExplorerClick
. an:
.
.
. sgigate /
. an
. doc
. sgigate . Explorer doc
. andocsgigate
. doc//
. docsgigate doc
.
.
sgigate / doc
. com
.
. .
. belowClick
.
.
. doc: Explorer . .
. / an : an
.//
. //
.
//. /
. /:/
. points/ you /
.
. doc / : The sgigate / Explorer / / .. selected
. IBMexternalbelow Click
. sgigateopengl an below // Click sgigate / . . below Click / below launch launch launch comClick
. IBMWeb
. URL IBMftpbelow externalClick
. belowClick/link pub
. IBMExplorer psExplorer the
doc
.
youExplorerexternalClickIBMpsthelinkWebdoc:ftppointsopenglcomtoresource. /sgigateURLZbelowpubselectedbelowThesgiWebdoc anpoints.
sgigate/link to resource points sgigate . ps.
com sgi The below sgigate launch IBM the Explorer
opengl/Click:ftp.doc.pub
.
the pub The selected URL below IBM sgigate.Web Click URL ps points you ftp
openglan//Z.Explorer.docan:/sgi/external/resource/launch.link
.
theThe selected URL below IBM sgigate.
com to Web Click URL ps points you ftp
openglan//Z.Explorer.docan:/sgi/external/resource/launch.link
.
the ps sgigate pub URL an external sgi.
Click to Web below URL points opengl you Explorer
link://Z.The.com/selected/IBMresource / ftp . launch
.
sgi opengl you resource ps The an external sgigate / .
com sgigate the below The link launch to .
IBM://Web.selected.URL.doc/ZClick/points.ftp
: you .
points external sgi opengl launch pub / com link.
an ps resource : pub Explorer doc selected Click
ftpsgigateIBM.below
.
sgi link URL resource points The an external pub.
com sgigate the Click The launch IBM to Explorer
sgigate / ftp : / / ps . selected . doc / opengl Web .
.
resource IBM the ps opengl sgi an Explorer pointssgigate/ClickselectedsgigatebelowsgiftpexternalThedoc
launch/link:pub.com
/ .
The points Z sgi pub to an ftp selected.
Click the URL below to opengl link Web external
/ you . sgigate . com / resource / doc / ps / Explorer . IBM
an .
sgigate opengl you resource ps the an external sgigate / .
com The to Click the link launch URL Explorer
IBM://Webdoc / sgi / points / below . ftp
.
The link you selected points to an external resource.
com the URL Click to launch IBM Web Explorer
ftp://pub.sgi.doc/openglZbelow/sgigate.ps
: you .
selected points URL resource ps sgigate an ftp pub.
com sgi The below sgigate opengl link the external
launch://tosgigate/.doc/Click.IBM
.
the ps Click IBM selected/
doc to Web com URL points opengl you ftp
linkbelow::Z/sgigate/Explorer:The:pub:external.an/launch
.
The opengl Z an external selected.
Click the URL below to link IBM Web Explorer
ftp://you.points.com/sgigate/sgigate/ps/pub.doc
.
pointsyouselectedpubTheanexternalresource .
Click sgigate the below The opengl link URL Explorer
launch://Web.com.to.doc/Zps/ftp.IBM
.
the points sgi resource URL below .
com to Web Click URL opengl link you Explorer
launchan//Z.sgigate.doc/The/pub/ftp.:/pssgigate/
. .
pssgiresourceURLbelowexternalselected .
com to Web Click URL points opengl you Explorer
linkan//Z.sgigate.doc/The/pub/IBM.:/ftp.launch
URL .
resource opengl URL pub points sgi an ftp ps.
com selected The Click sgi link launch the external
IBM://to.doc.sgigate..Webbelow/
.
sgigate/sgi to sgigate you below link The/
external you selected pub launch
psan::opengl.the/.ftp:IBM:com:Click:resource:resource/points
.
sgiWeb resource points the an external pub.
com sgigate to Click the launch IBM URL Explorer
ftp://ps.selected.doc/openglyoubelow/The/
.
link Explorer selected launch external points / Click sgigate / .
an opengl pub : points below
IBM.ps
an .
link external selected launch ftp points / com IBM.
an opengl pub : points Explorer doc resource Click
below.ps
: .
link external selected launch ftp points / com IBM.
an opengl pub : points Explorer doc resource Click
below.ps
.
sgigate/Webbelowlink external selected launch ftp points / Click IBM.
an opengl pub : points Explorer doc resource below
. URL doc
com.ps
.
.launch to pub opengl sgigate an Explorer ps.
Click sgi The below sgigate doc
external://points.resource.com/link/
.
pub launch sgigate / link selected an Explorer opengl.
Click resource sgi below selected IBM ftp sgigate doc
sgi URL below ftp sgigate/
com to Web Click URL pub link you external
launchan::/Z/doc/ps:points:selected:opengl.Explorer/IBM
the points link selected an Explorer opengl.
Click resource sgi below selected IBM ftp sgigate doc
external://The.ps.com
sgigate / . launch://sgigate.URL.doc/resource/ps/com/IBM/ftp/
.
The points Z sgi pub to an external selected.
Click the Web below to opengl link you .
ftp://sgigate.URL..resource/ps/com/launch/IBM/sgigate/:Explorer
Explorer .
points ftp sgi link IBM pub / com launch.resource : pub external Explorer selected Click
sgigate / ps . sgigate below . opengl
an .
sgi opengl you selected pub The an external resource.
Click sgigate the below The link launch URL Explorer
. IBM://Web.com.to.doc/Zpoints/ps.ftp
.
opengl external selected launch ftp ps / Click IBM.
an points pub : ps Explorer doc resource below
link.com
URL .
resource launch the ps link sgi an doc . /
Click selected sgigate below sgi IBM ftp The com
Explorer.:/pub/opengl/external
.
ps IBM sgigate points launch resource / com opengl.
an pub selected : resource ftp external sgi Click
opengl external selected link IBM ps / Click launch.
an points pub : ps Explorer doc resource below
ftp.com
.
selected link to resource ps sgigate an doc pub.
Click sgi The below sgigate launch IBM the com
ftp://opengl.points.external/Explorer/
. .
selected launch to resource ps sgigate an external pub.
com sgi The below sgigate IBM ftp the Explorer
sgigate / opengl / . link . Click . doc
.
to pub the sgigate Web below link The/
ftp URL you Click Web ps points Z launch
openglan::selected/com/IBM:Explorer.doc:external:sgi:resource
.
pub link the ps opengl selected an external points.
Click resource . selected launch IBM sgigate Explorer
ftp://The.doc.com
.
ps ftp sgigate / link resource / Click opengl.anpubselected:resourceexternaldocsgibelow
launchTheIBMThe/TheExplorer.com
. .
ps IBM sgigate points link resource : com . /
below pub selected an resource ftp external sgi Click
launch.doc/Explorer
.
opengl external selected launch ftp ps / Click IBM.anpointspub:psExplorerdocresourcebelow
link.com
ftp .
Web below points externalsgilinkftppub/Clicklaunch .
sgigate / resource : pub Explorer doc selected below
com.opengl.IBM
.
opengl external selected link ftp ps / Click launch.
an points pub : ps Explorer doc resource below
com.IBM
.
opengl external selected link ftp ps / Click IBM.
an points pub : ps Explorer doc resource below
com.launch
. .
opengl ftp selected link IBM ps / com launch.
an ps external Explorer resource Click
. below . doc
.
opengl external selected link ftp ps / com launch.
an points pub : ps Explorer doc resource Click
below.IBM
.
opengl external selected link IBM ps / Click launch.
an points pub : ps Explorer doc resource below
ftp.com
═══ <hidden> tp://www.sgi.com/Technology/openGL/opengl.html=Ц ═══
external.IBM
.
opengl external selected link ftp ps / com launch.
an points pub doc resource Click
below.IBM
you .
externalselectedlinkIBMps/Clicklaunch .
an points pub : ps Explorer doc resource below
. ftp . com
.
to pub sgigate selected Web below launch sgi.
com URL you Click Web ps points Z IBM
. openglan//.The.resource/Explorer/the/external/doc/ftp/:.link
Explorer .
.Webbelowsgi launch Web pub opengl The an Explorer ps.
Click sgigate the below The doc
external:.
the resource The sgi URL below ftp sgigate/
com to Web Click URL pub link you external
launchan::/Z/doc/ps:points:selected:opengl.Explorer/IBM
.
pub launch the points link selected an Explorer opengl.
Click resource sgi below selected IBM ftp sgigate doc
external://The.ps.com
to . an sgigate resource com an the resource com an you resource below an Z
resource doc sgigate / an resource ftp : link an resource / ps : Explorer an
resource ftp : opengl . / ps : IBM . launch . points an resource com an
resource external : Click
sgigate / doc external Click
. an.below doc IBM Click
. anbelowdocftpClick
. an
. an. below doc external Click
. an
. resource
.an:compub .
the resource The sgi URL below ftp sgigate/
com to Web Click URL pub link you external
launchan::/Z/doc/ps:points:selected:opengl.Explorer/IBM
/ The . points . com /
.
. :
.an:comsgigate/ps
. docresource Web
. sgigate/Click.resourceZ
. below Click . .Web
. doccom doc
. resource Z :
. .an
. Explorer
. .to doc resource
. to Explorer
. to resource .
. to resource . sgigate Click
. . todoc Explorerdoc
. to doc. an : an
.. sgigate / Explorer
. sgito resource
docsgigate / URL .
. below Click . .
.
. ExplorerExplorerbelowClick
. . an : an
..
an : com
. docresource
. .
sgigate / . : com the
. to / an : an
.
The link you selected points to an external resource.
Click the URL below to launch IBM Web Explorer
http://www.webcity.co.jp/info/matumot/index-e.html
The link you selected points to an external resource.
Click the URL below to launch IBM Web Explorer
http://www.sgi.com/Technology/openGL/paper.design/opengl.html
: an
.. : /
an . . below Click
. belowdesignClick
. design belowClick
. an
. belowClick . . below Click
.
. an.
. you : an
.
anthe sgi / to .
..
. paper launch
. points link
. IBM link . : an
.an:comopengl link
.
. sgi / belowClick . . .
The points Technology selected to below html sgi/
com the URL Click to paper launch Web external
IBMan::you/www/design/opengl:openGL:resource:link.Explorer/http
: .
URL below Technology launchwwwresourcepapertheanExplorerpoints .
Click The to below the IBM http URL design
. opengl html://Web.selected.com/sgi/link/opengl/openGL.external
com design
design
. com Web .
. com Web sgidesign .
.sgi / externalThe
.
. sgi/Click/sgiExplorerresource belowClick
. externalresourceExplorerhtml
. external. resource Explorer .
. httpExplorerhttp belowExplorerClick
. belowClick
. .URL
. belowClick
..Clickan sgi/:an
. com
. to URL selected
. . .
. to externalopenGL
.todesign
. to .
. / httpExplorerhtml
.selected sgi / : Explorer
. to .
The pointsTechnologyselectedtobelowhtmlsgi /
com the URL Click to paper launch Web external
IBMan::you/www/design/opengl:openGL:resource:link.Explorer/http
. .
Technology launch Web resource openGL the points.
Click The to below the IBM http URL Explorer
html://sgi.selected.com/paper/link/design/link.opengl.www
: . .sgi/
.com
. com belowwwwClick . .
. .Click/belowexternalTheClick
. com sgi belowClick
. com sgi belowClick
. /belowClick/com belowClick . : an
.com sgi / belowopenglClick
. combelow resource design selected Click
. com belowTechnologyexternalpaperClick . Explorer
. com . belowlaunchClick
. com belowClick
. com belowURLexternalClick
. . comsgi/below the Click
. combelow external you Clickcomto
. com belowClick
. . belowhttpClick
.an:comcom
. com html belowWebClick
. com html
.com link
sgi/an:com. belowIBMClick
. sgi / belowClick
. com belowpointsClick
. sgi belowExplorerClick
. .combelow design openGL Click
. anbelowExplorerClick
. an: : an
.sgi . Explorer .design
. andesignsgi
. design//
. designsgi design
.
.
sgi / design
. com
.
. ..
below Click
.
.
. design. : Explorer . .
. / an : an
.//
. //
. /. /
. / : /
. openGL /Web/
.
. designselected . /:Technologysgi/Explorer
sgi / an : an
.points
. designan/www/
. ./
/ .. resource
an : an
. http external belowClick
. sgi linkanbelow. /
/Clicksgi/. .belowClick/belowIBMIBMIBMcom
Click
. http
. tohttp html belowexternal Click
. .belowClick/launch
paper
. you http Exploreropengl ExplorerThe
design
The link you selected points to an external resource.
Click the URL below to launch IBM Web Explorer
http://www.webcity.co.jp/info/matumot/index-e.html
The link you selected points to an external resource.
Click the URL below to launch IBM Web Explorer
ftp://sgigate.sgi.com/pub/opengl/doc/design.ps.Z
linkan//you.doc.designan:/selected/Explorer/pub/IBM.launch
.
The .Zsgigateresourcetobelowftpsgi .
com the URL Click to points opengl Web external
linkan//you.doc.designan:/selected/Explorer/pub/IBM.launch
.
The points Z sgi ps to an Explorer selected.
Click the URL below to opengl link Web doc
launch://you.sgigate.com/resource/ftp/.pub/external.IBM
.
selected link Web pub points sgigate an Explorer sgi / .
com sgi The below sgigate launch IBM the .
ftp://URL.resource.to.design/youClick/opengl.external
. : Web .
opengl Explorer selected link IBM ps / com launch.
an points pub : ps doc design resource Click
externalsgiftp.below
selected launch to pub opengl sgigate an Explorer ps.
com sgi The Click sgigate IBM ftp the doc
/ external : / / points . resource . design / link URL .
.
pub ftp The points link selected an doc Click resource sgi below selected external Explorer sgigate design
IBM/launch:ps.com
/ .
sgigate opengl you selected ps the an external resource.
Click The to below the link launch URL Explorer
IBM./Web.sgi.com/pub/design/points/doc.ftp
an .
sgi link Web pub points The an Explorer sgi / .
com sgigate the Click The launch IBM to doc
sgi / ftp://URL..design/selected/opengl/below.external
.
sgigate launch Web resource opengl the an Explorer pub.
com The to Click the IBM ftp URL doc
external://ps.selected.design/linkyoubelow/sgi.points
. : Web .
resource opengl to pub points sgi an external ps.
com selected sgigate below sgi link launch The Explorer
IBM://thesgi/.design/Click.ftp
.
The points Z selected . Click ftp resource/
design the URL com to opengl link Web external
launch below : : you / sgi / doc : sgigate : ps : Explorer . an / IBM
.
sgigate link you selected . an Explorer resource.
Click The to below the launch ftp URL doc
external://Web.opengl.com/sgi/sgi/points/ps.design
.
.opengl Web resource ps sgigate an Explorer pub.
Click sgi The below sgigate link launch to doc
/ URL . com . the . design / you points / external . ftp
.
The opengl Z selected pub to below Explorer . .
com the URL Click to link launch Web doc
IBMan//you.sgi.design/sgigate/ps/external.:/pointssgi/
. .
.points Z selected pub to below Explorer resource.
com the URL Click to opengl link Web doc
. launchan//you.sgi.design/sgigate/ps/ftp.:/external.IBM
..to.
pub link to ps opengl selected an external points.
com resource sgigate Click selected launch IBM The Explorer
ftp:/design . sgi . . URL below /
.
sgi/selected the sgi Web below launch sgigate/
Explorer URL . Web resource ps Z IBM
points an : : link . The / . external : ftp : com : Click : pub : pub / opengl
.
selected .URLpubopenglTheanExplorerps .
com sgi the Click The IBM ftp to doc
external://points.resource.Web below / sgigate /
.
launch doc resource IBM Explorer opengl / Click sgi / .
an link ps : opengl design . below
ftp.points
an .
launch Explorer resource IBM external opengl / com ftp.
an link ps : opengl doc design pub Click
you points you . below.points
: .
launch Explorer resource IBM external opengl / com ftp.
an link ps : opengl doc design pub Click
below.points
.
sgi/URLbelowlaunchresource IBM external opengl / Click ftp.
an link ps : opengl doc design pub below
. to design
com.points
IBM.points
.
.IBM the ps link sgi an doc points.
Click selected sgigate below sgi ftp . design
Explorer://opengl.pub.com/launch/
.
ps launch resource an doc link.
Click pub selected below resource ftp external sgi design
ps launch Web Explorer
IBMan::Z/you/design/points:opengl:resource:link.doc/ftp
sgigate opengl you selected ps the an Explorer resource.
Click The URL below the link launch Web doc
IBM://sgi.to.design/pub/points/com/ftp/
.
sgigate opengl you selected ps the an Explorer resource.
Click The URL below the link launch Web .
external://sgi.topub / points / com / IBM / ftp / sgi / : doc
doc .
opengl external selected launch ftp ps / com IBM.
. pub : ps Explorer doc resource Click
sgi / points . sgi below . link
an .
selected link Web resource ps sgigate an Explorer pub.
Click sgigate launch IBM to doc
ftp://URL.com.the.design/youopengl/points.external
.
link Explorer resource IBM external points / Click ftp.
an opengl ps : points doc design pub below to design
launch.com
. . to .
pub IBM The points launch selected an design . /
Click resource sgi below selected ftp external sgigate com
doc.:/ps/link/Explorer
link Explorer resource launch ftp points / Click IBM.
an opengl ps : points doc design pub below
external.com
.
resource launch the pub points sgi an design ps.
Click selected sgigate below sgi IBM ftp The com
external://link.opengl.Explorer/doc/
. .
resource IBM the pub points sgi an Explorer ps.
com selected sgigate below sgi ftp external The doc
sgi / link / . launch . Click . design
.
the ps Z The sgi URL below launch sgigate/
external to Web Click URL points opengl you IBM
linkan::resource/com/ftp:doc.design:Explorer:selected:pub
.
ps launch The points link resource an Explorer opengl.
Click pub . resource IBM ftp sgi doc
external://sgigate.design.com
.
points external sgi / launch pub / Click link.anpsresource:pubExplorerdesignselectedbelow
IBMsgigateftpsgigate/sgigatedoc.com
. .
points ftp sgi opengl launch pub : com . /
below ps resource an pub external Explorer selected Click
The link you selected points to an external resource.
Click the URL below to launch IBM Web Explorer
http://www.webcity.co.jp/info/matumot/index-e.html
The link you selected points to an external resource.
Click the URL below to launch IBM Web Explorer
GLUspec.ps.gz
selected launchWebresourcelinktheanexternalps .
Click The to below the IBM gz URL Explorer
GLUspec.points
.
selected launchWebresourcelinktheanexternalpoints .
Click The to below the IBM gz URL Explorer
GLUspec.ps
. .
selected linkWebresourcepointstheanGLUspecps .
Click The . the launch IBM URL external
. Explorer . gz
.
selected Web resource link the an GLUspec ps.
Click The to below the IBM gz URL external
Explorer.points
. .
selected launch Web resource points the ps.
Click The to below the IBM gz URL Explorer
link.GLUspec
an external ps.
Click The to below the gz GLUspec URL Explorer
launch.points
an GLUspec . .
Click The to below the launch IBM URL external
Explorer.gz
.
selected launch Web resource link the an GLUspec ps
The link you selected points to an external resource.
Click the URL below to launch IBM Web Explorer
http://www.webcity.co.jp/info/matumot/index-e.html
The link you selected points to an external resource.
Click the URL below to launch IBM Web Explorer
http://www.sgi.com/Technology/openGL/opengl.html
. . openGLan//.the.selected/external/to/html/Explorer/http/:.link
external .
.wwwbelowTechnology launch www resource openGL
═══ 5.58.0.0.1. igate.sgi.com/pub/opengl/doc/design.ps.ZУ ═══
points.
Click The to below the IBM . Explorer
html:.
to selected the Technology Web below http The/
com URL www Click Web resource link you html
. launchan:://Explorer/points:opengl:sgi:openGL.external/IBM
.
resource launch to opengl link sgi an external openGL.
Click selected Technology below sgi IBM http The Explorer
═══ <hidden> isor/docs/oct95/oct95.duffy.shtml4Ъ ═══
. html://the.points.com
URL . an The selected com an to selected com an you selected below an selected
Explorer The / an selected http : link an selected / points : external an
selected http : openGL . / points : IBM . launch . opengl an selected com an
selected html : Click
The / Explorer html Click
an : com an . belowExplorerIBMClick an
.
. selected
.an:comresource .
to selected the Technology Web below http The/
com URL www Click Web resource link you html
. . launchan:://Explorer/points:opengl:sgi:openGL.external/IBM
html./the.opengl.com/
.
. :
.an:comThe/points
. Explorerselected www an : an
.The/Click.selected
. .belowClick..
www
. Explorercom Explorer
. selected
.selected you
.:
. .an
. : com :URLselected
..Explorer.external
. .URL Explorer selected
. URL external
. URL .
. URL selected . The Click
. URL Explorerexternal Explorer
. URL Explorer. an : an
.. The / external Technology URLselected
ExplorerThe / Web .
. .belowClick..
.
. externalexternalbelowClick
. . an : an
..
.an:com
. Explorerselected
. .an : an
The / . : com to
. URL / an : an
.
to selected the Technology Web below http The/
com URL www Click Web resource link you html
launchan:://Explorer/points:opengl:sgi:openGL.external/IBM
/ .
to openGL Technology selected Web an html sgi.
Click URL www below Web link launch you external
IBM://.The.com/the/opengl/resource.Explorer/points.http
. : an
.. : /
an : an
.
. belowClick ExplorerClick
. Explorer belowClick
. an
. .below Click. . below Click
.
. an.
. . : an
.
anURL The / Web .
.external
. .
. resource link
. selected openGL
. launch openGL . : an
.an:compointsopenGL
. .
. The / belowClick . . : com
. . : external . .
to selected the Technology Web below http The/
com URL www Click Web resource link you html
. launchan:://Explorer/points:opengl:sgi:openGL.external/IBM
: .
.wwwbelowthe link sgi resource URL an external selected.
Click to Web below URL launch IBM www Explorer
. points http://you.Technology.com/The/openGL/points/opengl.html
: an
. com you .
. com you TheExplorer .
.The / htmlto .
. The / Click / The external sgibelow Click
. htmlsgiexternalhttp
. html. sgi external .
. IBMexternalIBM below.external Click
: com below Click
. .www
. belowClick
.. Click anThe / : an
. com
. Web www Technology
. . .
. Web html
.Web Explorer
. Web .
. / IBMexternalhttp
.Technology The / : external
. below Click / Web.
to selected the Technology Web below http The/
com URL www Click Web resource link you html
launchan/ / Explorer / points : opengl : sgi :
openGL . external / IBM
. .
the link you sgi opengl URL . selected.
Click to Web below URL launch IBM www external
: / / The . Technology . com / resource / openGL / Explorer / openGL . points .
: . .The/
.com
. com belowClick
. .Click/belowhtmltoClick
. .comThebelow Click
. com The below: external
. /belowClick/com belowClick . : an
.com The / belowpointsClick
. . combelow sgi Explorer Technology Click
. belowthehtmlresourceClick . external
. com . belowlinkClick
. com belowClick
. .combelow www html : external
. . comThe/below URL Click
. combelow html ClickcomWeb
. .comClick
. . belowIBMClick
.an:comcom
. com http belowyouClick
. http
.com openGL
The/an:com. belowlaunchClick
. The / belowClick
. com selectedClick
. .Thebelow external Click
. .combelow Explorer opengl Click
. anbelowexternal Click
. an: . : an
.an
. Explorer
. .The.external. Explorer
. anExplorerThe
. //
. ExplorerThe Explorer
. .
.
The / Explorer
The link you selected points to an external resource.
Click the URL below to launch IBM Web Explorer
http://www.webcity.co.jp/info/matumot/index-e.html
The link you selected points to an external resource.
Click the URL below to launch IBM Web Explorer
http://www.digital.com:80/pub/doc/opengl/
: 80 :
. //
. //
. /. /
. .80 /
. link /you/
.
. comselected . /80theThe/digital
.
The / : 80 :
. pub
. com://
. ./
/ .80
Click resource
. : 80 :
. external doc anbelow
. The launch:an. / /below80 : The / . .
an
below
/
an
http
http
http Clickbelow
. external .
. Webexternal Explorer andoc below
. .anIBMpoints
. external digitalopengl digitalto
com .
to pub the selected Web an Explorer The/
Click URL www below Web points IBM you doc
http:8080//com/opengl80link80resource80launch.digital/external
.
to launch selected opengl Web : Explorer resource.
below URL www http you doc
external80//the.The.Click/pub/link/digital/com.points.
. launch://.digital.com:80/selected/dochttp . IBM
.
to .theresourceWebanexternalThe .
Click URL www below Web opengl link you Explorer
launch://.digital.com:80/selected/doc/pub/http.IBM
.
to opengl The points Web : doc selected.
below URL www an Web link launch you digital
IBM80//.the.Click/resource/external/.pub/Explorer.http
.
selected launch you pub opengl the : doc The / .
Click The to an the IBM http URL .
The / . external80//www.resource.Web.com/below/link.Explorer
. 80 you .
link doc selected launch http points / Click IBM.
: opengl pub 80 points digital com resource below
ExplorerTheexternal.an
.
selected IBM Web pub link the : doc points.
Click The to below the http external URL digital
/ Explorer 80 / / opengl . resource . com / launch www .
.
pub external to opengl launch selected : digital link.belowresourceTheanselectedExplorerdocthecom
http/IBM80points.Click
/ .
the link selected points URL : Explorer resource.
below URL launch IBM www doc
http./you.The.Click/pub/com/opengl/digital.external
: .
Theyou pub opengl to : doc The / .
Click the URL below to IBM http Web digital
external80//www..com/selected/link/an.Explorer
.
IBMyouresourcelinkURL:docpub .
Click to Web below URL http external www digital
Explorer80//points.selected.com/launchan/The.opengl
. 80 you .
resource opengl The : Explorer points.
Click selected the an The launch IBM to doc
http80//URLThe/.com/below.external
.
to opengl selected . below external resource/
com Web link launch you Explorer
. IBM an 80 80 / The / digital 80 the 80 points 80 doc . : / http
.
the launch : doc resource.
below to Web an URL IBM external www digital
Explorer80//you.link.Click/The/The/opengl/points.com
The link you selected points to an external resource.
Click the URL below to launch IBM Web Explorer
http://www.microstep.com/product/3dboard.html
The link you selected points to an external resource.
Click the URL below to launch IBM Web Explorer
http://www.webcity.co.jp/info/matumot/index-e.html
The link you selected points to an external resource.
Click the URL below to launch IBM Web Explorer
http://www.digital.com:80/pub/doc/opengl/opengl_new_glu.html
. the .
new http the link IBM points : Explorer launch.
Click opengl resource below points html glu selected doc
external80//.com.pub..toan/
.
pub/points you The pub URL an html resource/
doc to . URL opengl link www glu
. launch : 80 80 http . selected / . Explorer 80 external 80 Click 80 below 80 new 80 new / IBM
.
points .tonewIBMselected:doclink .
Click pub The below selected glu external the digital
pub / Explorer80//launch.opengl.com.URLan/resource/
.
html digital opengl glu doc IBM / below pub / .
: http link 80 IBM com . an
external.launch
URL : .
html doc opengl glu Explorer IBM / Click external.
: http link 80 IBM digital com new below
. Web launch Web . an.launch
80 .
html doc opengl glu Explorer IBM / Click external.
: http link 80 IBM digital com new below
an.launch
.
pub/toanhtml .openglgluExplorerIBM/belowexternal .
: http link 80 IBM digital com new an
. the com
Click.launch
. glu.launch
.
.glu The link http pub : digital launch.
below points resource an pub external . com
doc80//IBM.new.Click/html/
.
link glu . html http.
below new points an opengl external Explorer pub com
link html URL doc
glu:8080www/Web/com/launch80IBM80opengl80/ external
launch . pub / . glu80//pub.the.com/new/launch/Click/external/Explorer.
.
resource IBM Web points link The : doc opengl.
below selected to an The http html URL .
Explorer80//pub.the..new/launch/Click/glu/external/pub/80digital
digital .
IBM Explorer points html external link / Click glu.
. new 80 link doc digital opengl below
pub / launch . pub an . http
: .
points http URL opengl link resource : doc new.
below pub . resource html glu the digital
external80//to.Click./ Web IBM / launch . Explorer
.
http doc opengl glu Explorer launch / below external.
: IBM link 80 launch digital com new an
. the com
html.Click
. . the .
new glu selected launch html points : com . /
below opengl pub an points external Explorer resource Click
http doc opengl html external launch / below glu.
: IBM link 80 launch digital com new an
Explorer.Click
.
opengl html The new launch pub : com link.
below points resource an pub glu external selected Click
Explorer80//http.IBM.doc/digital/
. .
opengl glu The new launch pub : doc link.
Click points resource an pub external Explorer selected digital
/ http / . html . below . com
.
to an The linkwwwselectedpubtoanhtmlresource /
Explorer the URL below to launch IBM Web glu
http:8080opengl/Click/external80digital.com80doc80youpoints80new
.
linkselected launch http opengl : doc IBM.
below new . opengl glu external pub digital
Explorer80//resource.com.Click
.
launch Explorer pub / html new / below http.:linkopengl80newdoccompointsan
gluresourceexternalresource/resourcedigital.Click
. .
launch external pub IBM html new 80 Click . /
an link opengl : new Explorer doc points below
glu:8080www/Web/com/launch80IBM80opengl80http.digital/external
. .
IBM Explorer points http external link / below html.
: launch new 80 link doc digital opengl an
Click.glu.com
. http docopenglhtmlExplorerglu.
: IBM link 80 launch digital com new an
Click.external
.
http doc opengl html Explorer launch / below external.
: IBM link 80 launch digital com new an
Click.glu
. .
http Explorer opengl html external launch / Click glu.
: IBM . launch doc digital new below
. an . com
.
http .openglhtmlExplorerlaunch/Clickglu .
: IBM link 80 launch digital com new below
an.external
. .
http doc opengl html external launch . glu.
: IBM link 80 launch digital com new an
Explorer.Click
doc.external
.
http doc opengl html Explorer launch / Click glu.
selected new you resource points the an Explorer pub/
Click The to html URL doc
glu:8080www/Web/com/launch80IBM80opengl80http.digital/external
.
pub html URL new launch selected : digital link.
below resource The an selected glu external the com
Explorer80//to.opengl.Click/points/http/IBM.doc
. . . http://www.resource.new/digital/selected/doc/com/Explorer/80.html
digital .
.toanpoints glu to link http resource . launch.
below pub selected an resource external . com
doc80the .
selected new you resource points the an Explorer pub/
Click The to below the link html URL doc
glu:8080www/Web/com/launch80IBM80opengl80http.digital/external
.
link html opengl : digital http.
below new points an opengl external Explorer pub com
doc80//resource.launch.Click
The . : pub new Click : selected new Click : URL new an : Web new com pub / :
_ new Explorer 80 html : new / launch 80 digital : new Explorer 80 http . /
launch 80 external . glu . IBM : new Click : new doc 80 below
pub / com doc below
.:80Click:.an com external below: 80 /
.
. new
.:80Clicklink .
selected new you resource points the an Explorer pub/
Click The to below the link html URL doc
glu:8080www/Web/com/launch80IBM80opengl80http.digital/external
. 80
.:80Clickpub/launch
. comnew to . : 80 :
.pub/below.wwwnewWeb
. .anbelow..
to
. com Clickcom
. new Web . : 80 :
..The com new
. The digital80 :
.The . .
. The new . pub below
. The _comdigital _com
. The _com. : 80 :
.. pub / digital points Thenew
compub / the .
. .anbelow..
.
. digitaldigitalanbelow . : 80 :
..
.:80Click
. comnew
. ..:80:
pub / . 80 Click selected
. . The/:80:
.
selected new you resource points the an Explorer pub/
Click The to below the link html URL doc
glu:8080www/Web/com/launch80IBM80opengl80http.
/ .
selected http www points new the : doc opengl.
below The to an the html glu URL digital
external80//Web.pub.Click/resource/IBM/link.com/launch.Explorerdigital
. 80 :
.. 80 /
: . . an . below
. an. combelow
. com anbelow
. :
. an below: 80 Click _
:The pub / the .
...
. link html
. new http
. glu http . 80 :
.:80Clicklaunch http
. .. pub/an below ....
selected points the an Explorer pub/
Click The to below the link html URL doc
glu:8080www/Web/com/launch80IBM80opengl80http.digital/external
80 .
.toanresource html Web opengl link The : digital new.
below selected the
═══ <hidden> //www.sgi.com/Products/Dev_environ_ds.htmlBЫ ═══
external to com
. launch . Explorer80//URL.points.Click/pub/http/launch/IBM.doc
/
com
. 80 :
. Click URL .
. Click URL pubcom .
.pub / docselected .
. :
. pub / below / pub digital openglan below
. docopengldigitalExplorer
. doc. opengl digital .
. externaldigitalexternal an.digital below
..80Clickanbelow
. .to
. anbelow
.Click
. the to points
. . .
. the docIBM .
.the com
. .
. / externaldigitalExplorer
.points pub / 80 digital
. .anbelow/the
.
selectednew
you
resource
points
the
an
Explorer pub/
Click
The
to
below
the
link
html
URL
doc
glu:80./Web/com/launch80IBM80opengl80http.digital/external
.
.
resource html URL opengl IBM The . new.
below selected the an The glu external to digital
. 80 / / pub . points . Click / link / http / com / http . launch . Web
80
. .pub/
.Click
. Click Web below ..
. .below/andocselectedbelow
. .Clickpuban below
. Click pub an. 80 .
. /anbelow/Click anbelow . 80 :
.Click pub / anlaunchbelow
. . Clickan opengl com points below
. .an resource doc link below.digital
80 Click Click.an html below
. Click anbelow
. .Clickan to doc you .80digital
. . Clickpub/an The below .
Clickan doc www belowClickthe
. .Click.below
. . anexternalbelow
.:80ClickClick
. Click Explorer anURLbelow
. .Explorer
.Click http
pub/:80Click. anglubelow
. pub / anbelow
. Click an.new below
. .puban digital _ below
. .Clickan com IBM below
.Click : an .digitalbelow
. :80 . 80 :
.below / .:
. com
. .pub.digital. com
. :compub
. ./ /
. compub com
. .
.
pub / com
.
selected new you resource points the an Explorer pub/
Click The to below the doc
glu:8080www/Web/com/launch80IBM80opengl80http.digital/external
.
pub IBM URL points link selected an external opengl.
Click resource The below selected http html the Explorer
glu://to.digital.com:80/new/doc/launch/
80 . : 80 :
. //
. // ./. /
. ..80/
. IBM /URL/
.
. compoints . 80 resource pub / digital 80 . 80 Click opengl
. : 80 :
. external doc anbelow
. pub http:an. /
/below.80:pub/. .anbelow/glu
glu Clickbelow
. _ external . you
. theexternal Explorer andoc below
. .anbelow.html
link
. www external digitalan below / digitalselected
com .
selected new you resource points the an Explorer pub/
Click The to below the link html URL doc
80 IBM 80 opengl 80 http . digital / external
.
selected http Web points launch the : Explorer opengl.
below The to an . glu URL doc
external80//resource.pub.Click/new/IBM/digital/com.link.www
URL . http://Web.digital.com:80/points/doc/.glu.html
.
selected .wwwresourceopengltheanexternalpub .
Click The to below the launch IBM URL Explorer
: / / Web . digital . com : 80 / points / doc / new / glu . html
.
selected launch www pub link the : doc points.
below The to an the IBM http URL digital
html80//Web.resource.Click/opengl/external/.new/Explorer.glu
.
points http URL new launch resource : doc pub / .
Click pub selected an resource html glu The .
external80//to.opengl.the.com/Webbelow/IBM.Explorer. 80 URL .
IBM doc points http glu link / Click html.
: launch new 80 link digital com opengl below
Explorerpubexternal.an
.
points html the new IBM resource : doc link.
Click pub selected below resource glu external The digital
pub / Explorer 80 / / launch . opengl . com / http to .
to an resource IBMWebpointslinkThe:Exploreropengl .
below selected . The http html to doc
glu./URL.pub.Click/new/com/launch/digital.external
: .
pub .URLnewlaunchpub / .
Click resource The below selected html glu the digital
external80//to..com/points/IBM/an.Explorer
.
.html URL opengl IBM The : doc new.
Click selected the below The glu external to digital
. . Explorer80//link.points.com/httpWeban/pub.launch
. 80 URL .
opengl IBM . launch pub : Explorer link.
Click points resource an pub http html selected doc
. glu80//Thepub/.com/below.external
.
selected launch www points . below external opengl/
com The . the IBM http URL Explorer
. html Web / pub / digital 80 resource 80 link 80 doc . : / glu
.
resource http Web points . : doc opengl.
below selected the an The html external to digital
Explorer80//URL.IBM.Click/publaunch / link . com
. .
points http to opengl launch resource an doc new.
Click pub selected below resource html glu The digital
external://the.IBM.com/link/80.Explorer
.
selected newyouresourcepointstheanExplorerpub /
Click The to below the link html URL doc
glu:8080www/Web/com/launch80IBM80opengl80http.digital/external
Click the URL below to launch IBM Web Explorer
http://www.digital.com:80/pub/doc/opengl/opengl_new_glu.html
..the.
new http the link IBM points : Explorer Click opengl resource below points html glu selected doc
external80//.com.pub..toan/
.
pub/points you The pub URL an html resource/
doc to . URL opengl link www glu
. launch : 80 80 http . selected / . Explorer 80 external 80 Click 80 below 80 new 80 new / IBM
.
points .tonewIBMselected:doclink .
Click pub The below selected glu external the digital
pub / Explorer80//launch.opengl.com.URLan/resource/
.
html digital opengl glu doc IBM / below pub / .
: http link 80 IBM com . an
external.launch
. URL : .
html doc opengl glu Explorer external.
: http link 80 IBM digital com new below
. Web launch Web . an.launch
80 .
html doc opengl glu Explorer IBM / Click external.
: http link 80 IBM digital com new below
an.launch
.
pubhtml . opengl glu Explorer IBM / below external.
: http link 80 IBM digital com new an
. the com
Click.launch
.
.glu The link http pub : digital launch.
below points resource an pub external . com
doc80//IBM.new.Click/html/
.
link glu . html opengl . http.
below new points an opengl external Explorer pub com
.
selected new . points the an Explorer pub/
Click The to below the link html URL doc
glu:8080www/Web/com/launch80IBM80opengl80http./external
. selected IBM html opengl : digital http.
below new points an opengl external Explorer pub com
doc80//resource.launch.Click
. glu80//pub.the.com/new/launch/Click/external/Explorer.
.
resource IBM Web points link The : doc opengl.
below selected to an The http html URL .
Explorer80//pub.the..new/launch/Click/glu/external/pub/80digital
digital .
IBM Explorer points html external link / Click glu.
. new 80 link doc digital opengl below
pub / launch . . pub an . http
: .
points http URL opengl link resource : doc new.
below pub . resource html glu the digital
external80//to.Click.The./WebIBM/launch.Explorer
.
to an http docopenglgluExplorerlaunch/belowexternal .
: IBM link 80 launch digital com new an
. the com
html.Click
. . the .
new glu selected launch html points : com . /
below opengl pub an points external Explorer resource Click
digital.80
http doc opengl html external launch / below glu.
: IBM link 80 launch digital com new an
Explorer.Click
.
opengl html The new launch pub : com link.
below points resource an pub glu external selected Click
Explorer80//http.IBM.doc/digital/
. .
opengl glu The new launch pub : doc link.
Click points resource an pub external Explorer selected digital
/ http / . html . below . com
.
to an The linkwwwselectedpubtoanhtmlresource /
Explorer the URL below to launch IBM Web glu
http:8080opengl/Click/external80digital.com80doc80youpoints80new
.
linkselected launch http opengl : doc IBM.
below new . opengl glu external pub digital
Explorer80//resource.com.Click
.
launch Explorer pub / html new / below http.:linkopengl80newdoccompointsan
gluresourceexternalresource/resourcedigital.Click
. .
launch external pub IBM html new 80 Click . /
an link opengl : new Explorer doc points below
glu:8080www/Web/com/launch80IBM80opengl80http.digital/external
. .
IBM Explorer points http external link / below html.
: launch new 80 link doc digital opengl an
Click.glu.com
. http docopenglhtmlExplorerglu.
: IBM link 80 launch digital com new an
Click.external
.
http doc opengl html Explorer launch / below external.
: IBM link 80 launch digital com new an
Click.glu
. .
http Explorer opengl html external launch / Click glu.
: IBM . launch doc digital new below
. an . com
.
http .openglhtmlExplorerlaunch/Clickglu .
: IBM link 80 launch digital com new below
an.external
. .
http doc opengl html external launch . glu.
: IBM link 80 launch digital com new an
Explorer.Click
doc.external
.
http doc opengl html Explorer launch / Click glu.
selected new you resource points the an Explorer pub/
Click The to html URL doc
glu:8080www/Web/com/launch80IBM80opengl80http.digital/external
.
pub html URL new launch selected : digital link.
below resource The an selected glu external the com
Explorer80//to.opengl.Click/points/http/IBM.doc
. . . http://www.resource.new/digital/selected/doc/com/Explorer/80.html
digital .
.toanpoints glu to link http resource . launch.
below pub selected an resource external . com
doc80the .
selected new you resource points the an Explorer pub/
Click The to below the link html URL doc
glu:8080www/Web/com/launch80IBM80opengl80http.digital/external
.
link html opengl : digital http.
below new points an opengl external Explorer pub com
doc80//resource.launch.Click
The . : pub new Click : selected new Click : URL new an : Web new com pub / :
_ new Explorer 80 html : new / launch 80 digital : new Explorer 80 http . /
launch 80 external . glu . IBM : new Click : new doc 80 below
pub / com doc below
.:80Click:.an com external below: 80 /
.
. new
.:80Clicklink .
selected new you resource points the an Explorer pub/
Click The to below the link html URL doc
glu:8080www/Web/com/launch80IBM80opengl80http.digital/external
. 80
.:80Clickpub/launch
. comnew to . : 80 :
.pub/below.wwwnewWeb
. .anbelow..
to
. com Clickcom
. new Web . : 80 :
..The com new
. The digital80 :
.The . .
. The new . pub below
. The _comdigital _com
. The _com. : 80 :
.. pub / digital points Thenew
compub / the .
. .anbelow..
.
. digitaldigitalanbelow . : 80 :
..
.:80Click
. comnew
. ..:80:
pub / . 80 Click selected
. . The/:80:
.
selected new you resource points the an Explorer pub/
Click The to below the link html URL doc
glu:8080www/Web/com/launch80IBM80opengl80http.
/ .
selected http www points new the : doc opengl.
below The to an the html glu URL digital
external80//Web.pub.Click/resource/IBM/link.com/launch.Explorerdigital
. 80 :
.. 80 /
: . . an . below
. an. combelow
. com anbelow
. :
.
The link you selected points to an external resource.
Click the URL below to launch IBM Web Explorer
http://www.webcity.co.jp/info/matumot/index-e.html
The link you selected points to an external resource.
Click the URL below to launch IBM Web Explorer
http://www.unx.com/DD/advisor/docs/oct95/oct95.duffy.shtml
advisor unx Click
. .
.oct95 http
. points IBM
. external IBM . : advisor
.advisor:Clicklink IBM
.Click . . . shtml/an below ..: DD . .
the points . selected unx an duffy shtml/
Click to URL below unx oct95 http Web docs
externaladvisor::you/www/com/link:launch:resource:IBM.DD/Explorer
.URLanThe http www resource oct95 to advisor DD points.
below the unx an . Explorer URL com
. link . duffy://Web.selected.Click/shtml/IBM/link/launch.docs
: advisor
.docsthe .
. Explorer DD Exploreran . DDbelow
..:Clickan. below
. .URL
. anbelow
.: Click . . . below advisorshtml / : advisor
. .Click
. unx URL selected
. . .
. unx docslaunch . advisor
.unx com
. unx . .
. / ExplorerDDduffy
.selected shtml / : DD
. .anbelow/unx
unx
.
thepoints
The
selected
unx
an
duffy shtml/
Click
to
URL
below
unx
oct95
http
Web
docs
externaladvisor:./www/com/link:launch:resource:IBM.DD/Explorer
.
.
httpWebresourcelaunchto.points .
below the unx an to external Explorer URL DD
. : / / shtml . selected . Click / oct95 / IBM / com / IBM . link . www
:
. .shtml/
.Click
. Click . www below ..
. .below/andocsthebelow
.Click . Click shtml anbelow
. Click shtml an. : DD . .
. /anbelow/Click anbelow . : advisor
.Click shtml / anlinkbelow
. below / .Click anresourcecomselectedbelow
. .an The docs oct95 below.DD
..:ClickClick . anhttpbelow
. Click anbelow
.Click . Click anURLdocs. : DD
. . Clickshtml/an to
below ..Click
andocsyoubelow Click unx
. below / . Click . below
. . anExplorerbelow
.advisor:Click. Click
. Click duffy anWebbelow
. duffy
.Click IBM
shtml/advisor:Click. anexternalbelow
. .shtml/an below
. Click an.points below
.. shtml anDDbelow
. .Clickan com launch below
.: . : advisor
. : Click . shtml . DD .com
. advisorcomshtml
. ./ ./
. comshtml com
. an
below
. .
.
shtml / com
.
the points The selected unx an duffy shtml/
Click to URL below unx oct95 . docs
externaladvisor::you/www/com/link:launch:resource:IBM.DD/Explorer
.
shtml launch Web selected oct95 the an Explorer resource.
Click The to below the IBM http unx duffy
externaladvisor//URL.DD.comadvisor:/points/docs/link/
: . advisor : advisor
. //
. // .
./. /
.Click . . : /
. launch /Web/
.
. comselected . . : The shtml / DD
.
shtml / advisor : advisor
.points
. comadvisor/www/
. ./
/ ...:Clickresource
. advisor : advisor
. Explorer docs anbelow
. shtml IBMadvisoran. /
/below.:advisorshtml/. .anbelow/.externalexternalClick
below
. Explorer .
. unxExplorer duffy andocs below
. .anbelow.http
oct95
. you Explorer DD. an below / DDthe
.
the points The selected unx an duffy shtml/
Click to URL below unx oct95 http Web docs
unx .
the IBM www selected link unx advisor duffy resource.
below to URL an . external Web docs
Explorer://The.shtml.Click/points/launch/DD/com.oct95.you
. Web . IBMadvisor//www.DD.comselected / docs / . external . http
.
the .youTheresourceunxanExplorershtml .
Click to URL below unx link launch Web duffy
. advisor / / www . DD . com advisor : / / points / external . http
.
the link you shtml oct95 unx advisor docs selected.
below to URL an unx launch IBM Web DD
http://wwwClick / resource / Explorer / . points / duffy . external
.
selected IBM Web points link The advisor docs shtml / .
Click shtml the an The http external to .
Explorer://URL.resource.unx.com/wwwbelow/launch.duffy
. . :
launch docs selected IBM external oct95 / Click http.
advisor link points : oct95 DD com resource below
duffyshtmlExplorer.an
.
selected http unx points launch The advisor docs oct95.
Click shtml the below The external Explorer to DD
shtml / duffy : / / link . resource . com / IBM URL .
═══ 5.58.0.0.1.0.0.0.0.0.0.0.0.0.1. fy.shtml4Ъ ═══
. URL an The launchwwwselectedoct95toadvisorduffyresource .
below the . to IBM http URL docs
external./Web.shtml.Click/points/com/link/DD.Explorer
advisor .
shtmlWeb points link the . shtml / .
Click The to below the http external unx DD
Explorer://URL..com/selected/launch/an.duffy
.
.http Web resource launch to advisor docs points.
Click the unx below to external Explorer
duffy://oct95.selected.com/IBMwwwan/shtml.link
. : Web .
resource launch . link shtml advisor duffy oct95.
Click selected The an shtml IBM http the docs
. . . external://toshtml/.com/below.Explorer
.
the link you selected . below Explorer resource/
com to . unx launch IBM Web duffy
. http an . www / shtml / DD : The : oct95 : docs . advisor / external
.
The IBM www selected . advisor docs resource.
below the unx an to http Explorer URL DD
. duffy://Web.launch.Click/shtml/.link/oct95.com
. .
selected IBM URL resource link The an docs points.
Click shtml the below The http external to DD
Exploreradvisor//unxcom / oct95 / : . duffy
.
the points The selected unx an duffy shtml/
Click to URL below unx oct95 http Web docs
externaladvisor::you/www/com/link:launch:resource:IBM.DD/Explorer
..unx.
points IBM unx oct95 launch selected advisor duffy link.ClickresourceThebelowselectedhttpexternalthedocs
Explorer://.com.shtml..URLan/
.
shtml/selected to shtml Web an http The/
docs Web resource oct95 you external
to below the external Explorer unx DD
duffy://link.resource.com.Weban/The/
.
http DD resource external docs launch / below shtml / .
advisor IBM oct95 : launch com . an
Explorer.link
. Web advisor .
http docs resource external duffy launch . Explorer.
advisor IBM oct95 : launch DD com points below
. www link www . an.link
: .
http docs resource external duffy launch / Click Explorer.
advisor IBM oct95 : launch DD com points below
Web link Web . an.link
.
shtml/.http .resourceexternalduffylaunch/belowExplorer .
advisor IBM oct95 : launch DD com points an
. unx com
Click.link
oct95 : launch com Click points an
external.link
. .
.external to oct95 IBM shtml advisor DD link.
below selected The an shtml Explorer . com
docs://. Click / http /
.
oct95 external . http resource . IBM.
below points selected an resource Explorer duffy shtml com
oct95 http Web docs
. externaladvisor::you/www/com/link:launch:resource:IBM./Explorer
.
The launch www selected oct95 to advisor docs resource.
below the URL an to IBM http Web DD
. link . shtml / . .
external://shtml.unx.com/points/link/Click/Explorer/duffy..
The launch www selected oct95 to advisor docs resource.
below the URL an to IBM http Web .
duffy://shtml.unx..points/link/Click/external/Explorer/shtml/:DD.
launch duffy selected http Explorer oct95 / Click external.
. points : oct95 docs DD resource below
shtml / link . . . shtml an . IBM
advisor .
selected IBM Web resource oct95 The advisor docs points.
below shtml . The http external unx DD
. . Explorer://URL.Click.to./wwwlaunch/link.duffy
.
.URLanIBM docs resource external duffy link / below Explorer.
advisor launch oct95 : link DD com points an
. unx com
http.Click
The link you selected points to an external resource.
Click the URL below to launch IBM Web Explorer
http://www.webcity.co.jp/info/matumot/index-e.html
The link you selected points to an external resource.
Click the URL below to launch IBM Web Explorer
http://www.unx.com/DD/advisor/docs/oct95/oct95.duffy.shtml
. duffy://IBM.launch.docs/DD/
. .
resource external to points link shtml advisor docs oct95.
Click selected The an shtml Explorer duffy the DD
/ IBM / . http . below . com
.URLanto oct95 you the shtml URL an http The/
duffy unx Web below URL link launch www external
IBMadvisor::resource/Click/Explorer:DD.com:docs:selected:points
unx .
oct95 .thelinkIBMresourceadvisordocslaunch .
below points . resource external Explorer shtml DD
duffy://The.com.Click
.
link duffy shtml / http points / below IBM.advisoroct95resource:pointsdocscomselectedan
. externalTheExplorerThe/TheDD.Click
. .
link Explorer shtml launch http points : Click . /
an oct95 resource advisor points duffy docs selected below
. externaladvisor::you/www/com/link:launch:resource:IBM.DD/Explorer
. .
launch duffy selected IBM Explorer oct95 / below http.
advisor link points : oct95 docs DD resource an
Click . external . com
. IBM docsresourcehttpduffylink.external .
advisor launch oct95 : link DD com points an
Click.Explorer
.
IBM docs resource http duffy link / below Explorer.
advisor launch oct95 : link DD com points an
Click.external
. .
IBM duffy resource http Explorer link / Click external.
advisor launch . link docs DD points below
. an . com
.
IBM .resourcehttpduffylink/Clickexternal .
advisor launch oct95 : link DD com points below
an.Explorer
link com Click points an
docs.Explorer
.
IBMresource http duffy link / Click external.
the points The selected unx an duffy shtml/
Click to URL below . http Web docs
externaladvisor::you/www/com/link:launch:resource:IBM.DD/Explorer
shtml http Web points link the advisor DD oct95.
below The to an the external Explorer unx com
duffy://URL.resource.Click/selected/IBM/launch.docs
. . . . IBMadvisor//you.The.points/DD/the/docs/com/duffy/:.http
DD .
.URLanselected external URL oct95 IBM The . link.
below shtml the an The Explorer . com
shtml / docs:..unx.
the points The selected unx an duffy shtml/
Click to URL below unx oct95 http Web docs
externaladvisor::you/www/com/link:launch:resource:IBM.DD/Explorer
.
oct95 external . http resource advisor DD IBM.
below points selected an resource Explorer duffy shtml com
docs://The.link.Click
to . advisor shtml points Click advisor the points Click advisor Web points
points com shtml / advisor points duffy : http advisor points / link : DD
advisor points duffy : IBM . / link : Explorer . external . launch advisor
points Click advisor points docs : below
shtml / com docs below
. advisor. an com docs below
. .advisor. advisor : /
.
. points
.advisor:Clickoct95 .
theThe selected unx an duffy shtml/
Click to URL below unx oct95 http Web docs
externaladvisor::you/www/com/link:launch:resource:IBM.DD/Explorer
below points selected an resource Explorer duffy shtml com
. unx com
docs./The.launch.Click/
.
. :
.advisor:Clickshtml/link
. com. advisor : advisor
.shtml/below.youpointswww
. .anbelow..
URL
. . com Clickcom
. points www . pointsWeb
.:
. .advisor. : advisor
.. . com . DD
. .to com points
. to DD. : advisor
.to . .
. to points . shtml belowtocom DDcom
. to com. advisor : advisor
.. shtml / DD
. selected topoints
comshtml / unx .
. .an.
.
. DDDDanbelow DD
. compoints
. ..advisor:advisor
shtml / . : Click the
. unx oct95 http Web docs
externaladvisor::you/www/com/link:launch:resource:IBM.DD.
/ .
the IBM you selected points unx advisor docs resource.
below to URL an unx http external Web DD
═══ 5.58.0.0.1.0.0.0.1. http://www.unx.com/DD/advisor/docs/oct95/oct95.duffy.shtml4Ъ ═══
═══ <hidden> y/OpenGL/extensions.htmlFЭ ═══
Explorer://www.shtml.Click/The/launch/oct95.com/link.duffy
. DD
. : advisor
. . : /
. advisor : advisor
.
. anbelow DD
. com anbelow
. advisor
. ..
the points The selected unx an duffy shtml/
Click to URL below unx oct95 http Web docs unx com
externaladvisor::you/www/com/link:launch:resource:IBM.DD/Explorer
.
The link you selected points to an external resource.
Click the URL below to launch IBM Web Explorer
http://www.unx.com/DD/advisor/docs/oct95/oct95.duffy.shtml
. advisor unx Click
. .
.oct95 http advisor
.points IBM
. external IBM . : advisor
.advisor:Clicklink IBM
.DD . . . .
the points . selected unx an duffy shtml/
Click to URL below unx oct95 http Web docs unx com
externaladvisor::you/www/com/link:launch:resource:IBM.DD/Explorer
: .
.URLanThe http www resource oct95 to advisor DD points.
below the unx an . Explorer URL com
. link . duffy://Web.selected.Click/shtml/IBM/link/launch.docs
com
. : advisor
.Click Web .
. Click Web shtmlcom .
.. docsthe .
. shtml / below / shtml DD resourcean below
. docsresourceDDduffy
. docs. resource DD .
. . Explorer DD Exploreran . DDbelow
..:Clickan. DD
. .URL
. anbelow
.Click
. unx URL selected
. . .
. unx docslaunch . unx..
. / ExplorerDDduffy
.selected shtml / : DD
. .anbelow/unx
.
.
unx
.
thepoints
The
selected
unx
an
duffy shtml/
Click
to
URL
below
unx
oct95
http
Web
docs
. externaladvisor:./www/com/link:launch:resource:IBM.DD/Explorer
.
.
.http Web resource launch to . points.
below the unx an to external Explorer URL DD
. . : / / shtml . selected . Click / oct95 / IBM / com / IBM . link . www
:
. .shtml/.
.Click
. below The . Click.wwwbelow .
.
. .below/andocsthebelow
.Click shtml an. : DD . .
. /anbelow/Click anbelow . : advisor
.Click shtml / anlinkbelow
. .below/. Clickan resource com selected below
. anThedocsoct95below . DD
..:ClickClick . anhttpbelow
. Click anbelow
./ .Click shtml / antobelow .
.
Clickan docs you belowClickunx
. .below/.Click.below
. an Explorer below
.advisor:Click. Click
. Click duffy anWebbelow
. ..duffy
.Click IBM
shtml/advisor:Click/ .an external below
. .shtml/an below
. Click an.points below
..shtmlan DD below
. .an com launch below
.
. shtml /
. .below/. advisor
. com
..:Click.shtml.DD. com
. com shtml
. ./ ./
. comshtml com
. .anbelow..
.shtml / com
.
the points The selected unx an duffy shtml/
Click to URL below unx oct95 . docs
externaladvisor::you/www/com/link:launch:resource:IBM.
.
shtml launch Web selected oct95 the an Explorer resource.
Click The to below the IBM http unx duffy
externaladvisor//URL.DD.comadvisor:/points/docs/link/
: . advisor : advisor
. below / / /
. // .
./. /
.Web /
.
. comselected . . : The shtml / DD
The link you selected points to an external resource.
Click the URL below to launch IBM Web Explorer
http://www.webcity.co.jp/info/matumot/index-e.html
The link you selected points to an external resource.
Click the URL below to launch IBM Web Explorer
http://www.sgi.com/Products/Dev_environ_ds.html
. URL externalExplorerbelow environClick
. .belowClick.http
points
. _ external ds. below Click / dsthe
. . .
the Products The selected URL below Explorer sgi/
com to Web Click URL points http www environ
. . URL .
the IBM you selected link URL an Explorer resource.
Click to Web below . html www environ
external://The.sgi.com/Products/launch/ds. points . _
. www . IBMan//you.ds.Devan.selected/environ/.html.http
.
the ._TheresourceURLbelowexternalsgi .
com to Web Click URL link launch www Explorer
sgi / . . . an / / you . ds . Dev an : / selected . / Products / html . http
.
the link _ sgi points URL an environ selected.
Click to Web below URL launch IBM www ds
. . http://you..com/resource/external/.Products/Explorer.html
.
selected IBM www Products link The an environ sgi / .
com sgi the below The http html to .
. sgi / . external://Web.resource.URL.Dev/youClick/launch.Explorer
. . : www .
launch environ selected IBM html points / com http.
an link Products : points ds Dev resource Click
. Explorersgiexternal.below
.
selected http URL Products launch The an environ points.
com sgi the Click The html external to ds
/ Explorer : / / link . resource . Dev / IBM Web
the . http Web environ
html./www.sgi.com/Products/Dev/link/ds.external
an .
sgi .wwwProductslinkthe..
com The to Click the http html URL ds
external://Web..Dev/selected/launch/below.Explorer
.
.http www resource launch to an environ Products.
URL Click to html external Web .
Explorer://points.selected.Dev/IBMyoubelow/sgi.link
. : www .
resource launch . link sgi an Explorer points.
com selected The below sgi IBM http the environ
URL Dev
html://tosgi/.Dev/Click.external
.
the link _ selected . Click external resource/
Dev to . URL launch IBM www Explorer
. . http below . you / sgi / ds : The : points : environ . an / html
.
The IBM you selected . an environ resource.
Click the URL below to http external Web ds
sgi / . . . Explorer://www.launch.com/sgi/.link/points.Dev
. .
selected IBM Web resource link The below environ Products.
com sgi the Click The http html to ds
externalan//URL..Dev/points/:.Explorer
.
the Products The selected URL below Explorer sgi/
com to Web Click URL points http www environ
htmlan::_/you/Dev/link:launch:resource:IBM.ds/external
IBMan//_.ds.Devan:/sgi/environ/resource/resourceProductshtml.
..URL.
Products IBM URL points an Explorer link.comresourceTheClickselectedhttphtmltheenviron
external://.Dev.sgi..Webbelow/
.
sgi/selected to sgi www below http The/
environ Web . www resource points _ html
. . . link an : : IBM . the / . Explorer : external : com : Click : Products : Products / launch
.
selected .WebProductslaunchtheanenviron.
. to Click the html external URL ds
Explorer://link.resource.Dev.wwwbelow/The/
.
http ds resource html environ launch / Click sgi / .
an IBM points : launch Dev . below
URL Dev
external.link
. www an .
http environ resource html Explorer launch . external.
an IBM points : launch ds Dev Products Click
. you link you . below.link
: .
http environ resource html Explorer launch / com external.
an IBM points : launch ds Dev Products Click
. www link www . below.link
.
sgi/.http .resourcehtmlExplorerlaunch/Clickexternal .
an IBM points : launch ds Dev Products below
. URL Dev
. com.link
. .
.html to points IBM sgi an ds link
The link you selected points to an external resource.
Click the URL below to launch IBM Web Explorer
http://www.webcity.co.jp/info/matumot/index-e.html
The link you selected points to an external resource.
Click the URL below to launch IBM Web Explorer
http://www.austin.ibm.com/software/OpenGL/glossary/index.html
IBM.
below OpenGL resource austin points html glossary selected com
external://software.launch.Click
. http://selected.to.com/OpenGL/launch/Click/html/glossary.glossary://selected.to..OpenGL/launch/Click/http/html/selected/:Explorer..
index glossary resource ibm html link / Click http.
. OpenGL : link external Explorer points below
selected / launch . . . selected austin . IBM
an .
resource IBM Web points link software an external OpenGL.
below selected . software ibm http to Explorer
html://URL.Click.the./wwwindex/launch.glossary
.URLaustinIBM external points http glossary launch / below html.
an index link : launch Explorer com OpenGL austin
. to com
ibm.Click
.
The OpenGL software resource to austin glossary selected/
Click the URL below to link ibm Web external
software launch you resource OpenGL the austin http points.
Click The URL below the index IBM Web html
ibm://www.to.com/Explorer/an/external/link/link.glossary.selected
. glossary://IBM.index.external/Explorer/
. .
points http the OpenGL launch selected an external link.
Click resource software austin selected html glossary The Explorer
/ IBM / . ibm . below . com
.URLaustinthe link you The selected URL austin ibm software/
glossary to Web below URL launch index www http
IBMan::points/Click/html:Explorer.com:external:resource:OpenGL
. to .
link .ThelaunchIBMpointsanexternalindex .
below OpenGL . points http html selected Explorer
glossary://software.com.Click
.
launch glossary selected / ibm OpenGL / below IBM.anlinkpoints:OpenGLexternalcomresourceaustin
. httpsoftwarehtmlsoftware/softwareExplorer.Click
. .
launch html selected index ibm OpenGL : Click . /
austin link points an OpenGL glossary external resource below
. httpan::you/www/com/launch:index:points:IBM.Explorer/html
. .
index glossary resource IBM html link / below ibm.
an launch OpenGL : link external Explorer points austin
Click . http . com
. IBM externalpointsibmglossarylaunch.http .
an index link : launch Explorer com OpenGL austin
Click.html
.
IBM external points ibm glossary launch / below html.
an index link : launch Explorer com OpenGL austin
Click.http
. .
IBM glossary points ibm html launch / Click http.
an index . launch external Explorer OpenGL below
. austin . com
.
IBM .pointsibmglossarylaunch/Clickhttp .
an index link : launch Explorer com OpenGL below
austin.html
launch com Click OpenGL austin
external.html
.
IBM points ibm glossary launch / Click http.
The OpenGL software resource to austin glossary selected/
Click the URL below . ibm Web external
httpan::you/www/com/launch:index:points:IBM.Explorer/html
selected ibm Web OpenGL launch The an Explorer link.
below software the austin The http html to com
glossary://URL.points.Click/resource/IBM/index.external
. . . . IBMan//you.software.OpenGL/Explorer/The/external/com/glossary/:.ibm
Explorer .
.URLaustinresource http URL link IBM software . launch.
below selected The austin software html . com
selected / external:..to.
The OpenGL software resource to austin glossary selected/
Click the URL below to link ibm Web external
httpan::you/www/com/launch:index:points:IBM.Explorer/html
.
link http . ibm points an Explorer IBM.
below OpenGL resource austin points html glossary selected com
external://software.launch.Click
the . an selected OpenGL Click an The OpenGL Click an Web OpenGL austin OpenGL
com selected / an OpenGL glossary : ibm an OpenGL / launch : Explorer an
OpenGL glossary : IBM . / launch : html . http . index an OpenGL Click an
OpenGL external : below
selected / com external below
. an. austin com external below
. .an. an : /
.
. OpenGL
.an:Clicklink .
The software resource to austin glossary selected/
Click the URL below to link ibm Web external
httpan::you/www/com/launch:index:points:IBM.Explorer/html
below OpenGL resource austin points html glossary selected com
. to com
external./software.index.Click/
.
. :
.an:Clickselected/launch
. comOpenGL . an : an
.selected/below.youOpenGLwww
. .austinbelow..
URL
. . com Clickcom
. OpenGL www . OpenGLWeb
.:
. .an. : an
.. . com . Explorer
. .the com OpenGL
. the Explorer. : an
.the . .
. the OpenGL . selected below
thecom Explorercom
. the com. an : an
.. selected / Explorer
. resource theOpenGL
comselected / to .
. .austinbelow.
.
. ExplorerExploreraustinbelow Explorer
. comOpenGL
. ..an:an
selected / . : Click The
. to link ibm Web external
httpan::you/www/com/launch:index:points:IBM.Explorer.
/ .
The IBM you resource OpenGL to an external points.
below the URL austin to ibm http Web Explorer
The link you selected points to an external resource.
Click the URL below to launch IBM Web Explorer
http://www.webcity.co.jp/info/matumot/index-e.html
The link you selected points to an external resource.
Click the URL below to launch IBM Web Explorer
http://www.sgi.com/Technology/OpenGL/extensions.html
com below .Explorer Click.extensions
. Explorer belowClick
. an
. .Web .
to selected the Technology Web below html The/
com URL www Click Web resource launch you external
. Web Explorer
IBMan:://Explorer/points:OpenGL:sgi:link.extensions/http
the points Technology selected URL below IBM sgi.
com to www Click URL OpenGL link you http
launch://.Web.Explorer/extensions/an/external/resource/. The
. an Web com
. .
.resource launch points link
./
. . : extensions . .
to selected . Technology Web below html The/
com URL www Click Web resource launch you external
. Web Explorer
IBMan:://Explorer/points:OpenGL:sgi:link.extensions/http
: .
.wwwbelowthe launch sgi resource URL an extensions selected.
Click to Web below . http www Explorer
. points . . html://you.Technology.com/The/link/points/OpenGL.external
.
. com you TheExplorer .
.. externalto .
. Click
. externalsgiextensionshtml
. external. sgi extensions .
. . http extensions httpbelow . extensionsClick
..:combelow. Click.extensions ..www
. belowClick
.below Click / . com
. Web www Technology
. . .
. Web externalOpenGL . extensions
. .Web . .
. / httpextensionshtml
.Technology The / : extensions
. .belowClick/Web
.
.
Web
.
toselected
below
html The/
com
URL
www
Click
Web
resource
launch
you
external
IBMan:.//Explorer/points:OpenGL:sgi:link.extensions/http
.
.
.
═══ <hidden> OpenGL/glossary/index.html9Ь ═══
OpenGL URL . selected.
Click to Web below URL IBM http www extensions
. : / / The . Technology . com / resource / link / Explorer / link . points .
: . . The / .
.com
. .Clickthe.com . Click ..
. .Click/external to Click
.com The / belowpointsClick
. .Click/. combelow sgi Explorer Technology Click
. .below the external resource Click.extensions
..:comcom . belowlaunchClick an : an
. com belowClick
.belowexternalClick com Web
. .Click/.com.Click
. . . below http Click
.an:com
. com html belowyouClick
. ..html
.com link
The/an:coman
..The/below Click
. com below.selected Click
..Thebelow extensions Click
. .com.belowExplorerOpenGLClick an : /
..
. The /
. .Click/. an
. Explorer
..:com.The.extensions. Explorer
. .ExplorerThe
. ./ ./
. ExplorerThe Explorer
. .belowClick..
.
. The / Explorer
.
to selected the Technology Web below html The/
com URL www Click Web resource . external
IBMan:://Explorer/points:OpenGL:sgi:link.extensions.
.
The OpenGL you Technology resource to below http sgi.
com the URL Click to link launch Web html
. IBMan//www.extensions.Exploreran:/selected/external/points/
: . an : an
. .Click///
. // .
./. /
.an
. . .
.
The / an : an
. selected .
to selected the Technology Web below html The/
com URL www Click Web resource launch you external
IBMan:://Explorer/points:OpenGL:sgi:link.extensions/http
.
the points Technology resource URL an http sgi.
Click to Web below URL OpenGL link www html
launch://you.The.com/selected/Explorerexternalextensions.IBM
. . Web httphtmlbelow externalClick
. .belowClick.launch
resource
an
.http extensions. below Click / extensionsto
. .
to selected the Technology Web below html The/
com URL www Click Web resource launch you external
IBMan:://Explorer.:OpenGL:sgi:link.extensions.
. . Web .
to link Technology points Web an html sgi.
Click URL www below . IBM you external
http://the.The.com/selected/OpenGL/extensions..resource.
. you . linkan//.extensions.Exploreran.Technology/external/.IBM.launch
.
to .thesgiWebbelowhttpThe .
com URL www OpenGL you html
. an / / . extensions . Explorer an : / Technology . / selected / IBM . launch
.
to points The resource Technology.
Click URL www below Web OpenGL link you extensions
launch://..com/sgi/http/.selected/html.IBM
Web .
Technology link you selected points the an external The / .
com The to below the launch IBM URL .
http://www.sgi.Web.Explorer/Click/OpenGL.html
. . : you .
externalTechnologylinkIBMresource/comlaunch .
an points selected : resource extensions Explorer sgi Click
htmlThehttp.below
.
Technology launch Web selected OpenGL the an external resource.
com The to Click the IBM http URL extensions
The / html : / / points . sgi . Explorer / link www .
/ . . . www below the OpenGLTechnologyresourceURLanhtmlsgi .
Click to . . launch www external
IBM./you.The.com/selected/Explorer/points/
an .
The .youselectedpointsto...
com the URL Click to launch IBM Web extensions
http://www..Explorer/Technology/OpenGL/below.html
.
.launch you sgi OpenGL URL an external selected.
. Web Click URL IBM http www .
html://resource.Technology.Explorer/linkbelow/The.points
. : you .
OpenGL.pointsTheanhtmlresource .
com Technology the below The link launch to external
. Web Explorer
IBM://URLThe/.Explorer/Click.http
.
to points Technology . Click http sgi/
Explorer URL . Web OpenGL link
. launch below . / The / extensions : the : resource : external . an / IBM
.
the link Technology . an external sgi.
Click to Web below URL launch http
html://you.OpenGL.com/The/.points/resource.Explorer
. .
Technology link www sgi points the below external selected.to Click the launch IBM URL extensions
httpan//Web..Explorer/resource/:.html
.
to selected the Technology Web below html The/
com URL www Click Web resource launch you external Web Explorer
IBMan:://Explorer/points:OpenGL:sgi:link.extensions/http
linkan//.extensions.Exploreran:/The/external/sgi/sgiselectedIBM.
..Web.
selected link Web an html points.comsgitheClickTechnologylaunchIBMtoexternal
http://.Explorer.The..wwwbelow/
.
The/Technology URL The you below launch the/
external www . you sgi resource IBM
. . . points an : : link . to / . html : http : com : Click : selected : selected / OpenGL
.
Technology .wwwselectedOpenGLtoanexternal..
. URL http Web extensions
html://points.sgi.Explorer.youbelow/the/
.
launch extensions sgi IBM external OpenGL / Click The / .
an link resource : OpenGL Explorer . below
. Web Explorer
. http.points
. you an .
launch external sgi IBM html OpenGL . http.
an link resource : OpenGL extensions Explorer selected Click
. points . below.points
: .
launch external sgi IBM html http.
an link resource : OpenGL extensions Explorer selected Click
. you points you . below.points
.
The/.launch .sgiIBMhtmlOpenGL/Clickhttp .
an link resource : OpenGL extensions Explorer selected below
. Web Explorer
com.points
. .
.IBM URL resource link The an extensions points.
to selected the Technology Web below html com URL www Click Web resource launch you external
IBMan:://Explorer/points:OpenGL:sgi:link.extensions/http
an .
to resource The sgi Web an
The link you selected points to an external resource.
Click the URL below to launch IBM Web Explorer
http://www.webcity.co.jp/info/matumot/index-e.html
The link you selected points to an external resource.
Click the URL below to launch IBM Web Explorer
http://www.unx.com/DD/advisor/docs/oct95/oct95.duffy.shtml
. external://shtml.unx.com/points/link/Click/Explorer/duffy.duffy://shtml.unx..points/link/Click/external/Explorer/shtml/:DD..
launch duffy selected http Explorer oct95 / Click external.
. points : oct95 docs DD resource below
shtml / link . . . . shtml an . : DD
advisor .
selected IBM Web resource oct95 The advisor docs points.
below shtml . The http external unx DD
Explorer://URL.Click.to./wwwlaunch/link.duffy
.
.URLdocsresourceexternalduffylink/belowExplorer .
advisor launch oct95 : link DD com points an
. unx com
http.Click
.
the points The selected unx an duffy shtml/
Click to URL below unx oct95 http Web docs
The link you selected points to an external resource.
Click the URL below to launch IBM Web Explorer
http://www.unx.com/DD/advisor/docs/oct95/oct95.duffy.shtml
. duffy://IBM.launch.docs/DD/
. .
resource external to points link shtml advisor docs oct95.
Click selected The an shtml Explorer duffy the DD
/ IBM / . http . below . com
.URLanto oct95 you the shtml URL an http The/
duffy unx Web below URL link launch www external
IBMadvisor::resource/Click/Explorer:DD.com:docs:selected:points
unx .
oct95 .thelinkIBMresourceadvisordocslaunch .
below points . resource external Explorer shtml DD
duffy://The.com.Click
.
link duffy shtml / http points / below IBM.advisoroct95resource:pointsdocscomselectedan
. externalTheExplorerThe/TheDD.Click
. .
link Explorer shtml launch http points : Click . /
an oct95 resource advisor points duffy docs selected below
. externaladvisor::you/www/com/link:launch:resource:IBM.DD/Explorer
. .
launch duffy selected IBM Explorer oct95 / below http.
advisor link points : oct95 docs DD resource an
Click . external . com
. IBM docsresourcehttpduffylink.external .
advisor launch oct95 : link DD com points an
Click.Explorer
.
IBM docs resource http duffy link / below Explorer.
advisor launch oct95 : link DD com points an
Click.external
. .
IBM duffy resource http Explorer link / Click external.
advisor launch . link docs DD points below
. an . com
.
IBM .resourcehttpduffylink/Clickexternal .
advisor launch oct95 : link DD com points below
an.Explorer
link com Click points an
docs.Explorer
.
IBMresource http duffy link / Click external.
the points The selected unx an duffy shtml/
Click to URL below . http Web docs
externaladvisor::you/www/com/link:launch:resource:IBM.DD/Explorer
shtml http Web points link the advisor DD oct95.
below The to an the external Explorer unx com
duffy://URL.resource.Click/selected/IBM/launch.docs
. . . . IBMadvisor//you.The.points/DD/the/docs/com/duffy/:.http
DD .
.URLanselected external URL oct95 IBM The . link.
below shtml the an The Explorer . com
shtml / docs:..unx.
the points The selected unx an duffy shtml/
Click to URL below unx oct95 http Web docs
externaladvisor::you/www/com/link:launch:resource:IBM.DD/Explorer
.
oct95 external . http resource advisor DD IBM.
below points selected an resource Explorer duffy shtml com
docs://The.link.Click
to . advisor shtml points Click advisor the points Click advisor Web points
points com shtml / advisor points duffy : http advisor points / link : DD
advisor points duffy : IBM . / link : Explorer . external . launch advisor
points Click advisor points docs : below
shtml / com docs below
. advisor. an com docs below
. .advisor. advisor : /
.
. points
.advisor:Clickoct95 .
theThe selected unx an duffy shtml/
Click to URL below unx oct95 http Web docs
externaladvisor::you/www/com/link:launch:resource:IBM.DD/Explorer
below points selected an resource Explorer duffy shtml com
. unx com
docs./The.launch.Click/
.
. :
.advisor:Clickshtml/link
. com. advisor : advisor
.shtml/below.youpointswww
. .anbelow..
URL
. . com Clickcom
. points www . pointsWeb
.:
. .advisor. : advisor
.. . com . DD
. .to com points
. to DD. : advisor
.to . .
. to points . shtml belowtocom DDcom
. to com. advisor : advisor
.. shtml / DD
. selected topoints
comshtml / unx .
. .an.
.
. DDDDanbelow DD
. compoints
. ..advisor:advisor
shtml / . : Click the
. unx oct95 http Web docs
externaladvisor::you/www/com/link:launch:resource:IBM.DD.
/ .
the IBM you selected points unx advisor docs resource.
below to URL an unx http external Web DD
the points The selected unx an duffy shtml/
Click to URL below unx oct95 http Web docs
externaladvisor::you/www/com/link:launch:resource:IBM.DD/Explorer
. .
shtml IBMWebpointslinktheadvisordocsoct95 .
below The to an the http external unx com
Explorer://URL.resource.Click/selected/launch/DD.duffy
DD
. com anbelow
. advisor
. ...unx.
the points The selected unx an duffy shtml/
Click to URL below unx oct95 http Web docs unx com
externaladvisor::you/www/com/link:launch:resource:IBM.DD/Explorer
.
The link you selected points to an external resource.
Click the URL below to launch IBM Web Explorer
http://www.unx.com/DD/advisor/docs/oct95/oct95..shtml
. advisor unx Click
. .
.oct95 http advisor
.points IBM
. external IBM . : advisor
.advisor:Click.linkIBM
.DD . . . .
the points . selected unx an duffy shtml/
Click to URL below unx oct95 http Web docs unx com
externaladvisor::you/www/com/link:launch:resource:IBM.DD/Explorer
: .
.URLanThe http www resource oct95 to advisor DD points.
below the unx an . Explorer URL com
. link . . duffy://Web.selected.Click/shtml/IBM/link/launch.docs
com
. : advisor
.. .
. Click Web shtmlcom .
.. docsthe .
. shtml / below / shtml DD resourcean .below
. docsresourceDDduffy
. docs. resource DD .
. . Explorer DD Exploreran . DDbelow
..:Clickan. DD . ..URL
. anbelow
.Click
. unx URL selected
. . .
. unx docslaunch . unx..
. / ExplorerDDduffy
.selected shtml / : DD
. .anbelow/unx
.
.
unx
.
thepoints
The
.
an
duffy shtml/
Click
to
URL
below
unx
oct95
http
Web
docs
. externaladvisor:./www/com/link:launch:resource:IBM.DD/Explorer
.
.
.http . launch to . points.
below the unx an to external Explorer URL DD
. . : / / shtml . selected . Click / oct95 / IBM / com / IBM . link . www
:
.
.. shtml / .
.Click
. below The . Click.wwwbelow .
.
. .below/.docsthebelow
.Click shtml an. : DD . .
. /anbelow/Click anbelow . : advisor
..Clickshtml/an link below
. .below/. Clickan resource com selected below
. anThedocsoct95below . DD
..:ClickClick . anhttpbelow . advisor : advisor
. Click anbelow
./ .Click shtml / antobelow .
.
. andocsyoubelow Click unx
. .below/.Click.below
. an Explorer below
.advisor:Click. .
. Click duffy anWebbelow
. ..duffy
.Click IBM
shtml/advisor:Click/ .an external belowan com launch below.advisor:/
.
. shtml /
. .below/. advisor
. com
..:Click.shtml.DD. com
. com shtml
. ./ ./
. comshtml com
. .anbelow..
. . shtml / com
.
the points The selected unx an duffy shtml/
Click to URL below unx oct95 . docs
externaladvisor::you/www/com/link:launch:resource:IBM.
.
shtml launch Web selected oct95 the an Explorer resource.
Click The to below the IBM http unx duffy
externaladvisor//URL.DD.comadvisor:/points/docs/link/
: . advisor : advisor
. below / / /
. // .
./. . /
.Web /
.
. comselected . . : The shtml / DD
the points The selected unx an duffy shtml/
Click to URL below unx oct95 http Web docs
externaladvisor::you/www/com/link:launch:resource:IBM.DD/Explorer
.
The linkwwwselectedoct95toadvisorExplorerresource .
below the unx an to launch IBM URL duffy
http://Web.shtml.Click/points/comyoudocsyouDD.external
. . unx Explorerduffydocs below
. .anbelow.http
oct95
an
.
external
Web
docs
. Explorer://The.shtml.Click/points/launch/DD..oct95.you
.
Web
. IBMadvisor//www.DD.comadvisor.selected/docs/.external.http
.
the .youTheresourceunxanExplorershtml .
Click . launch Web duffy
. advisor / / www . DD . com advisor : / selected . / points / external . http
.
the link you shtml oct95 unx . selected.
below to URL IBM Web DD
http://www..Click/resource/Explorer/.points/duffy.external
.
.
unx
.
selected IBM Web points link The advisor docs shtml Click shtml the an The http external to .
Explorer://URL.resource.unx.com/wwwbelow/launch.duffy
. . : Web .
.docs selected IBM external oct95 / Click http.
advisor link points : oct95 DD com resource below
. . . duffyshtmlExplorer.an
.
selected http unx points launch The advisor docs oct95.
Click shtml the below The external Explorer to DD
/ duffy : / / link . resource . com / IBM URL .
Web .
points Explorer the link IBM selected advisor DD launch.belowresourceshtmlanselectedduffydocsThecom
external/http:oct95.Click
. external./Web.shtml.Click/points/com/link/DD.
advisor
.
shtml .Webpointslinkthe...
Click The to below the http external unx DD
. shtml / Explorer://URL..com/selected/launch/an.duffy
duffy://oct95.selected.com/IBMwwwan/shtml.link
. : Web .
.launch . link shtml advisor duffy oct95.
Click selected The an shtml IBM http the docs
. unx com
external://toshtml/.com/below.: DD
.
the link you selected . below Explorer resource/
com to . unx launch IBM Web .
. http an . www / shtml / DD : The : oct95 : docs . advisor / external
.
The IBM www selected . advisor docs resource.
below the unx an to http Explorer URL .
duffy://Web.launch.Click/shtml/.link/oct95.com
.
.
URL
an
selected
IBMURLresourcelinkTheandocspoints
.
.
the
below
The
http
external
to
DD
Exploreradvisor//unx..com/oct95/:.duffy
.
thepoints
The
selected
unx
an
duffy shtml/
Click
to
URL
═══ <hidden> i.com/Technology/OpenGL/extensions.htmlFЭ ═══
http Web docs
. unx com
externaladvisor::you/www/com/link:launch:resource:IBM.DD/Explorer
link IBMadvisor//you.DD.comadvisor:/shtml/docs/resource/resourcepointsexternal.
..unx.
points IBM unx oct95 . advisor duffy link.ClickresourceThebelowselectedhttpexternalthedocsunx com
Explorer://.com.shtml..URLan/
.
shtml/selected to shtml Web an http The/
docs URL . Web resource oct95 you external
. . . . . link advisor : : IBM . the / . duffy : Explorer : Click : below : points : points / launch
.
selected .URLpointslaunchtheadvisordocs..
. to below . Explorer unx DD
shtml / duffy://link.resource.com.Weban/The/
.
http DD resource external docs launch / below shtml / .
advisor IBM oct95 : launch com . an
. unx com
Explorer.link
. Web advisor .
http docs resource external duffy Explorer.
advisor IBM oct95 : launch DD com points below
. www link www . an.link
: .
http docs resource external duffy launch . Explorer.
advisor IBM oct95 : launch DD com points below
. Web link Web . an.link
. shtml / . http . resource external duffy launch / below Explorer.
advisor IBM oct95 : launch DD com points an
. unx com
Click.link
. .
.external to oct95 IBM shtml advisor DD link.
the points The selected unx an duffy shtml.ClicktoURLbelowunxoct95httpWebdocs
externaladvisor::/ com / link : launch : resource : IBM . DD / Explorer
advisor .
the oct95 you shtml resource unx advisor docs .
the points The selected unx an duffy shtml/
Click to URL below unx oct95 http Web docs
externaladvisor::you/www/com/link:launch:resource:IBM.DD/Explorer
Explorer .
The link you selected points to an external resource.
Click the URL below to launch IBM Web Explorer
http://www.unx.com/DD/advisor/docs/oct95/oct95.duffy.shtml
. . external://shtml.unx.com/points/link/Click/Explorer/duffy.. . duffy://shtml.unx..points/link/Click/external/Explorer/shtml/:DD..
launch duffy selected http Explorer oct95 / Click external.
. points : oct95 docs DD resource below
shtml / . . . . shtml an . IBM . : DD
advisor .
selected IBM Web resource oct95 The advisor docs points.
below shtml . The http external unx DD
/ URL . Click . to . / www launch / link . duffy
.
.URLan.docs resource external duffy link / below Explorer.
advisor launch oct95 : link DD com points an
. unx com
http.Click
.
the points The selected unx an duffy shtml/
Click to URL below unx oct95 http Web docs
. . externaladvisor::you/www/com/link:launch:resource:IBM.DD/Explorer
link . . . com.an.http.DD
. resource . . . . . .
The link you selected points to an external resource.
Click the URL below to launch IBM Web Explorer
http://www.unx.com/DD/advisor/docs/oct95/oct95.duffy.shtml
. duffy://IBM.launch.docs/DD/
. .
resource external to points link shtml advisor docs oct95.
Click selected The an shtml Explorer duffy the DD
/ IBM / . http . below . com
.URLanto oct95 you the shtml URL an http The/
duffy unx Web below URL link launch www external
IBMadvisor::resource/Click/Explorer:DD.com:docs:selected:points
unx .
oct95 .thelinkIBMresourceadvisordocslaunch .
below points . resource external Explorer shtml DD
duffy://The.com.Click
.
link duffy shtml / http points / below IBM.advisoroct95resource:pointsdocscomselectedan
. externalTheExplorerThe/TheDD.Click
. .
link Explorer shtml launch http points : Click . /
an oct95 resource advisor points duffy docs selected below
The link you selected points to an external resource.
Click the URL below to launch IBM Web Explorer
http://www.webcity.co.jp/info/matumot/index-e.html
The link you selected points to an external resource.
Click the URL below to launch IBM Web Explorer
http://www.unx.com/DD/advisor/docs/oct95/oct95.duffy.shtml
. . Click.external
. .
IBM duffy resource http Explorer link / Click external.
advisor launch . link docs DD points below
. an . com
.
IBM .resourcehttpduffylink/Clickexternal .
advisor launch oct95 : link DD com
an.Explorer
/ below external.
advisor launch . link com Click points an
docs.Explorer
.
IBM .resourcehttpduffylink/Clickexternal .
the points The selected unx an duffy shtml/
Click to URL below . http Web docs
externaladvisor::you/www/com/link:launch:resource:IBM.
.
shtml http Web points link the advisor DD oct95.
below The to an the external Explorer unx com
duffy://URL.resource.Click/selected/IBM/launch.docs
. . . . . IBMadvisor//you.The.points/DD/the/docs/com/duffy/:.http
DD .
.URLanselected external URL oct95 IBM The . link.
below shtml the an The Explorer . com
. shtml / docs:..unx.
the points The selected unx an duffy shtml/
Click to URL below unx oct95 http Web docs
. externaladvisor::you/www/com/link:launch:resource:IBM.DD/Explorer
.
oct95 external . http resource advisor DD IBM.
below points selected an resource Explorer duffy shtml com
docs://The.link.Click
to . advisor advisor the points Click advisor Web points an . points com shtml
/ advisor points duffy : http advisor points / link : DD advisor points duffy :
IBM . / link : Explorer . external . launch advisor points Click advisor points
docs : below
shtml / com docs belowbelow . advisor .
. advisor. an com docs below
. .advisor. advisor : /
.
. points
.advisor:Clickoct95 .
the .Theselectedunxanduffyshtml /
Click to URL below unx oct95 http Web docs
externaladvisor::you/www/com/link:launch:resource:IBM.DD/Explorer
the link http resource advisor DD IBM.belowpointsselectedanresourceExplorerduffyshtmlcom
. unx com
docs./The.launch.Click/
.
. :
.advisor:Clickshtml/link
. . com points..advisor:advisor
.shtml/below.youpointswww
. .anbelow..
URL
. . com Clickcom
. points www . . pointsWeb
.:
. .advisor. : advisor
.. . . com . DD
. .to com points
. to DD. : advisor
.to . .
. to points .
. tocom DDcom
. to com. advisor : advisor
.. shtml / DD
. selected topoints
comshtml / unx .
. .
an
below
. .
.
. DDDDanbelow . .DD
. compoints
. ..advisor:advisor
shtml / . : Click the
. an duffy shtml/
Click to . unx oct95 http Web docs
externaladvisor::you/www/com/link:launch:resource:IBM.DD.
/ .
the IBM you selected points unx advisor docs resource.
below unx http external Web DD
the points The selected unx an duffy shtml/
Click to URL below unx oct95 http Web docs
externaladvisor::you/www/com/link:launch:resource:IBM.DD/Explorer
shtml IBM Web points link the advisor docs oct95.
below The to an the http external unx com
Explorer://URL.resource.Click/selected/launch/DD.duffy
. combelow . DD
. com anbelow
. advisor
. ...unx.