Files
wsg/docs/ARCHI_APP_FACADE.md
T
Jérôme Bousquié cfd8b421a2 plan passage à App
2026-07-07 11:57:57 +02:00

3.9 KiB

ARCHI_APP_FACADE.md : Vers une Architecture Orientée Scène

1. Vision et Objectifs

Le passage d'une orchestration manuelle à une façade App vise à réduire le "boilerplate" tout en conservant la modularité. L'utilisateur utilise désormais une "Recette par défaut" basée sur une structure de Scène, tout en gardant la liberté de construire son moteur "brique par brique" s'il le souhaite.

Les piliers :

  • Déclaratif : Toutes les ressources sont déclarées avant le lancement de la boucle.
  • Orienté Scène : L'utilisateur gère des relations (associations) plutôt que des appels de rendu directs.
  • Flexible : L'injection de l'async est gérée via un Runtime injecté.
  • Transparent : La "recette" est documentée, permettant une déconstruction totale vers les briques de bas niveau (Context, Renderer, PipelineCache).

2. Le Workflow de l'utilisateur (Exemple)

// 1. Déclaration : Initialisation asynchrone
let mut app = App::builder()
    .with_runtime(tokio::runtime::Runtime::new().unwrap()) // Injection de l'async
    .build()
    .await;

// 2. Enregistrement des ressources (Labels identifiants ou références)
let shader_id = app.register_shader("basic", "assets/basic.wgsl");
let mat_id = app.create_material("basic_mat", shader_id); 
let mesh_id = app.create_mesh("my_quad", &vertices, &indices);

// 3. Association dans la scène
app.scene.add_entity("main_quad", mesh_id, mat_id);

// 4. Exécution via un Trait pour la boucle
struct MyGame { /* ... */ }
impl AppHandler for MyGame {
    fn render(&mut self, app: &mut App) {
        // Modification dynamique (ex: transparence, visibilité)
        app.scene.get_material("basic_mat").set_opacity(0.5);
    }
}
app.run(MyGame::new());

3. Gestion des Identifiants (Handles)

Pour éviter les problèmes de Borrow Checker, nous utilisons un système de Handles (ou Label) :

  • Référencement : String (label) ou Handle (interne) pour accéder aux ressources.
  • Accès : L'utilisateur manipule ses ressources via app.scene.get_material("nom") ou en conservant les IDs retournés lors de la création.
  • Sécurité : Les IDs garantissent que la ressource existe toujours dans le dépôt de la Scene.

4. La "Recette" : Comment reproduire manuellement

Si App ne convient pas, voici les étapes de la "recette" interne que l'utilisateur peut répliquer :

  1. Init GPU : Context::new(window) → configure().
  2. Setup PipelineCache : Instancier le cache et compiler les shaders nécessaires.
  3. Setup Renderer : Créer le Renderer avec le format de surface.
  4. Boucle winit :
    • RedrawRequested → Frame::try_new()
    • renderer.render() → renderer.present()
  5. Nettoyage : Gestion propre de la fermeture via elwt.exit().

5. Avantages et Points d'attention

Avantages

  • Performance : Le moteur peut trier les entités pour minimiser les changements de pipelines.
  • Ergonomie : Suppression des appels manuels à device et format dans le main.
  • Sécurité : Séparation claire entre la phase de déclaration (Init) et la phase d'exécution (Loop).

Points d'attention (Portes de sortie)

  • Accès Bas-Niveau : App expose ses champs renderer, context et cache en public. Un utilisateur avancé peut toujours bypasser app.scene pour des besoins très spécifiques.
  • Gestion Async : Le choix du runtime reste la responsabilité de l'utilisateur. App se contente d'exécuter les futurs fournis.
  • Dynamisme : Si une ressource doit être créée en cours de jeu, l'utilisateur doit l'ajouter dans la Scene via une méthode app.scene.add_entity(...) qui est thread-safe.

6. Synthèse des responsabilités

  • App : Orchestrateur principal, propriétaire de la Window et de la Surface.
  • Scene : Dépôt de ressources et gestionnaire de visibilité/associations.
  • AppHandler : Trait de logique utilisateur, séparant update et render.