TGA格式图像是游戏中十分常见的一种图像格式,所以有必要了解其内部格式以及编程实现。 TGA图像一般有非压缩和压缩两种格式,下面分别进行介绍。 一、非压缩TGA图像
注:前面的标记绿色的部分(共12字节)表示对于所有的非压缩TGA格式图像值都是相同的!所以通常用来在读取数据时鉴别是否为TGA图像。 下面的程序实现了绘制一个立方体,并进行纹理贴图。
需要注意的是:TGA图像中数据存放的顺序是BGR(A),而在OpenGL中顺序是RGB(A),所以在进行纹理生成的时候必须先进行格式的转化。 在OpenGL中只能加载24位或者32位的TGA图像生成纹理。 TGATexture.h定义了一些结构体以及函数声明:
[cpp] view plain copy print? #ifndef TGATEXTURE_H #define TGATEXTURE_H #include <GL/glut.h> #include <iostream> using namespace std; typedef struct { GLubyte *p_w_picpathData; GLuint bpp; GLuint width; GLuint height; GLuint texID; }TextureImage; bool LoadTGA(TextureImage *texture,char *fileName); #endif
TGATexture.cpp则包含加载TGA图像生成纹理的函数具体实现:
[cpp] view plain copy print? #include "TGATexture.h" bool LoadTGA(TextureImage *texture, char *filename) { GLubyte TGAheader[12]={0,0,2,0,0,0,0,0,0,0,0,0}; GLubyte TGAcompare[12]; GLubyte header[6]; GLuint bytesPerPixel; GLuint p_w_picpathSize; GLuint temp; GLuint type=GL_RGBA; FILE *file = fopen(filename, "rb"); if( file==NULL || fread(TGAcompare,1,sizeof(TGAcompare),file)!=sizeof(TGAcompare) || memcmp(TGAheader,TGAcompare,sizeof(TGAheader))!=0 || fread(header,1,sizeof(header),file)!=sizeof(header)) { if (file == NULL) return false; else { fclose(file); return false; } } texture->width = header[1] * 256 + header[0]; texture->height = header[3] * 256 + header[2]; if( texture->width <=0 || texture->height <=0 || (header[4]!=24 && header[4]!=32)) { fclose(file); return false; } texture->bpp = header[4]; bytesPerPixel = texture->bpp/8; p_w_picpathSize = texture->width*texture->height*bytesPerPixel; texture->p_w_picpathData=(GLubyte *)malloc(p_w_picpathSize); if( texture->p_w_picpathData==NULL || fread(texture->p_w_picpathData, 1, p_w_picpathSize, file)!=p_w_picpathSize) { if(texture->p_w_picpathData!=NULL) free(texture->p_w_picpathData); fclose(file); return false; } for(GLuint i=0; i<int(p_w_picpathSize); i+=bytesPerPixel) { temp=texture->p_w_picpathData[i]; texture->p_w_picpathData[i] = texture->p_w_picpathData[i + 2]; texture->p_w_picpathData[i + 2] = temp; } fclose (file); glGenTextures(1, &texture[0].texID); glBindTexture(GL_TEXTURE_2D, texture[0].texID); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); if (texture[0].bpp==24) { type=GL_RGB; } glTexImage2D(GL_TEXTURE_2D, 0, type, texture[0].width, texture[0].height, 0, type, GL_UNSIGNED_BYTE, texture[0].p_w_picpathData); return true; }
main.cpp主程序:
[cpp] view plain copy print? #include "TGATexture.h" TextureImage texture[1]; GLfloat xRot,yRot,zRot; int init() { if(!LoadTGA(&texture[0],"GSK1.tga")) return GL_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 GL_TRUE; } void display() { 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); glTexCoord2f(0.0f, 0.0f); glVertex3f(-1.0f, -1.0f, 1.0f); glTexCoord2f(1.0f, 0.0f); glVertex3f( 1.0f, -1.0f, 1.0f); glTexCoord2f(1.0f, 1.0f); glVertex3f( 1.0f, 1.0f, 1.0f); glTexCoord2f(0.0f, 1.0f); glVertex3f(-1.0f, 1.0f, 1.0f); glEnd(); glBindTexture(GL_TEXTURE_2D,texture[0].texID); glBegin(GL_QUADS); glTexCoord2f(1.0f, 0.0f); glVertex3f(-1.0f, -1.0f, -1.0f); glTexCoord2f(1.0f, 1.0f); glVertex3f(-1.0f, 1.0f, -1.0f); glTexCoord2f(0.0f, 1.0f); glVertex3f( 1.0f, 1.0f, -1.0f); glTexCoord2f(0.0f, 0.0f); glVertex3f( 1.0f, -1.0f, -1.0f); glEnd(); glBindTexture(GL_TEXTURE_2D,texture[0].texID); glBegin(GL_QUADS); glTexCoord2f(0.0f, 1.0f); glVertex3f(-1.0f, 1.0f, -1.0f); glTexCoord2f(0.0f, 0.0f); glVertex3f(-1.0f, 1.0f, 1.0f); glTexCoord2f(1.0f, 0.0f); glVertex3f( 1.0f, 1.0f, 1.0f); glTexCoord2f(1.0f, 1.0f); glVertex3f( 1.0f, 1.0f, -1.0f); glEnd(); glBindTexture(GL_TEXTURE_2D,texture[0].texID); glBegin(GL_QUADS); glTexCoord2f(1.0f, 1.0f); glVertex3f(-1.0f, -1.0f, -1.0f); glTexCoord2f(0.0f, 1.0f); glVertex3f( 1.0f, -1.0f, -1.0f); glTexCoord2f(0.0f, 0.0f); glVertex3f( 1.0f, -1.0f, 1.0f); glTexCoord2f(1.0f, 0.0f); glVertex3f(-1.0f, -1.0f, 1.0f); glEnd(); glBindTexture(GL_TEXTURE_2D,texture[0].texID); glBegin(GL_QUADS); glTexCoord2f(1.0f, 0.0f); glVertex3f( 1.0f, -1.0f, -1.0f); glTexCoord2f(1.0f, 1.0f); glVertex3f( 1.0f, 1.0f, -1.0f); glTexCoord2f(0.0f, 1.0f); glVertex3f( 1.0f, 1.0f, 1.0f); glTexCoord2f(0.0f, 0.0f); glVertex3f( 1.0f, -1.0f, 1.0f); glEnd(); glBindTexture(GL_TEXTURE_2D,texture[0].texID); glBegin(GL_QUADS); glTexCoord2f(0.0f, 0.0f); glVertex3f(-1.0f, -1.0f, -1.0f); glTexCoord2f(1.0f, 0.0f); glVertex3f(-1.0f, -1.0f, 1.0f); glTexCoord2f(1.0f, 1.0f); glVertex3f(-1.0f, 1.0f, 1.0f); glTexCoord2f(0.0f, 1.0f); glVertex3f(-1.0f, 1.0f, -1.0f); glEnd(); glutSwapBuffers(); } void reshape(int w,int h) { 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(); } void keyboard(unsigned char key,int x,int y) { 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; } } int main(int argc,char** argv) { glutInit(&argc,argv); glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB); glutInitWindowSize(400,400); glutInitWindowPosition(100,100); glutCreateWindow("Texture Map"); init(); glutDisplayFunc(display); glutReshapeFunc(reshape); glutKeyboardFunc(keyboard); glutMainLoop(); return 0; }
|