1. 程式人生 > >在OpenGL中使用FreeImage庫生成紋理

在OpenGL中使用FreeImage庫生成紋理

        在學習OpenGL紋理時,由於圖片格式繁多,不能自己一一去實現圖片解析,之前寫了一個簡單的Image庫只支援bmp和tga,但現在很流行png圖片,還有jpg圖片等等,所以沒辦法一一去花時間寫圖片解析庫,而且png格式和jpg格式等涉及到複雜的壓縮演算法,也作了一定的研究,但估計等自己的庫寫好也需要很久很久(呵呵,能力有限),所以打算使用一個開源的影象解析庫,然後對其進行封裝。在網上搜索了所謂的四大Image庫,決定使用FreeImage, 除了其跨平臺,簡潔高效的特性外再就是看著這庫名順眼!

        FreeImage可以幫你解析他所支援的圖片檔案,但OpenGL建立紋理函式glTexImage2D卻有個問題,最後一個引數(畫素資料指標)中不需要進行行對齊, 而且會根據format引數決定RGB格式(主要有GL_RGB和GL_RGBA), 而且OpenGL畫素rgb的順序是低位存red, 高位存blue,這個和一般的解析庫的畫素存取是相反的,綜合上述,簡單的寫了一個將FreeImage的bitmap轉換成OpenGL需要的bitmap格式的函式, 下面給出示例程式碼:

#include <GL/gl.h>
#include <GL/glu.h>
#include <GL/glut.h>

#include <stdio.h>
#include <malloc.h>

#include "FreeImage.h"

#define ERROR(...)		printf(__VA_ARGS__);exit(0)


typedef struct 
{
	int			w;
	int 			h;
	unsigned char	        *buf;
	GLuint			rgb_mode;
}GLBITMAP;


static GLuint	S_png_tex = 0;
static GLuint	S_jpg_tex = 0;
static GLuint 	S_bmp_tex = 0;
static GLuint	S_tga_tex = 0;
static GLuint	S_ico_tex = 0;


GLBITMAP * FIBitmap2GLBitmap(FIBITMAP *fibmp)
{
	int i, j, k;
	int pitch = FreeImage_GetPitch(fibmp);
	unsigned char *bits = FreeImage_GetBits(fibmp);
	int bpp = FreeImage_GetBPP(fibmp);
	GLBITMAP *glbmp = (GLBITMAP *)malloc(sizeof(GLBITMAP));	
	RGBQUAD *palette = NULL;

	if ( !glbmp ) return NULL;
	
	glbmp->w = FreeImage_GetWidth(fibmp);
	glbmp->h = FreeImage_GetHeight(fibmp);	

	switch ( bpp ) {
	case 8:
		if ( !(palette = FreeImage_GetPalette(fibmp)) ) return NULL; 
		if ( !(glbmp->buf = (unsigned char *)malloc(glbmp->w*glbmp->h*3)) ) return NULL;
		glbmp->rgb_mode = GL_RGB;
		for ( i = 0; i < glbmp->h; ++i ) {
			for ( j = 0; j < glbmp->w; ++j ) {
				k = bits[i*pitch+j];
				glbmp->buf[(i*glbmp->w+j)*3+0] = palette[k].rgbRed;
				glbmp->buf[(i*glbmp->w+j)*3+1] = palette[k].rgbGreen;
				glbmp->buf[(i*glbmp->w+j)*3+2] = palette[k].rgbBlue;
			}
		}
		break;
	case 24:
		if ( !(glbmp->buf = (unsigned char *)malloc(glbmp->w*glbmp->h*3)) ) return NULL;
		glbmp->rgb_mode = GL_RGB;
		for ( i = 0; i < glbmp->h; ++i ) {
			for ( j = 0; j < glbmp->w; ++j ) {
				glbmp->buf[(i*glbmp->w+j)*3+0] = bits[i*pitch+j*3+2];
				glbmp->buf[(i*glbmp->w+j)*3+1] = bits[i*pitch+j*3+1];
				glbmp->buf[(i*glbmp->w+j)*3+2] = bits[i*pitch+j*3+0];
			}
		}
		break;
	case 32:
		if ( !(glbmp->buf = (unsigned char *)malloc(glbmp->w*glbmp->h*4)) ) return NULL;
		glbmp->rgb_mode = GL_RGBA;
		for ( i = 0; i < glbmp->h; ++i ) {
			for ( j = 0; j < glbmp->w; ++j ) {
				glbmp->buf[(i*glbmp->w+j)*4+0] = bits[i*pitch+j*4+2];
				glbmp->buf[(i*glbmp->w+j)*4+1] = bits[i*pitch+j*4+1];
				glbmp->buf[(i*glbmp->w+j)*4+2] = bits[i*pitch+j*4+0];
				glbmp->buf[(i*glbmp->w+j)*4+3] = bits[i*pitch+j*4+3];
			}
		}
		break;
	default: return NULL;	
	}

	return glbmp;
}

