在学习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)