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 );
}
所以我一直在使用 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 );
}