OpenGL学习三十五:加载压缩TGA

(此节内容对应NEHE教程第33课)

 

利用压缩算法可以减低图片大小。降低图片存储所需的物理存储空间,但是也会相应的增加图片解压缩带来的时间消耗

对于TGA文件的压缩可以简单理解为,在图片信息存储区。并不是把每一个像素点的RGB值都进行存储,而是临近的像素点如果RGB值相同,那么进行合并形成“块”对于一个”块“来说 他们有一个共同的RGB值,但是块是由很多个像素点组成的


0~~11 头信息 第3位(2)是2 代表未压缩
第3位(2)是10 代表未压缩RLE压缩
12~13 图像宽度 byte[13]*256+byte[12]
14~15 图像高度 byte[15]*256+byte[14]
16 图像每像素存储占用位(bit)数 24或32
接下来读一个字符 代表接下来的”块“中包含的像素点数 用chumk代替
如果 0<=chumk<=127 代表接下来的 chumk+1个像素点的RGB值都不同,因此每一个都需要读取

如果 128<=chumk 代表接下来的 chumk-127个像素点的RGB值相同,因此只需要读取一次即可


Texture.h

#ifndef __TEXTURE_H__
#define __TEXTURE_H__

#pragma comment(lib, "Opengl32.lib")					

#include 								
								
typedef	struct									
{
	GLubyte	* imageData;								
	GLuint	bpp;										
	GLuint	width;										
	GLuint	height;										
	GLuint	texID;										
	GLuint	type;				
} Texture;	

#endif

Tga.h

#ifndef __TGA_H__
#define __TGA_H__

#pragma comment(lib, "Opengl32.lib")				

#include 							
#include "texture.h"

typedef struct
{
	GLubyte Header[12];									
} TGAHeader;


typedef struct
{
	GLubyte		header[6];							
	GLuint		bytesPerPixel;							
	GLuint		imageSize;							
	GLuint		temp;								
	GLuint		type;	
	GLuint		Height;									
	GLuint		Width;									
	GLuint		Bpp;									
} TGA;


TGAHeader tgaheader;								
TGA tga;												


GLubyte uTGAcompare[12] = {0,0,2, 0,0,0,0,0,0,0,0,0};	
GLubyte cTGAcompare[12] = {0,0,10,0,0,0,0,0,0,0,0,0};	
bool LoadUncompressedTGA(Texture *, char *, FILE *);	
bool LoadCompressedTGA(Texture *, char *, FILE *);		

#endif

TGALoader.cpp

#include "tga.h"

bool LoadTGA(Texture * texture, char * filename)				
{
	FILE * fTGA;									
	fTGA = fopen(filename, "rb");								

	if(fTGA == NULL)										
	{
		MessageBox(NULL, "Could not open texture file", "ERROR", MB_OK);	
		return false;													
	}

	if(fread(&tgaheader, sizeof(TGAHeader), 1, fTGA) == 0)					
	{
		MessageBox(NULL, "Could not read file header", "ERROR", MB_OK);		e
		if(fTGA != NULL)													
		{
			fclose(fTGA);													
		}
		return false;														
	}

	if(memcmp(uTGAcompare, &tgaheader, sizeof(tgaheader)) == 0)				
	{																		
		LoadUncompressedTGA(texture, filename, fTGA);					
	}
	else if(memcmp(cTGAcompare, &tgaheader, sizeof(tgaheader)) == 0)		
	{																		
		LoadCompressedTGA(texture, filename, fTGA);						
	}
	else																
	{
		MessageBox(NULL, "TGA file be type 2 or type 10 ", "Invalid Image", MB_OK);	
		fclose(fTGA);
		return false;															
	}
	return true;														
}

