If you haven’t started your entry for the TC Lisper’s Programming Contest, you’re not too late. The deadline is September 19th.
If you have started, post a comment here or there to let us know how it’s going!
If you haven’t started your entry for the TC Lisper’s Programming Contest, you’re not too late. The deadline is September 19th.
If you have started, post a comment here or there to let us know how it’s going!
Your Lisp program will be given two input images from the same web cam. The first image will contain zero people, the second image will contain at least one person.
Your program’s goal is to find the people. You will get points for emitting the pixel coordinates of a pixel inside a person. You’ll get bonus points if it’s a head pixel. Be careful, though. You’ll lose points for emitting more than one pixel per person.
I hope that by later in the month I will have time to participate in the 2010 International Lisp Games Expo.
In the previous tutorial, we drew a rotating pyramid and a rotating cube. The next NeHe tutorial renders a textured cube rotating at different speeds around each axis.
Again, we’re going to start with our simple-tutorial base.
Here is the resulting tut06.lisp.
We’re going to use a slot in our window class to store the texture. Note: it might be nice some day to break the cube out into its own class which could store its own position, rotation, and texture. For now though, we’re just going to keep piling stuff into our window class.
To load the texture, I’m going to use the CL-PNG wrapper around the PNG library. So, let’s get it loaded.
Then, I’m going to need some function that reads in a PNG and creates an OpenGL texture from it. I’m going to make my function take a filename for the PNG image and an optional texture id to use for the texture. (If you don’t pass in a texture id, one is created using gl:gen-textures. The argument to gl:gen-textures tells OpenGL how many textures you want to reserve. You can call gl:gen-textures multiple times. I’m not sure what benefit, if any, you get from allocating several of them simultaneously.)
So, we’re going to open the file and decode the PNG. Then, we’re going to try to turn it into a texture. If we succeed, then we’re going to
To load the image, we’re going to open the file and decode it. We have to make sure to open the file for binary input.
To turn the PNG into a texture, we first have to make sure that OpenGL knows that we’re going to start tweaking this particular texture. To do that, we use bind-texture and tell it we’re working with a two-dimensional texture here. (OpenGL supports 1-, 2-, and 3-dimensional textures.)
Now, we’re going to need to hand OpenGL our texture data. The CL-PNG library keeps our data in a three-dimensional array (width, height, channels). We need to get this down to a one-dimensional array for OpenGL. Fortunately, we can take advantage of the fact that Common Lisp arrays are stored contiguously. We’ll create an array called data that is a one-dimensional view into our three-dimensional array and let OpenGL copy from it.
To copy the data into the texture, we need to tell OpenGL how the data is laid out.
The level-of-detail is used if we’re going to manually specify what this image looks like at different resolutions. For our purposes in this tutorial, we’re just going to let OpenGL handle all of the scaling for our texture so we’ll stick with the default level of detail.
The internal-format tells OpenGL what type of texture this is going to be. We’re going to use the number of bits per sample and the number image channels to figure out what format this texture should be inside OpenGL.
The border parameter can be either zero or one. If it is zero, then the image width and height must be a power of two. If it is one, then the image width and height must be two plus a power of two. For our purposes, we’re just going to assume that the image is a power of two in width and height.
The format parameter declares what kind of data we have in our array. We’re going to use the number of image channels to come up with the right value here. With the internal format, we were able to blend both the size of the samples and the meaning of the samples into one parameter. For our input data, we give both format and data-type.
For the data type, we work from the number of bits per sample.
After we have the texture data loaded, we tell OpenGL how to scale our texture when it needs it in a smaller or larger size. We are going to tell it to use linear filtering whether it needs to minimize or magnify our texture.
That wraps up making the texture. If we ran into an error somewhere along the line of turning the png into a texture, we’re going to delete the texture if we allocated it and return nil.
To initialize our texture, we’re going to load it with the function above. Assuming that it loaded okay, we’re going to go ahead and enable texturing.
For this tutorial, our rotation state is going to consist of three angles, one for the rotation around the x-axis, one for the rotation around the y-axis, and one for the rotation around the z-axis. Each of these will initially be zero.
We’re also going to add the rotation state into our window class.
And, make sure we initialize our rotation state.
tick functionAgain, we’re going to try to stay near 60 frames per second. Recall that the tick interval is specified in milliseconds per tick.
We’re going to use a different rotation speed for each axis. We’ll update all three at once in the tick method.
In the base code, we already cleared the color buffer and the depth buffer and reset the modelview matrix. Now, retrieve our rotation angles, move back into the screen, rotate through each of our angles, and draw the cube with textures.
To draw the cube, we first want to make sure that we have the right texture selected. Then we are going to draw each face of the cube as a textured quad.
The texured cube faces are going to be like our colored faces. Before each vertex though, instead of specifying a color, we’re going to specify the texture coordinates for that vertex. The coordinates in the texture range from 0.0 to 1.0. The point (0,0) is at the top left of the texture and the point (1,1) is at the bottom right of the texure.
This isn’t the same coordinate system mentioned in the original NeHe document. The reason for that is that he is loading a Windows Bitmap. Windows Bitmaps are stored with the image from bottom to top as you proceed through the file.
Here is the front face. Note how we are going counterclockwise in both the texture coordinates and the spatial coordinates. (Note: It is traditional to show the texture coordinates and vertex coordinates as sort of two columns of source code.)
The same sort of logic continues around to the remaining five faces. I’m going to write a little function though to hopefully speed this along. Hopefully, if I use constants and an inline function, most of the calculation herein will get optimized into constants, too.
Now, I can whip through the faces just saying which way is left, which way is up, and which way is forward for that face.
And, now we have a textured cube.
In the previous tutorial, we drew a rotating triangle and a rotating square on the screen. The next NeHe tutorial fleshes out these polygons into solid shapes: a (square-bottomed) pyramid and a cube.
Again, we’re going to start with our simple-tutorial base.
Here is the resulting tut05.lisp.
This tutorial is almost identical to the previous one. For variety, I am going to use what I called the alternate version
of managing the modelview matrix in the previous tutorial.
Again, our rotation state is just going to be two angles: one for the pyramid and one for the cube. They are both going to default to zero.
We’re also going to add the rotation state into our window class.
And, make sure we initialize our rotation state.
tick functionAgain, we’re going to try to stay near 60 frames per second.
And, our tick method is unchanged from the previous tutorial except that we now have a pyramid and cube instead of a triangle and quad.
In the base code, we already cleared the color buffer and the depth buffer and reset the modelview matrix. Now, we’re going to retrieve our rotations, position our pyramid, save our modelview matrix, rotate for it, draw it, and restore our saved modelview matrix. Then, we’re going to position our cube, save our modelview matrix, rotate for it, draw it, and restore our saved modelview matrix.
For the pyramid, we’re going to slide to the left and back into the screen.
Then, we’re going to rotate the coordinate system around the Y-axis.
Again, the first parameter to rotate is an angle (in degrees). The remaining parameters are the axis about which to rotate.
Now, we’re going to draw the pyramid. We’re going to draw each of the four triangles that make up the pyramid. We’re going to keep each vertexes colored the same way regardless of which face the vertex is being drawn on at the moment.
The front face is going to be just about the same as our triangle from the previous tutorials. We’re just going to kick the bottom forward a bit.
The right face is going to share two vertexes with our front face and introduce a third.
The back face is going to share two points with the right face and one point with the front face.
The left face is going to share two points with the back face and two points with the front face (and, of course, the apex with the right face).
This completes the four sides of our pyramid. The NeHe tutorial doesn’t bother drawing a bottom for the pyramid. It won’t ever be seen with the way the rest of this code is organized, but I am going to include it here for completeness.
At the point we need to position the cube, we’re sitting at the point where the triangle was drawn. So, we need to slide to the right before drawing the cube.
Now, we’re going to rotate the coordinate system around the x-axis.
Now, we’re going to draw the cube with each face a different color.
The top face is going to be green. We are taking care here to draw the vertexes in counter-clockwise order when viewed from above the cube.
The bottom face is going to be orange. We are still taking care to draw the vertexes in counter-clockwise order when looking at this face from outside the cube. For the bottom face, that would be looking at the cube from below. For consistency, should we later want to texture map the cube, we’re going to start working from the front of the cube this time instead of the back as if we just flipped the cube 180 degrees forward and are now looking at the bottom.
Next, we’re going to draw the front face. We are going to make it red. Again, we’re going to keep our vertexes counter clockwise and we’re going to start with the one that’s in the upper right when we’re looking at the face.
Next, we’re going to draw the back face. We are going to make it yellow. Again, we’re going to keep our vertexes counter clockwise and we’re going to start with the one that’s in the upper right when we’re looking at the face (as if we’ve rotated the cube forward 180 degrees so that what was back is now front).
We’re going to draw the left side in blue.
For this tutorial, we’re never going to see the right side of the cube, but we’re going to draw it anyway for completeness. It will be magenta.
And, now we have a cube.
In all of the above examples, we have only used vertex inside a with-primitives call. There is good reason for this. We cannot just make a vertex whenever we want. It has to be a part of a shape. The with-primitives call starts building a shape (so far, we’ve only used triangles or quads) and then ends the shape at the end of the form. In C, we would need to do something like this to explicitly begin and end the shape.
If you try to make a vertex that isn’t part of a shape, things get corrupted. In C, you can probably still limp along and never notice. Unless you explicitly check the OpenGL error state on a regular basis, you’ll never notice that OpenGL is screaming quietly to itself.
CL-OpenGL checks the OpenGL error state for us though. It notices right away that something has gone wrong if we try to make a vertex outside of a with-primitives call.