Eu tive um problema semelhante a isso. É irritante que haja tão pouca documentação sobre o uso de glfwSetWindowUserPointer e glfGetWindowUserPointer. Aqui está a minha solução para o seu problema:
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;
}
}
De qualquer forma, como esse é um dos principais resultados do uso do GLFW com classes C ++, também fornecerei meu método de encapsular um glfwWindow em uma classe C ++. Eu acho que essa é a maneira mais elegante de fazer isso, pois evita o uso de globais, singletons ou unique_ptrs, permite que o programador manipule a janela em um estilo muito mais OO / C ++ - y e permite subclassificação (ao custo de um arquivo de cabeçalho um pouco mais confuso).
// 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
}
E para:
// 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);
}
Provavelmente, isso pode ser facilmente integrado a uma classe WindowManager / InputManager, mas acho que é mais fácil fazer com que cada janela se gerencie.
Window *window
). Como isso resolve o problema?Os retornos de chamada devem ser funções livres ou estáticas, como você descobriu. Os retornos de chamada tomam
GLFWwindow*
como o primeiro argumento no lugar de umthis
ponteiro automático .Com o GLFW, você pode usar
glwSetWindowUserPointer
eglfwGetWindowUserPointer
armazenar e recuperar uma referênciaWindowManager
ou umaWindow
instância por janela .Lembre-se de que o GLFW não usa funções virtuais como polimorfismo direto, pois é uma API C pura. Essas APIs sempre assumem funções livres (C não possui classes ou funções membro, virtuais ou não) e passam "instâncias de objetos" explícitas como parâmetros (geralmente como o primeiro parâmetro; C não possui
this
). As boas APIs C também incluem a funcionalidade de ponteiro do usuário (às vezes chamada de "dados do usuário" entre outras coisas), para que você não precise usar globais.resposta antiga:
Se você precisar acessar outros dados em seu
WindowManager
(ou em outros sistemas), pode ser necessário que eles estejam acessíveis globalmente, se desejar acessá-los a partir de retornos de chamada. Por exemplo, tenha um globalstd::unique_ptr<Engine>
que você possa usar para acessar seu gerenciador de janelas ou apenas faça um globalstd::unique_ptr<WindowManager>
(substituastd::unique_ptr
por algo "melhor para singletons", se desejar).Se você deseja suporte a várias janelas, também terá
WindowManager
uma estrutura de dados para mapear oGLFWwindow*' 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 * `que eles receberam para procurar os dados de que precisam.fonte