Saya punya masalah yang mirip dengan ini. Sangat menjengkelkan bahwa ada sedikit dokumentasi tentang penggunaan glfwSetWindowUserPointer dan glfGetWindowUserPointer. Inilah solusi saya untuk masalah Anda:
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;
}
}
Lagi pula, karena ini adalah salah satu hasil teratas untuk menggunakan GLFW dengan kelas C ++, saya juga akan memberikan metode saya mengenkapsulasi glfwWindow dalam kelas C ++. Saya pikir ini adalah cara yang paling elegan untuk melakukannya, karena ia tidak harus menggunakan global, singleton atau unique_ptrs, memungkinkan programmer memanipulasi jendela dengan gaya OO / C ++ - y yang jauh lebih banyak, dan memungkinkan subklasifikasi (dengan mengorbankan file header yang sedikit lebih berantakan).
// 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
}
Dan untuk:
// 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);
}
Ini mungkin dapat dengan mudah diintegrasikan dengan kelas WindowManager / InputManager, tapi saya pikir akan lebih mudah untuk mengatur setiap jendela itu sendiri.
Window *window
). Bagaimana ini menyelesaikan masalah?Panggilan balik harus berupa fungsi bebas atau fungsi statis, seperti yang Anda ketahui. Callback mengambil
GLFWwindow*
sebagai argumen pertama mereka sebagai penggantithis
penunjuk otomatis .Dengan GLFW Anda dapat menggunakan
glwSetWindowUserPointer
danglfwGetWindowUserPointer
untuk menyimpan dan mengambil referensi keWindowManager
atau contoh per-jendelaWindow
.Ingatlah bahwa GLFW tidak menggunakan fungsi virtual segala jenis polimorfisme langsung karena ini adalah API C murni. API semacam itu selalu menganggap fungsi bebas (C tidak memiliki fungsi kelas atau anggota sama sekali, virtual atau lainnya) dan meneruskan "instance objek" eksplisit sebagai parameter (biasanya sebagai parameter pertama; C tidak memiliki
this
). API C yang bagus juga menyertakan fungsi pointer pengguna (kadang-kadang disebut "data pengguna" di antara hal-hal lain) sehingga Anda tidak harus menggunakan global.jawaban lama:
Jika Anda perlu mengakses data lain di
WindowManager
(atau sistem lain) Anda, Anda mungkin harus membuatnya dapat diakses secara global jika Anda ingin mengaksesnya dari callback. Misalnya, memiliki globalstd::unique_ptr<Engine>
yang dapat Anda gunakan untuk mengakses window manager Anda, atau hanya membuat globalstd::unique_ptr<WindowManager>
(gantistd::unique_ptr
dengan sesuatu yang "lebih baik untuk lajang" jika Anda mau).Jika Anda ingin dukungan beberapa jendela, Anda juga harus memiliki
WindowManager
beberapa struktur data untuk memetakanGLFWwindow*' 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
GLFWwow * * yang mereka terima untuk mencari data yang mereka butuhkan.sumber