This section is provided for those who flew through the workshop so far and want to make their program a little bit more efficient or flashy. It assumes a little bit more knowledge than the rest of the workshop. For the benefit of others who went straight to the "real" next page, demonstrators won't spend much time explaining details of this page if it takes away from those who need more help. Well, on to the optimistation and fancy stuff.
When GLUT generates the teapot it also generates per-vertex texture coordinates. These are ignored when texturing is disabled (as it is by default), but we can use them if we generate a texture map that we want to apply to the model. Here is some code for generating a texture map and loading it into OpenGL:
GLuint i;
GLboolean flag;
GLubyte data[256]; /* texture map data */
flag = GL_FALSE;
/* generate chessboard image */
for (i = 0; i < 64; i++)
{
if (!(i % 8))
flag = !flag;
if (flag) /* square is black */
{
data[4 * i ] = 0;
data[4 * i+ 1] = 0;
data[4 * i + 2] = 0;
data[4 * i + 3] = 255;
}
else /* square is white */
{
data[4 * i ] = 255;
data[4 * i+ 1] = 255;
data[4 * i + 2] = 255;
data[4 * i + 3] = 255;
}
flag = !flag;
}
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
/* set texture filtering parameters */
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
GL_NEAREST_MIPMAP_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,
GL_NEAREST);
/* set texture wrapping parameters */
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
/* load texture and build mipmaps */
gluBuild2DMipmaps (GL_TEXTURE_2D, GL_RGBA, 8, 8, GL_RGBA, GL_UNSIGNED_BYTE,
data);
It should look something like:
Spherical environment mapping simulates reflections on a object by using the object's vertex normals to generate texture coordinates into a texture that represents the surrounding environment. Think of a shiny object inside a sphere. Whatever is on the inside surface of the sphere should be reflected by the surface of the object. Now, if you paint the outside world onto the inside of the sphere, the reflection of that on the object will approximate reflection of the outside world. For a more in depth explaination of sphere maps including how to generate them, look here. Here is a sample environment map:
If you are super enthusiastic you can generate your own spherical environment map. Or you can load the above image. OpenGL does not provide any means to load textures. In order to create a texture, you need to provide OpenGL with an array of pixels in a format it recgonises. In the previous example, we generated the array. However, now we would like to load an image. This functionality is built into the Clean input/output library, CLIO. It uses OpenIL (Open Image Library) to load images:
void _InitTextureSphereEnvMap(void)
{
CLtexture* texture;
CLimage* image;
image = clioLoadImage("figure7.jpg");
texture = clNewTexture();
clCopyImage(&texture->image, image);
clLoadTexture(texture);
glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP);
glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP);
glEnable(GL_TEXTURE_GEN_S);
glEnable(GL_TEXTURE_GEN_T);
clDeleteImage(image);
clDeleteTexture(texture);
}
Oh and if you are using Clean you should make sure to
#include the following cl.h,
clu.h, and clio.h. You also might need the
Makefile to compile it (here). The end result
should look something like this:
You can move the lights around the teapot by updating their positions
just like with the teapot animation. Also, like moving the triangle
into view, you can modify input into the glLight()
function with the GL_POSITION parameter, or you can use
the modelview matrix. Just like calls to glVertex() are
defined within the coordinate system of the current modelview matrix,
the position of the light is defined relative to the current modelview
matrix with a call is made to glLight() that sets a new
position. Try something like:
/* disable lighting and texturing so light markers are drawn with colour */ glDisable(GL_LIGHTING); glDisable(GL_TEXTURE_2D); glPushMatrix(); glRotatef(light0_angle, 0.0f, 1.0f, 0.0f); glTranslatef(-5.0f, 0.0f, 0.0f); glutSolidCube(0.1f); /* draw a cube to mark the position of the light */ glLightfv(GL_LIGHT0, GL_POSITION, origin); glPopMatrix(); /* enable lighting and texturing so teapot is rendered properly */ glEnable(GL_LIGHTING); glEnable(GL_TEXTURE_2D);
If you managed to get all this done... well, I'd be pretty happy with that. If you stumbled along the way or just want to have a look at my code for this page you can find it here.
(Back to the "real" next) Next: Loading Models