i figure it would be a better idea to design my engine/framework to be agnostic of the API backends used below
The very first question you need to ask yourself is why do this at all? Unless you're actually planning to port your code to D3D or some other API today, this kind of architecture astronaut thinking will likely just waste your time. And if you are planning to port to D3D today, why? You have code that works for OpenGL already, which works on every major desktop platform. What concrete benefit is your game going to get out of the ability to switch rendering backends?
Now the problem i'm having is that i can't quite figure out a good way
to do this. How high-level is enough? Does anybody have a guideline to this, or good examples?
This is usually because you don't have a clear set of requirements about what this abstraction should provide. You should figure that out for yourself (it's not really possible for others to tell you what your usage goals should be).
What I'd recommend you do to tackle this is think of the lowest-level of abstraction you want the rest of your code to interact with, graphics-wise. For me, this is basically "textures, shaders and geometry" where "geometry" is "a collection of vertex and index buffers." To that end I'd write an abstraction that bundles up a collection of buffers and calls it Geometry
. I would not write a Buffer
class and implement it as D3DBuffer
and OpenGLBuffer
. That way lies madness: there are a lot of subtle differences between the buffer (and other similar) concepts in both APIs, and that can result in a very leaky abstraction.
It's very hard to say how high-level is good enough. That's got to be up to you and your needs. What is easier is to say how how low-level is not good enough. You need to provide some actual abstraction over these rendering APIs, some actual distance between them and the rest of your code. If your implementation of your abstraction ends up looking a lot like
void SomeFunction() {
#ifdef OPENGL
glSomeFunction();
#else
SomeD3DFunction();
}
then your abstraction is probably too low-level. Think bigger. Look at the where your gameplay code interacts with your rendering code and identify points where you think there's too much boilerplate, push those into your rendering abstraction.
Make it actually do some useful work for you rather than just translate calls from one API to another.