I'm creating a window class in C++ to provide a bit of abstraction for a GLFW window.
window.h
#pragma once
#define GLFW_INCLUDE_VULKAN
#include <GLFW/glfw3.h>
class Window {
GLFWwindow* m_Window;
GLFWmonitor* m_Monitor;
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);
~Window();
GLFWwindow* getWindow();
const char** getRequiredExtensions();
private:
void queryVulkanSupport();
void initGLFW();
void createWindow();
void setIcon(const char* path);
void center();
void setFullscreen();
void setWindowSizeCallback();
static void static_WindowSizeCallback(GLFWwindow* window, int width, int height);
void windowSizeCallback(int width, int height);
void setKeyCallback();
static void static_KeyCallback(GLFWwindow* window, int key, int scancode, int action, int mods);
void keyCallback(int key, int scancode, int action, int mods);
};
window.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) {
initGLFW();
queryVulkanSupport();
m_Monitor = glfwGetPrimaryMonitor();
createWindow();
setIcon(iconPath);
setWindowSizeCallback();
setKeyCallback();
}
Window::~Window() {
glfwDestroyWindow(m_Window);
glfwTerminate();
}
GLFWwindow* Window::getWindow() {
return m_Window;
}
const char** Window::getRequiredExtensions()
{
uint32_t count;
const char** extensions = glfwGetRequiredInstanceExtensions(&count);
return extensions;
}
void Window::queryVulkanSupport() {
if (!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, this);
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) / 2, (vidMode->height - m_Height) / 2);
}
void Window::setFullscreen() {
if (!m_Fullscreen) {
const GLFWvidmode* vidMode = glfwGetVideoMode(m_Monitor);
glfwGetWindowPos(m_Window, &m_PosX, &m_PosY);
glfwGetWindowSize(m_Window, &m_Width, &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 width, int height) {
Window* actualWindow = (Window*) glfwGetWindowUserPointer(window);
actualWindow->windowSizeCallback(width, height);
}
void Window::windowSizeCallback(int width, int height) {
glfwSetWindowSize(m_Window, width, height);
}
void Window::setKeyCallback() {
glfwSetKeyCallback(m_Window, static_KeyCallback);
}
void Window::static_KeyCallback(GLFWwindow* window, int key, int scancode, int action, int mods) {
Window* actualWindow = (Window*) glfwGetWindowUserPointer(window);
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");
while (!glfwWindowShouldClose(window.getWindow())) {
glfwPollEvents();
}
}
The code works as intended. I'm really new to c++ though and I assume there are tons I could improve about this class, not just in terms of speed, but also structure.
I'm especially concerned with the way I get around the fact that GLFW callbacks are static. In my callbacks I want to access methods in my class and so I create a pointer to the actual 'window user' using glfwGetWindowUserPointer, to access the actual class methods an member variables.
Still I'm just looking for any thoughts on how to improve this code.