C++ GLFW3 输入处理

C++ GLFW3 input handling

所以我一直在使用 OpenGL + GLFW 开发游戏引擎。最初我一直在使用 LWJGL 包装器并使用 Java。我决定将我的代码库移植到 C++。我一直在像这样通过 lambda 使用 "glfwSetCursorPosCallback" 函数:

//Java:
glfwSetCursorPosCallback(win, (window, xpos, ypos) -> {
    engine.onCursorMoved(xpos, ypos);
});

这样做让我可以将引擎 class 中所有不同的 "events" 结合在一起,并使 GLFW 设置代码 + 原始更新循环与引擎代码的其余部分分开。离开引擎 class 干净整洁。

我想用 C++ 做同样的事情,但以下是无效的:

glfwSetCursorPosCallback(window, [engine](GLFWwindow* window, double x, double y) {
    engine.onCursorMoved(x, y);
});

对于 C++ lambda,如果 lambda 被用作函数参数,则不能在“[]”块中传递任何内容。

所以我在最初的问题之上进一步研究了它,我还了解到使用 lambda 的性能更差。

所以我尝试将成员函数作为参数传递:

// I changed "onCursorMoved" use the proper parameter signature
// "onCursorMoved(GLFWwindow* window, double x, double y)"
glfwSetCursorPosCallback(window, engine.onCursorMoved);

尝试此操作也失败了,因为您无法将实例化的 classes 成员函数作为参数传递给 glfwSetCursorPosCallback。

所以我问,我应该采取什么方法?有没有办法绕过 lambda/member 功能限制,或者我完全没有的一些完全不同的方法?

P.S。 - 我对 C++ 很陌生,所以如果答案显而易见,请原谅我。

编辑:为了帮助 illustrate/clarify 我想要实现的目标,这是基于我之前的 Java 版本的 Engine.h。

class Engine {
private:
    //member variables for scene graph, etc
public:
    Engine();
    ~Engine();
public:
    void onWindowResized(int width, int height);
    void onCursorMoved(double x, double y);
    void onUpdate(float timeStep);
    void onRender();
};

基本上,以 "on" 为前缀的不同函数在 main 中由 GLFW callbacks/loop 触发,还有其他可能。这种方法是否可行,不知何故,或者是否有更好的方法在 C++ 中执行此操作,来自 Java 一切都在对象中,这种情况下这种心态是否有缺陷?

只写回调函数的名字:

//callbacks header file
void cursor_position_callback(GLFWwindow* window, double xpos, double ypos);

//GLFW init function
glfwSetCursorPosCallback(window, cursor_position_callback);

使用 glfwSetWindowUserPointer() 设置给定 window 应调用回调的 Engine 实例。

然后在(无捕获)lambda 中,您可以使用 window 调用 glfwGetWindowUserPointer(),将 void* 转换为 Engine*,并调用适当的成员函数。

示例:

#include <GLFW/glfw3.h>
#include <cstdlib>

class Engine
{
public:
    void onCursorPos( double x, double y )
    {
        mX = x;
        mY = y;
    }

    double mX, mY;
};

int main()
{
    if( !glfwInit() )
        exit( EXIT_FAILURE );

    glfwWindowHint( GLFW_CONTEXT_VERSION_MAJOR, 2 );
    glfwWindowHint( GLFW_CONTEXT_VERSION_MINOR, 1 );
    GLFWwindow* window = glfwCreateWindow( 640, 480, "Simple example", NULL, NULL );

    Engine engine;
    glfwSetWindowUserPointer( window, &engine );

    glfwSetCursorPosCallback( window, []( GLFWwindow* window, double x, double y )
    {
        Engine* engine = static_cast<Engine*>( glfwGetWindowUserPointer( window ) );
        engine->onCursorPos( x, y );
    } );

    glfwMakeContextCurrent( window );
    glfwSwapInterval( 1 );

    while( !glfwWindowShouldClose( window ) )
    {
        glClearColor( engine.mX / 640.0, engine.mY / 480.0, 1.0, 1.0 );
        glClear( GL_COLOR_BUFFER_BIT );

        glfwSwapBuffers( window );
        glfwPollEvents();
    }
    glfwDestroyWindow( window );
    glfwTerminate();
    exit( EXIT_SUCCESS );
}