TGA格式图像是游戏中十分常见的一种图像格式,所以有必要了解其内部格式以及编程实现。

TGA图像一般有非压缩和压缩两种格式,下面分别进行介绍。

一、非压缩TGA图像


注:前面的标记绿色的部分(共12字节)表示对于所有的非压缩TGA格式图像值都是相同的!所以通常用来在读取数据时鉴别是否为TGA图像。


























下面的程序实现了绘制一个立方体,并进行纹理贴图。


需要注意的是:TGA图像中数据存放的顺序是BGR(A),而在OpenGL中顺序是RGB(A),所以在进行纹理生成的时候必须先进行格式的转化。

在OpenGL中只能加载24位或者32位的TGA图像生成纹理。

TGATexture.h定义了一些结构体以及函数声明:

[cpp]view plaincopyprint?

#ifndefTGATEXTURE_H

#defineTGATEXTURE_H

#include<GL/glut.h>

#include<iostream>

usingnamespacestd;

//纹理结构体定义

typedefstruct

{

GLubyte*p_w_picpathData;//图像数据

GLuintbpp;//像素深度

GLuintwidth;//图像宽度

GLuintheight;//图像高度

GLuinttexID;//对应的纹理ID

}TextureImage;

//加载TGA图像,生成纹理

boolLoadTGA(TextureImage*texture,char*fileName);

#endif

TGATexture.cpp则包含加载TGA图像生成纹理的函数具体实现:



[cpp]view plaincopyprint?

#include"TGATexture.h"

//加载TGA图像(无压缩格式),生成纹理

boolLoadTGA(TextureImage*texture,char*filename)//LoadsATGAFileIntoMemory

{

GLubyteTGAheader[12]={0,0,2,0,0,0,0,0,0,0,0,0};//UncompressedTGAHeader

GLubyteTGAcompare[12];//UsedToCompareTGAHeader

GLubyteheader[6];//First6UsefulBytesFromTheHeader

GLuintbytesPerPixel;//HoldsNumberOfBytesPerPixelUsedInTheTGAFile

GLuintp_w_picpathSize;//UsedToStoreTheImageSizeWhenSettingAsideRam

GLuinttemp;//TemporaryVariable

GLuinttype=GL_RGBA;//SetTheDefaultGLModeToRBGA(32BPP)

FILE*file=fopen(filename,"rb");//OpenTheTGAFile

if(file==NULL||//DoesFileEvenExist?

fread(TGAcompare,1,sizeof(TGAcompare),file)!=sizeof(TGAcompare)||//AreThere12BytesToRead?

memcmp(TGAheader,TGAcompare,sizeof(TGAheader))!=0||//DoesTheHeaderMatchWhatWeWant?

fread(header,1,sizeof(header),file)!=sizeof(header))//IfSoReadNext6HeaderBytes

{

if(file==NULL)//DidTheFileEvenExist?*AddedJimStrong*

returnfalse;//ReturnFalse

else

{

fclose(file);//IfAnythingFailed,CloseTheFile

returnfalse;//ReturnFalse

}

}

texture->width=header[1]*256+header[0];//DetermineTheTGAWidth(highbyte*256+lowbyte)

texture->height=header[3]*256+header[2];//DetermineTheTGAHeight(highbyte*256+lowbyte)

//OpenGL中纹理只能使用24位或者32位的TGA图像

if(texture->width<=0||//IsTheWidthLessThanOrEqualToZero

texture->height<=0||//IsTheHeightLessThanOrEqualToZero

(header[4]!=24&&header[4]!=32))//IsTheTGA24or32Bit?

{

fclose(file);//IfAnythingFailed,CloseTheFile

returnfalse;//ReturnFalse

}

texture->bpp=header[4];//GrabTheTGA'sBitsPerPixel(24or32)

bytesPerPixel=texture->bpp/8;//DivideBy8ToGetTheBytesPerPixel

p_w_picpathSize=texture->width*texture->height*bytesPerPixel;//CalculateTheMemoryRequiredForTheTGAData

texture->p_w_picpathData=(GLubyte*)malloc(p_w_picpathSize);//ReserveMemoryToHoldTheTGAData

if(texture->p_w_picpathData==NULL||//DoesTheStorageMemoryExist?

fread(texture->p_w_picpathData,1,p_w_picpathSize,file)!=p_w_picpathSize)//DoesTheImageSizeMatchTheMemoryReserved?

{

if(texture->p_w_picpathData!=NULL)//WasImageDataLoaded

free(texture->p_w_picpathData);//IfSo,ReleaseTheImageData

fclose(file);//CloseTheFile

returnfalse;//ReturnFalse

}

//RGB数据格式转换,便于在OpenGL中使用

for(GLuinti=0;i<int(p_w_picpathSize);i+=bytesPerPixel)//LoopThroughTheImageData

{//SwapsThe1stAnd3rdBytes('R'edand'B'lue)

temp=texture->p_w_picpathData[i];//TemporarilyStoreTheValueAtImageData'i'

texture->p_w_picpathData[i]=texture->p_w_picpathData[i+2];//SetThe1stByteToTheValueOfThe3rdByte

texture->p_w_picpathData[i+2]=temp;//SetThe3rdByteToTheValueIn'temp'(1stByteValue)

}

fclose(file);//CloseTheFile

//BuildATextureFromTheData

glGenTextures(1,&texture[0].texID);//GenerateOpenGLtextureIDs

glBindTexture(GL_TEXTURE_2D,texture[0].texID);//BindOurTexture

glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);//LinearFiltered

glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);//LinearFiltered

if(texture[0].bpp==24)//WasTheTGA24Bits

{

type=GL_RGB;//IfSoSetThe'type'ToGL_RGB

}

glTexImage2D(GL_TEXTURE_2D,0,type,texture[0].width,texture[0].height,0,type,GL_UNSIGNED_BYTE,texture[0].p_w_picpathData);

returntrue;//TextureBuildingWentOk,ReturnTrue

}

main.cpp主程序:



[cpp]view plaincopyprint?

#include"TGATexture.h"

TextureImagetexture[1];

GLfloatxRot,yRot,zRot;//controlcube'srotation

intinit()

{

if(!LoadTGA(&texture[0],"GSK1.tga"))

returnGL_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);

returnGL_TRUE;

}

voiddisplay()

{

glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);

glLoadIdentity();

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

glRotatef(xRot,1.0f,0.0f,0.0f);

glRotatef(yRot,0.0f,1.0f,0.0f);

glRotatef(zRot,0.0f,0.0f,1.0f);

glBindTexture(GL_TEXTURE_2D,texture[0].texID);

glBegin(GL_QUADS);

//FrontFace

//BottomLeftOfTheTextureandQuad

glTexCoord2f(0.0f,0.0f);glVertex3f(-1.0f,-1.0f,1.0f);

//BottomRightOfTheTextureandQuad

glTexCoord2f(1.0f,0.0f);glVertex3f(1.0f,-1.0f,1.0f);

//TopRightOfTheTextureandQuad

glTexCoord2f(1.0f,1.0f);glVertex3f(1.0f,1.0f,1.0f);

//TopLeftOfTheTextureandQuad

glTexCoord2f(0.0f,1.0f);glVertex3f(-1.0f,1.0f,1.0f);

glEnd();

glBindTexture(GL_TEXTURE_2D,texture[0].texID);

glBegin(GL_QUADS);

//BackFace

//BottomRightOfTheTextureandQuad

glTexCoord2f(1.0f,0.0f);glVertex3f(-1.0f,-1.0f,-1.0f);

//TopRightOfTheTextureandQuad

glTexCoord2f(1.0f,1.0f);glVertex3f(-1.0f,1.0f,-1.0f);

//TopLeftOfTheTextureandQuad

glTexCoord2f(0.0f,1.0f);glVertex3f(1.0f,1.0f,-1.0f);

//BottomLeftOfTheTextureandQuad

glTexCoord2f(0.0f,0.0f);glVertex3f(1.0f,-1.0f,-1.0f);

glEnd();

glBindTexture(GL_TEXTURE_2D,texture[0].texID);

glBegin(GL_QUADS);

