Kinesia Online Course
Computer Graphics
Kinesia LLC, 2003

    1. Introduction
    2. Line Drawing
    3. Drawing Objects
    4. More Drawing Tools
    5. Normal Vectors and Polygonal Models of Surfaces
    6. Viewing I -- Affine Transformations
    7. Viewing II -- Projections
    8. Color
    9. Lighting
    10. Blending, antialiasing, fog ..
    11. Display Lists, Bitmaps and Images
    12. Texture Mapping
    13. Curves and Surfaces
    14. Games and SDL

    Texture Mapping

    I know of no more encouraging fact,
    than the unquestionable ability of man,
    to elevate his life by conscious endeavor.
    Henry David Thoreau

    1. Texture Mapping an Image

      Texture mapping -- applying a graphics image, a picutre, or a pattern to a surface.

      Properties of texture maps:

    2. a texture map can apply an actual picture to a surface such as a label on a can or a picture on a billboard or can apply semirepetitive patterns such as wood grain or stone surfaces

    3. more generally, a texture map can hold any kind of information that affects the appearance of a surface

    4. can be done by table look up; the individual values in a texture array are often called texels

    5. used often in real-time rendering settings such as games to reduce computational load

    6. can hold colors that are applied to a surface to overwrite current color of objects ( in this case no lightling calculations should be performed )

    7. can hold attributes such as color, brightness, or transparency to blend with existing colors

    8. can hold attributes such as reflectivity coefficients, normal displacements or other parameters in the lighting model
    9. Steps in Texture Mapping:

    10. Create a Texture Object and Specify a Texture for That Object:

        data describing a texture may consist of one, two, three, or four elements per texel, representing anything from a modulation constant to an (R, G, B, A) quadruple.

    11. Indicate How the Texture Is to Be Applied to Each Pixel:

        You can choose any of four possible functions for computing the final RGBA value from the fragment color and the texture-image data:
        1. decal mode -- the texture color is the final color; the texture is painted on top of the fragment
        2. replace mode -- a variant of the decal mode
        3. modulate mode -- use texture to modulate or scale the fragment's color; this technique is useful for combining the effects of lighting with texturing
        4. constant mode -- a constant color is blended with that of the fragment, based on the texture value

    12. Enable Texture Mapping:

        glEnable ( GL_TEXTURE_1D );
        glEnable ( GL_TEXTURE_2D );
        glDisable ( GL_TEXTURE_1D );
        glDisable ( GL_TEXTURE_2D );

    13. Draw the Scene, Supplying Both Texture and Geometric Coordinates:

        Need to specify both texture coordinates and geometric coordinates .
        e.g. 2-D textural map,
          texture coordinates: [0.0, 1.0]
          object coordinates: anything
          e.g. brick wall, we can assign texture coordinates
          (0,0), (1,0), (1,1), (0,1)
          We must also indicate how texture coordinates outside the range [0.0,1.0] should be treated.
    14. Texture Names:

      To start things off, we first need a texture name. This is essentially a number that OpenGL uses to index all the different textures.

      GLuint texture;
      
      // allocate a texture name
      glGenTextures( 1, &texture );
      

      Now that we have our texture name, we can switch between different textures we want using the function glBindTxeture. This essentially chooses what texture we are working with.

      // select our current texture
      glBindTexture( GL_TEXTURE_2D, texture );
      

      Texture Parameters:

      Now we can begin to work on our current texture. Before we start, we should set one little texture environment state which tells OpenGL how the texture will act when it is rendered into a scene.

      // select modulate to mix texture with color for shading
      glTexEnvf( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE );
        

      Next, we have four texture parameters we need to setup. Here is where we can setup such wonderful effects like bilinear and trilinear texture filtering, and mipmapping. We also can setup whether the texture wraps over at the edges or is clamped at the ends. The most common feature used is 'repeating'.

      // when texture area is small, bilinear filter the closest mipmap
      glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
                       GL_LINEAR_MIPMAP_NEAREST );
      // when texture area is large, bilinear filter the original
      glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
      
      // the texture wraps over at the edges (repeat)
      glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT );
      glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT );
        

    15. A sample example

      //checker.cpp
      #include <GL/gl.h>
      #include <GL/glu.h>
      #include <GL/glut.h>
      #include <stdlib.h>
      #include <stdio.h>
      
      /*  Create checkerboard texture  */
      #define checkImageWidth 64
      #define checkImageHeight 64
      static GLubyte checkImage[checkImageHeight][checkImageWidth][4];
      
      static GLuint texName;
      
      void makeCheckImage(void)
      {
         int i, j, c;
          
         for (i = 0; i < checkImageHeight; i++) {
            for (j = 0; j < checkImageWidth; j++) {
               c = ((((i&0x8)==0)^((j&0x8))==0))*255;
               checkImage[i][j][0] = (GLubyte) c;
               checkImage[i][j][1] = (GLubyte) c;
               checkImage[i][j][2] = (GLubyte) c;
               checkImage[i][j][3] = (GLubyte) 255;
            }
         }
      }
      
      void init(void)
      {    
         glClearColor (0.0, 0.0, 0.0, 0.0);
         glShadeModel(GL_FLAT);
         glEnable(GL_DEPTH_TEST);
      
         makeCheckImage();
         glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
      
         glGenTextures(1, &texName);
         glBindTexture(GL_TEXTURE_2D, texName);
      
         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, 
                         GL_NEAREST);
         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, 
                         GL_NEAREST);
         glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, checkImageWidth, 
                      checkImageHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, 
                      checkImage);
      }
      
      void display(void)
      {
         glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
         glEnable(GL_TEXTURE_2D);
         glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL);
         glBindTexture(GL_TEXTURE_2D, texName);
         glBegin(GL_QUADS);
         glTexCoord2f(0.0, 0.0); glVertex3f(-2.0, -1.0, 0.0);
         glTexCoord2f(0.0, 1.0); glVertex3f(-2.0, 1.0, 0.0);
         glTexCoord2f(1.0, 1.0); glVertex3f(0.0, 1.0, 0.0);
         glTexCoord2f(1.0, 0.0); glVertex3f(0.0, -1.0, 0.0);
      
         glTexCoord2f(0.0, 0.0); glVertex3f(1.0, -1.0, 0.0);
         glTexCoord2f(0.0, 1.0); glVertex3f(1.0, 1.0, 0.0);
         glTexCoord2f(1.0, 1.0); glVertex3f(2.41421, 1.0, -1.41421);
         glTexCoord2f(1.0, 0.0); glVertex3f(2.41421, -1.0, -1.41421);
         glEnd();
         glFlush();
         glDisable(GL_TEXTURE_2D);
      }
      
      void reshape(int w, int h)
      {
         glViewport(0, 0, (GLsizei) w, (GLsizei) h);
         glMatrixMode(GL_PROJECTION);
         glLoadIdentity();
         gluPerspective(60.0, (GLfloat) w/(GLfloat) h, 1.0, 30.0);
         glMatrixMode(GL_MODELVIEW);
         glLoadIdentity();
         glTranslatef(0.0, 0.0, -3.6);
      }
      
      int main(int argc, char** argv)
      {
         glutInit(&argc, argv);
         glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB | GLUT_DEPTH);
         glutInitWindowSize(250, 250);
         glutInitWindowPosition(100, 100);
         glutCreateWindow(argv[0]);
         init();
         glutDisplayFunc(display);
         glutReshapeFunc(reshape);
         glutKeyboardFunc(keyboard);
         glutMainLoop();
         return 0; 
      }
        

      void glTexImage2D(GLenum target, GLint level, GLint internalFormat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid *pixels);
      Defines a two-dimensional texture. The target parameter is set to either the constant GL_TEXTURE_2D or GL_PROXY_TEXTURE_2D. You use the level parameter if you're supplying multiple resolutions of the texture map; with only one resolution, level should be 0.

      void glCopyTexImage2D(GLenum target, GLint level, GLint internalFormat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border);
      Creates a two-dimensional texture, using framebuffer data to define the texels. The pixels are read from the current GL_READ_BUFFER and are processed exactly as if glCopyPixels() had been called but stopped before final conversion. The settings of glPixelTransfer*() are applied.
      The target parameter must be set to the constant GL_TEXTURE_2D. The level, internalFormat, and border parameters have the same effects that they have for glTexImage2D(). The texture array is taken from a screen-aligned pixel rectangle with the lower-left corner at coordinates specified by the (x, y) parameters. The width and height parameters specify the size of this pixel rectangle. Both width and height must have the form 2m+2b, where m is a nonnegative integer (which can have a different value for width than for height) and b is the value of border.