J'ai eu un problème similaire à cela. Il est ennuyeux qu'il y ait si peu de documentation sur l'utilisation de glfwSetWindowUserPointer et glfGetWindowUserPointer. Voici ma solution à votre problème:
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;
}
}
Quoi qu'il en soit, comme c'est l'un des meilleurs résultats pour l'utilisation de GLFW avec des classes C ++, je vais également fournir ma méthode d'encapsulation d'un glfwWindow dans une classe C ++. Je pense que c'est la façon la plus élégante de le faire, car cela évite d'avoir à utiliser des globaux, des singletons ou des uniques_ptrs, permet au programmeur de manipuler la fenêtre dans un style beaucoup plus OO / C ++ - y, et autorise le sous-classement (au prix de un fichier d'en-tête légèrement plus encombré).
// 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
}
Et pour:
// 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);
}
Cela peut probablement être assez facilement intégré à une classe WindowManager / InputManager, mais je pense qu'il est plus facile de faire gérer chaque fenêtre par elle-même.
Window *window
). Comment cela résout-il le problème?Les rappels doivent être des fonctions libres ou des fonctions statiques, comme vous l'avez découvert. Les rappels prennent un
GLFWwindow*
comme premier argument à la place d'unthis
pointeur automatique .Avec GLFW, vous pouvez utiliser
glwSetWindowUserPointer
etglfwGetWindowUserPointer
pour stocker et récupérer une référence àWindowManager
ou uneWindow
instance par fenêtre .N'oubliez pas que GLFW n'utilise pas de fonctions virtuelles de polymorphisme direct car c'est une pure API C. Ces API supposent toujours des fonctions libres (C n'a aucune classe ou fonction membre du tout, virtuelle ou autre) et transmettent des "instances d'objet" explicites en tant que paramètres (généralement comme premier paramètre; C n'en a pas
this
). Les bonnes API C incluent également la fonctionnalité de pointeur utilisateur (parfois appelée «données utilisateur», entre autres), vous n'avez donc pas à utiliser de globaux.ancienne réponse:
Si vous devez accéder à d'autres données de votre
WindowManager
(ou d'autres systèmes), vous devrez peut-être les rendre accessibles globalement si vous souhaitez y accéder à partir de rappels. Par exemple, ayez un globalstd::unique_ptr<Engine>
que vous pouvez utiliser pour accéder à votre gestionnaire de fenêtres, ou créez simplement un globalstd::unique_ptr<WindowManager>
(remplacez-lestd::unique_ptr
par quelque chose de "meilleur pour les singletons" si vous le souhaitez).Si vous souhaitez prendre en charge plusieurs fenêtres, vous devrez également
WindowManager
contenir une structure de données pour mapper laGLFWwindow*' values to your own
fenêtreclasses 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 * `qu'ils ont reçue pour rechercher les données dont ils ont besoin.la source