Salut! Je n'ai pas donné de nouvelles depuis longtemps, mais il va y avoir beaucoup de changement au niveau de ce projet, en effet.
J'ai remarqué la lenteur de la SFML et on m'a clairement fait savoir que la SFML n'était clairement pas une référence pour utiliser opengl de manière performante pour de gros projets. On m'a également dit que la création d'un contexte opengl par texture de rendu n'est pas une bonne solution qu'il valait mieux n'utiliser qu'un seul contexte. (Bien que dans un contexte multithread ou pour créer plusieurs fenêtre pas le choix, mais dans le cas du multithreading on m'a conseillé d'utiliser VULKAN)
Et je vais avoir besoin du multithreading pour faire plusieurs rendus hors écran simultanément (SFML ne le fait pas par défaut) en même temps, car, les appels à glDraw pour toutes mes textures de rendu sont lent, même si j'utilise le bindless texturing et les buffers pour ne faire qu'un seul appel à glDraw par texture de rendu.
Autre chose qui ralenti (mais côté CPU ici) ce sont les fonctions virtuelles, en effets, la recherche de la bonne fonction à appeler se fait à l'exécution et la SFML utilise des fonctions virtuelles.
J'ai alors réfléchi à une autre solution, sans pour autant supprimer l'héritage parce que j'avais pensé à un système de type ECS mais dans ce cas je devrais récupérer les composants de transformations de toutes les entités enfants, les enfants des enfants, etc... et calculer la matrice de transformation finale combinée et également les positions relatives hors que avec l'héritage je peux faire ça automatiquement avec une méthode onMove par exemple que je redéfini, comme ça, tout se remet à jour automatiquement à chaque fois que j'appelle move, sinon je devrai le faire manuellement après chaque appel à move. (SFML ne possède pas de méthode onMove)
Alors j'ai recherché une solution pour pouvoir utiliser l'héritage sans utiliser de fonctions virtuelles comme le fait la SFML, et j'ai trouvé une solution, qui utilise les templates variadique et le polymorphisme d'inclusion.
J'ai testé ça dans la fonction main la rapidité et je me suis rendu compte que c'est vachement plus rapide (4 fois plus rapide) que d'utiliser des fonctions virtuelles comme le fait la SFML, en plus j'en utilise pas mal dans ODFAEG actuellement, ce qui ralenti.
La solution que j'ai trouvée est d'inclure chaque nouveau type dans un tuple, et générer une série de fonctions qui vont se charger d'appeler un foncteur, sur le bon type. (En faisant une vérification (SFINAE) sur le nombre d'arguments et le type des arguments dans le cas d'une surcharge de fonction pour pas que le compilateur râle parce qu'il ne trouve pas la fonction lors de l'appel)
Et à l'exécution il va choisir la bonne fonction à appeler suivant le type, au moyen de if, else..., le type n'est rien d'autre que la position du type dans le "parameter pack".
Voici un code qui montre ce que ça donne au niveau de l'utilisation, j'ai testé et, ça à l'air vraiment cool, comme le type du tuple change à l'exécution je ne peux pas le stocker dans une classe en tant que variable membre, mais je peux le créer et le passer à une fonction (la boucle de jeux) ce qui m'évite de devoir utiliser un global.
Je pense également à mettre les constructeurs en privé et utiliser une factory qui va se charger de gérer les variables globale, plutôt qu'utiliser des variables statiques qui pose problème lors de l'utilisation de plugin, vu que sur windows, elles ne sont pas partagées lors de l'appel du pointeur de fonction extrait de l'une dll.
struct transformable {
template<typename D>
void move() {
static_cast<D&>(*this).onMove();
}
};
struct entity : transformable {
unsigned int containerIdx, childrenContainerIdx, type, childrenContainerType, id;
static unsigned int nbEntities;
std::string managerName;
entity() : transformable () {
id = nbEntities;
nbEntities++;
}
template <typename D, typename EntityManager>
auto addChild(EntityManager& em, D* entity) {
auto newem = em.add(entity);
return newem;
}
template <typename EntityManagerArray, typename D, typename... Args, size_t... Ints, class = typename std::enable_if<sizeof...(Args) == 3>::type>
void operator()(EntityManagerArray& ema, D* entity, std::string f, std::tuple<Args...> args, std::index_sequence<Ints...>) {
if (f == "move") {
move(ema, entity, std::get<Ints>(args)...);
}
}
template <typename R, typename EntityManagerArray, typename D, typename... Args, size_t... Ints, class = typename std::enable_if<sizeof...(Args) == 3>::type>
void operator()(EntityManagerArray& ema, D* entity, std::string f, std::tuple<Args...> args, std::index_sequence<Ints...>, R& ret) {
if (f == "move") {
ret = move(ema, entity, std::get<Ints>(args)...);
}
}
template <typename R, typename EntityManagerArray, typename D, typename... Args, size_t... Ints, class... E, class = typename std::enable_if<sizeof...(Args) == 0>::type>
void operator()(EntityManagerArray& ema, D* entity, std::string f, std::tuple<Args...> args, std::index_sequence<Ints...>, R& ret) {
if (f == "f") {
ret = func();
}
}
float func() {
return 1.1f;
}
template <typename EntityManagerArray, typename D>
bool move(EntityManagerArray& ema, D* entity, float x, float y, float z) {
transformable::move<D>();
auto tp = std::make_tuple(x, y, z);
ema.apply(entity->childrenContainerType, entity->childrenContainerIdx, "move", tp);
return true;
}
void onMove() {
}
};
unsigned int entity::nbEntities = 0;
struct sphere : entity
{
sphere() : entity() {
}
void onMove() {
std::cout<<"update datas on sphere instance : "<<id<<" moved"<<std::endl;
}
};
struct rectangle : entity
{
rectangle() : entity() {
}
void onMove() {
std::cout<<"update datas on rectangle instance : "<<entity::id<<" moved"<<std::endl;
}
};
struct convexshape : entity
{
convexshape() : entity() {
}
void onMove() {
std::cout<<"update datas on convex shape instance : "<<entity::id<<" shape"<<std::endl;
}
};
template <typename D>
struct appli {
bool running = false;
bool isRunning () {
return running;
}
template<typename EntityManagerArray>
void update(EntityManagerArray em) {
}
template<typename EntityManagerArray>
void init(EntityManagerArray& em) {
static_cast<D*>(this)->onInit(em);
}
template<typename EntityManagerArray>
void exec(EntityManagerArray& ema) {
if (!running) {
running = true;
init(ema);
}
while(running) {
static_cast<D*>(this)->onExec(ema);
}
}
};
struct myappli : appli<myappli> {
sphere sph;
rectangle rect, rect2;
convexshape shape, shape2;
myappli() : appli<myappli>() {
}
template<typename ManagerArrayEntity>
void onInit(ManagerArrayEntity& ema) {
sph.managerName="entity managers";
rect.managerName="entity managers";
shape.managerName="entity managers";
::EntityManager<IEntityManager, entity> ems;
//ems.name = "entity managers";
::EntityManager<IEntityManager, entity> childrenem;
//childrenem.name = "sphere children manager";
auto children0em = sph.addChild(childrenem, &rect2);
auto children1em = sph.addChild(children0em, &shape2);
children1em.name = "sphere children";
auto em = ems.add(&shape).add(&rect).add(&sph);
em.name = "entity managers";
auto emas = ema.add(&em).add(&children1em);
sph.childrenContainerIdx = children1em.containerIdx;
sph.childrenContainerType = children1em.type;
exec(emas);
}
template<typename ManagerEntityArray>
void onExec(ManagerEntityArray& ema) {
bool retb;
auto tp = std::make_tuple(1.1f, 2.2f, 3.3f);
ema.apply(0, 0, sph.type, sph.containerIdx, "move", tp, retb);
float retf;
auto tp2 = std::make_tuple();
ema.apply(0, 0, sph.type, sph.containerIdx, "f", tp2, retf);
std::cout<<"rets : "<<retb<<","<<retf<<std::endl;
ema.apply(0, 0, rect.type, rect.containerIdx, "move", tp, retb);
ema.apply(0, 0, shape.type, shape.containerIdx, "move", tp, retb);
}
};
int main(int argc, char* argv[])
{
myappli appli;
EntityManagerArray<IEntityManager> entityManagerArray;
appli.exec(entityManagerArray);
De gros changements sont à venir donc..., je ne sais pas si ODFAEG va rester un projet SFML, mais en tout cas le design de la SFML va être remplacé. (Enfin tout dépendra de la rapidité de ce nouveau design à l'exécution lorsque je l'implémenterai dans le framework et surtout, si ça fonctionne pour tout mes projets utilisant le framework.)