У меня была похожая проблема с этим. Раздражает, что так мало документации по использованию glfwSetWindowUserPointer и glfGetWindowUserPointer. Вот мое решение вашей проблемы:
WindowManager::WindowManager() {
// ...
glfwSetUserPointer(window_, this);
glfwSetKeyCallback(window_, key_callback_);
// ...
}
void WindowManager::key_callback(GLFWwindow *window, int, int ,int, int) {
WindowManager *windowManager =
static_cast<WindowManager*>(glfwGetUserPointer(window));
Keyboard *keyboard = windowManager->keyboard_;
switch(key) {
case GLFW_KEY_ESCAPE:
keyboard->reconfigure();
break;
}
}
В любом случае, поскольку это один из лучших результатов использования GLFW с классами C ++, я также предоставлю свой метод инкапсуляции glfwWindow в класс C ++. Я думаю, что это самый элегантный способ сделать это, так как он избегает необходимости использовать globals, singletons или unique_ptrs, позволяет программисту манипулировать окном в гораздо более OO / C ++ - y стиле и позволяет создавать подклассы (за счет немного более загроможденный заголовочный файл).
// Window.hpp
#include <GLFW/glfw3.h>
class Window {
public:
Window();
auto ViewportDidResize(int w, int h) -> void;
// Make virtual you want to subclass so that windows have
// different contents. Another strategy is to split the
// rendering calls into a renderer class.
(virtual) auto RenderScene(void) -> void;
(virtual) auto UpdateScene(double ms) -> void;
// etc for input, quitting
private:
GLFWwindow *m_glfwWindow;
// Here are our callbacks. I like making them inline so they don't take up
// any of the cpp file
inline static auto WindowResizeCallback(
GLFWwindow *win,
int w,
int h) -> void {
Window *window = static_cast<Window*>(glfwGetUserPointer(win));
window->ViewportDidResize(w, h);
}
inline static auto WindowRefreshCallback(
void) -> void {
Window *window = static_cast<Window*>(glfwGetUserPointer(win));
window->RenderScene(void);
}
// same for input, quitting
}
И для:
// Window.cpp
#include <GLFW/glfw3.h>
#include "Window.hpp"
Window::Window() {
// initialise glfw and m_glfwWindow,
// create openGL context, initialise any other c++ resources
glfwInit();
m_glfwWindow = glfwCreateWindow(800, 600, "GL", NULL, NULL);
// needed for glfwGetUserPointer to work
glfwSetWindowUserPointer(m_glfwWindow, this);
// set our static functions as callbacks
glfwSetFramebufferSizeCallback(m_glfwWindow, WindowResizeCallback);
glfwSetWindowRefreshCallback(m_glfwWindow, WindowRefreshCallback);
}
// Standard window methods are called for each window
auto
Window::ViewportDidResize(int w, int h) -> void
{
glViewport(0, 0, (GLsizei)w, (GLsizei)h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glMatrixMode(GL_MODELVIEW);
}
Вероятно, это может быть довольно легко интегрировано с классом WindowManager / InputManager, но я думаю, что проще просто управлять каждым окном самостоятельно.
Window *window
). Как это решить проблему?Как вы выяснили, обратные вызовы должны быть свободными или статическими функциями. Обратные вызовы принимают в
GLFWwindow*
качестве первого аргумента вместо автоматическогоthis
указателя.С GLFW вы можете использовать
glwSetWindowUserPointer
иglfwGetWindowUserPointer
для хранения и извлечения ссылкиWindowManager
наWindow
экземпляр для каждого окна .Помните, что GLFW не использует виртуальные функции любого вида прямого полиморфизма, поскольку это чистый C API. Такие API всегда предполагают свободные функции (C не имеет классов или функций-членов вообще, виртуальные или иные) и передают явные «экземпляры объекта» в качестве параметров (обычно в качестве первого параметра; C не имеет
this
). Хорошие API C также включают в себя функциональность указателя пользователя (иногда называемую «пользовательскими данными»), поэтому вам не нужно использовать глобальные переменные.старый ответ:
Если вам нужен доступ к другим данным в вашей
WindowManager
(или других системах), вам может потребоваться, чтобы они были глобально доступны, если вы хотите получить доступ к ним из обратных вызовов. Например, имейте глобал,std::unique_ptr<Engine>
который вы можете использовать для доступа к своему оконному менеджеру, или просто сделайте глобалstd::unique_ptr<WindowManager>
(заменитеstd::unique_ptr
что-нибудь «лучше для одиночных игр», если хотите).Если вам нужна поддержка нескольких окон, вы также должны будете
WindowManager
содержать некоторую структуру данных для сопоставленияGLFWwindow*' values to your own
Windowclasses in some way, e.g. using a
std :: unordered_mapor the like. Your callback could then access the global and query the datastructure using the
GLFWwindow *, которую они получили, для поиска нужных им данных.источник