Tuve un problema similar a esto. Es molesto que haya tan poca documentación sobre el uso de glfwSetWindowUserPointer y glfGetWindowUserPointer. Aquí está mi solución a su 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 todos modos, como este es uno de los mejores resultados para usar GLFW con clases de C ++, también proporcionaré mi método de encapsular un glfwWindow en una clase de C ++. Creo que esta es la forma más elegante de hacerlo, ya que evita tener que usar globals, singletons o unique_ptrs, permite que el programador manipule la ventana en un estilo mucho más OO / C ++ y permite subclases (a costa de un archivo de encabezado un poco más desordenado).
// 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
}
Y 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);
}
Probablemente esto se pueda integrar fácilmente con una clase WindowManager / InputManager, pero creo que es más fácil hacer que cada ventana se administre sola.
Window *window
). ¿Cómo resuelve esto el problema?Las devoluciones de llamada deben ser funciones libres o funciones estáticas, como ha descubierto. Las devoluciones de llamada toman a
GLFWwindow*
como su primer argumento en lugar de unthis
puntero automático .Con GLFW puede usar
glwSetWindowUserPointer
yglfwGetWindowUserPointer
almacenar y recuperar una referenciaWindowManager
o unaWindow
instancia por ventana .Recuerde que GLFW no utiliza funciones virtuales de ningún tipo de polimorfismo directo, ya que es una API C pura. Dichas API siempre asumen funciones libres (C no tiene clases ni funciones miembro, virtuales o de otro tipo) y pasan "instancias de objeto" explícitas como parámetros (generalmente como el primer parámetro; C no tiene
this
). Las buenas API de C también incluyen la funcionalidad de puntero de usuario (a veces llamada "datos de usuario", entre otras cosas) para que no tenga que usar globales.vieja respuesta:
Si necesita acceder a otros datos en su
WindowManager
(u otros sistemas), es posible que deba tener acceso global a ellos si desea acceder a ellos desde devoluciones de llamada. Por ejemplo, tenga un globalstd::unique_ptr<Engine>
que pueda usar para acceder a su administrador de ventanas, o simplemente haga un globalstd::unique_ptr<WindowManager>
(reemplacestd::unique_ptr
con algo "mejor para singletons" si lo desea).Si desea compatibilidad con múltiples ventanas, también deberá
WindowManager
contener alguna estructura de datos para asignarGLFWwindow*' values to your own
Windowclasses in some way, e.g. using a
std ::or the like. Your callback could then access the global and query the datastructure using the
unordered_map GLFWwindow * `que recibieron para buscar los datos que necesitan.fuente