bool LoadUncompressedTGA(Texture * texture, char * filename, FILE * fTGA)	
{																		
	if(fread(tga.header, sizeof(tga.header), 1, fTGA) == 0)					
	{										
		MessageBox(NULL, "Could not read info header", "ERROR", MB_OK);		
		if(fTGA != NULL)													
		{
			fclose(fTGA);												
		}
		return false;														
	}	

	texture->width  = tga.header[1] * 256 + tga.header[0];				
	texture->height = tga.header[3] * 256 + tga.header[2];					
	texture->bpp	= tga.header[4];									
	tga.Width		= texture->width;															
	tga.Height		= texture->height;									
	tga.Bpp			= texture->bpp;											

	if((texture->width <= 0) || (texture->height <= 0) || ((texture->bpp != 24) && (texture->bpp !=32)))	
	{
		MessageBox(NULL, "Invalid texture information", "ERROR", MB_OK);	
		if(fTGA != NULL)													
		{
			fclose(fTGA);													
		}
		return false;														
	}

	if(texture->bpp == 24)													
		texture->type	= GL_RGB;											
	else																	
		texture->type	= GL_RGBA;										

	tga.bytesPerPixel	= (tga.Bpp / 8);								
	tga.imageSize		= (tga.bytesPerPixel * tga.Width * tga.Height);		
	texture->imageData	= (GLubyte *)malloc(tga.imageSize);					

	if(texture->imageData == NULL)											
	{
		MessageBox(NULL, "Could not allocate memory for image", "ERROR", MB_OK);	
		fclose(fTGA);														
		return false;													
	}

	if(fread(texture->imageData, 1, tga.imageSize, fTGA) != tga.imageSize)
	{
		MessageBox(NULL, "Could not read image data", "ERROR", MB_OK);		
		if(texture->imageData != NULL)										
		{
			free(texture->imageData);									
		}
		fclose(fTGA);														
		return false;														
	}

	// Byte Swapping Optimized By Steve Thomas
	for(GLuint cswap = 0; cswap < (int)tga.imageSize; cswap += tga.bytesPerPixel)
	{
		texture->imageData[cswap] ^= texture->imageData[cswap+2] ^=
		texture->imageData[cswap] ^= texture->imageData[cswap+2];
	}

	fclose(fTGA);															
	return true;															
}

