Context : I'm developing my own graphic engine. I'm trying to follow the SOLID principles and rely on polymorphism and virtual inheritance as much as I can to get a generic interface for different modules of my engine (window, user configuration, input).
Goal : I want my program to be able to display a window in a generic way and returning me a pointer to a window, regardless of the library used, a pointer that I can then use in the rest of my program. So far I have tried working with GLFW, SFML and SDL and have managed to successfully display a window with an interface like this :
// Prototypes
// IWindow.h
class IWindow
{
protected:
void* pWindow;
bool isOpen;
public:
IWindow() : pWindow(nullptr), isOpen(true) {}
virtual void getEvent() = 0;
virtual void create(int,int) = 0;
virtual bool windowShouldClose() {return this->isOpen;};
virtual ~IWindow(){};
};
// GLFWindow.h
#include "IWindow.h"
class GLFWindow : public IWindow
{
public:
GLFWindow();
void create(int,int) override final;
void getEvent() override final;
~GLFWindow(){};
};
// Implementations
// GLFWindow.cpp
#include "GLFWindow.h"
#include <GLFW/glfw3.h>
void GLFWindow::create(int height,int width)
{
glfwInit();
glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
glfwWindowHint(GLFW_RESIZABLE, GLFW_FALSE);
pWindow = static_cast<void*>(glfwCreateWindow(height, width, "Vulkan", nullptr, nullptr));
};
void GLFWindow::getEvent()
{
glfwPollEvents();
this->isOpen = !glfwWindowShouldClose(static_cast<GLFWwindow*>(pWindow));
}
// Implementations for SDL and SFML quite similar....
// main.cpp
//[...] creation of windowManager which is a pointer of type IWindow
windowManager->create(config->window_w,config->window_h); // width and height of window
while (windowManager->windowShouldClose()) //loopEvent
{
windowManager->getEvent();
}
The library is chosed through a string in a YAML file, among GLFW, SDL and SFML.
Problem : I chose to rely on a void pointer for the window pointer to not depend on any of the library implementations (GLFWindow*, SDL_Window* for instance). The downside of that is I have to cast the window pointer to a void pointer each time I want to work with the libraries. Ultimately, what I want is my create method to be able to return me a generic window pointer
auto window {windowManager->create(config->window_w,config->window_h)};
because right now I don't have access to the window pointer directly in my main.
What I've tried :
- First I was inspired by this : When to use a void pointer?
- Then I wanted to get rid of the void pointer due to lack of type safety so I replaced the void pointer to a PIMPL. With a PIMPL, I managed to get rid of the casting but it could't let me access the original window pointer : How to access private member of impl class from original class using PIMPL approach
- I also looked at type erasure : "Type Erasure enables you to use various concrete types through a single generic interface." But I can't find a way to return a generic window pointer.
- I also looked at covariant types for virtual functions.
- In the end, I started to read about static polymorphism and template : https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#Rt-generic-oo
And then I got lost. I'm looking for guidance on how to tackle this problem regarding the path I've explored.