OpenGL编程学习实战教程(5)

在上一节中,我们知道了怎么在OpenGL程序里,画一些基本的图形,并且画了一个钟表出来。然而,这个钟的时间是我们事先给它的,所以它只能显示一个固定的时间。所以,这一节我们将来学习怎么让画面动起来!

我希望这个表能够获取系统时间,并且随着系统时间的改变,指针的读数也会改变。

在实现动画这一块,OpenGL给我们提供了双缓冲。当A缓冲区显示时,B缓冲区正在绘制图形。当B绘制完毕时,就交换缓冲区,此时B显示,而A就进行绘画。从而实现平滑地显示每一帧地显示,观众就永远看不到没有完成的画面。计算机的在交换缓冲区的时候,速度很快,所以一般用户是觉察不到的。

为了能让我们的程序能够使用双缓冲,我们需要改变main函数中glutInitDisplayMode()函数的参数,把GLUT_SINGLE改为GLUT_DOUBLE,表示我们现在要使用双缓冲(double)了,以前是单缓冲(single)。

glutInitDisplayMode(GLUT_RGB| GLUT_DOUBLE);

在openGL中,并没有提供交换缓冲这个函数,因为有些硬件不支持这个特性。对于不同的操作系统,有不同的方法。我们使用的GLUT辅助库,帮我们解决了这个问题,我们只用调用glutSwapBuffers();函数就OK了。

所以我们再把Draw函数中的glFlush()函数换成glutSwapBuffers()。就可以了。

这个时候编译运行,会同样的出现钟表,画面并没有动起来,因为Draw函数只调用了一次,我们希望程序能不停地显示。怎么做呢?

我们在main函数中使用glutIdleFunc(&Update)函数,可以设置一个回调函数Update。设置了以后,Update便会在循环中不断地被调用,直到有窗口消息产生。这里暂时不管窗口消息是啥,我们就知道Update会不断被调用就是了。

于是我们写一个Update函数.

void Update()
{
    glutPostRedisplay();
}

glutPostRedisplay函数,就和它的名字一样,它发送了一个消息给glut窗口,告诉它重新绘制一下画面,结果就是Draw函数会被调用。

这时我们再编译运行一次,发现同样可以显示画面。其实这个时候,画面是在不断地更新的,只是你感觉不出来而已。

OpenGL编程学习实战教程

指针并没有动,因为指针的读数和h,m,s三个参数有关,而这三个参数的值是固定的。把这三个参数改为全局变量,让其在其他函数中也可以被使用,然后在Update函数中,更新h,m,s的值为当前系统的时间就可以了。最后记得去掉draw函数中的

h=10;
m=25;
s=25;

void Update()
{
    time_t rawtime;
    struct tm * timeinfo;

time ( &rawtime );
    timeinfo = localtime ( &rawtime );
    h=timeinfo->tm_hour;
    m=timeinfo->tm_min;
    s=timeinfo->tm_sec;
    glutPostRedisplay();
}

OpenGL编程学习实战教程

这个时候,在编译运行,效果就出来了!

附本节全部代码:

#include <GL/glut.h>
#include <stdio.h>
#include <math.h>
#include <time.h>
#define PI 3.1415926
float h,m,s;
void Draw()
{
    int i;
    float R,TR,h_Angle,m_Angle,s_Angle,count,h_Length,m_Length,s_Length;
    R=0.5;
    TR=R-0.05;
    glClear(GL_COLOR_BUFFER_BIT);
    glLineWidth(5);
    glBegin(GL_LINE_LOOP);
 for (i=0; i<100; i++)
    {
        glVertex2f(R*cos(2*PI/100*i),R*sin(2*PI/100*i));
    }
    glEnd();
    glLineWidth(2);
 for (i=0; i<12; i++)
 {
    glBegin(GL_LINES);
            glVertex2f(TR*sin(2*PI/12*i),TR*cos(2*PI/12*i));
            glVertex2f(R*sin(2*PI/12*i),R*cos(2*PI/12*i));
        glEnd();
 }
    glLineWidth(1);

h_Length=0.2;
 m_Length=0.3;
 s_Length=0.4;
 count=60;
 s_Angle=s/count;
 count*=60;
 m_Angle=(m*60+s)/count;
 count*=12;
 h_Angle=(h*60*60+m*60+s)/count;
 glLineWidth(1);
 glBegin(GL_LINES);
        glVertex2f(0.0f,0.0f);
        glVertex2f(s_Length*sin(2*PI*s_Angle),s_Length*cos(2*PI*s_Angle));
    glEnd();
    glLineWidth(5);
    glBegin(GL_LINES);
        glVertex2f(0.0f,0.0f);
        glVertex2f(h_Length*sin(2*PI*h_Angle),h_Length*cos(2*PI*h_Angle));
    glEnd();
    glLineWidth(3);
    glBegin(GL_LINES);
        glVertex2f(0.0f,0.0f);
        glVertex2f(m_Length*sin(2*PI*m_Angle),m_Length*cos(2*PI*m_Angle));
    glEnd();
    glLineWidth(1);

glBegin(GL_POLYGON);
 for (i=0; i<100; i++)
    {
        glVertex2f(0.03*cos(2*PI/100*i),0.03*sin(2*PI/100*i));
    }
    glEnd();
    glutSwapBuffers();
}
void Update()
{
    time_t rawtime;
    struct tm * timeinfo;

time ( &rawtime );
    timeinfo = localtime ( &rawtime );
    h=timeinfo->tm_hour;
    m=timeinfo->tm_min;
    s=timeinfo->tm_sec;
    glutPostRedisplay();
}
int main(int argc, char *argv[])
{
    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE);
    glutInitWindowPosition(100, 100);
    glutInitWindowSize(400, 400);
    glutCreateWindow("HelloOpenGL");
    glutIdleFunc(&Update);
    glutDisplayFunc(&Draw);
    glutMainLoop();
    return 0;
}

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:http://www.heiqu.com/1dd33752d840e115225e85aedc5cc649.html