Application c++ contenu dynamique ?

Salut à tous.

Je suis un peu coincé.
J’aimerais faire une application en c++ avec opengl, mais avec un contenu dynamique depuis fichier externe.

Pour vous expliquez en court:

Fichier C++:

  • j’ouvre un contexte opengl (ce qui permet d’exécuté du code opengl)
  • dans ma boucle principale, j’exécutes des codes opengl (ce qui m’affiche de beau carré dans ma fenêtre)

Fichier texte:

  • J’ai juste du code opengl: qui permet d’afficher des triangles.
  • 5 minutes plus tard, on remplace le codes opengl du fichier texte, avec des codes opengl pour qu’il affiche des ronds.

J’aimerais que mon application C++ compilé: puisse inclure les codes du fichier externe, puis les exécutes dans ma boucle principale.

Ceci est-il possible ? (je crois que non, mais j’aimerais quand même posé)

/!\ Je ne suis pas programmeur. /!\

… mais, c’est qui qui va compiler le code C++ contenu dans ton fichier texte ?

Il me semble que dans ce genre là, le mieux qu’on puisse faire c’est d’utiliser des shaders (GLSL) qui peuvent être contenus dans des fichiers à part.

Mon but est d’avoir un rendu dynamique.

  1. compilation application c++
  2. execution application: il affiche un rendu, après x temps, il m’affiche un autre rendu dont le code est dans un fichier externe.

Je sais pas si avec GLSL c’est possible, j’ai juste suivit un peu les cours de base, dessiner des choses simple.

J’ai entendu parler de glsl mais je croyais que c’est juste pour appliquer des ajouts sur le rendu.
Je vais googler.

Moi je ne connais pas OpenGL (décidément t’es mal barré avec des gens qui connaissent que la moitié du problème :laughing:) mais la solution qui me saute aux yeux c’est de créer un DSL (domain-specific language) que tu utiliseras dans ton fichier texte, et en C++ tu écris un parseur qui va transformer ce DSL en appels OpenGL, éventuellement avec une étape AST (abstract syntax tree) intermédiaire si tu réutilises les séquences de nombreuses fois.

Bref, un mini compilateur/interpréteur dédié à tes besoins, qui traite non pas du C++ mais un mini langage que tu vas créer toi-même.

En fait c’est comme interfacer du C ou asm dans le C++, ce qui est courant.

Sa semble parfait, je vais voir un peu de quoi il s’agit et les détails.

Surtout que j’ai aussi en parallèle un but: analyse code-parser-interpréter.

OpenGL, pour faire court:

  • contexte opengl
  • code opengl

Avec un langage: c, c++, python etc.
On créer une fenêtre via gtk, qt, etc.

À l’intérieur de la fenêtre (dans les codes), on ajoute un contexte opengl, qui pourra faire fonctionner notre code opengl.

Le code opengl, exemple: tu lui dis fait moi une ligne de x à y, et à l’affichage de ton application tu as une ligne de l’endroit x à y.
Via opengl, tu peux tous dessiner (et ainsi le colorier, transformer etc).

Quand on ouvre un contexte opengl, on consomme directement 30-40mb de ram !
C’est un peu pour cet raison et d’autres, que je veux utiliser qu’un seul contexte.

En fait ce que je disais c’est pas bien différent que de lire un fichier de config texte :

  • tu transformes le texte en objects C++ (étape parser => AST)
  • tu traites ces objets (étape AST => interpréteur)

Le fait que derrière tu utilises de l’OpenGL n’est qu’un détail.

Avec un peu de polymorphisme bien pensé (classe de base qui fournit une interface abstraite / classes dérivées concrètes) tu peux même réduire la partie interpréteur à néant : le parser instancie directement la bonne classe dérivée et ensuite tu n’as plus qu’à appeler l’interface abstraite sans te poser de questions. Autrement dit ton AST est directement exécutable.

