I'm writing an open source game engine called YoghurtGum for mobile platforms (Windows Mobile, Android). This was one of my big big problems. First I solved it like this:
class RenderMethod
{
public:
virtual bool Init();
virtual bool Tick();
virtual bool Render();
virtual void* GetSomeData();
}
Did you spot the void*? That's because RenderMethodDirectDraw returns a DirectDraw surface while RenderMethodDirect3D returns a vertex pool. Everything else was split as well. I had a Sprite class that had either a SpriteDirectDraw pointer or a SpriteDirect3D pointer. It kind of sucked.
So lately, I've been rewriting things a lot. What I have now is a RenderMethodDirectDraw.dll and a RenderMethodDirect3D.dll. You can, in fact, try to use Direct3D, fail, and use DirectDraw instead. That's because the API remains the same.
If you want to create a sprite, you don't do it directly but through a factory. The factory then calls the correct function in the DLL and converts it into a parent.
So, this is in the RenderMethod API:
virtual Sprite* CreateSprite(const char* a_Name) = 0;
And this is the definition in RenderMethodDirectDraw:
Sprite* RenderMethodDirectDraw::CreateSprite(const char* a_Name)
{
bool found = false;
uint32 i;
for (i = 0; i < m_SpriteDataFilled; i++)
{
if (!strcmp(m_SpriteData[i].name, a_Name))
{
found = true;
break;
}
}
if (!found)
{
ERROR_EXPLAIN("Could not find sprite named '%s'", a_Name);
return NULL;
}
if (m_SpriteList[m_SpriteTotal]) { delete m_SpriteList[m_SpriteTotal]; }
m_SpriteList[m_SpriteTotal] = new SpriteDirectDraw();
((SpriteDirectDraw*)m_SpriteList[m_SpriteTotal])->SetData(&m_SpriteData[i]);
return (m_SpriteList[m_SpriteTotal++]);
}
I hope this makes sense. :)
P.S. I would loved to have used STL for this, but there's no support on Android. :(
Basically:
- Keep every render in its own context. Either a DLL, or a static library or just a bunch of headers. As long as you have a RenderMethodX, SpriteX and StuffX you'r golden.
- Steal as much as you can from the Ogre source.
EDIT: Yes it does make sense to have virtual interfaces like this. If your first attempt fails, you can try another render method. This way you can keep all your code render method agnostic.