#include <GL/glut.h>
#include <math.h>
#define DEG_TO_RAD 0.017453 //角度转为弧度的参数,即 2*PI/360
float theta=30.0; //直线与X轴正方向的夹角
float length=200.0; //直线的长度
float x=300.0, y=200.0; //直线的第一个端点
void init (void)
{
glClearColor (1.0, 1.0, 1.0, 0.0);
glMatrixMode (GL_PROJECTION);
gluOrtho2D (0.0, 640.0, 0.0, 480.0);
}
void display (void)
{
glClear (GL_COLOR_BUFFER_BIT);
glColor3f (1.0, 0.0, 0.0);
glBegin (GL_POLYGON);
glVertex2f (x, y);
glVertex2f ( x + length*cos(DEG_TO_RAD*theta),
y + length*sin(DEG_TO_RAD*theta) );
glVertex2f ( x + length*cos(DEG_TO_RAD* (theta+30) ),
y + length*sin(DEG_TO_RAD* (theta+30)) );
glEnd ( );
glFlush ( );
}
void idleFunc()
{
theta += 0.1;
if (theta>360) theta -=360;
glutPostRedisplay(); //重新调用绘制函数
}
void main (int argc, char** argv)
{
glutInit (&argc, argv);
glutInitDisplayMode (GLUT_SINGLE | GLUT_RGB);
glutInitWindowPosition (50, 100);
glutInitWindowSize (640, 480);
glutCreateWindow ("Draw Triangle with Single Buffer");
init ( );
glutDisplayFunc (display);
glutIdleFunc(idleFunc); //指定空闲回调函数
glutMainLoop ( );
}
什么情况下调用?——GLUT事件队列中当前没有事件
Idle Callback 用途——更新场景数据
该例子中,我们使红色三角形围绕其中的一个顶点旋转,该顶点就是(300,200),三角形的另外两个顶点由两个参数length和theta确定,length是这两个顶点离固定顶点(300,200)的距离,这两个顶点与(300,200)连线的夹角分别为theta和theta+30度(相对于X轴正方向),所以,当改变theta的值时,三角形的位置会围绕(300,200)旋转。
该程序中改变theta的值是在函数idleFunc中,每次增加0.1度,当大于360度时,又使之变为0度,始终使theta在)0~360度之间循环变化。该函数我们用glutIdleFunc(idleFunc)指定为空闲回调函数,当事件队列中没有事件需要处理时,该空闲回调函数得到执行。
执行后,会看到红色的三角形在旋转中有闪烁的现象,这是由于计算机的显示屏工作时都以固定的频率进行刷新,刷新时从显示卡的内存里取颜色缓存的内容,表现在显示屏上。对于应用程序来说,屏幕的刷新无法控制。该程序绘制时,实际上是对显示卡内存里的颜色缓存进行操作,所以程序对颜色缓存的写和显示屏刷新时对颜色缓存的读是不同步的,所以在某个时刻,颜色缓存的所有颜色值可能不是针对某个确定的theta值,所以三角形看起来不完整。
虽然应用程序无法将两个读写过程同步,但借助于双缓存技术,可以保证绘制一个完整的红色三角形。双缓存技术使用两个颜色缓存――前台缓存和后台缓存,前台缓存用于刷新显示屏,后台缓存用于应用程序的绘制。在绘制完成一个完整的三角形后,我们只要交换前台缓存和后台缓存,就能输出完整的图形。交换前台缓存和后台缓存的函数是void glutSwapBuffers() ,用它取代显示回调函数中的glFlush()即可。
要用双缓存技术,需要在初始化时就指定,把原来的
glutInitDisplayMode (GLUT_SINGLE | GLUT_RGB)
改为glutInitDisplayMode (GLUT_DOUBLE | GLUT_RGB)。
#include <GL/glut.h>
#include <math.h>
#define DEG_TO_RAD 0.017453 //角度转为弧度的参数,即 2*PI/360
float theta=0.0; //直线与X轴正方向的夹角
void init (void)
{
glClearColor (0.0, 0.0, 0.0, 0.0);
glMatrixMode (GL_PROJECTION);
gluOrtho2D (-1, 1, -1, 1);
}
void display (void)
{
GLfloat sin_theta, cos_theta;
sin_theta = sin ( DEG_TO_RAD * theta);
cos_theta = cos ( DEG_TO_RAD * theta);
glClear(GL_COLOR_BUFFER_BIT);
glBegin(GL_POLYGON);
glColor3f(1.0,1.0,1.0);
glVertex2f(cos_theta, sin_theta);
glVertex2f(-sin_theta, cos_theta);
glVertex2f(-cos_theta, -sin_theta);
glVertex2f(sin_theta, -cos_theta);
glEnd();
glFlush ( );
}
void idleFunc()
{
theta += 2.0;
if(theta > 360.0) theta -=360;
glutPostRedisplay();
}
void main (int argc, char** argv)
{
glutInit (&argc, argv);
glutInitDisplayMode (GLUT_SINGLE| GLUT_RGB);
glutInitWindowPosition (50, 100);
glutInitWindowSize (640, 480);
glutCreateWindow ("Draw Triangle with Single Buffer");
init ( );
glutDisplayFunc (display);
glutIdleFunc(idleFunc); //指定空闲回调函数
glutMainLoop ( );
}