bool LoadCompressedTGA(Texture * texture, char * filename, FILE * fTGA)		
{ 
	if(fread(tga.header, sizeof(tga.header), 1, fTGA) == 0)				
	{
		MessageBox(NULL, "Could not read info header", "ERROR", MB_OK);		
		if(fTGA != NULL)													
		{
			fclose(fTGA);												
		}
		return false;														
	}

	texture->width  = tga.header[1] * 256 + tga.header[0];					
	texture->height = tga.header[3] * 256 + tga.header[2];					
	texture->bpp	= tga.header[4];										
	tga.Width		= texture->width;										
	tga.Height		= texture->height;										
	tga.Bpp			= texture->bpp;											

	if((texture->width <= 0) || (texture->height <= 0) || ((texture->bpp != 24) && (texture->bpp !=32)))	
	{
		MessageBox(NULL, "Invalid texture information", "ERROR", MB_OK);	
		if(fTGA != NULL)												
		{
			fclose(fTGA);												
		}
		return false;														
	}

	if(texture->bpp == 24)													
		texture->type	= GL_RGB;											
	else																	
		texture->type	= GL_RGBA;										

	tga.bytesPerPixel	= (tga.Bpp / 8);									
	tga.imageSize		= (tga.bytesPerPixel * tga.Width * tga.Height);		
	texture->imageData	= (GLubyte *)malloc(tga.imageSize);				

	if(texture->imageData == NULL)											
		MessageBox(NULL, "Could not allocate memory for image", "ERROR", MB_OK);	
		fclose(fTGA);														
		return false;														
	}

	GLuint pixelcount	= tga.Height * tga.Width;							
	GLuint currentpixel	= 0;											
	GLuint currentbyte	= 0;												
	GLubyte * colorbuffer = (GLubyte *)malloc(tga.bytesPerPixel);		

	do
	{
		GLubyte chunkheader = 0;											

		if(fread(&chunkheader, sizeof(GLubyte), 1, fTGA) == 0)				
		{
			MessageBox(NULL, "Could not read RLE header", "ERROR", MB_OK);	
			if(fTGA != NULL)												
			{
				fclose(fTGA);											
			}
			if(texture->imageData != NULL)								
			{
				free(texture->imageData);								
			}
			return false;													
		}

		if(chunkheader < 128)												
		{																	
			chunkheader++;												
			for(short counter = 0; counter < chunkheader; counter++)		
			{
				if(fread(colorbuffer, 1, tga.bytesPerPixel, fTGA) != tga.bytesPerPixel) 
				{
					MessageBox(NULL, "Could not read image data", "ERROR", MB_OK);		

					if(fTGA != NULL)													
					{
						fclose(fTGA);													
					}

					if(colorbuffer != NULL)												
					{
						free(colorbuffer);												
					}

					if(texture->imageData != NULL)										
					{
						free(texture->imageData);										
					}

					return false;														
				}
																						
				texture->imageData[currentbyte		] = colorbuffer[2];				   
				texture->imageData[currentbyte + 1	] = colorbuffer[1];
				texture->imageData[currentbyte + 2	] = colorbuffer[0];

				if(tga.bytesPerPixel == 4)												
				{
					texture->imageData[currentbyte + 3] = colorbuffer[3];				
				}

				currentbyte += tga.bytesPerPixel;										
				currentpixel++;															

				if(currentpixel > pixelcount)											
				{
					MessageBox(NULL, "Too many pixels read", "ERROR", NULL);			

					if(fTGA != NULL)													
					{
						fclose(fTGA);												
					}	

					if(colorbuffer != NULL)												
					{
						free(colorbuffer);												
					}

					if(texture->imageData != NULL)										
					{
						free(texture->imageData);										
					}

					return false;														
				}
			}
		}
		else																			
		{
			chunkheader -= 127;															
			if(fread(colorbuffer, 1, tga.bytesPerPixel, fTGA) != tga.bytesPerPixel)		
			{	
				MessageBox(NULL, "Could not read from file", "ERROR", MB_OK);			

				if(fTGA != NULL)														
				{
					fclose(fTGA);														
				}

				if(colorbuffer != NULL)													
				{
					free(colorbuffer);												
				}

				if(texture->imageData != NULL)											
				{
					free(texture->imageData);										
				}

				return false;															
			}

			for(short counter = 0; counter < chunkheader; counter++)					
			{																			
				texture->imageData[currentbyte		] = colorbuffer[2];				
				texture->imageData[currentbyte + 1	] = colorbuffer[1];
				texture->imageData[currentbyte + 2	] = colorbuffer[0];

				if(tga.bytesPerPixel == 4)												
				{
					texture->imageData[currentbyte + 3] = colorbuffer[3];				
				}

				currentbyte += tga.bytesPerPixel;										
				currentpixel++;															
				if(currentpixel > pixelcount)											
				{
					MessageBox(NULL, "Too many pixels read", "ERROR", NULL);			

					if(fTGA != NULL)													
					{
						fclose(fTGA);													
					}	

					if(colorbuffer != NULL)												
					{
						free(colorbuffer);												
					}

					if(texture->imageData != NULL)										
					{
						free(texture->imageData);									
					}

					return false;														
				}
			}
		}
	}

	while(currentpixel < pixelcount);													
	fclose(fTGA);																		
	return true;																		
}

main.cpp

#include "header.h"											
#include "texture.h"											

bool LoadTGA(Texture *, char *);								

float	spin;													

Texture texture[2];												

LRESULT	CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);			

int LoadGLTextures()											
{
	int Status=FALSE;											

	// Load The Bitmap, Check For Errors.
	if (LoadTGA(&texture[0], "Data/Uncompressed.tga") &&
		LoadTGA(&texture[1], "Data/Compressed.tga"))
	{
		Status=TRUE;											

		for (int loop=0; loop<2; loop++)						
		{
			
			glGenTextures(1, &texture[loop].texID);				
			glBindTexture(GL_TEXTURE_2D, texture[loop].texID);
			glTexImage2D(GL_TEXTURE_2D, 0, texture[loop].bpp / 8, texture[loop].width, texture[loop].height, 0, texture[loop].type, GL_UNSIGNED_BYTE, texture[loop].imageData);
			glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
			glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);

			if (texture[loop].imageData)						
			{
				free(texture[loop].imageData);					
			}
		}
	}
	return Status;											
}

