您的位置:首页 > 运维架构

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

2014-01-22 13:29 375 查看
(此节内容对应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 <windows.h>

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 <windows.h>
#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();
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: