Miałem podobny problem do tego. To denerwujące, że jest tak mało dokumentacji na temat korzystania z glfwSetWindowUserPointer i glfGetWindowUserPointer. Oto moje rozwiązanie twojego problemu:
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;
}
}
W każdym razie, ponieważ jest to jeden z najlepszych wyników dla używania GLFW z klasami C ++, przedstawię również moją metodę enkapsulacji glfwWindow w klasie C ++. Myślę, że jest to najbardziej elegancki sposób, aby to zrobić, ponieważ pozwala uniknąć konieczności korzystania z globałów, singletonów lub unikatowych_ptrs, pozwala programiście manipulować oknem w znacznie większym stylu OO / C ++ - i umożliwia podklasowanie (kosztem nieco bardziej zaśmiecony plik nagłówka).
// 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
}
I dla:
// 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);
}
Prawdopodobnie można to dość łatwo zintegrować z klasą WindowManager / InputManager, ale myślę, że łatwiej jest po prostu zarządzać każdym oknem.
Window *window
.). Jak to rozwiązać problem?Jak już się przekonałeś, wywołania zwrotne muszą być funkcjami swobodnymi lub funkcjami statycznymi. Oddzwonienia przyjmują
GLFWwindow*
jako swój pierwszy argument zamiast automatycznegothis
wskaźnika.Z GLFW możesz używać
glwSetWindowUserPointer
iglfwGetWindowUserPointer
do przechowywania i pobierania referencjiWindowManager
lubWindow
instancji dla okna .Pamiętaj, że GLFW nie korzysta z funkcji wirtualnych żadnego bezpośredniego polimorfizmu, ponieważ jest to czysty interfejs API języka C. Takie interfejsy API zawsze przyjmują funkcje bezpłatne (C nie ma żadnych klas lub funkcji składowych, wirtualnych lub innych) i przekazują jawne „instancje obiektów” jako parametry (zwykle jako pierwszy parametr; C nie ma
this
). Dobre interfejsy API C zawierają również funkcję wskaźnika użytkownika (czasami nazywaną między innymi „danymi użytkownika”), więc nie musisz używać globałów.stara odpowiedź:
Jeśli chcesz uzyskać dostęp do innych danych w swoim
WindowManager
(lub innych systemach), może być konieczne, aby były one globalnie dostępne, jeśli chcesz uzyskać dostęp do nich z oddzwaniania. Na przykład, miej globalnystd::unique_ptr<Engine>
, którego możesz użyć, aby uzyskać dostęp do menedżera okien, lub po prostu stwórz globalnystd::unique_ptr<WindowManager>
(zamień nastd::unique_ptr
coś „lepszego dla singletonów”, jeśli chcesz).Jeśli chcesz obsługiwać wiele okien, będziesz także
WindowManager
zawierał strukturę danych do mapowaniaGLFWwindow*' 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 * `, które otrzymali, aby wyszukać potrzebne dane.źródło