void ReSizeGLScene(GLsizei width, GLsizei height)				
{
	if (height==0)												
	{
		height=1;										
	}

	glViewport(0,0,width,height);							

	glMatrixMode(GL_PROJECTION);							
	glLoadIdentity();										

	// Calculate The Aspect Ratio Of The Window
	gluPerspective(45.0f,(GLfloat)width/(GLfloat)height,0.1f,100.0f);

	glMatrixMode(GL_MODELVIEW);									
	glLoadIdentity();										
}

int InitGL(void)												
{
	if (!LoadGLTextures())									
	{
		return FALSE;											
	}

	glEnable(GL_TEXTURE_2D);									
	glShadeModel(GL_SMOOTH);								
	glClearColor(0.0f, 0.0f, 0.0f, 0.5f);						
	glClearDepth(1.0f);											
	glEnable(GL_DEPTH_TEST);									
	glDepthFunc(GL_LEQUAL);									
	glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);			

	return TRUE;											
}

void DrawGLScene(void)											
{
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);		
	glLoadIdentity();											
	glTranslatef(0.0f,0.0f,-10.0f);								

	spin+=0.05f;												

	for (int loop=0; loop<20; loop++)						
	{
		glPushMatrix();											
		glRotatef(spin+loop*18.0f,1.0f,0.0f,0.0f);			
		glTranslatef(-2.0f,2.0f,0.0f);							

		glBindTexture(GL_TEXTURE_2D, texture[0].texID);			
		glBegin(GL_QUADS);									
			glTexCoord2f(0.0f, 1.0f); glVertex3f(-1.0f,  1.0f, 0.0f);
			glTexCoord2f(1.0f, 1.0f); glVertex3f( 1.0f,  1.0f, 0.0f);
			glTexCoord2f(1.0f, 0.0f); glVertex3f( 1.0f, -1.0f, 0.0f);
			glTexCoord2f(0.0f, 0.0f); glVertex3f(-1.0f, -1.0f, 0.0f);
		glEnd();												
		glPopMatrix();											

		glPushMatrix();										
		glTranslatef(2.0f,0.0f,0.0f);							
		glRotatef(spin+loop*36.0f,0.0f,1.0f,0.0f);				
		glTranslatef(1.0f,0.0f,0.0f);							

		glBindTexture(GL_TEXTURE_2D, texture[1].texID);			
		glBegin(GL_QUADS);										
			glTexCoord2f(0.0f, 0.0f); glVertex3f(-1.0f,  1.0f, 0.0f);
			glTexCoord2f(1.0f, 0.0f); glVertex3f( 1.0f,  1.0f, 0.0f);
			glTexCoord2f(1.0f, 1.0f); glVertex3f( 1.0f, -1.0f, 0.0f);
			glTexCoord2f(0.0f, 1.0f); glVertex3f(-1.0f, -1.0f, 0.0f);
		glEnd();												
		glPopMatrix();											
	}
	glFlush();											
}



void rotate()
{
	spin+=0.05f;
	glutPostRedisplay();
}
void keyboard(unsigned char key,int x,int y)
{
	switch (key)
	{

	case 'S':
		glutIdleFunc(rotate);
		break;
	case 'R':
		glutIdleFunc(NULL);
		break;
	}

}


int main(int argc,char **argv)
{
	glutInit(&argc,argv);
	glutInitDisplayMode(GLUT_SINGLE|GLUT_RGB|GLUT_DEPTH);
	glutInitWindowSize(800,600);
	glutInitWindowPosition(100,100);
	glutCreateWindow("加载压缩TGA");
	InitGL();
	glutDisplayFunc(DrawGLScene);
	glutKeyboardFunc(keyboard);
	glutReshapeFunc(ReSizeGLScene);
	glutMainLoop();
}


你可能感兴趣的:(OpenGL)