c ++ Наличие нескольких графических опций - PullRequest
4 голосов
/ 13 сентября 2008

В настоящее время мое приложение использует только Direct3D9 для графики, однако в будущем я планирую расширить его до D3D10 и, возможно, OpenGL. Вопрос в том, как мне сделать это аккуратно?

В настоящее время в моем коде есть различные методы Render

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

Переданная функция зависит от точного состояния, например MainMenu-> Render, Loading-> Render и т. Д. Затем они часто вызывают методы других объектов.

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

И пример класса, производного от entity :: Base

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

Каждый метод затем заботится о том, как лучше всего отрендерить, учитывая более подробные настройки (например, поддерживаются пиксельные шейдеры или нет).

Проблема в том, что я действительно не уверен, как расширить это, чтобы можно было использовать один из режимов рендеринга (D3D v OpenGL), которые могут несколько отличаться ...

Ответы [ 2 ]

6 голосов
/ 13 сентября 2008

Определите интерфейс, достаточный для требований графического вывода вашего приложения. Затем реализуйте этот интерфейс для каждого средства визуализации, которое вы хотите поддерживать.

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
};

Правильная разработка и поддержка этих интерфейсов может быть очень сложной задачей.

В случае, если вы также работаете с объектами, зависящими от драйвера рендеринга, такими как текстуры, вы можете использовать фабричный шаблон, чтобы отдельные рендереры создавали свою собственную реализацию, например. ITexture с использованием заводского метода в 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);
    }
  //...
};

Разве не стоит взглянуть на существующие (3d) движки? По моему опыту, разработка такого рода интерфейсов действительно отвлекает от того, что вы действительно хотите сделать:)

1 голос
/ 16 сентября 2008

Я бы сказал, что если вы хотите действительно полный ответ, посмотрите исходный код Ogre3D. Они имеют как D3D, так и OpenGL задние части. Посмотрите на: http://www.ogre3d.org По сути, их API-интерфейс вынуждает вас работать в D3D-стиле, создавая объекты буфера и заполняя их данными, а затем отправляя вызовы отрисовки этих буферов. Так или иначе, аппаратному оборудованию это нравится, так что это неплохой путь.

И затем, как только вы увидите, как они работают, вы можете просто пойти дальше и использовать его и избавить себя от необходимости заново реализовывать все, что оно уже обеспечивает. : -)

...