在OpenGL中使用FreeImage庫生成紋理
阿新 • • 發佈:2019-02-09
在學習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)