效果图:
这里显示的图和原图有明显的色差,目前猜测是opengl渲染时的颜色表顺序跟BMP文件里的颜色表顺序相反导致。
BMP里应该是BGRBGRBRG... ,而opengl渲染时应该是按照RGBRGBRGB...的顺序,所以就是B和R是反的,白色和
黑色区域不变是因为白色是全F,黑色是全0,交换后还是一样,这也证明了猜测。此问题待解决。
原图: 显示:
使用freeglut开源库
freeglut库是glut库的开源实现,API同glut的无缝衔接,几乎无区别
下载地址:http://download.chinaunix.net/download/0004000/3280.shtml
这里使用的是freeglut-2.4.0.tar.gz 版本;
1. 将freeglut-2.4.0.tar.gz 在linux下解压,然后进入解压后的文件夹,首先执行./configure, 然后执行make, 然后执行make install,
都执行成功后会显示.h文件安装到 /usr/include/GL/目录下,而库文件安装到 /usr/lib/目录下。
库文件要用libglut.so,libGLU.so,libGL.so, 头文件用gl.h ,glu.h, glut.h
2. Eclipse新建C工程, 配置工程属性,C/C++ Build --> Setting --> GCC C Compiler--> Directories --> Include Path 中加上/usr/include/GL/
GCC C Linker --> Miscellaneous 中加上 /usr/lib/ligblut.so, /usr/lib/libGLU.so, /usr/lib/libGL.so ,注意这里使用的动态库,不能用静态编译-a。
非Eclipse参考http://blog.csdn.net/qwyang/article/details/7163165,然后就可以开始写opengl程序了。
3. BMP格式是windows专有的,在linux下读写就需要用文件流操作,然后自定义一下bmp文件的头结构体。头文件如下:
里面的结构体都是从windows下的头文件中直接拷过来的,AUX_RGBImageRec结构体是从glaux.h文件中拷过来的,opengl纹理贴图的时候需要这个结构体的指针,这个结构体包含了一个图片的长,宽和RGB颜色表,opengl根据这个信息就能画出这个图片。
/* * gluttest.h * * Created on: Jul 4, 2014 * Author: root */ #ifndef GLUTTEST_H_ #define GLUTTEST_H_ #include "glut.h" #include "gl.h" #include "freeglut.h" typedef unsigned long DWORD; typedef int BOOL; typedef unsigned char BYTE; typedef unsigned short WORD; typedef char CHAR; typedef short SHORT; typedef long LONG;
typedef struct _AUX_RGBImageRec { GLint sizeX, sizeY; unsigned char *data; } AUX_RGBImageRec; typedef struct tagBITMAPFILEHEADER { WORD bfType; DWORD bfSize; WORD bfReserved1; WORD bfReserved2; DWORD bfOffBits; } BITMAPFILEHEADER; typedef struct tagBITMAPINFOHEADER{ DWORD biSize; LONG biWidth; LONG biHeight; WORD biPlanes; WORD biBitCount; DWORD biCompression; DWORD biSizeImage; LONG biXPelsPerMeter; LONG biYPelsPerMeter; DWORD biClrUsed; DWORD biClrImportant; } BITMAPINFOHEADER; #endif /* GLUTTEST_H_ */
接下来是 .c文件,这里新建的是C文件,没有了new 和 delete, 分配内存用malloc, 释放用free。
/* * gluttest.c * * Created on: Jul 4, 2014 * Author: root */ #include <stdio.h> #include <stdlib.h> #include <string.h> #include "gluttest.h" GLuint texture[1]; //存储一个纹理 AUX_RGBImageRec *newload(char * Filename) { BITMAPFILEHEADER bmpHeader;//文件头 BITMAPINFOHEADER bmpInfo;//信息头 FILE * pfile; if ((pfile = fopen(Filename, "rb")) == NULL) { return NULL; } int fortest1 = sizeof(BITMAPFILEHEADER); int fortest2 = sizeof(BITMAPINFOHEADER); //读取文件头到bmpHeader //int nn = fread(&bmpHeader, sizeof(BITMAPFILEHEADER),1, pfile); /************************************************************* * 这里之前用整个结构体一起读取的方法,但是除了第一项读取正确外后面的都错位了, * 具体原因不清楚,改成一项一项读之后就可以了。后面的结构体也是 ************************************************************* */ int nn = fread(&(bmpHeader.bfType), sizeof(WORD), 1, pfile); fread(&(bmpHeader.bfSize), sizeof(DWORD), 1, pfile); fread(&(bmpHeader.bfReserved1), sizeof(WORD), 1, pfile); fread(&(bmpHeader.bfReserved2), sizeof(WORD), 1, pfile); fread(&(bmpHeader.bfOffBits), sizeof(DWORD), 1, pfile); if ( nn == 0) { printf("read bmp header failed!"); return NULL; } /*0x4d42=’BM’,表示是Windows支持的BMP格式。 (注意:查ascii表B 0x42,M0x4d,bfType 为两个字节,B为low字节,M为high字节 所以bfType=0x4D42,而不是0x424D */ if (bmpHeader.bfType != 0x4d42) { printf("invalid file type!"); return NULL; } //读取文件信息头bmpInfo fread(&bmpInfo.biSize, 1, sizeof(DWORD), pfile); fread(&bmpInfo.biWidth, 1, sizeof(LONG), pfile); fread(&bmpInfo.biHeight, 1, sizeof(LONG), pfile); fread(&bmpInfo.biPlanes, 1, sizeof(WORD), pfile); fread(&bmpInfo.biBitCount, 1, sizeof(WORD), pfile); fread(&bmpInfo.biCompression, 1, sizeof(DWORD), pfile); fread(&bmpInfo.biSizeImage, 1, sizeof(DWORD), pfile); fread(&bmpInfo.biXPelsPerMeter, 1, sizeof(LONG), pfile); fread(&bmpInfo.biYPelsPerMeter, 1, sizeof(LONG), pfile); fread(&bmpInfo.biClrUsed, 1, sizeof(DWORD), pfile); fread(&bmpInfo.biClrImportant, 1, sizeof(DWORD), pfile); // if (fread(&bmpInfo, 1, sizeof(BITMAPINFOHEADER), pfile) == 0) // { // printf("read bmp infor header failed!\n"); // return NULL; // } //确认是24位位图 if (bmpInfo.biBitCount != 24)//图像的位数 { printf("File is not 24 bit.Application doesn't support this kind of file!"); return NULL; } //计算颜色表区域大小:结构体的大小(包含颜色表)-颜色数据的偏移量 DWORD dataBytes = bmpHeader.bfSize - bmpHeader.bfOffBits; BYTE * pBmpData = (BYTE *)malloc(dataBytes); memset(pBmpData, '\0', dataBytes); if (!pBmpData) { printf("memory error!"); free(pBmpData); return NULL; } BYTE * tmpChar = pBmpData; int ktmp = 0; int restnum = dataBytes; /* 这里整个读取会有问题,改成分包读,每次读500字节 */ while ( ktmp < dataBytes) { if (restnum < 500) { fread(tmpChar, 1, restnum, pfile); ktmp += restnum; break; } fread(tmpChar, 1, 500, pfile); tmpChar += 500; ktmp += 500; restnum -= 500; } if (ktmp == 0) { printf("Read bmp data failed!"); //delete pBmpInfo; free(pBmpData); return NULL; } AUX_RGBImageRec * rgbImage = (AUX_RGBImageRec *)malloc(dataBytes+sizeof(GLint)*2); //rgbImage->data = (unsigned char *)malloc(dataBytes); //memset(rgbImage->data, '\0', sizeof(rgbImage->data)); rgbImage->data = pBmpData; //memcpy(rgbImage->data, pBmpData, dataBytes); rgbImage->sizeX = bmpInfo.biWidth; rgbImage->sizeY = bmpInfo.biHeight; return rgbImage; } //生成纹理 int LoadGLTextures() { char * fpath; fpath = "/home/zhu/aaa.bmp"; int Status = 0; AUX_RGBImageRec *TextureImage[1]; memset(TextureImage, 0, sizeof(void *)*1); if (TextureImage[0] = newload(fpath)) { Status = 1; //注册纹理 glGenTextures(1, &texture[0]); //绑定纹理名称 glBindTexture(GL_TEXTURE_2D, texture[0]); //生成纹理数据 glTexImage2D(GL_TEXTURE_2D, 0, 3, TextureImage[0]->sizeX, TextureImage[0]->sizeY, 0, GL_RGB, GL_UNSIGNED_BYTE, TextureImage[0]->data); //线性滤波 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); } if (TextureImage[0]) { if (TextureImage[0]->data) { free(TextureImage[0]->data); } free(TextureImage[0]); } return Status; } //调用入口 int InitGL(GLvoid) { if (!LoadGLTextures()) { return 0; } glEnable(GL_TEXTURE_2D); //glShadeModel(GL_SMOOTH); //设置背景色为黑色 glClearColor(0.0f, 0.0f, 0.0f, 0.0f); return 1; } //贴图绘制 void DrawGLScene(GLvoid) { //清除屏幕缓存 glClear(GL_COLOR_BUFFER_BIT); //重置当前的模型观察矩阵 glLoadIdentity(); /************************************** * 旋转函数备用 -90表示顺时针绕Z轴旋转90度 ***************************************/ //glRotatef(-90,0.0f,0.0f,1.0f); //开始绘制四边形 glBegin(GL_QUADS); //贴图及映射(glTexCoord2f对应纹理坐标, glVertex2f对应矩形坐标,此处已做旋转处理) glTexCoord2f(0.0f, 0.0f); glVertex2f(-1.0f, 1.0f); glTexCoord2f(0.0f, 1.0f); glVertex2f( 1.0f, 1.0f); glTexCoord2f(1.0f, 1.0f); glVertex2f( 1.0f, -1.0f); glTexCoord2f(1.0f, 0.0f); glVertex2f(-1.0f, -1.0f); glEnd(); glFlush(); //交换缓冲区 //glutSwapBuffers(); } //void idle() //{ // // // if (!LoadGLTextures()) // { // printf("load GL Textures Error\n"); // exit(-1); // //return false; // } // DrawGLScene(); // sleep(500); //} int main(int argc, char **argv) { //初始化glut运行 glutInit(&argc,argv); //GLUT_SINGLE表示单缓冲 glutInitDisplayMode(GLUT_DEPTH|GLUT_SINGLE|GLUT_RGBA); glutInitWindowPosition(300,100); glutInitWindowSize(450, 600); glutCreateWindow("hello"); InitGL(); glutDisplayFunc(&DrawGLScene); //glutIdleFunc(idle); glutMainLoop(); return 0; }
(完)