docs: reset DRAFT.md after Étape 7 completion
This commit is contained in:
+6
-199
@@ -1,204 +1,11 @@
|
||||
# DRAFT — Plan d'implémentation : « Rattachement PipelineCache → Scene & Mesh → Material »
|
||||
# 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.
|
||||
>
|
||||
> **Étape.** Consolidation des ressources (PLAN Phase 2 : associer le `PipelineCache` à la `Scene` ;
|
||||
> `Mesh` référence son `Material`) — recouvre la partie non cochée de la Phase 1 (ROADMAP 1.2, refactor
|
||||
> *matériau* de `Mesh`) sans toucher au refactor `Arc<Geometry>` (reporté).
|
||||
>
|
||||
> **Objectif.** La gestion des matériaux est **entièrement portée par la `Scene`** (elle possède
|
||||
> device + format + `PipelineCache`, et fabrique elle-même meshes et matériaux). Chaque `Mesh` possède
|
||||
> une référence vers son `Material` ; l'entité ne porte plus de `material_id` (le lien vit sur le mesh).
|
||||
> L'API déclarative reste `AppBuilder` + scène automatique, sans wgpu dans les exemples.
|
||||
|
||||
> **État de départ vérifié (2026-09-17).**
|
||||
> - `App` porte `cache: Option<PipelineCache>` (champ privé, accesseur `App::cache()`), **indépendant de la
|
||||
> `Scene`**. Les exemples font `Material::new(format, id, app.cache())` puis `scene.add_material(...)`.
|
||||
> - `Scene` **ne possède ni device, ni format, ni cache** : elle ne fait que stocker des `Arc<Mesh>` /
|
||||
> `Arc<Material>` *préfabriqués* et résout les entités en `(mesh_id, material_id)`.
|
||||
> - Le lien mesh→matériau est porté par `Entity { mesh_id, material_id, transform }` ; `Mesh` (resources/mesh.rs)
|
||||
> est un **conteneur GPU pur** (`vertex_buffer`, `index_buffer`, `num_vertices`, `num_indices`), sans matériau.
|
||||
> - `Renderer::render_scene` itère `scene.iter_entities()` qui re-parse `(label, &Mesh, &Material, &Transform)`
|
||||
> et appelle `draw_entity` ; les buffers frame/object sont déjà portés par le `Renderer` (Étape 3-4).
|
||||
> - `manual.rs` est **indépendant** de `App`/`Scene` : il possède son propre `PipelineCache` local
|
||||
> (chemin bas-niveau). Il n'est pas concerné par le déplacement du cache, seulement revalidé.
|
||||
> - Tests : seul `lib/tests/wgsl_validate.rs` (naga) — **aucun test ne dépend** des signatures modifiées
|
||||
> (`add_entity`, `add_material`, `Mesh`, `Material`, `iter_entities`).
|
||||
|
||||
> **Point d'étape — 2026-09-17.** Étape 7 implémentée : `Scene` possède `gpu: Option<SceneGpu>`
|
||||
> (device + format + `PipelineCache`), `Mesh` porte `Option<Arc<Material>>`, `Entity` n'a plus de
|
||||
> `material_id`, `iter_entities` rend `(&str, &Arc<Mesh>, &Transform)`, le `Renderer` résout le matériau
|
||||
> (`mesh.material()` sinon `scene.default_material()`), `App` n'a plus de champ `cache` (`init_gpu` fait
|
||||
> le branchement dans `resumed`), exemples `cube`/`simple` migrés vers `register_shader` +
|
||||
> `add_material_shader` + `create_mesh` + `add_entity`, `manual` inchangé. Validation : `cargo build
|
||||
> --workspace --examples` 0 warning, `cargo test --workspace` vert (3 tests), `cargo doc --no-deps`
|
||||
> 0 warning, `cargo fmt --all` ; exécution fenêtrée `cargo run -p wsg-lib --example simple`/`cube`
|
||||
> lancée (buffering, aucune panique).
|
||||
|
||||
---
|
||||
|
||||
## Étape 7.1 — La `Scene` possède le contexte pipeline (device + format + cache)
|
||||
|
||||
**But** : donner à la `Scene` de quoi fabriquer elle-même pipelines et meshes, à la place de `App`.
|
||||
|
||||
- [X] **7.1.1 Nouveau champ `Scene.gpu: Option<SceneGpu>`** dans `scene/scene.rs`, avec
|
||||
```
|
||||
pub struct SceneGpu {
|
||||
device: Arc<wgpu::Device>,
|
||||
format: wgpu::TextureFormat,
|
||||
cache: PipelineCache,
|
||||
}
|
||||
```
|
||||
`Scene::new()` → `gpu: None` (la `Scene` reste constructible sans GPU, cf. `AppBuilder::build`).
|
||||
- [X] **7.1.2 `Scene::init_gpu(&mut self, device: Arc<wgpu::Device>, format: wgpu::TextureFormat) -> &mut Self`** :
|
||||
pose `gpu = Some(SceneGpu { device, format, cache: PipelineCache::new(device.clone()) })` puis `&mut *self`.
|
||||
Appelé **une fois dans `AppRunner::resumed`**, juste après la création du `Context`/`Renderer` et **avant**
|
||||
`handler.setup(app)` (setup enregistre shaders/matériaux/meshes/entités → doit trouver le `gpu` prêt).
|
||||
- [X] **7.1.3 Accesseurs `pub` gardés** (panique si `gpu` absent, message « scene pipeline not initialized yet ») :
|
||||
- `scene.device() -> &wgpu::Device`
|
||||
- `scene.format() -> wgpu::TextureFormat`
|
||||
- `scene.cache() -> &PipelineCache` et `scene.cache_mut() -> &mut PipelineCache`
|
||||
- `scene.register_shader(id, path) -> Result<String, String>` (délègue à `cache.register_shader`, erreur si ID déjà pris)
|
||||
- [X] **7.1.4 Retirer la duplication de cache d'`App`** (`app.rs`) :
|
||||
- supprimer le champ `cache: Option<PipelineCache>` et `AppBuilder` n'initialise plus `cache: None` ;
|
||||
- `resumed` ne crée plus `let cache = PipelineCache::new(device)` séparément — il appelle `scene.init_gpu(...)` ;
|
||||
- accesseur `App::cache()` : **supprimé** (les exemples passent à `app.scene.cache()`), ou conservé en mince
|
||||
délégation `self.scene.cache_mut()` si l'on veut préserver l'API (voir Décisions).
|
||||
- [X] **Validation** : `cargo check --workspace --examples` 0 warning ; les exemples compilent (appelés à migrer
|
||||
en 7.4). `cargo doc --no-deps` 0 warning.
|
||||
|
||||
## Étape 7.2 — La `Scene` fabrique matériaux & meshes (liage matériau sur le mesh)
|
||||
|
||||
**But** : le `Mesh` porte son `Material` ; la `Scene` construit matériaux (via son cache+format) et meshes
|
||||
(via son device) sans que l'utilisateur touche `Material::new` / `Mesh::new`.
|
||||
|
||||
- [X] **7.2.1 `Mesh` gagne un champ matériau** (`resources/mesh.rs`) :
|
||||
```
|
||||
pub struct Mesh {
|
||||
pub vertex_buffer: wgpu::Buffer,
|
||||
pub index_buffer: Option<wgpu::Buffer>,
|
||||
pub num_vertices: u32,
|
||||
pub num_indices: u32,
|
||||
material: Option<Arc<Material>>, // nouveau
|
||||
}
|
||||
```
|
||||
- `Mesh::new(device, verts, indices)` **inchangé** → `material: None`.
|
||||
- Nouveau `Mesh::with_material(device, verts, indices, material: Arc<Material>)` (helper).
|
||||
- Accesseurs : `mesh.material() -> Option<&Arc<Material>>`, `mesh.set_material(Arc<Material>)`.
|
||||
- [X] **7.2.2 `Scene::add_material_shader(&mut self, id, shader_id) -> Result<String, String>`** : exige `gpu` ;
|
||||
construit `Material::new(self.format(), shader_id, self.cache_mut())`, insère dans `materials`, retourne `id`.
|
||||
- [X] **7.2.3 `Scene::create_mesh(&mut self, id, vertices: &[Vertex], indices: Option<&[u16]>, material: Option<&str>) -> Result<String, String>`** :
|
||||
exige `gpu` ; `let mut m = Mesh::new(self.device(), verts, indices)` ; si `material = Some(name)` → résout
|
||||
`Arc<Material>` depuis `materials` (erreur si absent) et `m.set_material(...)` ; insère `Arc::new(m)`.
|
||||
- [X] **7.2.4 Conserver les chemins custom** pour l'utilisateur avancé :
|
||||
- `add_material(id, Arc<Material>)` et `add_mesh(id, Arc<Mesh>)` **inchangés** (le `Mesh` custom peut
|
||||
ensuite être lié via `mesh.set_material(...)` ou rester sans matériau → défaut en 7.3.5).
|
||||
- [X] **Validation** : `cargo check --workspace --examples` 0 warning ; `cargo doc --no-deps` OK ; un test
|
||||
unitaire additionnel si souhaité (`Scene::add_material_shader`/`create_mesh` nécessitent un `gpu` — test
|
||||
hors-suite GPU, validation par compilation des exemples).
|
||||
|
||||
## Étape 7.3 — Le lien mesh→matériau remplace le `material_id` d'entité
|
||||
|
||||
**But** : `Entity` ne référencie plus qu'un `mesh_id` ; le rendu résout le matériau **depuis le mesh**.
|
||||
|
||||
- [X] **7.3.1 `Entity`** (`scene/entity.rs`) : retirer le champ `material_id`.
|
||||
```
|
||||
pub struct Entity { mesh_id: String, transform: Transform }
|
||||
```
|
||||
`Entity::new(mesh_id, transform)` ; supprimer `material_id()`, garder `mesh_id()`, `transform()`, `set_transform()`.
|
||||
- [X] **7.3.2 `Scene` — signatures d'entité sans `material_id`** :
|
||||
- `add_entity(&mut self, label, mesh_id)` → identité.
|
||||
- `add_entity_with_transform(&mut self, label, mesh_id, transform)`.
|
||||
- Validation d'existence inchangée : `mesh_id` doit exister dans `meshes` (le matériau est implicite → on ne
|
||||
valide plus `material_id`).
|
||||
- [X] **7.3.3 `iter_entities()`** → `impl Iterator<Item = (&str, &Arc<Mesh>, &Transform)> + '_` :
|
||||
résout `meshes.get(entity.mesh_id())`, **n'appelle plus** `get_material`. Le matériau arrive via `mesh.material()`.
|
||||
- [X] **7.3.4 `Renderer::render_scene`** (`core/renderer.rs`) : boucler sur `(label, mesh, transform)` ;
|
||||
matériau = `mesh.material().cloned()` **sinon** `scene.default_material()` (7.3.5). `draw_entity` inchangé
|
||||
(reçoit `&Material`, pose pipeline + bind groups frame/object).
|
||||
- [X] **7.3.5 `Scene::default_material(&self) -> Arc<Material>`** : matériau `standard` fabriqué **paresseusement**
|
||||
(une fois, mis en cache) depuis `SceneGpu`. Note : **le flat « unlit » reste orthogonal** — c'est le flag
|
||||
`Renderer::set_unlit` qui rend le flat (options.x du shader) ; le matériau par défaut est simplement le
|
||||
pipeline `standard`. La « variante unlit » du PLAN = le rendu flat activé par le Renderer, pas une propriété
|
||||
du `Material`.
|
||||
- [X] **Validation / cas limites** : scène vide (aucune entité → pass vide, comme avant) ; mesh **sans matériau**
|
||||
→ `default_material()` ; mesh **0-vertex** → `draw_entity` continue de retourner tôt (`num_vertices == 0`).
|
||||
|
||||
## Étape 7.4 — Migration des exemples
|
||||
|
||||
- [X] **`cube.rs`** (API déclarative, sans wgpu) — `setup` devient :
|
||||
```rust
|
||||
app.scene.register_shader("standard", wsg_lib::utils::STANDARD_SHADER_PATH).unwrap();
|
||||
app.scene.add_material_shader("cube_material", "standard").unwrap();
|
||||
app.scene.create_mesh("cube_mesh", &cube_vertices(), Some(&cube_indices()), Some("cube_material")).unwrap();
|
||||
app.scene.add_entity("cube", "cube_mesh").unwrap();
|
||||
```
|
||||
La rotation dans `AppHandler::update` (`set_entity_transform`) est **inchangée**.
|
||||
- [X] **`simple.rs`** (quad plat, unlit) — `setup` :
|
||||
```rust
|
||||
app.renderer_mut().set_unlit(true);
|
||||
app.scene.register_shader("standard", wsg_lib::utils::STANDARD_SHADER_PATH).unwrap();
|
||||
app.scene.add_material_shader("standard_material", "standard").unwrap();
|
||||
app.scene.create_mesh("quad_mesh", &vertices, Some(&indices), Some("standard_material")).unwrap();
|
||||
app.scene.add_entity("quad", "quad_mesh").unwrap();
|
||||
```
|
||||
(Le comportement est identique : le quad flat vient du flag `set_unlit(true)`.)
|
||||
- [X] **`manual.rs`** : **inchangé** (bas-niveau, son propre `PipelineCache` local, hors `Scene`). À revalider
|
||||
uniquement : `cargo check --workspace --examples` 0 warning ; il compile et tourne (quad flat).
|
||||
- [X] **Validation** : `cargo run -p examples` cube (rotation + éclairage visibles) et simple (quad flat) sans
|
||||
panique ; `cargo check --workspace --examples` 0 warning ; `cargo test --workspace` vert.
|
||||
|
||||
## Étape 7.5 — Exports, docs & commits
|
||||
|
||||
- [X] **Exports** : vérifier que les nouveaux types/méthodes sont `pub` et re-exportés là où l'API le promet
|
||||
(`resources/mod.rs` déjà `pub use`, `scene/mod.rs` déjà `pub use`) ; `#![warn(missing_docs)]` → tous doc.
|
||||
- [X] **Docs** :
|
||||
- `docs/PLAN.md` : cocher les 3 lignes non cochées de la Phase 2 — « Associer le PipelineCache à la Scene »,
|
||||
« chaque Mesh possède une référence vers un Material », « injection automatique du standard_shader ».
|
||||
- `docs/ROADMAP.md` : cocher la sous-partie *matériau* du 1.2 ; **laisser non coché** le refactor
|
||||
`Arc<Geometry>` (stockage `Geometry` dans `Mesh`) qui reste reporté.
|
||||
- `README.md` : refléter l'API déclarative (si les exemples changent).
|
||||
- [X] **Validation finale** : `cargo check --workspace` 0 warning ; `cargo doc --no-deps` 0 warning ;
|
||||
`cargo fmt --all` ; `cargo test --workspace`.
|
||||
- [X] **Commits conventionnels** : `refactor(resources): Scene owns pipeline cache, Mesh->Material link` puis
|
||||
`docs: mark PLAN Phase 2 / ROADMAP 1.2(material)` (deux commits séparés code/docs, comme à l'Étape 5).
|
||||
|
||||
---
|
||||
|
||||
## Décisions actées (à verrouiller avant l'implémentation)
|
||||
|
||||
| Décision | Option proposée / actée | Justification |
|
||||
|----------|------------------------|---------------|
|
||||
| Où vit le `PipelineCache` | **Dans la `Scene`** (`SceneGpu.cache`) ; `App` n'a plus de champ `cache` | PLAN Phase 2 : « la gestion des matériaux entièrement portée par la scène » ; `App` = orchestrateur mince |
|
||||
| Construction des matériaux | **Par la `Scene`** (`add_material_shader`) depuis un `shader_id`, via son cache+format ; `add_material(Arc<Material>)` conservé pour usage custom | un seul point de vérité device/format ; les exemples ne touchent plus `Material::new` |
|
||||
| Liage mesh→matériau | **Le `Mesh` possède `Option<Arc<Material>>`** ; l'entité ne porte plus `material_id` | PLAN : « chaque Mesh possède une référence vers un Material » ; API déclarative simplifiée ; `iter_entities` plus léger |
|
||||
| `Entity` | `{ mesh_id, transform }` uniquement | le matériau est déduit du mesh ; une dimension de moins à synchroniser |
|
||||
| Matériau par défaut | Injeté par `Scene::default_material()` = shader `standard` ; le flat reste `Renderer::set_unlit` | PLAN : injection auto du `standard_shader` ; « variante unlit » = flag rendu, **orthogonal** au `Material` |
|
||||
| Partage « 1 mesh, N matériaux » | **Abandonné au MVP** : un mesh = un matériau ; le cas d'usage est reporté au step « handles/arènes » (ROADMAP Phase 2) | cohérence avec l'entité simplifiée ; trade-off assumé et tracé (voir Réflexions) |
|
||||
| API `App::cache()` | **Supprimée**, exemples migrés vers `app.scene` (ou mince délégation si compat souhaitée) | évite deux chemins d'accès au cache ; `manual.rs` garde son cache local (découplé) |
|
||||
|
||||
## Réflexions / trade-offs
|
||||
|
||||
- **Perte du partage multi-matériaux par mesh.** Aujourd'hui deux entités peuvent référencer le même `mesh_id`
|
||||
avec deux `material_id` différents. En liant le matériau au mesh, ce cas n'est plus exprimable. C'est un
|
||||
choix **MVP assumé** (le PLAN le demande) ; il reviendra naturellement avec les **handles typés** et le
|
||||
conteneur centralisé (ROADMAP Phase 2, ARCHI_RENDU : tri de rendu par matériau). Le batching n'est pas perdu :
|
||||
il se fera sur `mesh.material().pipeline` au lieu de `material_id`.
|
||||
- **Le `default_material()` dépend de `gpu`.** Une `Scene` non initialisée (avant `resumed`) ne peut pas fabriquer
|
||||
de matériau. Toute fabrication (matériau, mesh) **panique** avec un message clair si `gpu` est absent — ce ne
|
||||
peut arriver en pratique que si `handler.setup` est appelé hors de `resumed` (invariant garanti par l'API).
|
||||
- **Ne pas confondre avec ROADMAP 1.2 (refactor `Arc<Geometry>`).** Ce DRAFT lie le **matériau** au mesh. Le
|
||||
fait que `Mesh` stocke aussi `Arc<Geometry>` (positions/indices/normales/uvs en CPU) reste **reporté** et sera
|
||||
une étape distincte.
|
||||
|
||||
---
|
||||
|
||||
## Liens / vérification finale
|
||||
|
||||
- `cargo check --workspace --examples` 0 warning.
|
||||
- `cargo test --workspace` (Pod + naga) vert.
|
||||
- `cargo doc --no-deps` 0 warning.
|
||||
- `cargo fmt --all`.
|
||||
- Exemples : `cube` (lit, rotation) et `simple` (unlit, quad) tournent sans panique ; `manual` compile et tourne.
|
||||
> **État.** Prêt pour l'étape suivante. L'Étape 7 (consolidation : `PipelineCache` → `Scene`,
|
||||
> `Mesh` → `Material`, matériau par défaut) est terminée et vérifiée le 2026-09-17 ; le détail des
|
||||
> cases cochées est conservé dans l'historique git de ce fichier et les statuts dans `docs/PLAN.md`
|
||||
> + `docs/ROADMAP.md`. Candidat suivant suggéré : ROADMAP 1.2 (refactor `Mesh` → `Arc<Geometry>`),
|
||||
> reporté à ce stade.
|
||||
|
||||
Reference in New Issue
Block a user