//TopFace

//TopLeftOfTheTextureandQuad

glTexCoord2f(0.0f,1.0f);glVertex3f(-1.0f,1.0f,-1.0f);

//BottomLeftOfTheTextureandQuad

glTexCoord2f(0.0f,0.0f);glVertex3f(-1.0f,1.0f,1.0f);

//BottomRightOfTheTextureandQuad

glTexCoord2f(1.0f,0.0f);glVertex3f(1.0f,1.0f,1.0f);

//TopRightOfTheTextureandQuad

glTexCoord2f(1.0f,1.0f);glVertex3f(1.0f,1.0f,-1.0f);

glEnd();

glBindTexture(GL_TEXTURE_2D,texture[0].texID);

glBegin(GL_QUADS);

//BottomFace

//TopRightOfTheTextureandQuad

glTexCoord2f(1.0f,1.0f);glVertex3f(-1.0f,-1.0f,-1.0f);

//TopLeftOfTheTextureandQuad

glTexCoord2f(0.0f,1.0f);glVertex3f(1.0f,-1.0f,-1.0f);

//BottomLeftOfTheTextureandQuad

glTexCoord2f(0.0f,0.0f);glVertex3f(1.0f,-1.0f,1.0f);

//BottomRightOfTheTextureandQuad

glTexCoord2f(1.0f,0.0f);glVertex3f(-1.0f,-1.0f,1.0f);

glEnd();

glBindTexture(GL_TEXTURE_2D,texture[0].texID);

glBegin(GL_QUADS);

//Rightface

//BottomRightOfTheTextureandQuad

glTexCoord2f(1.0f,0.0f);glVertex3f(1.0f,-1.0f,-1.0f);

//TopRightOfTheTextureandQuad

glTexCoord2f(1.0f,1.0f);glVertex3f(1.0f,1.0f,-1.0f);

//TopLeftOfTheTextureandQuad

glTexCoord2f(0.0f,1.0f);glVertex3f(1.0f,1.0f,1.0f);

//BottomLeftOfTheTextureandQuad

glTexCoord2f(0.0f,0.0f);glVertex3f(1.0f,-1.0f,1.0f);

glEnd();

glBindTexture(GL_TEXTURE_2D,texture[0].texID);

glBegin(GL_QUADS);

//LeftFace

//BottomLeftOfTheTextureandQuad

glTexCoord2f(0.0f,0.0f);glVertex3f(-1.0f,-1.0f,-1.0f);

//BottomRightOfTheTextureandQuad

glTexCoord2f(1.0f,0.0f);glVertex3f(-1.0f,-1.0f,1.0f);

//TopRightOfTheTextureandQuad

glTexCoord2f(1.0f,1.0f);glVertex3f(-1.0f,1.0f,1.0f);

//TopLeftOfTheTextureandQuad

glTexCoord2f(0.0f,1.0f);glVertex3f(-1.0f,1.0f,-1.0f);

glEnd();

glutSwapBuffers();

}

voidreshape(intw,inth)

{

if(0==h)

h=1;

glViewport(0,0,(GLsizei)w,(GLsizei)h);

glMatrixMode(GL_PROJECTION);

glLoadIdentity();

gluPerspective(60.0f,(GLfloat)w/(GLfloat)h,1,100);

glMatrixMode(GL_MODELVIEW);

glLoadIdentity();

}

voidkeyboard(unsignedcharkey,intx,inty)

{

switch(key){

case'x':

xRot+=1.0f;

glutPostRedisplay();

break;

case'y':

yRot+=1.0f;

glutPostRedisplay();

break;

case'z':

zRot+=1.0f;

glutPostRedisplay();

break;

default:

break;

}

}

intmain(intargc,char**argv)

{

glutInit(&argc,argv);

glutInitDisplayMode(GLUT_DOUBLE|GLUT_RGB);

glutInitWindowSize(400,400);

glutInitWindowPosition(100,100);

glutCreateWindow("TextureMap");

init();

glutDisplayFunc(display);

glutReshapeFunc(reshape);

glutKeyboardFunc(keyboard);

glutMainLoop();

return0;

}