学习的参考书基本是按照GL编程指南,如果有消息机制概念,对于GLUT的理解是很自然的。下面就按照自己写的第一个程序详细解释一下GL,还是比较容易上手的。
程序实现的功能是,根据当前随即种子摇出来的结果来动态改变绿色十字架的线宽、坐标、颜色……不断绘制显示在屏幕。
注意,对于图形建模比如画线、画多边形等这些细节可以查阅书籍,不再重复点出来,网上千篇一律的东西还是很多的。下面的注解是个人的理解,包括参考、查阅其他资料。
需要提点的就是我目前用的是图书馆借出来的第四版GL编程指南,有些东西比较落后了,照搬的话可能不好使。目前的glut版本最新的是api version =4,应该是变动还不是特别大,这个可以读下glut头文件,而正规的参考手册spec只标注了api version=3。
不需要一下子就把什么库都装最新的,当遇到问题时候再一点点加。
#include<gl/glut.h> #include<Windows.h> #include<ctime> //获取屏幕的大小,用了windows头文件的函数:GetSystemMetrics(SM_CXSCREEN),原意是想实现全屏显示, //但是屏幕最后还是会留出窗口框,后来跟进使用glutFullScreen函数可以实现这样更能。 int ScreenWidth; int ScreenHeight; void ReDraw(void); float GetRand(int,int); void Timer0(int value); /////////////////main//////////////////////// void main(int argc,char **argv) { srand(unsigned(time(0))); glutInit(&argc,argv); //显示模式设置,此处设置单缓存和RGB颜色。对于慢速绘制的小程序来说这个是受得了的 //但是如果帧速率过快或者象素过多处理复杂的情况下,应该使用缓冲,何为双缓冲,其实就是所谓的“乒乓操作”, //这个概念在FPGA应用中也很常见,再简单点说就是个2级的流水线操作了。 glutInitDisplayMode(GLUT_SINGLE|GLUT_RGB); //Full size of your windows ScreenWidth = GetSystemMetrics(SM_CXSCREEN); ScreenHeight = GetSystemMetrics(SM_CYSCREEN); //一系列初始化窗口操作,如果是MFC或者是Visual C++则一个函数createwindows的事情。 glutInitWindowSize(ScreenWidth,ScreenHeight); glutInitWindowPosition(0,0); glutCreateWindow("AutoCross"); //init the background to black //设置清屏操作时候显示的颜色,发现这个颜色实则是个4维的向量,目前只要了解前三分量是RGB即可。RGB分量是颜色的一种分解, //这种分解其实在数字图像处理中没有HSI分解来的方便,但是RGB分解方式更符合自然。之所以说RGB处理起来不方便,是因为 //HSI是色度和亮度分离的变量,人眼对亮度和色度的敏感是不一样的,对亮度会更敏感一点。因此在改善图像质量情况下可以在色度和亮度上分别作文章,而RGB是什么,是象征每一种合成的颜色. //人不可能对每种颜色都敏感,细微的变换很难被察觉。总之RGB是对外显示的效果,而其本质是HSI,就像处理时域波形很难描述地清楚的时候,转换到频域去就 //一目了然。另外在图像数据传输时候,在相同带宽下色亮分离传输容量比原始的RGB传输大。 glClearColor(0.0,0.0,0.0,0.0); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); glPointSize(1.4); //Set left-corner as source of cordinator gluOrtho2D(0.0,ScreenWidth,0.0,ScreenHeight); //finish windows initial //此处涉及消息机制,但是被GLUT隐藏了,所有的消息(事件触发的标识)都对于一个消息处理函数,windows对消息处理函数的原型是有要求的必须是回调函数, //即系统会根据消息列表里 //取出来的消息寻找对于的消息处理函数的入口来调用消息处理函数,在windows的应用程序中将系统消息以及用户定义的消息存储在一个巨大消息链表(双向链表),树 //枝状,在基类和派生类的消息中 //情况更复杂一些,涉及到如何判断当前消息时继承是在主干部还是在枝节部。但是这些在glut里面都隐藏了,所需要做的就是注册消息函数,根据消息处理函数原型编写 //消息处理函数 //进入大循环 glutDisplayFunc(ReDraw); glutTimerFunc(20,Timer0,0); glutMainLoop(); } void ReDraw(void) { glClearColor(0.0,0.0,0.0,0.0); glClear(GL_COLOR_BUFFER_BIT); glFlush(); } //用到定时器,和mfc中的定时器几乎一样,根据id来区分不同定时器,如果应用中使用多个定时器的话,需要分别注册,然后在定时器处理函数中根据入口参数id的 //不同可以用一个大的case语句来分情况判断是哪个定时器触发。 void Timer0(int id) { //set the background to black glLineWidth(GetRand(1,10)); glColor3f(0,GetRand(0,1),0); float y = GetRand(0,ScreenHeight); glBegin(GL_LINES); glVertex2f(0.0f,y); glVertex2f(ScreenWidth,y); glEnd(); float x = GetRand(0,ScreenWidth); glBegin(GL_LINES); glVertex2f(x,0); glVertex2f(x,ScreenHeight); glEnd(); glFlush(); glutTimerFunc(int(GetRand(20,100)),Timer0,0);//for continue timer counting } ////////////////////GetRand//////////////////// float GetRand(int start,int end) { return start + (end - start)*rand()/(RAND_MAX + 1.0); }