Bonjour à tous,
Ce post fais suite à celui-ci : http://www.developpez.net/forums/d12...programmation/.
Je viens demander votre aide pour résoudre un problème de design. En effet, pour la suite j'ai besoin de partir sur de bases saines, afin par la suite de ne pas à avoir à recommencer une n-ième fois..
Voici l'ensemble du problème résumé ci-dessous :
- La bibliothèque va être un moteur de rendus multi-api (typiquement opengl et directx, mais pourquoi pas opengl es, software, etc).
- Si besoin le choix de l'api peut se faire à la compilation, grâce aux templates, préprocesseur ou tout autre manière. Mais cela n'est pas une obligation et dépendra du design général.
- boost et c++11 sont fortement conseillés
- Le moteur doit être facilement extensible.
- Éviter les pointeurs nus au maximum!
Voici le schéma général : une ressource CPU devient une ressource GPU, et un renderer applique tout un tas de traitements dessus. En effet, le traitement différé (dans un renderer) est obligatoire pour des raisons liés aux APIs.
Par exemple:
Maintenant je cherche à trouver un bon design pour tout cela. J'ai donc trouver plusieurs pistes, chacune possédant plusieurs avantages et inconvénients.
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10 class shader_base { shader_base(const std::string &src); }; class ogl_shader {}; class dx_shader {}; // Le shader (ressource GPU), est crée à partir d'un code source (ressource GPU). // Il sera ensuite binder par le bon renderer.
Je vais les exposer ci-dessous. J'espère que vous pourrais me donner une direction, ou même une voie perpendiculaire à tout ça
- Visiteur
Je suis tout d'abord partis sur le design pattern du visiteur, surtout inspiré par l'article d'Emmanuel Deloget. Malheureusement, il en ressort que c'est peut-être pas le plus adapté dans le choix où l'api serait choisit à la compilation : en effet dans un pareil cas, il perd son intérêt non?
Mais surtout qu'il crée des dépendances entre les classes, et complique l'ajout de fonctionnalités.
- Template
Pour cela j'ai pensé créer une classe template renderer, spécialisé suivant les APIs par des classes "tags".
Cette fois-ci le problème c'est que certaines classes dépendaient de l'api alors que ça ne devait pas être le cas : imaginons une classe material constitué de shaders. Comment je déclare les shaders dans ma classe material, sans faire renderer<ogl>::shader_type?
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13 template<typename T> class renderer; struct ogl {}; // tag opengl template<> class renderer<ogl> { typename ogl_shader shader_type; typename ogl_texture texture_type; // ainsi de suite };
Et cela pose problème car cette classe doit être indépendante de l'api.
- Préprocesseur
Dans les choix de l'API à la compilation j'ai opté pour la solution suivante à base de préprocesseur:
Et ce fichier serait inclus partout où l'on se sert des objets liés aux APIs. Néanmoins cela oblige donc tout le monde à avoir accès à plus que l'interface de base par exemple..
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10 #if defined USE_OPENGL typename ogl_shader shader_type; typename ogl_texture texture_type; // ainsi de suite #elif defined USE_DIRECTX // rebelote #endif
Et puis j'aime bien les templates
- Interface abstraite
Cette fois-ci c'est un renderer abstrait comme suivant (basé sur un article de Laurent Gomilla http://loulou.developpez.com/tutorie.../partie8/#L4.3):
Seulement cela oblige dans les classes filles à downgrader les classes reçus en paramètres de la façon suivante:
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8 class renderer_base { virtual std::shared_ptr<shader_base> createShader(/*...*/) = 0; virtual void bind(const std::shared_ptr<shader_base> &s) = 0; // ... };
Cela m'embête un peu de downgrader comme ça, au tant du point de vue design que performance.
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10 class renderer_ogl { virtual void bind(const std::shared_ptr<shader_base> &s) { auto shader = std::static_pointer_cast<shader_ogl>(s); // suite du code ... } };
Donc j'espère bien que quelqu'un pourra m'éclairer et que mon post n'est pas trop longQuitte à proposer une autre solution à base de traits ou autre!
Merci d'avance!
Partager