De manière extrêmement simplifiée ça pourrait donner un truc du genre (non je n’ai pas essayé de le compiler, mais ça devrait marcher à une ou deux typos près, en rajoutant les bons [mono]#include[/mono]s et sous réserve d’un compilateur compatible C++11) :

[code]struct Base {
Base(size_t pos) : m_pos(pos) {}
virtual ~Base() = default;
virtual void run() const = 0;
const size_t m_pos;
};

struct DerivA : public Base {
using Base::Base;
virtual void run() const override {
// en vrai ça sera un appel OpenGL adapté à “A”
std::cout << "je suis un A en position " << m_pos << std::endl;
}
};

struct DerivB : public Base {
using Base::Base;
virtual void run() const override {
// en vrai ça sera un appel OpenGL adapté à “B”
std::cout << "je suis un B en position " << m_pos << std::endl;
}
};

int main() {
const std::string data = “ABAABAAABBBABABA”;
std::vector<std::unique_ptr> ast;
// parser
for (size_t i = 0; i < data.size(); ++i) {
if (data[i] == ‘A’)
ast.emplace_back(std::unique_ptr(new DerivA(i)));
else if (data[i] == ‘B’)
ast.emplace_back(std::unique_ptr(new DerivB(i)));
else
throw std::runtime_error(“seuls A ou B sont acceptés”);
}
// interpréteur (si on peut encore appeler ça comme ça)
for (const auto& obj: ast)
obj->run();
}[/code]
Bien entendu là c’est super simplifié (surtout au niveau du parser :mrgreen: et pourtant il utilise déjà 90% du code de [mono]main[/mono]) mais l’idée générale est là.

Si on ne cherche pas à réinventer la poudre, on peut également utiliser des outils qui font déjà ce boulot comme Lua qui est justement un interpréteur fait pour être embarqué dans du C/C++.

Ça dépend des besoins. S’il s’agit juste d’une liste de polygones à afficher (et j’ai bien l’impression que c’est le cas), embarquer un interpréteur Lua c’est un peu comme utiliser un rouleau compresseur pour ouvrir une porte : ça va apporter plus de problèmes que ça n’en résoudra. :wink:
Un simple parser basé sur [mono]boost.spirit[/mono] avec quelques classes polymorphiques comme j’ai montré sera plus rapide à mettre en place AMHA (et largement plus performant au runtime en plus).

Ton code marche bien:
je suis un A en position 0
je suis un B en position 1
je suis un A en position 2
je suis un A en position 3
je suis un B en position 4
je suis un A en position 5
je suis un A en position 6
je suis un A en position 7
je suis un B en position 8
je suis un B en position 9
je suis un B en position 10
je suis un A en position 11
je suis un B en position 12
je suis un A en position 13
je suis un B en position 14
je suis un A en position 15

Je vais essayer d’adapter.

Grand merci à vous.

Ça dépend des besoins. S’il s’agit juste d’une liste de polygones à afficher (et j’ai bien l’impression que c’est le cas), embarquer un interpréteur Lua c’est un peu comme utiliser un rouleau compresseur pour ouvrir une porte : ça va apporter plus de problèmes que ça n’en résoudra. :wink:
Un simple parser basé sur [mono]boost.spirit[/mono] avec quelques classes polymorphiques comme j’ai montré sera plus rapide à mettre en place AMHA (et largement plus performant au runtime en plus).[/quote]
Bof. boost c’est une arme de guerre. Ce que tu présente c’est une AST trop basique pour voir quoi que ce soit (pas de contexte pas de maramètre).
Je pense que ça dépend des besoins :
[ul]
[li]si tu as besoin d’un langage puissant soit tu veux faire simple et tu fait du lua, soit tu souhaite avoir une maîtrise totale de ton langage et tu utilise quelque chose comme spirit (mais faut pas croire c’est complexe)[/li]
[li]si tu as vraiment besoin de choses simples, alors utiliser un parser json ou yaml par exemple est bien plus simple[/li][/ul]

L’argument de la performance en soit ne me semble pas très pertinent (je suis toujours réticent à parler de perf’), créer ton contexte OpenGL est probablement beaucoup plus lourd que parser tes fichiers même en XML avec XPath (ce qui est probablement la solution la plus complexe). Si tu te permet d’être monothreadé et de charger l’ensemble du fichier avant de l’exécuter, c’est que tu n’a pas de problème de performance. De plus de ce que j’ai compris. Ce que tu souhaite c’est grosso modo avoir une fenêtre et lui faire charger un fichier ou un autre quand tu le souhaite à la volée, tu n’a pas la contrainte forte de faire du temps réel (parser et afficher l’image en 1/60s). Bref parler de performance me semble mal placé, la complétude (gérer toutes les fonctionnalités que tu souhaite), la correction (ne pas avoir de bug) et la maintenabilité (faire des choses « simples »), me semble nettement plus prioritaire (mais ce n’est qu’un avis).

“De plus de ce que j’ai compris. Ce que tu souhaite c’est grosso modo avoir une fenêtre et lui faire charger un fichier ou un autre quand tu le souhaite à la volée”

Quand on y pense, oui c’est exactement, ça.

Pour préciser mon but:

  • une fenêtre principale avec un contexte opengl, sans contenu, ni bordure.
  • des fenêtres (et leurs contenus) (fait totalement en opengl), devront être le contenu de la fenêtre principale.

Comme un système de fenêtrage si on peut dire, mais mon application principale devrait à la fois gérer le fenêtrage et le contenu et leurs sous-fonctionnements.

Je suis un peu mélangé dans ma tête pour choisir le bon choix du fonctionnement.

Mais quoi que je choisisses au final, je devrais bien charger ces codes d’exterieur et les exécuter.
La performance est préférable, je m’attends pas à une rapiditer extrème, j’aimerais juste que la fenêtre s’affiche à une vitesse normale (comme les fenêtres actuel que nous utilisons).

[quote=“kripteks”]Mais quoi que je choisisses au final, je devrais bien charger ces codes d’exterieur et les exécuter.
La performance est préférable, je m’attends pas à une rapiditer extrème, j’aimerais juste que la fenêtre s’affiche à une vitesse normale (comme les fenêtres actuel que nous utilisons).[/quote]
Oui mais justement je pense que c’est des cas où tu ne verra pas la différence de performance.