在OpenGL中使用FreeImage库生成纹理

本文介绍了在OpenGL中使用FreeImage库来处理多种图片格式,以生成纹理。由于OpenGL的像素格式要求与FreeImage不一致,需要对FreeImage的位图进行转换,代码示例展示了如何完成这一过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

        在学习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)
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值