Uncompressed TGAs

Introduction

Uncompressed TGAsIn the previous tutorial, we used 2 images to create transparency. This was achieved with blending and is known as masking.

This tutorial will explain how to create the same effect but instead this time we will be using a different technique. This tutorial will use targa images. These images have a .tga extension.

TGA file has a built in alpha layer. This image essentially contains the mask as part of the image. We therefore only need 1 image file instead of 2.

There are a number of types of TGA files. They can either contain only red green and blue values or they can contain red, green and blue values along with an additional alpha value. Black and white TGAs can also be created. The TGA can also be either compressed or uncompressed. This allows a number of different types. We will only be discussing uncompressed TGAs in this tutorial as they are far easier to load.

This tutorial is a modified version of the previous tutorial. You may also want to review the Texture Mapping tutorial as a lot of the bitmap loading code is reused here.

Contents of main.cpp :


We will be loading 2 textures. These will be the background and checker images. The backgroud image contains no alpha layer and the checker pattern does.

GLuint texture[2];

char *tgas[] = {
	"zeus.tga",
	"rockchecker.tga"
};

There is no standard structure to store a TGA file like there is for a bitmap file. We therefore create our own structure to contain the information we desire.

struct TGAFile
{

The typeCode will hold whether the image has an alpha layer and if the image is compressed or not.

	unsigned char typeCode;

We will also need to store the width, height and bits per pixel for the image.

	short int width;
	short int height;
	unsigned char bpp;

When setting up the texture, we need to know whether the image has an alpha layer. This will be stored in the format variable and can have a value of either GL_RGB orGL_RGBA.

	GLenum format;

Lastly we need to store the actual image data.

	unsigned char *imageData;
};

The next step is to load a TGA and to store the data in the structure declared above.

Before we can load a TGA image, we need to understand the structure of it. A TGA file has the following data :

unsigned char idLength;
unsigned char colorMapType;
unsigned char imageType;
short int colorMapOrigin;
short int colorMapLength;
unsigned char colorMapEntrySize;
short int originX;
short int originY;
short int width;
short int height;
unsigned char bits;
unsigned char descriptor;

Each one of these will be discussed as we are loading the file.

bool loadUncompressedTGA(char *filename, TGAFile *tgaFile)
{

We need to create a pointer to a FILE structure to point to the TGA file.

	FILE *file;

We also need a temporary variable to hold an unsigned char because like the bitmap, the color values are represented in a blue-green-red order instead of a red-green-blue order.

	unsigned char tmpRGB;

We do not need all of the data in a TGA file. The individual elements of a TGA file are made up of both unsigned char and unsigned short values. We create 2 temporary variables of these types to discard certain values.

	unsigned char ucNull;
	unsigned short usNull;

This sneaky code that I came up with will add the current directory onto the filename. It has not changed since the Texture Mapping tutorial.

	TCHAR path[256];
	char fullPath[256];
	GetModuleFileName(NULL, path, 256);

	TCHAR *pos = wcsrchr(path, '\\');
	*(pos + 1) = '\0';
	
	wcstombs(fullPath, path, 256);
	
	strcat(fullPath, filename);

	file = fopen(fullPath,"rb");

	if (!file)
	{
		MessageBox(NULL, L"Can't Find TGA", L"Error", MB_OK);
		return false;
	}

The idLength variable specifies the number of characters in the identification field. A 0specifies that no identification field is included. The colorMapType specifies the type of color map and this is always 0. Neither of these variables are particularly useful, so we simply discard them by reading them into the ucNull variable.

	fread(&ucNull,sizeof(unsigned char),1,file);
	fread(&ucNull,sizeof(unsigned char),1,file);

The imageType variable is very important. This specifies what type of TGA is being processed. The possible values are shown in the table below :

imageType Description
2 Uncompressed RGB Image
3 Uncompressed Black and White Image
10 Run-length Encoded RGB Image
11 Compressed Black and White Image

We want to store this value in our TGAFile structure.

	fread(&tgaFile->typeCode,sizeof(unsigned char),1,file);

We make sure that an uncompressed TGA is being loaded and display an error if not.

	if (tgaFile->typeCode != 2 && tgaFile->typeCode != 3)
	{
		MessageBox(NULL, L"Incorrect texture type", L"Error", MB_OK);
		fclose(file);
		return false;
	}

The colorMapOrigin value is always 0 as well as the colorMapLength andcolorMapEntrySize variables. We want to simply discard these values.

	fread(&usNull,sizeof(unsigned short),1,file);
	fread(&usNull,sizeof(unsigned short),1,file);
	fread(&ucNull,sizeof(unsigned char),1,file);

The originX and originY values specify the lower-left coordinate of the image. This is always (0,0). Once again this is of no use to us, so we discard them.

	fread(&usNull,sizeof(unsigned short),1,file);
	fread(&usNull,sizeof(unsigned short),1,file);

The widthheight and bits per pixel is extremely important, so we load those into ourTGAFile structure.

	fread(&tgaFile->width, sizeof(unsigned short), 1, file);
	fread(&tgaFile->height, sizeof(unsigned short), 1, file);
	fread(&tgaFile->bpp, sizeof(unsigned char), 1, file);

The descriptor specifies whether the image is a 24 bit(0x00) or 32 bit(0x08) image. We could use this for our format variable or we can use the method that will be discussed shortly. As we are using a different method, we will discard this variable.

	fread(&ucNull,sizeof(unsigned char),1,file);

As we are dealing with variables of sizes in bytes and not bits, it is more convenient to convert the bits per pixel to bytes per pixel. This is a simple division by 8.

	int colorMode = tgaFile->bpp / 8;

If there is an extra byte for the alpha layer, we set the format variable to GL_RGBA. If not, we use the standard GL_RGB flag.

	if (colorMode == 3)
		tgaFile->format = GL_RGB;
	else
		tgaFile->format = GL_RGBA;

The next step is to allocate enough memory for all pixels of the image. We multiply the number of pixels by the number of bytes per pixel to get the total image size in bytes.

	long imageSize = tgaFile->width * tgaFile->height * colorMode;

	tgaFile->imageData = new unsigned char[imageSize];

	if (!tgaFile->imageData)
	{
		MessageBox(NULL, L"Out of Memory", L"Error", MB_OK);
		delete[] tgaFile->imageData;
		fclose(file);
		return false;
	}

The image data follows the TGA header. Now that we have allocated the memory, we can load the image data.

	fread(tgaFile->imageData,sizeof(unsigned char),imageSize,file);

	if (!tgaFile->imageData)
	{
		MessageBox(NULL, L"Error reading TGA", L"Error", MB_OK);
		fclose(file);
		return false;
	}

Like the bitmap, we need to swap all red and blue values to get the standard RGB order.

	for (int i = 0; i < imageSize; i += colorMode)
	{
		tmpRGB = tgaFile->imageData[i];
		tgaFile->imageData[i] = tgaFile->imageData[i+2];
		tgaFile->imageData[i+2] = tmpRGB;
	}

	fclose(file);

	return true;
}

