这节我们将读取几个图片,生成一个纹理集,然后让程序循环显示图片。
为了方便,我直接把图片的数量和每个图片的名字保存在一个txt文档里面,方便程序地读取。
如:
在init函数中,打开data.txt,读取图片的数量和图片的名字,然后调用LoadBitmap函数,把所生成的纹理保存在一个容器vector中,然后在Update函数中,控制显示的图片id,从而达到循环显示。
具体的实现很简单,所以就不多说了~
vector<unsigned int> V_ID; //用来保存生成的纹理id int now,cnt; //now是当前所使用的纹理在vector中的下标 //cnt是用来计时的变量 void Update() { cnt++; if (cnt >= 100) //当cnt加到的时候,换下一张图片 { now++; now%=V_ID.size(); //保证now值的正确性 cnt=0; //将cnt值置,开始下一个图片的显示 } glutPostRedisplay(); }void init() { int n,i; char str[100],file[100]; V_ID.clear(); //清空容器 FILE *fp; fp=fopen("data/data.txt","r"); fscanf(fp,"%d",&n); while (n--) { fscanf(fp,"%s",str); sprintf(file,"data/%s",str); i=LoadBitmap(file); if (i == -1) //读取图片失败 continue; else V_ID.push_back(i); //把图片的id放到V_ID的末尾保存起来 } fclose(fp); now=0; }
图片实现了循环以后呢,我还希望图片在交替的时候,有一个淡入淡出的效果。怎么做呢?
还记得glColor3f函数吧,这个函数有一个可以带4个参数的形式:glColor4f。
这里的第四个参数,也就是alpha值。我们通过OpenGL提供的颜色混合功能,使用alpha值来实现这个效果。
在生活中,如果把两张照片(不透明)叠在一起,很明显,我们只能看见在最顶上的那张照片。如果一张照片被处理了,变成了透明的,那么我们就可以看见两张照片了。在OpenGL中,如果我们在一个区域画了一个绿色的矩形,随后在同样的区域画了一个黄色的矩形,那么我们就只能看见黄色的矩形,因为新画得黄矩形把原来那个覆盖了。如果我们想看见两个不同颜色矩形叠加在一起的效果,通过alpha混合就可以创建半透明的图像片段。
要使用alpha值,首先要开启混合功能。调用glEnable(GL_BLEND);
然后就是glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);这个函数是指定了两个图像片断混合的方式,在绘制图片之前,我们先调用glColor4f(1.0,1.0,1.0,alpha);
其中alpha值是[0,1]之间的,如果定为1,就是不透明,定为0就是,完全透明。淡入淡出的实现其实就是让这个值在[0,1]之间浮动即可。
所以,根据cnt值的变化,进行如下的操作:
if (cnt <= 50) glColor4f(1.0,1.0,1.0,(float)cnt/50.0); else glColor4f(1.0,1.0,1.0,1.0-((float)cnt-50.0)/50.0);
附本节代码:
#include <GL/glut.h> #include <stdio.h> #include <math.h> #include <time.h> #include <stdlib.h> #include <windows.h> #include <vector> #include <iostream> #define PI 3.1415926 #define BITMAP_ID 0x4D42 float h,m,s; using std::vector; using std::cout; using std::endl; int LoadBitmap(const char *file) { unsigned int ID; //纹理的id int width,height,i; byte *image,t; //接受图像数据 FILE *fp; //文件指针 BITMAPFILEHEADER FileHeader; //接受位图文件头 BITMAPINFOHEADER InfoHeader; //接受位图信息头 fp=fopen(file,"rb"); if (fp == NULL) { perror("LoadBitmap"); //打开文件失败 return -1; } fread(&FileHeader, sizeof(BITMAPFILEHEADER), 1, fp); if(FileHeader.bfType != BITMAP_ID) //确保文件是一个位图文件,效验文件类型 { printf("Error: This file is not a bmp file!"); fclose(fp); return -1; } fread(&InfoHeader, sizeof(BITMAPINFOHEADER), 1, fp); width=InfoHeader.biWidth; height=InfoHeader.biHeight; if (InfoHeader.biSizeImage == 0) //确保图像数据的大小 { InfoHeader.biSizeImage = width*height*3; } fseek(fp, FileHeader.bfOffBits, SEEK_SET); //将文件指针移动到实际图像数据处 image=(byte *)malloc(sizeof(byte)*InfoHeader.biSizeImage); //申请空间 if (image == NULL) { free(image); printf("Error: No enough space!"); return -1; } fread(image, 1, InfoHeader.biSizeImage, fp); for(i=0; i<InfoHeader.biSizeImage; i+=3) { t=image[i]; image[i]=image[i+2]; image[i+2]=t; } fclose(fp); glGenTextures(1, &ID); glBindTexture(GL_TEXTURE_2D, ID); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_CLAMP); glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_CLAMP); gluBuild2DMipmaps(GL_TEXTURE_2D, 3, width, height, GL_RGB, GL_UNSIGNED_BYTE, image); return ID; } vector<unsigned int> V_ID; //用来保存生成的纹理id int now,cnt; //now是当前所使用的纹理在vector中的下标 //cnt是用来计时的变量 void Draw() { glClearColor(0.0,0.0,0.0,0.0); glClear(GL_COLOR_BUFFER_BIT); glEnable(GL_TEXTURE_2D); glBindTexture(GL_TEXTURE_2D, V_ID[now]); glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); if (cnt <= 50) glColor4f(1.0,1.0,1.0,(float)cnt/50.0); else glColor4f(1.0,1.0,1.0,1.0-((float)cnt-50.0)/50.0); glBegin(GL_QUADS); glTexCoord2f(0.0f, 0.0f);glVertex2f(-1,-1); glTexCoord2f(1.0f, 0.0f);glVertex2f(1,-1); glTexCoord2f(1.0f, 1.0f);glVertex2f(1,1); glTexCoord2f(0.0f, 1.0f);glVertex2f(-1,1); glEnd(); glDisable(GL_TEXTURE_2D); glutSwapBuffers(); } void Update() { cnt++; if (cnt >= 100) //当cnt加到100的时候,换下一张图片 { now++; now%=V_ID.size(); //保证now值的正确性 cnt=0; //将cnt值置0,开始下一个图片的显示 } glutPostRedisplay(); } void Reshape(int w,int h) { w=w>h?h:w; glViewport(0,0,(GLsizei)w,(GLsizei)w); } void init() { int n,i; char str[100],file[100]; V_ID.clear(); //清空容器 FILE *fp; fp=fopen("data/data.txt","r"); fscanf(fp,"%d",&n); while (n--) { fscanf(fp,"%s",str); sprintf(file,"data/%s",str); i=LoadBitmap(file); if (i == -1) //读取图片失败 continue; else V_ID.push_back(i); //把图片的id放到V_ID的末尾保存起来 } fclose(fp); now=0; } int main(int argc, char *argv[]) { glutInit(&argc, argv); glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE); glutInitWindowPosition(100, 100); glutInitWindowSize(400, 400); glutCreateWindow("HelloOpenGL"); glutReshapeFunc(&Reshape); glutIdleFunc(&Update); glutDisplayFunc(&Draw); init(); glutMainLoop(); return 0; }