Texture Mapping in OpenGL

Texture mapping

Check out my texture mapping notes for an overview of texture mapping principles

  1. Load the texture data from file
  2. Generate a texture(unique ID)
  3. Select current texture
  4. Specify filtering
  5. Generate the textures from the image data
  6. Enable texture mapping
  7. Draw the scene, providing texture coordinates for each vertex

Loading the texture

The texture data is stored in a picture file. In this example we will use the .BMP format as it is the simplest to manpulate.

	BITMAPINFOHEADER	bitmapInfoHeader;	// bitmap info header
	unsigned char*		bitmapData;			// the texture data
	bitmapData=NULL;
	bitmapData = LoadBitmapFile("world.bmp", &bitmapInfoHeader);

The LoadBitmapFile(...) function readds the file from disk;

unsigned char *LoadBitmapFile(char *filename, BITMAPINFOHEADER *bitmapInfoHeader)
{
	FILE *filePtr;							// the file pointer
	BITMAPFILEHEADER	bitmapFileHeader;		// bitmap file header
	unsigned char		*bitmapImage;			// bitmap image data
	int					imageIdx = 0;		// image index counter
	unsigned char		tempRGB;				// swap variable

	// open filename in "read binary" mode
	filePtr = fopen(filename, "rb");
	if (filePtr == NULL)
		return NULL;

	// read the bitmap file header
	fread(&bitmapFileHeader, sizeof(BITMAPFILEHEADER), 1, filePtr);
	
	// verify that this is a bitmap by checking for the universal bitmap id
	if (bitmapFileHeader.bfType != BITMAP_ID)
	{
		fclose(filePtr);
		return NULL;
	}

	// read the bitmap information header
	fread(bitmapInfoHeader, sizeof(BITMAPINFOHEADER), 1, filePtr);

	// move file pointer to beginning of bitmap data
	fseek(filePtr, bitmapFileHeader.bfOffBits, SEEK_SET);

	// allocate enough memory for the bitmap image data
	int size=bitmapInfoHeader->biHeight*bitmapInfoHeader->biWidth*3;
	bitmapImage = new unsigned char[size];

	// verify memory allocation
	if (!bitmapImage)
	{
		delete [] bitmapImage;
		fclose(filePtr);
		return NULL;
	}

	// read in the bitmap image data
	fread(bitmapImage, 1, size, filePtr);
	
	// make sure bitmap image data was read
	if (bitmapImage == NULL)
	{
		fclose(filePtr);	
		return NULL;
	}

	// swap the R and B values to get RGB since the bitmap color format is in BGR
	for (imageIdx = 0; imageIdx < size; imageIdx+=3)
	{
		tempRGB = bitmapImage[imageIdx];
		bitmapImage[imageIdx] = bitmapImage[imageIdx + 2];
		bitmapImage[imageIdx + 2] = tempRGB;
	}

	// close the file and return the bitmap image data
	fclose(filePtr);

	return bitmapImage;
}

Generating the texture

We need to ask OpenGL to generate unique texture name (texture ID).

//  need one name for each texture in the application
unsigned int		texture;

The function glGenTextures(...) generates an array of texture names.

// first parameter is number of names requires
// second parameter is array to store texture names
glGenTextures(1, &texture); 

Select Current 2D texture

Set current texture (the following texture operations apply to current texture).

glBindTexture(GL_TEXTURE_2D, texture);  

Specify texel filtering

Need to tell OpenGL how filtering is to be applied. There are two categories of filtering;

  1. Magnification; the pixel is smaller than the corresponding texel
  2. Minification; the pixel is larger than corresponding texel

     

// specify point sampling for minification and magnification, for current texture

glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);

Generate the textures from image data

The texture data is stored internally within the OpenGL system (possibly on a graphics card). This phase takes the bitmap data and stores it as a texture.

glTexImage2D(GL_TEXTURE_2D,
				0, 							//Mipmap level (normally 0 for topmost level)
				GL_RGB,						//We want the texture to have Red, green and blue components
				bitmapInfoHeader.biWidth,	//texture width  (must be 2n pixels across (+ 2 for a border)
				bitmapInfoHeader.biHeight,	//texture height (must be 2n pixels high (+ 2 for a border)
				0,							//border (0=no border, 1=border)
				GL_RGB,						//format of the bitmap data
				GL_UNSIGNED_BYTE,			//type of each piece of colour data
				bitmapData);				//pointer to bitmap data

If we are using Mipmaps, then we need to call this function once for each mipmap, changing the mipmap level number appropriately.

 

Enable texture mapping

Before we draw anything, must turn on texturing;

glEnable(GL_TEXTURE_2D);			// enable 2D texturing

Draw the scene

This code creates a quad, associating the vertices of the quad with the corners of the texture;

	//draw
	glBindTexture(GL_TEXTURE_2D, texture); // select current texture from array of loaded textures
	glColor3f(1.0f,1.0f,1.0f); 
	// set current color to white (important), try red to see what happens
	// draw the quad	
	//give each vertex a texture coordinate	
	glBegin(GL_QUADS);		
		glTexCoord2i(1,1);	
		glVertex3i(1,1,0);
		// select a texture coord. for each vertex
		glTexCoord2i(1,0);	
		glVertex3i(1,-1,0);
		glTexCoord2i(0,0);	
		glVertex3i(-1,-1,0);
		glTexCoord2i(0,1);	
		glVertex3i(-1,1,0);
	glEnd();

Putting it all together

See the "simpletexture" project on the common drive for details.