使用 GLFW 执行连续动画

Perform continuous animation with GLFW

我想用OpenGL实现一个可以用鼠标点击开始和暂停的动画。由于我目前使用的是GLFW,所以GLUT中的函数不再适用

在GLUT中,实现可以是这样的:

void windowMouse(int button, int state, int x, int y) {
    if (button == GLUT_LEFT_BUTTON && state == GLUT_DOWN) {
        // start
        glutIdleFunc(idleFunction);
    }
    else if (button == GLUT_RIGHT_BUTTON && state == GLUT_DOWN) {
        // pause
        glutIdleFunc(NULL);
    }
}

但是,glutIdleFunc() 在 GLFW 中不起作用。我刚刚编写了一个编码框架来实现我的目标,但一直在寻找合适的函数来替换 glutIdleFunc().

void mouse_button_callback(GLFWwindow* window, int button, int action, int mode)
{
    if (button == GLFW_MOUSE_BUTTON_LEFT && action == GLFW_PRESS)
    {
        // start
    }
    else if (button == GLFW_MOUSE_BUTTON_RIGHT && action == GLFW_PRESS)
    {
        // pause
    }
}

GLFW有没有什么功能可以替代之前的功能?或者有什么办法可以用GLFW做连续动画吗?

通过 glfwPostEmptyEvent()glfwWaitEventsTimeout() 发挥创意:

// g++ main.cpp `pkg-config --cflags --libs glfw3 gl`
#include <GLFW/glfw3.h>

void (*idleFunc)(GLFWwindow*) = nullptr;

void idle( GLFWwindow* aWindow )
{
    static float angle = 0.0f;
    static double prvTime = glfwGetTime();
    const double curTime = glfwGetTime();
    const double dt = (curTime - prvTime);
    prvTime = curTime;

    angle += 60.0 * dt;

    int w, h;
    glfwGetFramebufferSize( aWindow, &w, &h );
    glViewport( 0, 0, w, h );
    glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );

    glMatrixMode( GL_PROJECTION );
    glLoadIdentity();
    glMatrixMode( GL_MODELVIEW );
    glLoadIdentity();

    glPushMatrix();
    glRotatef( angle, 0, 0, 1 );
    glBegin(GL_TRIANGLES);
    glColor3ub( 0, 255, 0 );
    glVertex2f( -0.5, -0.5 );
    glVertex2f(  0.5, -0.5 );
    glVertex2f(  0.0,  0.5 );
    glEnd();
    glPopMatrix();

    glfwSwapBuffers( aWindow );
}

void display( GLFWwindow* aWindow )
{
    int w, h;
    glfwGetFramebufferSize( aWindow, &w, &h );
    glViewport( 0, 0, w, h );
    glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );

    glMatrixMode( GL_PROJECTION );
    glLoadIdentity();
    glMatrixMode( GL_MODELVIEW );
    glLoadIdentity();

    glBegin(GL_TRIANGLES);
    glColor3ub( 255, 0, 0 );
    glVertex2f( -0.5, -0.5 );
    glVertex2f(  0.5, -0.5 );
    glVertex2f(  0.0,  0.5 );
    glEnd();

    glfwSwapBuffers( aWindow );
}

void button( GLFWwindow* window, int button, int action, int mode )
{
    if (button == GLFW_MOUSE_BUTTON_LEFT && action == GLFW_PRESS)
    {
        idleFunc = idle;
        glfwPostEmptyEvent();
    }
    else if (button == GLFW_MOUSE_BUTTON_RIGHT && action == GLFW_PRESS)
    {
        idleFunc = nullptr;
        glfwPostEmptyEvent();
    }
}

int main( int, char** )
{
    glfwInit();
    GLFWwindow* window = glfwCreateWindow( 640, 480, "GLFW", NULL, NULL );
    glfwMakeContextCurrent( window );

    glfwSetMouseButtonCallback( window, button );

    while( !glfwWindowShouldClose( window ) )
    {
        if(idleFunc)
        {
            idleFunc(window);
            glfwWaitEventsTimeout(0.016);
        }
        else
        {
            display(window);
            glfwWaitEvents();
        }
    }

    glfwTerminate();
}

glfwPostEmptyEvent() 以及 main()glfwWindowShouldClose() 循环的结构让您可以模拟 glutPostRedisplay() 的行为,而 glfwWaitEventsTimeout()idleFunc()(如果有)运行 每 16 毫秒左右。