void FreeGLBitmap(GLBITMAP *glbmp)
{
	if ( glbmp ) {
		if ( glbmp->buf ) free(glbmp->buf);
		free(glbmp);
	}
}


GLuint loadtexture(const char *filename)
{
	GLuint tex = 0;
	int tmp_bit;
	int i;
	int w, h;
	int bpp;
	unsigned char *bits = NULL;
	FREE_IMAGE_FORMAT fif = FIF_UNKNOWN;
	FIBITMAP *bitmap = NULL;
	GLBITMAP *glbmp = NULL;

	fif = FreeImage_GetFileType(filename, 0);
	if ( FIF_UNKNOWN == fif ) {
		fif = FreeImage_GetFIFFromFilename(filename);
		if ( FIF_UNKNOWN == fif )
			return 0;	
	}
	if ( FreeImage_FIFSupportsReading(fif) ) 
		bitmap = FreeImage_Load(fif, filename, 0);
	
	if ( !bitmap ) 
		return 0;

	printf("bit: %d\n", FreeImage_GetBPP(bitmap));

	glbmp = FIBitmap2GLBitmap(bitmap);
	if ( !glbmp )
		return 0;

	glGenTextures(1, &tex);
	glBindTexture(GL_TEXTURE_2D, tex);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
	glTexImage2D(GL_TEXTURE_2D, 0, glbmp->rgb_mode, glbmp->w, glbmp->h, 0, glbmp->rgb_mode, GL_UNSIGNED_BYTE, glbmp->buf);
	
	FreeGLBitmap(glbmp);
	FreeImage_Unload(bitmap);	

	return tex;
}


static GLfloat rot_z = 0.0f;
void display(void)
{
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
	
	glLoadIdentity();
	glTranslatef(0.0f, 0.0f, -10.0f);
	
	glTranslatef(0.0f, 2.0f, 0.0f);
	glBindTexture(GL_TEXTURE_2D, S_bmp_tex);
	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();
	
	glTranslatef(-2.0, -2.0f, 0.0f);
	glBindTexture(GL_TEXTURE_2D, S_png_tex);
	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();

	glTranslatef(2.0, -2.0f, 0.0f);
	glBindTexture(GL_TEXTURE_2D, S_jpg_tex);
	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();

	glTranslatef(2.0, 2.0f, 0.0f);
	glBindTexture(GL_TEXTURE_2D, S_tga_tex);
	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();

	rot_z += 0.1f;

	glutSwapBuffers();
}

void reshape(int w, int h)
{
	if ( 0 == h ) h = 1;
	glViewport(0, 0, w, h);
	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();
	gluPerspective(45.0f, (GLfloat)w/(GLfloat)h, 0.1f, 100.0f);
	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();
}


#define LOADTEXTURE(t, f)	do{ if(!((t) = loadtexture(f))){ ERROR("load texture(%s) failed!\n", f); } }while(0)
void init(void)
{
#if defined(FREEIMAGE_LIB)
	FreeImage_Initialise(0);
#endif
	
	LOADTEXTURE(S_bmp_tex, "images/BG.bmp");
	LOADTEXTURE(S_png_tex, "images/brown.png");
	LOADTEXTURE(S_jpg_tex, "images/apple.jpg");
	LOADTEXTURE(S_tga_tex, "images/Font.tga");

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

int main(int argc, char *argv[])
{
	glutInit(&argc, argv);
	glutInitDisplayMode(GLUT_DEPTH | GLUT_DOUBLE | GLUT_RGBA);
	glutInitWindowPosition(0, 0);
	glutInitWindowSize(640, 480);
	glutCreateWindow("OpenGL - FreeImage!");
	init();
	glutReshapeFunc(reshape);
	glutDisplayFunc(display);
	glutIdleFunc(display);
	glutMainLoop();
#if defined(FREEIMAGE_LIB)
	FreeImage_DeInitialise();
#endif
	return 0;
}


編譯: gcc -o ImageGL ImageGL.c -lGL -lGLU -lglut -lfreeimage (ubuntu 10.04)