Files
wsg/docs/DRAFT.md
T
Jérôme Bousquié 9ad47e8790 docs(étape8): valider et documenter le refactor stockage CPU Arc<Geometry> (8.6)
- DRAFT.md : cases 8.1-8.6 cochées, état 'terminée et vérifiée 2026-09-18', bilan final.
- README.md : workflow manuel et déclaratif (extraits Mesh::new -> Geometry/from_geometry),
  note API create_mesh(Geometry), section architecture + table quick reference, roadmap +1 (CPU storage).
- ROADMAP.md (1.2) : colors + refactor Mesh/Scene cochés 'fait', déviation D3 'implémenté'.
- PLAN.md : statut réel à jour 2026-09-18 (Étape 8 effectuée).
- resources/README.md : Mesh::new() -> from_geometry() + rétention CPU.
2026-09-18 10:22:43 +02:00

161 lines
12 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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 **terminée et vérifiée le 2026-09-18** : `Mesh.geometry: Arc<Geometry>` + buffers
> dérivés, API `create_mesh` basée `Geometry`, exemples réécrits, validation verte, docs à jour.
---
# É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**
- [x] 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>`
- [x] 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
- [x] 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
- [x] 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`
- [x] `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"))`.
- [x] `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).
- [x] `lib/examples/manual.rs` (exemple bas-niveau, utilise `Mesh::new(renderer.device(),
&vertices, ...)`) :
- [ ] réécrire sur `Mesh::from_geometry(device, Arc<Geometry>, None)`.
- [x] mettre à jour les en-têtes / commentaires des exemples (références à `Vertex` en public).
## Étape 8.6 — Validation
- [x] `cargo fmt --all` (aucun diff résiduel).
- [x] `cargo check --workspace` puis `cargo build --workspace` **sans warning** (veiller à la
régularité des tableaux dans les exemples).
- [x] `cargo test --workspace` (zéro test à ce stade, mais compilation clean).
- [x] `cargo doc --no-deps` **sans warning `missing_docs`** (la crate est en `#![warn(missing_docs)]`).
- [x] Lancer les 3 exemples (simple, cube, manual) et constater l'absence de panic / rendu visé.
- [x] 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
- [x] Caser le refactor : `Mesh.geometry: Arc<Geometry>` + buffers dérivés, API `create_mesh`
basée `Geometry`, exemples réécrits, validation verte, docs à jour.
- [x] 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.
## Bilan (2026-09-18)
L'Étape 8 est **terminée et vérifiée** :
- `Geometry` (math) : champ `colors`, constructeur `Geometry::new(positions)` + builder
fluent (`.with_normals/.with_uvs/.with_colors/.with_indices`), `validate()` + `GeometryError`,
`indices()` et `to_vertices()`/`try_into_vertices()` (zip positions/normals/uvs/colors avec défauts
normale `[0,0,1]`, uv `[0,0]`, blanc opaque).
- `Mesh` (resources) : retient `geometry: Arc<Geometry>` (CPU, D5) + buffers GPU pré-uploadés ;
constructeur **unique** `Mesh::from_geometry(device, Arc<Geometry>, Option<Arc<Material>>)`
(D4) — `Mesh::new`/`with_material` (`&[Vertex]`) supprimés ; accesseurs `geometry()`/`material()`/`set_material()`.
- `Scene` : `create_mesh(id, Geometry, Option<&str>)` (D4) ; `Geometry` exposé via `math` (D2)
et ré-exporté en convenance depuis `resources`.
- Exemples cube/simple/manual réécrits sur `Geometry` (8.5). `simple` passe par `None` pour
vérifier le matériau par défaut (`Scene::default_material`).
- Validation : `cargo fmt` (aucun diff), `build`/`check` sans warning, `test` vert (1 unitaire
shader + 1 doc-test `Geometry::new`), `doc` sans `missing_docs`, 3 exemples lancés (rendu sans panic).
- Commits : `refactor(...)` (8.1–8.5) + `docs(...)` (8.6).
**Prochain chantier possible** : la suite du ROADMAP — gestion des matériaux/textures (Phase 2/4,
ex. `Texture` + `uniform` diffuse), ou remonter vers les **handles typés** (Phase 2/5) / pipeline
**GPU-driven** (Phase 3) avec la bounding box dans `Geometry` (le champ `colors` et la rétention CPU
`Arc<Geometry>` posent déjà la base du culling).
---
_Fin du DRAFT Étape 8 — implémentée et vérifiée le 2026-09-18._