I'm working on a multi render library. The point of it is to have a swapable backend at runtime to render the same item.
The renderer is given to the window (which is a wrapper over SDL2). Then the window is in charge of drawing a IDrawable, which is a virtual class implemented in a namespace for each backend. The implementation of IDrawable in each namespace got the same tag as the backend, for preventing rendering a drawable with the wrong backend.
Here's the code. I would appreciate some reviews on the architecture; what's good and what's wrong.
Thanks!
#include <string>
#include <iostream>
enum Tag
{
VK,
GL
};
class IDrawable
{
public:
virtual void draw() = 0;
virtual Tag getTag() const = 0;
};
namespace gl
{
class D : public IDrawable
{
public:
void draw()
{
std::cout << "Drawable gl::D\n";
}
Tag getTag() const { return tag; };
private:
Tag tag = Tag::GL;
};
}
namespace vk
{
class D : public IDrawable
{
public:
void draw()
{
std::cout << "Drawable vk::D\n";
}
Tag getTag() const { return tag; };
private:
Tag tag = Tag::VK;
};
}
class Backend
{
public:
virtual void render(IDrawable * d) = 0;
};
class Opengl : public Backend
{
public:
void render(IDrawable * d)
{
std::cout << "Backend gl\n";
d->draw();
}
Tag getTag() { return tag; };
private:
Tag tag = Tag::GL;
};
class Vulkan : public Backend
{
public:
void render(IDrawable * d)
{
std::cout << "Backend vk\n";
d->draw();
}
Tag getTag() { return tag; };
private:
Tag tag = Tag::VK;
};
template <typename T>
class Renderer
{
static_assert(std::is_base_of<Backend, T>::value, "Backend not valid");
public:
void draw(IDrawable * d)
{
if(backend.getTag() == d->getTag())
{
backend.render(d);
}
else
{
std::cout << "Cannot render\n";
}
}
T backend;
};
template <typename T>
class Window
{
public:
Window(Renderer<T> r) : rend(r) {}
void draw(IDrawable * d)
{
rend.draw(d);
}
private:
Renderer<T> rend;
};
int main()
{
Renderer<Opengl> a;
Renderer<Vulkan> b;
Window w(a);
Window k(b);
gl::D d1;
vk::D d2;
w.draw(&d1);
k.draw(&d2);
w.draw(&d2); // Should fail
return 0;
}