Ich hatte ein ähnliches Problem. Es ist ärgerlich, dass es so wenig Dokumentation zur Verwendung von glfwSetWindowUserPointer und glfGetWindowUserPointer gibt. Hier ist meine Lösung für Ihr Problem:
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;
}
}
Da dies eines der besten Ergebnisse für die Verwendung von GLFW mit C ++ - Klassen ist, werde ich auch meine Methode zum Einkapseln eines glfwWindow in eine C ++ - Klasse bereitstellen. Ich denke, dass dies die eleganteste Art ist, dies zu tun, da keine Globals, Singletons oder unique_ptrs verwendet werden müssen, der Programmierer das Fenster in einem viel OO / C ++ - y-Stil manipulieren kann und Unterklassen zulässt (auf Kosten von eine etwas überladenere Header-Datei).
// 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
}
Und für:
// 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);
}
Dies kann wahrscheinlich recht einfach in eine WindowManager / InputManager-Klasse integriert werden, aber ich denke, es ist einfacher, jedes Fenster selbst verwalten zu lassen.
Window *window
). Wie löst dies das Problem?Die Rückrufe müssen freie oder statische Funktionen sein, wie Sie herausgefunden haben. Die Rückrufe verwenden a
GLFWwindow*
als erstes Argument anstelle eines automatischenthis
Zeigers.Mit GLFW können Sie einen Verweis auf oder eine Instanz pro Fenster verwenden
glwSetWindowUserPointer
undglfwGetWindowUserPointer
speichern und abrufen .WindowManager
Window
Denken Sie daran, dass GLFW keine direkten Funktionen für virtuelle Funktionen verwendet, da es sich um eine reine C-API handelt. Solche APIs übernehmen immer freie Funktionen (C hat überhaupt keine Klassen oder Elementfunktionen, weder virtuell noch anderweitig) und übergeben explizite "Objektinstanzen" als Parameter (normalerweise als erster Parameter; C hat keine
this
). Gute C-APIs enthalten auch die Benutzerzeigerfunktionalität (manchmal auch als "Benutzerdaten" bezeichnet), sodass Sie keine globalen Zeichen verwenden müssen.alte Antwort:
Wenn Sie auf andere Daten in Ihrem
WindowManager
(oder anderen Systemen) zugreifen müssen, müssen Sie möglicherweise global auf diese zugreifen können, wenn Sie über Rückrufe darauf zugreifen möchten. Habenstd::unique_ptr<Engine>
Sie zum Beispiel eine globale , mit der Sie auf Ihren Fenstermanager zugreifen können, oder erstellen Sie einfach eine globalestd::unique_ptr<WindowManager>
(ersetzen Sie siestd::unique_ptr
durch etwas "Besseres für Singletons", wenn Sie dies wünschen).Wenn Sie die Unterstützung mehrerer Fenster wünschen, müssen Sie auch eine
WindowManager
Datenstruktur zum Zuordnen vonGLFWwindow*' 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 * `enthalten, die sie erhalten haben, um die benötigten Daten nachzuschlagen.quelle