Files
wsg/docs/DRAFT.md
T
Jérôme Bousquié 6f6b72ae8d docs(draft): valider les décisions restantes Étape 8 (D2, D4, D5, D6)
- D2 : Geometry reste en math (structure de donnees pure), re-export racine
- D4 : voie unique Mesh::from_geometry(Arc<Geometry>) ; suppression de l API &[Vertex]
- D5 : retention CPU (Arc<Geometry>) + buffers GPU pre-uploades
- D6 : convertisseur nomme Geometry::to_vertices() avec regles de remplissage

Toutes les decisions D1-D6 et la proposition 8.1 sont desormais validees.
2026-09-18 08:42:35 +02:00

10 KiB
Raw Blame History

DRAFT — Plan d'implémentation

Usage. Ce fichier (dans docs/) sert de brouillon pour le plan détaillé de l'étape en cours. Son contenu est effacé au début de chaque nouvelle étape. La source de vérité de l'état est le code + README.md ; les autres docs docs/* restent stables.

État. Étape 8 en préparation — refactor du stockage CPU des données géométriques : Mesh contient geometry: Arc<Geometry>. Étape 7 terminée et vérifiée le 2026-09-17.


Étape 8 — Stockage CPU : Mesh contient Arc<Geometry>

Objectif

Donner à Mesh une source de vérité CPU partagée pour sa géométrie, en plus de ses buffers GPU. Le ROADMAP 1.2 demande Mesh { geometry: Arc<Geometry>, vertex_buffer, index_buffer, ... } : on met en œuvre la partie stockage CPU (geometry: Arc<Geometry>), en déviant sur le champ transform (voir Décisions D3).

Valeurs apportées :

  • Réutilisation mémoire : plusieurs meshes peuvent partager le même Arc<Geometry> (ex. deux meshes cube différents partagent une géométrie cube).
  • Base pour les phases suivantes : bounding box (culling, Phase 3), compute transforms, accès UV pour les textures (Phase 4), accès normales pour des calculs CPU.
  • Nettoyage du modèle de données : Geometry existe aujourd'hui (lib/src/math/geometry.rs) mais n'est référencé nulle part dans le code. Il devient le type canonique côté CPU.

État de départ vérifié (2026-09-17)

  • Geometry (lib/src/math/geometry.rs) : { positions: Vec<[f32;3]>, normals, uvs, indices } — défini et ré-exporté mais jamais utilisé (aucune construction, aucun champ lu).
  • Vertex (lib/src/resources/vertex.rs) : tuple CPU position/normal/uv/color → contrat GPU (stride 56 o, VertexBufferLayout construit sur ses offsets, standard shader lit color unlit).
  • Mesh (lib/src/resources/mesh.rs) : { vertex_buffer, index_buffer, num_vertices, num_indices, material: Option<Arc<Material>> }, construit via Mesh::new(device, vertices, indices) / Mesh::with_material. Il n'utilise pas Geometry : il prend des &[Vertex] et les uploade.
  • Scene::create_mesh(id, vertices: &[Vertex], indices, material) (lib/src/scene/scene.rs) uploade via Mesh::new puis lie le matériau. Les buffers GPU restent la seule donnée : aucune rétention CPU.
  • Entity = { mesh_id, transform } ; iter_entities renvoie (&str, &Arc<Mesh>, &Transform) (lib/src/scene/scene.rs). Un mesh est partagé par plusieurs entités à des transforms différents.
  • Le ROADMAP 1.2 liste transform: Transform sur Mesh → déviation justifiée en D3.

Décisions / compromis

# Question Options Décision retenue Justification
D1 Format CPU stocké (a) garder Geometry en tableaux éclatés positions/normals/uvs/indices ; (b) y ajouter colors ; (c) ranger un Vec<Vertex> (a)+(b) : Geometry en tableaux + colors, et conversion Geometry -> Vec<Vertex> — validé 2026-09-18 Respecte le contrat GPU (Vertex) sans duplication conceptuelle : Geometry = données CPU pures, Vertex = format d'upload interleaved. Le shader lit color ⇒ il faut porter la couleur dans Geometry.
D2 Où Geometry vit / qui le ré-exporte (a) reste en math ; (b) déplacé en resources (a) reste en math, ré-exporté de lib.rs — validé 2026-09-18 Cohérent : c'est une structure de données pure, comme Transform/Camera. Exposer via math::Geometry (déjà le cas) + une ré-export resources optionnelle à la convenance.
D3 Champ transform sur Mesh (a) l'ajouter (ROADMAP littéral) ; (b) le laisser sur Entity (b) : transform reste sur Entity — validé 2026-09-18 Un Mesh est partagé par plusieurs entités à des transforms différents (modèle instancé). Mettre un transform unique sur Mesh casserait ce modèle (Étape 4/7). Déviation documentée au ROADMAP 1.2.
D4 API de création (a) Mesh::new(device, vertices, indices) actuel ; (b) Mesh::new(device, geometry) ; garder ou non surcharge (b) : Mesh::from_geometry(device, Arc<Geometry>) ; suppression de l'ancienne voie &[Vertex] dans Mesh et Scene — validé 2026-09-18 Une seule source canonique. Les examples (non contraignants) sont réécrits pour construire une Geometry. Vertex reste utilisé en interne pour l'upload.
D5 Rétention CPU + GPU (a) ne garder que GPU ; (b) garder CPU Arc et les buffers GPU pré-uploadés (b) : Mesh garde geometry: Arc<Geometry> ET vertex_buffer/index_buffer — validé 2026-09-18 Pas de re-upload par frame (perf) ; le Arc sert les phases futures (bbox, compute, textures). Double stockage assumé.
D6 Convertisseur Geometry -> Vertex (a) méthode Geometry::to_vertices() ; (b) impl From<&Geometry> (a) Geometry::to_vertices() (ou into_vertices) — validé 2026-09-18 Explicite, avec règles de remplissage documentées (normales/UV/couleur par défaut si absents).

Étape 8.1 — Étendre Geometry (couleur + validation) — proposition validée 2026-09-18

  • Dans lib/src/math/geometry.rs :
    • ajouter colors: Option<Vec<[f32; 4]>> en champ optionnel (parallèle à normals/uvs).
    • documenter les invariants : positions obligatoire ; normals, uvs, colors, indices optionnels mais doivent avoir la même longueur que positions quand présents.
    • ajouter un constructeur ergonomique, ex. Geometry::new(positions, indices) -> Geometry (positions/valeurs par défaut) et un builder fluent .with_normals(..)/.with_uvs(..)/.with_colors(..) retournant Self.
    • ajouter une validation Geometry::validate() -> Result<(), GeometryError> (ou un Self::from_... vérifiant les longueurs) — erreur si les tableaux optionnels ont une longueur différente de positions.

Étape 8.2 — Convertisseur Geometry → Vec<Vertex>

  • Dans lib/src/math/geometry.rs (ou un petit trait dédié), implémenter :
    • Geometry::to_vertices() -> Vec<Vertex> qui zip positions/normals/uvs/colors avec des valeurs par défaut : normale [0,0,1], uv [0,0], couleur blanche [1,1,1,1].
    • documenter clairement ces défauts (i.e. une géométrie sans normales via Phong sera plate).
    • (optionnel) Geometry::indices() accesseur sûr (clone ou slice) pour l'upload.

Étape 8.3 — Mesh contient Arc<Geometry> et construit ses buffers

  • Dans lib/src/resources/mesh.rs :
    • ajouter le champ geometry: Arc<Geometry>.
    • remplacer/ajouter Mesh::from_geometry(device: &wgpu::Device, geometry: Arc<Geometry>, material: Option<Arc<Material>>) -> Mesh :
      • let vertices = geometry.to_vertices(); let indices = geometry.indices;
      • upload vertex_buffer (stride = size_of::<Vertex>(), create_buffer_init),
      • upload index_buffer si indices présent (index u16).
    • conserver num_vertices/num_indices (dérivés de la géométrie) pour render.
    • accesseurs publics : geometry() -> &Arc<Geometry>, material(), set_material().
    • supprimer les anciennes voies Mesh::new(device, vertices: &[Vertex], ...) / Mesh::with_material(...) (remplacées). Mettre à jour la doc resources/mod.rs (ligne « mesh::new() uploads Vertex arrays... ») pour refléter Geometry.

Étape 8.4 — Adapter Scene / l'API déclarative

  • Dans lib/src/scene/scene.rs :
    • changer create_mesh(id, vertices: &[Vertex], indices, material) → create_mesh(id, geometry: Geometry, material: Option<&str>) -> Result<...> :
      • il construit Arc<Geometry>, appelle Mesh::from_geometry(self.device(), arc, mat).
    • mettre à jour la doc de Scene / resources sur le rôle de Geometry.
    • ré-export : exposer Geometry à la racine (déjà via math::Geometry) et, à la convenance, depuis wsg_lib::resources pour les exemples.

Étape 8.5 — Réécrire les exemples (non contraignants) sur Geometry

  • lib/examples/cube.rs :
    • remplacer cube_vertices() -> Vec<Vertex> / cube_indices() par un builder de Geometry (ou Geometry::new(...).with_normals(...).with_indices(...)) ; couleur blanche par défaut → vérifier le rendu Phong inchangé.
    • appeler scene.create_mesh("cube_mesh", geometry, Some("cube_material")).
  • lib/examples/simple.rs :
    • construire une Geometry (positions ± couleurs par sommet pour le quad unlit) ;
    • scene.create_mesh("quad", geometry, None) (matériau par défaut).
  • lib/examples/manual.rs (exemple bas-niveau, utilise Mesh::new(renderer.device(), &vertices, ...)) :
    • réécrire sur Mesh::from_geometry(device, Arc<Geometry>, None).
  • mettre à jour les en-têtes / commentaires des exemples (références à Vertex en public).

Étape 8.6 — Validation

  • cargo fmt --all (aucun diff résiduel).
  • cargo check --workspace puis cargo build --workspace sans warning (veiller à la régularité des tableaux dans les exemples).
  • cargo test --workspace (zéro test à ce stade, mais compilation clean).
  • cargo doc --no-deps sans warning missing_docs (la crate est en #![warn(missing_docs)]).
  • Lancer les 3 exemples (simple, cube, manual) et constater l'absence de panic / rendu visé.
  • Mettre à jour README.md (extraits de code Mesh::new → Geometry, section architecture) et les statuts docs/PLAN.md + docs/ROADMAP.md (cocher le refactor 1.2 « stockage CPU » ; laisser transform documenté comme déviation en D3).

Point d'étape

  • Caser le refactor : Mesh.geometry: Arc<Geometry> + buffers dérivés, API create_mesh basée Geometry, exemples réécrits, validation verte, docs à jour.
  • Deux commits séparés comme d'habitude : un refactor(...) (8.1–8.5) puis un docs(...) (8.6). Rédiger un court bilan et ouvrir la question du prochain chantier.

Fin du DRAFT Étape 8 — à valider avant implémentation.