Now that we have the ability to load our TGA, we can use OpenGL ES to generate our texture. The beginning of our loadTextures function remains the same. One difference is the TGAFile structure that is created to hold our TGA.

bool loadTextures()
{
	TGAFile tgaFile;

	glGenTextures(2, texture);

	for (int i = 0; i < 2; i++)
	{

Our new function is now called.

		if (!loadUncompressedTGA(tgas[i], &tgaFile))
			return false;

		glBindTexture(GL_TEXTURE_2D, texture[i]);

The same data is passed onto the glTexImage2D, except now the data from theTGAFile structure is used. This generic method will allow the use of RGB and RGBAimages.

		glTexImage2D(GL_TEXTURE_2D, 0, tgaFile.format, tgaFile.width,
			tgaFile.height, 0, tgaFile.format, GL_UNSIGNED_BYTE,
			tgaFile.imageData);

		glTexParameterf(GL_TEXTURE_2D, 
			GL_TEXTURE_MIN_FILTER, GL_LINEAR);
		glTexParameterf(GL_TEXTURE_2D,
			GL_TEXTURE_MAG_FILTER, GL_LINEAR);

		delete[] tgaFile.imageData;
	}

	return true;
}

An advantage of using TGA files is that you do not need to disable depth testing. The only differences in the init is to enable blending and to set the blending function.

The blending function is set to (GL_SRC_ALPHAGL_ONE_MINUS_SRC_ALPHA). This is our standard blending function for transparency.

bool init()
{
	.
	.
	glEnable(GL_BLEND);
	glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
	
	return true;
}

Our display function now only needs to render the textures normally without worrying about any extra blending or masking.

void display()
{
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
	glLoadIdentity();

	glTranslatef(0.0f, 0.0f, -2.0f);

	glTexCoordPointer(2, GL_FLOAT, 0, bgTexCoords);
	glBindTexture(GL_TEXTURE_2D, texture[0]);
	glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);

	glTexCoordPointer(2, GL_FLOAT, 0, checkerCoords);
	glBindTexture(GL_TEXTURE_2D, texture[1]);
	glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);

	glFlush();
	glutSwapBuffers();
}

Congratulations. You can now create transparency effects using TGA files. You now also have the ability to load TGA files. You may agree that this is a much easier method than having separate image files for masking.

Please let me know of any comments you may have : Contact Me

GLUT|ES Source Files :Embedded Visual C++ 4.0 
UG Source Files :
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值