docs: reconcile README/ROADMAP/PLAN state and settle slotmap vs String IDs
- README stays the source of truth for current state; drive/item-5 now reflects the settled decision: String IDs for the MVP, slotmap deferred. - ROADMAP gains a 'point de depart' (present-state) block, marks glam done, removes the slotmap Phase-1 mandates, and documents the String-ID decision plus the deferred 'typed handles' step. - PLAN corrects stale [X] checkmarks (App render() cannot draw, Scene rendering not automated, simple example does not compile) and notes its verification checklist against current reality. - Remove the unused slotmap direct dependency from wsg-lib (package remains in Cargo.lock only as a transitive dep of glow).
This commit is contained in:
Generated
-1
@@ -2331,7 +2331,6 @@ dependencies = [
|
|||||||
"bytemuck",
|
"bytemuck",
|
||||||
"glam",
|
"glam",
|
||||||
"pollster",
|
"pollster",
|
||||||
"slotmap",
|
|
||||||
"thiserror 2.0.18",
|
"thiserror 2.0.18",
|
||||||
"wgpu",
|
"wgpu",
|
||||||
"winit",
|
"winit",
|
||||||
|
|||||||
@@ -1,88 +1,167 @@
|
|||||||
# WSG - WGPU Simple Graphics Library
|
# WSG - WGPU Simple Graphics Library
|
||||||
|
|
||||||
WSG is a Rust library that wraps [wgpu](https://github.com/gfx-rs/wgpu) to provide a simple, declarative API for 3D graphics. It abstracts away the complexity of managing GPU resources while exposing low-level primitives for advanced users.
|
WSG is a Rust library that wraps [wgpu](https://github.com/gfx-rs/wgpu) and [winit](https://crates.io/crates/winit) for simple GPU drawing. It groups the five core wgpu objects (Instance, Surface, Adapter, Device, Queue) behind a single `Context`, adds small building blocks (`Mesh`, `Material`, `PipelineCache`, `Frame`), and exposes the low-level primitives for advanced users.
|
||||||
|
|
||||||
|
> **Status: unstable development version.** The manual workflow below is fully working. The high-level "declarative" workflow and the GPU-driven two-pass pipeline described in the architecture docs are **not implemented yet** — see [Status](#status) and [Roadmap](#roadmap).
|
||||||
|
|
||||||
NOTE : the development version is currently unstable and the examples described below may not work as expected.
|
## Status
|
||||||
|
|
||||||
|
| Area | State |
|
||||||
|
|------|-------|
|
||||||
|
| Manual workflow (`Context` + `Renderer` + `PipelineCache`) | ✅ Working |
|
||||||
|
| `App` / `AppBuilder` / `AppHandler` event-loop facade | 🚧 Scaffold — window, events and frame presentation work, but the `render()` callback cannot draw yet (the per-frame view is not exposed to it) |
|
||||||
|
| `Scene` resource/entity registry | 🚧 Registration API works; the engine does not render the scene yet |
|
||||||
|
| GPU-driven two-pass pipeline (Compute → indirect draw) | 📋 Roadmap — spec in [docs/tech/ARCHI_CPU_GPU.md](docs/tech/ARCHI_CPU_GPU.md) |
|
||||||
|
| 3D transforms (MVP uniforms, camera in the pipeline) | 📋 Roadmap — the bundled shader draws positions straight to NDC today |
|
||||||
|
|
||||||
|
Note: the bundled `basic_shader.wgsl` treats vertex positions as already in NDC space, so what you can see today is flat, untransformed drawing (e.g. a colored quad) — not a 3D scene.
|
||||||
|
|
||||||
## What it does
|
## What it does
|
||||||
|
|
||||||
WSG provides two complementary workflows:
|
### Manual workflow (working — recommended today)
|
||||||
|
|
||||||
### Declarative workflow (recommended)
|
Bypass the `App` facade and drive `Context`, `Renderer` and `PipelineCache` yourself. This is the only workflow that renders pixels today (same code as the `manual` example):
|
||||||
|
|
||||||
Register your scene's resources and entities once at startup, then let WSG handle rendering each frame via a GPU-Driven pipeline (Compute Pass → Render Pass):
|
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
use wsg_lib::{App, AppHandler};
|
use std::sync::Arc;
|
||||||
use wsg_lib::resources::{Mesh, Material, Vertex};
|
use winit::event_loop::EventLoop;
|
||||||
|
use winit::window::WindowBuilder;
|
||||||
|
use wsg_lib::core::{Context, Frame, Renderer};
|
||||||
|
use wsg_lib::pipeline::PipelineCache;
|
||||||
|
use wsg_lib::resources::{Material, Mesh, Vertex};
|
||||||
|
use wsg_lib::utils;
|
||||||
|
|
||||||
struct MyGame { /* ... */ }
|
fn main() {
|
||||||
|
// Window + async GPU init
|
||||||
|
let event_loop = EventLoop::new().unwrap();
|
||||||
|
let window = Arc::new(WindowBuilder::new().build(&event_loop).unwrap());
|
||||||
|
let context = pollster::block_on(Context::new(window.clone())).expect("GPU init failed");
|
||||||
|
let format = context.configure(&context.adapter, 800, 600).expect("surface config failed");
|
||||||
|
|
||||||
|
// Renderer + shader cache (falls back to the embedded shader if the file is missing)
|
||||||
|
let renderer = Renderer::new(&context, format);
|
||||||
|
let mut cache = PipelineCache::new(Arc::new(context.device.clone()));
|
||||||
|
cache.register_shader("basic", utils::BASIC_SHADER_PATH).unwrap();
|
||||||
|
|
||||||
|
// Material + mesh
|
||||||
|
let material = Material::new(renderer.format(), "basic", &mut cache);
|
||||||
|
let vertices: [Vertex; 4] = [
|
||||||
|
Vertex { position: [-0.5, 0.5, 0.0], normal: [0.0, 0.0, 1.0], uv: [0.0, 0.0], color: [1.0, 0.0, 0.0, 1.0] },
|
||||||
|
Vertex { position: [ 0.5, 0.5, 0.0], normal: [0.0, 0.0, 1.0], uv: [1.0, 0.0], color: [0.0, 1.0, 0.0, 1.0] },
|
||||||
|
Vertex { position: [ 0.5, -0.5, 0.0], normal: [0.0, 0.0, 1.0], uv: [1.0, 1.0], color: [0.0, 0.0, 1.0, 1.0] },
|
||||||
|
Vertex { position: [-0.5, -0.5, 0.0], normal: [0.0, 0.0, 1.0], uv: [0.0, 1.0], color: [1.0, 1.0, 0.0, 1.0] },
|
||||||
|
];
|
||||||
|
let indices: [u16; 6] = [0, 1, 2, 0, 2, 3];
|
||||||
|
let mesh = Mesh::new(renderer.device(), &vertices, Some(&indices));
|
||||||
|
|
||||||
|
// Render loop
|
||||||
|
event_loop.run(|event, elwt| {
|
||||||
|
match event {
|
||||||
|
winit::event::Event::AboutToWait => window.request_redraw(),
|
||||||
|
winit::event::Event::WindowEvent { event: winit::event::WindowEvent::RedrawRequested, .. } => {
|
||||||
|
if let Some(frame) = Frame::try_new(&context.surface) {
|
||||||
|
renderer.render(frame.view(), &mesh, &material);
|
||||||
|
renderer.present(frame);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
winit::event::Event::WindowEvent { event: winit::event::WindowEvent::CloseRequested, .. } => elwt.exit(),
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}).unwrap();
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Declarative workflow (work in progress)
|
||||||
|
|
||||||
|
The intended API: register your scene's resources and entities once, then let `App` handle the window lifecycle, event processing and frame presentation. Users implement the `AppHandler` trait to inject per-frame logic:
|
||||||
|
|
||||||
|
```rust
|
||||||
|
use wsg_lib::app::AppBuilder;
|
||||||
|
use wsg_lib::{App, AppHandler};
|
||||||
|
|
||||||
|
struct MyGame;
|
||||||
|
|
||||||
impl AppHandler for MyGame {
|
impl AppHandler for MyGame {
|
||||||
fn update(&mut self, _app: &mut App) {
|
// update() has an empty default — implement it to mutate scene state each frame.
|
||||||
// Modify scene state (transformations, entities) — only place allowed for mutations
|
fn render(&mut self, _app: &mut App) {
|
||||||
}
|
// The engine acquires and presents the frame around this callback,
|
||||||
|
// but scene rendering is not automated yet — see Roadmap.
|
||||||
fn render(&mut self, app: &mut App) {
|
|
||||||
// WSG automatically runs Compute Pass → Render Pass on the current scene.
|
|
||||||
// No manual iteration needed — draw_indexed_indirect handles everything.
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[pollster::main]
|
#[pollster::main]
|
||||||
async fn main() -> Result<(), wsg_lib::utils::WsgError> {
|
async fn main() -> Result<(), wsg_lib::utils::WsgError> {
|
||||||
let mut app = AppBuilder::new().build().await?;
|
let app = AppBuilder::new().build().await?;
|
||||||
|
|
||||||
// Declare resources (once, before the render loop)
|
// Scene registration is available (string IDs):
|
||||||
app.cache.register_shader("basic", "assets/shaders/basic_shader.wgsl")?;
|
// app.scene.add_mesh("quad", Arc::new(mesh))?;
|
||||||
let vertices: [Vertex; 4] = [/* ... */];
|
// app.scene.add_material("mat", Arc::new(material))?;
|
||||||
let indices: [u16; 6] = [0, 1, 2, 0, 2, 3];
|
// app.scene.add_entity("my_quad", "quad", "mat")?;
|
||||||
let mesh = Mesh::new(app.context.device(), &vertices, Some(&indices));
|
// ...but the engine will not draw them until the declarative pipeline lands.
|
||||||
let material = Material::new(app.renderer.format(), "basic", &mut app.cache);
|
|
||||||
|
|
||||||
app.scene.add_mesh("quad", Arc::new(mesh))?;
|
app.run(MyGame)
|
||||||
app.scene.add_material("mat", Arc::new(material))?;
|
|
||||||
app.scene.add_entity("my_quad", "quad", "mat")?;
|
|
||||||
|
|
||||||
// Run the render loop — WSG handles Compute Pass + Render Pass each frame
|
|
||||||
app.run(MyGame {})
|
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
### Manual workflow
|
> API note: `Scene::add_mesh` / `add_material` / `add_entity` and `PipelineCache::register_shader`
|
||||||
|
> currently return `Result<_, String>` — typed error unification is on the roadmap.
|
||||||
For fine-grained control, bypass the Scene facade entirely and manipulate Context, Renderer, and PipelineCache directly through their public APIs.
|
|
||||||
|
|
||||||
## Architecture overview
|
## Architecture overview
|
||||||
|
|
||||||
WSG follows a GPU-Driven two-layer architecture:
|
- **Manager layer (`Context`)** — owns the GPU hardware lifecycle (Instance → Surface → Adapter → Device → Queue). Created once at startup; `configure()` sets up the swapchain, `Frame` wraps each frame's surface texture + view.
|
||||||
|
- **Executor layer (`Renderer`)** — binds a `Material` pipeline + `Mesh` buffers into a RenderPass and submits the commands. Today this is one encoder + one submit **per object**.
|
||||||
|
- **Supporting pieces** — `PipelineCache` (shader → compiled RenderPipeline, `Arc`-shared), `Material`, `Mesh`/`Vertex`, `Scene` (string-ID registry), `Camera`/`Transform` (types only, not yet used by the pipeline).
|
||||||
|
|
||||||
- **Manager layer (Context)** — owns GPU hardware lifecycle (Instance → Surface → Adapter → Device → Queue). Created once at startup.
|
The planned target architecture — a GPU-driven two-pass pipeline (Compute Pass: world matrices + frustum culling → Indirect Draw Buffer, then a single `draw_indexed_indirect` per frame) — is specified in [docs/tech/ARCHI_APP.md](docs/tech/ARCHI_APP.md) and [docs/tech/ARCHI_CPU_GPU.md](docs/tech/ARCHI_CPU_GPU.md) but is **not implemented yet**.
|
||||||
- **Executor layer (Renderer)** — orchestrates a two-pass pipeline per frame: Compute Pass (World Matrix calculation + Frustum Culling → Indirect Draw Buffer) then Render Pass (`draw_indexed_indirect`). Dynamic, changes each frame.
|
|
||||||
|
|
||||||
The high-level `App` facade ties everything together, automating window lifecycle, event processing, and frame presentation. Users implement the `AppHandler` trait to inject game logic.
|
|
||||||
|
|
||||||
## Quick reference
|
## Quick reference
|
||||||
|
|
||||||
| Concept | Type | Responsibility |
|
| Concept | Type | Responsibility | Status |
|
||||||
|---------|------|---------------|
|
|---------|------|---------------|--------|
|
||||||
| App | Facade | Window lifecycle + event loop + render automation |
|
| App / AppBuilder | Facade | Window lifecycle + winit event loop + frame presentation | 🚧 Scaffold (no scene rendering) |
|
||||||
| AppHandler | Trait | User-defined update/render callbacks |
|
| AppHandler | Trait | User-defined `update()` / `render()` callbacks | ✅ (render() has no frame access yet) |
|
||||||
| Scene | Struct | Resource depot + entity graph (declarative) |
|
| Scene | Struct | String-ID registry: meshes, materials, entities | 🚧 Registration only |
|
||||||
| Context | Struct | GPU hardware lifecycle (Manager) |
|
| Context | Struct | GPU hardware lifecycle (Instance, Surface, Adapter, Device, Queue) | ✅ |
|
||||||
| Renderer | Struct | Two-pass pipeline: Compute + Render |
|
| Renderer | Struct | Binds Material + Mesh into a RenderPass, submits | ✅ (one submit per object) |
|
||||||
| Material | Struct | Shader ID → compiled RenderPipeline |
|
| PipelineCache | Struct | Shader → compiled RenderPipeline cache | ✅ |
|
||||||
| Mesh | Struct | Persistent GPU geometry container |
|
| Material | Struct | Shader ID → RenderPipeline | ✅ |
|
||||||
| Vertex | Struct | CPU-side vertex attribute tuple |
|
| Mesh / Vertex | Struct | GPU geometry container / CPU-side vertex tuple | ✅ |
|
||||||
| PipelineCache | Struct | Shader compilation cache |
|
| Frame | Struct | Per-frame RAII wrapper (surface texture + view) | ✅ |
|
||||||
| Frame | Struct | Per-frame RAII wrapper for surface texture + view |
|
| Camera / Transform | Struct | Camera & transform math | 📋 Types only, not in the pipeline |
|
||||||
|
|
||||||
## Getting started
|
## Getting started
|
||||||
|
|
||||||
```bash
|
WSG is **not published on crates.io** — depend on it by path:
|
||||||
cargo add wsg-lib # Add the dependency
|
|
||||||
# Then build your app following the declarative example above
|
```toml
|
||||||
|
[dependencies]
|
||||||
|
wsg-lib = { path = "/path/to/wsg/lib" }
|
||||||
|
pollster = "0.4" # only if you use the async AppBuilder
|
||||||
```
|
```
|
||||||
|
|
||||||
For details on the architecture and internal modules, see [ARCHI_APP](docs/ARCHI_APP.md).
|
| Action | Command |
|
||||||
|
|--------|---------|
|
||||||
|
| Build everything | `cargo build --workspace` |
|
||||||
|
| Run the working example | `cargo run -p wsg-lib --example manual` |
|
||||||
|
| Check everything (incl. examples) | `cargo check --all-targets` |
|
||||||
|
|
||||||
|
The `manual` example is the reference for the working workflow. The `simple` example (App facade) is work in progress and currently does not compile.
|
||||||
|
|
||||||
|
## Documentation
|
||||||
|
|
||||||
|
The architecture docs live in `docs/tech/` and are written in **French**:
|
||||||
|
|
||||||
|
- [ARCHI_APP](docs/tech/ARCHI_APP.md) — engine architecture. ⚠️ Describes the *target* architecture; the GPU-driven pipeline parts are not implemented yet.
|
||||||
|
- [ARCHI_CPU_GPU](docs/tech/ARCHI_CPU_GPU.md) — CPU/GPU workload split specification.
|
||||||
|
- [ARCHI_RENDU](docs/tech/ARCHI_RENDU.md) — update/render mutability model.
|
||||||
|
- [ARCHI_ARENES](docs/tech/ARCHI_ARENES.md) — planned slotmap-based generational resource handles.
|
||||||
|
- [FRAME_LOOP](docs/tech/FRAME_LOOP.md) — frame lifetime and resource persistence.
|
||||||
|
|
||||||
|
## Roadmap
|
||||||
|
|
||||||
|
1. **Scene auto-rendering** — `App`/`Renderer` iterate registered entities and draw them in one encoder/submit per frame; expose the frame view to `AppHandler::render` for custom draws.
|
||||||
|
2. **GPU-driven two-pass pipeline** — Compute Pass (world matrices + frustum culling) filling an indirect draw buffer, single `draw_indexed_indirect` (see ARCHI_CPU_GPU).
|
||||||
|
3. **CPU→GPU transform sync** — persistent transform buffers with ring (triple) buffering.
|
||||||
|
4. **Real 3D pipeline** — MVP uniforms + camera support in the vertex shader.
|
||||||
|
5. **Typed resource handles** — keep String IDs for the MVP (current design, source of truth in `Scene`); slotmap-based generational handles (`ARCHI_ARENES.md`) are deferred to a later performance pass.
|
||||||
|
6. **Error unification** — replace `Result<_, String>` in `Scene`/`PipelineCache` with typed errors.
|
||||||
|
|||||||
+13
-7
@@ -11,6 +11,12 @@ generated: { by: human:jerome, at: 2026-07-31T00:00:00Z }
|
|||||||
|
|
||||||
Ce plan définit les étapes prioritaires pour finaliser l'architecture actuelle. L'objectif est de rendre l'API intuitive pour l'utilisateur standard tout en conservant la puissance de contrôle pour l'utilisateur avancé.
|
Ce plan définit les étapes prioritaires pour finaliser l'architecture actuelle. L'objectif est de rendre l'API intuitive pour l'utilisateur standard tout en conservant la puissance de contrôle pour l'utilisateur avancé.
|
||||||
|
|
||||||
|
> **Statut réel (à jour au 2026-09-14).** Ce plan couvre la phase de *consolidation* passée ; la source
|
||||||
|
> de vérité sur l'état actuel est **README.md** et le code. Plusieurs cases `[X]` ci-dessous ont été
|
||||||
|
> re-corrigées car elles ne reflétaient plus la réalité : notamment l'exemple `simple` **ne compile pas**
|
||||||
|
> actuellement (`App::new()` obsolète, à remplacer par `AppBuilder`) et le rendu de la `Scene` n'est
|
||||||
|
> **pas automatisé** (items Phase 2 et Check-list concernés).
|
||||||
|
|
||||||
## Phase 1 : Finalisation et Nettoyage de l'Existant (Priorité Absolue)
|
## Phase 1 : Finalisation et Nettoyage de l'Existant (Priorité Absolue)
|
||||||
|
|
||||||
Cette phase vise à supprimer la dette technique et à unifier les accès.
|
Cette phase vise à supprimer la dette technique et à unifier les accès.
|
||||||
@@ -39,19 +45,19 @@ Une fois la plomberie encapsulée, nous devons rendre l'assemblage des objets co
|
|||||||
### Intégration de la Scene
|
### Intégration de la Scene
|
||||||
|
|
||||||
- [X] Formaliser la structure `Scene` : un conteneur qui liste les Entities.
|
- [X] Formaliser la structure `Scene` : un conteneur qui liste les Entities.
|
||||||
- [X] Associer le `PipelineCache` à la Scene pour que le rendu des matériaux soit automatique.
|
- [ ] Associer le `PipelineCache` à la Scene pour que le rendu des matériaux soit automatique (actuellement le cache est porté par `App`, indépendant de la Scene ; le rendu n'est pas automatisé).
|
||||||
- [X] Implémenter la logique `app.render(scene)` : cette méthode doit parcourir la scène, récupérer les matériaux, gérer les pipelines via le cache, et soumettre les draw calls.
|
- [ ] Implémenter la logique `app.render(scene)` : cette méthode doit parcourir la scène, récupérer les matériaux, gérer les pipelines via le cache, et soumettre les draw calls (non implémenté — cf. README, étape 1 du Roadmap : scene auto-rendering).
|
||||||
|
|
||||||
### Gestion des Matériaux et Shaders
|
### Gestion des Matériaux et Shaders
|
||||||
|
|
||||||
- [X] S'assurer que chaque Mesh possède une référence vers un Material.
|
- [ ] S'assurer que chaque Mesh possède une référence vers un Material (à l'heure actuelle le lien est porté par l'entité `(mesh_id, material_id)` de la Scene, pas par le Mesh lui-même).
|
||||||
- [X] Implémenter le comportement par défaut : si aucun matériau n'est assigné, le moteur injecte automatiquement le `basic_shader`.
|
- [ ] Implémenter le comportement par défaut : si aucun matériau n'est assigné, le moteur injecte automatiquement le `basic_shader` (non implémenté).
|
||||||
|
|
||||||
## Phase 3 : Documentation et Interface (API "User-Friendly")
|
## Phase 3 : Documentation et Interface (API "User-Friendly")
|
||||||
|
|
||||||
### Refonte des Exemples
|
### Refonte des Exemples
|
||||||
|
|
||||||
- [X] `simple.rs` doit devenir le modèle : **15 lignes** de code, pas de manipulation WGPU explicite.
|
- [ ] `simple.rs` doit devenir le modèle : **15 lignes** de code, pas de manipulation WGPU explicite (actuellement ne compile pas — API obsolète `App::new()` → `AppBuilder`).
|
||||||
- [X] `manual.rs` doit rester disponible en tant que tutoriel pour ceux qui veulent contourner l'abstraction App.
|
- [X] `manual.rs` doit rester disponible en tant que tutoriel pour ceux qui veulent contourner l'abstraction App.
|
||||||
|
|
||||||
### Nettoyage du Code Interne
|
### Nettoyage du Code Interne
|
||||||
@@ -68,8 +74,8 @@ Une fois les phases 1 à 3 validées, nous pourrons introduire :
|
|||||||
|
|
||||||
## Check-list de Vérification pour le LLM d'Assistance
|
## Check-list de Vérification pour le LLM d'Assistance
|
||||||
|
|
||||||
- [X] Est-ce que `simple.rs` compile sans importer `winit` ou `wgpu` ?
|
- [ ] Est-ce que `simple.rs` compile sans importer `winit` ou `wgpu` ? (ne compile pas actuellement ; `App::new()` → `AppBuilder`)
|
||||||
- [X] Est-ce que `App::run` gère bien le cycle update → render → present ?
|
- [ ] Est-ce que `App::run` gère bien le cycle update → render → present ? (boucle + présentation OK, mais `render()` ne peut pas encore dessiner — vue de frame non exposée)
|
||||||
- [X] Les modules sont-ils bien exposés via `lib.rs` ?
|
- [X] Les modules sont-ils bien exposés via `lib.rs` ?
|
||||||
- [X] `pollster` est-il uniquement en dev-dependencies ?
|
- [X] `pollster` est-il uniquement en dev-dependencies ?
|
||||||
|
|
||||||
|
|||||||
+15
-9
@@ -11,6 +11,14 @@ generated: { by: human:jerome, at: 2026-07-31T00:00:00Z }
|
|||||||
|
|
||||||
> Basé sur l'architecture existante (ARCHI_APP, ARCHI_ARENES, ARCHI_CPU_GPU, ARCHI_RENDU).
|
> Basé sur l'architecture existante (ARCHI_APP, ARCHI_ARENES, ARCHI_CPU_GPU, ARCHI_RENDU).
|
||||||
> Objectif : prototype fonctionnel d'abord, enrichissement progressif ensuite.
|
> Objectif : prototype fonctionnel d'abord, enrichissement progressif ensuite.
|
||||||
|
>
|
||||||
|
> **Point de départ (état réel au 2026-09-14 — la source de vérité est README.md).**
|
||||||
|
> Les fondations suivantes existent et fonctionnent déjà ; cette roadmap décrit la **trajectoire à
|
||||||
|
> venir** à partir de cet état (elle reprend les étapes 1-4 du README avant la montée GPU-driven) :
|
||||||
|
> - Workflow manuel (`Context` + `Renderer` + `PipelineCache`) : ✅ fonctionnel (exemple `manual`).
|
||||||
|
> - Façade `App` / `AppBuilder` / `AppHandler` : 🚧 scaffold — boucle et présentation OK, mais `render()` ne peut pas encore dessiner (vue de frame non exposée) et le rendu de la scène n'est pas automatisé.
|
||||||
|
> - `Scene` avec identifiants **String** (décision prise — voir tableau Notes de Décision) : 🚧 enregistrement seul.
|
||||||
|
> - `Camera` / `Transform` et `glam` : types et mathématiques présents (`math/`, `resources/camera.rs`), non branchés au pipeline.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -19,8 +27,8 @@ generated: { by: human:jerome, at: 2026-07-31T00:00:00Z }
|
|||||||
**Objectif** : Afficher un cube (ou autre mesh) 3D avec un éclairage Phong basique.
|
**Objectif** : Afficher un cube (ou autre mesh) 3D avec un éclairage Phong basique.
|
||||||
|
|
||||||
### 1.1 Dépendances & Mathématiques
|
### 1.1 Dépendances & Mathématiques
|
||||||
- [ ] Ajouter `glam = "0.33"` en dépendance (`lib/Cargo.toml`)
|
- [x] `glam = "0.33"` ajouté (`lib/Cargo.toml`) — déjà présent, utilisé par `math/transform.rs` et `resources/camera.rs`
|
||||||
- [ ] Ajouter `slotmap = "1.0"` en dépendance
|
- [x] `slotmap` **retiré** — décision prise : **String IDs pour le MVP** ; slotmap reporté à l'étape "handles typés" (voir Notes de Décision)
|
||||||
- [ ] Créer module `math/` (ou `transform.rs`) :
|
- [ ] Créer module `math/` (ou `transform.rs`) :
|
||||||
- [ ] Struct `Transform { translation: Vec3, rotation: Quat, scale: Vec3 }`
|
- [ ] Struct `Transform { translation: Vec3, rotation: Quat, scale: Vec3 }`
|
||||||
- [ ] Méthode `to_matrix() -> Mat4` pour calculer la matrice locale
|
- [ ] Méthode `to_matrix() -> Mat4` pour calculer la matrice locale
|
||||||
@@ -46,12 +54,10 @@ generated: { by: human:jerome, at: 2026-07-31T00:00:00Z }
|
|||||||
- [ ] Uniforms : `view_matrix`, `proj_matrix`, `world_matrix`, `light_dir`, `light_color`
|
- [ ] Uniforms : `view_matrix`, `proj_matrix`, `world_matrix`, `light_dir`, `light_color`
|
||||||
- [ ] Mettre à jour `Material` pour supporter les uniforms du shader Phong
|
- [ ] Mettre à jour `Material` pour supporter les uniforms du shader Phong
|
||||||
|
|
||||||
### 1.4 Scene avec Arènes (slotmap)
|
### 1.4 Scene avec identifiants (MVP : String IDs)
|
||||||
- [ ] Implémenter `Scene` avec arènes générationalles :
|
- [x] `Scene` implémentée avec **String IDs** (`HashMap<String, Arc<Mesh>>`, `...Material`, entités) — état actuel validé ; décision : rester en String IDs pour le MVP
|
||||||
- [ ] `SlotMap<MeshId, Mesh>`
|
- [x] Méthodes : `add_mesh()`, `get_mesh()`, `add_material()`, `add_entity()`, `iter_entities()`, `remove_entity()`
|
||||||
- [ ] `SlotMap<MaterialId, Material>` (préparation future)
|
- [ ] **Reporté (étape "Handles typés")** : migrer vers `slotmap` générationnel (`MeshId`/`MaterialId`) quand l'éviction/les performances le justifieront
|
||||||
- [ ] Méthodes : `add_mesh()`, `get_mesh()`, `iter_meshes()`
|
|
||||||
- [ ] Les entités stockent des `MeshId` (handles typés), pas des références
|
|
||||||
|
|
||||||
### 1.5 Rendu du Prototype
|
### 1.5 Rendu du Prototype
|
||||||
- [ ] Uniform buffer pour la frame : `view_matrix`, `proj_matrix`, `light_dir`
|
- [ ] Uniform buffer pour la frame : `view_matrix`, `proj_matrix`, `light_dir`
|
||||||
@@ -143,4 +149,4 @@ generated: { by: human:jerome, at: 2026-07-31T00:00:00Z }
|
|||||||
| **UVs en Phase 4** | Inutiles avant les textures ; on garde `Geometry` simple au départ |
|
| **UVs en Phase 4** | Inutiles avant les textures ; on garde `Geometry` simple au départ |
|
||||||
| **BBox en Phase 3** | Utile uniquement pour le frustum culling GPU |
|
| **BBox en Phase 3** | Utile uniquement pour le frustum culling GPU |
|
||||||
| **World Matrix CPU → MVP, GPU → Phase 3** | Le MVP est plus simple avec un uniform par mesh ; la migration GPU-driven est progressive |
|
| **World Matrix CPU → MVP, GPU → Phase 3** | Le MVP est plus simple avec un uniform par mesh ; la migration GPU-driven est progressive |
|
||||||
| **slotmap dès Phase 1** | Architecture décidée (`ARCHI_ARENES.md`) ; mieux de l'adopter tôt que de refactorer |
|
| **String IDs pour le MVP, slotmap reporté** | Le code et le README utilisent des String IDs (simples, sûrs, figés avant la boucle de rendu) ; `ARCHI_ARENES.md` reste la cible "handles typés" pour plus tard. La dépendance `slotmap` a été retirée tant qu'elle est inutilisée |
|
||||||
|
|||||||
@@ -12,7 +12,6 @@ winit = "0.29" # For window management — pinned to match examples
|
|||||||
thiserror = "2"
|
thiserror = "2"
|
||||||
bytemuck = { version = "1.25.0", features = ["derive"] }
|
bytemuck = { version = "1.25.0", features = ["derive"] }
|
||||||
glam = "0.33"
|
glam = "0.33"
|
||||||
slotmap = "1.0"
|
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
pollster = { version="0.4.0", features = ["macro"] }
|
pollster = { version="0.4.0", features = ["macro"] }
|
||||||
|
|||||||
Reference in New Issue
Block a user