9ad47e8790
- 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.
161 lines
12 KiB
Markdown
161 lines
12 KiB
Markdown
# 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._
|