Im creating a window class in C++ to provide a bit of abstraction for a GLFW window. To me it makes sense to add a key_callback as a method in my class. The issue is ofcourse that GLFW is written in C, and so it requires callbacks to be static.
I found that GLFW has a glfwSetWindowUserPointer function that sets:
.. sets the user-defined pointer of the specified window.. ----- Docs
So I went with the following solution:
In my windowwindow.h:
#pragma once
#define GLFW_INCLUDE_VULKAN
#include <GLFW/glfw3.h>
class Window {
GLFWwindow* window;m_Window;
//GLFWmonitor* Morem_Monitor;
members.. const char* m_Title;
GLFWimage m_Icon[1];
int m_Width, m_Height;
int m_PosX, m_PosY;
bool m_Fullscreen;
public:
Window(...int width, int height, const char* title, const char* iconPath);
// Constructor ~Window();
GLFWwindow* getWindow();
const char** getRequiredExtensions();
private:
//void Stuff...queryVulkanSupport();
void setKeyCallbackinitGLFW();
// Function to setvoid keycallbackcreateWindow();
void setIcon(const char* path);
void center();
void setFullscreen();
void setWindowSizeCallback();
static void static_KeyCallbackstatic_WindowSizeCallback(GLFWwindow* window, int keywidth, int scancode,height);
void windowSizeCallback(int actionwidth, int modsheight);
// The static keycallbackvoid setKeyCallback();
static void keyCallbackstatic_KeyCallback(GLFWwindow* window, int key, int scancode, int action, int mods);
// Non static keycallbackvoid keyCallback(int key, int scancode, int action, int mods);
};
In my windowwindow.cpp:
#include "window.h"
#define STB_IMAGE_IMPLEMENTATION
#include <stb/stb_image.h>
#include <stdexcept>
#include <string>
Window::Window(...int width, int height, const char* title, const char* iconPath)
: m_Fullscreen(false), m_Width(width), m_Height(height), m_Title(title) {
glfwSetWindowUserPointerinitGLFW(window,);
this queryVulkanSupport();
m_Monitor = glfwGetPrimaryMonitor();
createWindow();
setIcon(iconPath);
setWindowSizeCallback();
setKeyCallback();
}
Window::~Window() {
// moreglfwDestroyWindow(m_Window);
stuff glfwTerminate();
}
GLFWwindow* Window::getWindow() {
return m_Window;
}
const char** Window::getRequiredExtensions()
{
uint32_t count;
const char** extensions = glfwGetRequiredInstanceExtensions(&count);
return extensions;
}
void Window::setKeyCallbackqueryVulkanSupport() {
glfwSetKeyCallbackif (!glfwVulkanSupported()) {
throw std::runtime_error("Vulkan not supported!");
}
}
void Window::initGLFW() {
if (!glfwInit()) {
throw std::runtime_error("Failed to initialize GLFW!");
}
}
void Window::createWindow() {
glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
m_Window = glfwCreateWindow(m_Width, m_Height, m_Title, nullptr, nullptr);
if (!m_Window) {
throw std::runtime_error("Could not create GLFW window!");
}
glfwSetWindowUserPointer(m_Window, static_KeyCallbackthis);
/ center();
}
void Window::setIcon(const char* path) {
m_Icon[0].pixels = stbi_load(path, &m_Icon[0].width, &m_Icon[0].height, 0, 4);
if (m_Icon[0].pixels)
glfwSetWindowIcon(m_Window, 1, m_Icon);
}
void Window::center() {
const GLFWvidmode* vidMode = glfwGetVideoMode(m_Monitor);
glfwSetWindowPos(m_Window, (vidMode->width - m_Width) / Set2, keycallback(vidMode->height to- staticm_Height) member/ function2);
}
void Window::static_KeyCallbacksetFullscreen(GLFWwindow*) window{
if (!m_Fullscreen) {
const GLFWvidmode* vidMode = glfwGetVideoMode(m_Monitor);
glfwGetWindowPos(m_Window, int&m_PosX, key&m_PosY);
glfwGetWindowSize(m_Window, int&m_Width, scancode&m_Height);
glfwSetWindowMonitor(m_Window, m_Monitor, 0, 0, vidMode->width, vidMode->height, vidMode->refreshRate);
glfwSetWindowSize(m_Window, vidMode->width, vidMode->height);
m_Fullscreen = !m_Fullscreen;
}
else {
glfwSetWindowMonitor(m_Window, nullptr, m_PosX, m_PosY, m_Width, m_Height, 0);
glfwSetWindowSize(m_Window, m_Width, m_Height);
m_Fullscreen = !m_Fullscreen;
}
}
void Window::setWindowSizeCallback() {
glfwSetWindowSizeCallback(m_Window, static_WindowSizeCallback);
}
void Window::static_WindowSizeCallback(GLFWwindow* window, int actionwidth, int modsheight) {
Window* actualWindow = (Window*) glfwGetWindowUserPointer(window);
// Get a pointeractualWindow->windowSizeCallback(width, toheight);
}
void theWindow::windowSizeCallback(int windowwidth, instanceint thatheight) has{
the actual window. glfwSetWindowSize(m_Window, width, height);
}
void Window::setKeyCallback() {
actualWindow->keyCallbackglfwSetKeyCallback(m_Window, static_KeyCallback);
}
void Window::static_KeyCallback(GLFWwindow* window, int key, int scancode, int action, int mods); //{
Acces that actual Window* actualWindow = (Window*) glfwGetWindowUserPointer(window);
instanceses method actualWindow->keyCallback(key, scancode, action, mods);
}
void Window::keyCallback(int key, int scancode, int action, int mods) {
if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS)
glfwSetWindowShouldClose(m_Window, true);
if (key == GLFW_KEY_F11 && action == GLFW_RELEASE)
setFullscreen();
}
main.cpp
#include "window.h"
int main() {
Window window(600, 300, "Vulkan engine!", "include/Ressources/VulkanIcon.png");
Do stuff. while (!glfwWindowShouldClose(window.getWindow())) {
glfwPollEvents();
}
}
The primary reason that I need(or would like) the callbackcode works as intended. Im really new to be nonstatic is becausec++ tho and I want to use methods from the Windowassume there is tons i could improve about this class inside the callback, not just in terms of speed, but also structure.
Clearly there is some overhead in havingIm especially concerned with the way I get around the fact that GLFW callbacks are static. In my callbacks I want to retriveacces methods in my class and so I create a pointer to the actual instance everytime a button is pressed'window user' using glfwGetWindowUserPointer, to acces the actual class methods an member variables.
Still i'm just looking for any thought on how to improve this code.
Links to so my question is, would you consider this an optimal solution?GLFW and STB.