2008-09-13 17 views
4

Momentan verwendet meine App nur Direct3D9 für Grafiken, aber in der Zukunft plane ich, dies auf D3D10 und möglicherweise OpenGL zu erweitern. Die Frage ist, wie kann ich das sauber machen?C++ mit mehreren Grafikoptionen

Derzeit gibt es verschiedene Render-Methoden in meinem Code

void Render(boost::function<void()> &Call) 
{ 
    D3dDevice->BeginScene(); 
    Call(); 
    D3dDevice->EndScene(); 
    D3dDevice->Present(0,0,0,0); 
} 

Die Funktion dann über den genauen Zustand übergeben, hängt zB MainMenu-> Render, Belade-> Render usw. Diese werden dann die oftern nennen Methoden anderer Objekte.

void RenderGame() 
{ 
    for(entity::iterator it = entity::instances.begin();it != entity::instance.end(); ++it) 
     (*it)->Render(); 
    UI->Render(); 
} 

Und eine Beispielklasse von Unternehmen abgeleitet :: Base

class Sprite: public Base 
{ 
    IDirect3DTexture9 *Tex; 
    Point2 Pos; 
    Size2 Size; 
public: 
    Sprite(IDirect3DTexture9 *Tex, const Point2 &Pos, const Size2 &Size); 
    virtual void Render(); 
}; 

Jede Methode kümmert sich dann um, wie am besten, die detailliertere Einstellungen gegeben zu machen (zB sind Pixel-Shader unterstützt oder nicht).

Das Problem ist, ich bin wirklich nicht sicher, wie diese in der Lage sein, verlängern eines zu verwenden, was etwas anders (D3D v OpenGL) sein kann Rendermodi ...

Antwort

6

eine Schnittstelle definieren, das ausreicht, für die Grafikausgabe Ihrer Anwendung. Implementiere dann diese Schnittstelle für jeden Renderer, den du unterstützen willst.

class IRenderer { 
    public: 
    virtual ~IRenderer() {} 
    virtual void RenderModel(CModel* model) = 0; 
    virtual void DrawScreenQuad(int x1, int y1, int x2, int y2) = 0; 
    // ...etc... 
}; 

class COpenGLRenderer : public IRenderer { 
    public: 
    virtual void RenderModel(CModel* model) { 
     // render model using OpenGL 
    } 
    virtual void DrawScreenQuad(int x1, int y1, int x2, int y2) { 
     // draw screen aligned quad using OpenGL 
    } 
}; 

class CDirect3DRenderer : public IRenderer { 
    // similar, but render using Direct3D 
}; 

Richtig entwerfen und pflegen dieser Schnittstellen kann jedoch sehr schwierig sein.

Falls Sie auch mit Rendertreiber-abhängigen Objekten wie Texturen arbeiten, können Sie ein Factory-Muster verwenden, damit die separaten Renderer jeweils ihre eigene Implementierung von z. ITexture unter Verwendung einer Factory-Methode in IRenderer:

class IRenderer { 
    //... 
    virtual ITexture* CreateTexture(const char* filename) = 0; 
    //... 
}; 

class COpenGLRenderer : public IRenderer { 
    //... 
    virtual ITexture* CreateTexture(const char* filename) { 
     // COpenGLTexture is the OpenGL specific ITexture implementation 
     return new COpenGLTexture(filename); 
    } 
    //... 
}; 

Ist es nicht eine Idee, wenn bei bestehenden (3d) Motoren suchen? Meiner Erfahrung nach lenkt das Entwerfen dieser Art von Interfaces wirklich von dem ab, was du eigentlich machen willst :)

+0

Da ich bereits das d3d9-Zeug für alles, was ich brauche, habe, möchte ich nur die Option auf andere APIs erweitern. Da ich bereits Klassen habe, die die meisten d3d-Sachen umhüllen (zB Textur, Sprite, Mesh), könnte ich diese einfach überladen und die actaul-Objekte mit API-unabhängigen Dingen belassen. –

1

Ich würde sagen, wenn du die Antwort wirklich komplett haben willst, schau dir den Quellcode für Ogre3D an. Sie haben beide und OpenGL Backends. Sehen Sie sich an: http://www.ogre3d.org Im Grunde zwingt ihre API-Art Sie in eine D3D-ish-Weise zu arbeiten, Pufferobjekte zu erstellen und sie mit Daten zu füllen und dann Zeichnungsaufrufe für diese Puffer auszuführen. So mag es die Hardware sowieso, also ist es kein schlechter Weg.

Und dann, wenn Sie sehen, wie sie Dinge tun, können Sie auch nur einfach weitermachen und es sich sparen, die Mühe, alles neu zu implementieren, was es bereits bietet. :-)