博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
OpenGL学习三十五:加载压缩TGA
阅读量:4213 次
发布时间:2019-05-26

本文共 12636 字,大约阅读时间需要 42 分钟。

(此节内容对应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();}

转载地址:http://pfumi.baihongyu.com/

你可能感兴趣的文章
Extjs自定义组件
查看>>
TreeGrid 异步加载节点
查看>>
Struts2 标签库讲解
查看>>
Google Web工具包 GWT
查看>>
材料与工程学科相关软件
查看>>
windows 下AdNDP 安装使用
查看>>
Project 2013项目管理教程(1):项目管理概述及预备
查看>>
ssh客户端后台运行
查看>>
【React Native】把现代web科技带给移动开发者(一)
查看>>
【GoLang】Web工作方式
查看>>
Launch Sublime Text 3 from the command line
查看>>
【数据库之mysql】mysql的安装(一)
查看>>
【数据库之mysql】 mysql 入门教程(二)
查看>>
【HTML5/CSS/JS】A list of Font Awesome icons and their CSS content values(一)
查看>>
【HTML5/CSS/JS】<br>与<p>标签区别(二)
查看>>
【HTML5/CSS/JS】开发跨平台应用工具的选择(三)
查看>>
【心灵鸡汤】Give it five minutes不要让一个好主意随风而去
查看>>
【React Native】Invariant Violation: Application AwesomeProject has not been registered
查看>>
【ReactNative】真机上无法调试 could not connect to development server
查看>>
【XCode 4.6】常用快捷键 特别是格式化代码ctrl+i
查看>>