refactor(mesh): stockage CPU Arc<Geometry> (Étape 8, 8.1-8.5)

- geometry: ajoute le champ optionnel colors + constructeur new() et builder
  fluent (.with_normals/.with_uvs/.with_colors/.with_indices) + validate() et
  GeometryError (longueurs des tableaux optionnels + bornes des indices).
- geometry: ajoute to_vertices()/try_into_vertices() -> Vec<Vertex> (zip avec
  défauts : normale [0,0,1], UV [0,0], couleur blanche) (D6).
- mesh: remplace new()/with_material() par from_geometry(device, Arc<Geometry>,
  material); garde geometry: Arc<Geometry> (rétention CPU+GPU, D5) + nouveaux
  accesseurs geometry()/material()/set_material() (D4).
- scene: create_mesh(id, Geometry, Option<&str>) déclare un mesh depuis une
  Geometry; expose Geometry via math (D2) et un ré-export de convenance resources.
- exemples (cube/simple/manual) réécrits pour construire une Geometry.
This commit is contained in:
Jérôme Bousquié
2026-09-18 09:58:19 +02:00
parent 6f6b72ae8d
commit 4a94ad4ac1
8 changed files with 377 additions and 157 deletions
+22 -34
View File
@@ -1,7 +1,9 @@
//! Workflow bas-niveau : utilisation directe du `Context`, `Renderer`, `PipelineCache`, `Mesh` et
//! `Material`, contournant la façade `App`. Rendu d'un quad plat (shader `standard` **unlit**) via la
//! boucle winit 0.30 (`EventLoop::run_app` + `ApplicationHandler`). La fenêtre et le GPU sont créés
//! dans `resumed()`, comme l'exigent winit 0.30 et la migration faite dans `app.rs`.
//! dans `resumed()`, comme l'exigent winit 0.30 et la migration faite dans `app.rs`. Depuis l'Étape 8
//! (DRAFT 8.5) le mesh est construit via `Mesh::from_geometry(device, Arc<Geometry>, None)` à partir
//! d'une `Geometry` (positions + couleurs par sommet) au lieu de `Mesh::new(device, &[Vertex], ..)`.
use std::sync::Arc;
use winit::application::ApplicationHandler;
use winit::dpi::LogicalSize;
@@ -12,9 +14,7 @@ use wsg_lib::core::Context;
use wsg_lib::core::Frame;
use wsg_lib::core::Renderer;
use wsg_lib::pipeline::PipelineCache;
use wsg_lib::resources::Material;
use wsg_lib::resources::Mesh;
use wsg_lib::resources::Vertex;
use wsg_lib::resources::{Geometry, Material, Mesh};
use wsg_lib::utils;
/// Application bas-niveau : détient les objets GPU + window, tous créés dans `resumed`.
@@ -70,36 +70,24 @@ impl ApplicationHandler for App {
// 3. Material : On utilise renderer.device() et renderer.format()
let material = Material::new(renderer.format(), "standard", &mut cache);
// Mesh : On utilise le device du renderer
let vertices = [
// Position (x,y,z) | Normale (x,y,z) | UV (u,v) | Couleur (r,g,b,a)
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],
}, // Haut-Gauche (Rouge)
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],
}, // Haut-Droite (Vert)
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],
}, // Bas-Droite (Bleu)
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],
}, // Bas-Gauche (Jaune)
];
let indices: [u16; 6] = [0, 1, 2, 0, 2, 3];
let mesh = Mesh::new(renderer.device(), &vertices, Some(&indices));
// Mesh : on utilise le device du renderer. Depuis l'Étape 8 le mesh est construit depuis une
// `Geometry` (positions + couleurs par sommet) via `Mesh::from_geometry` — le mesh garde aussi
// l'`Arc<Geometry>` côté CPU (rétention D5).
let geometry = Geometry::new(vec![
// Position (x,y,z) | Couleur (r,g,b,a) — normales/UV par défaut via to_vertices
[-0.5, 0.5, 0.0],
[0.5, 0.5, 0.0],
[0.5, -0.5, 0.0],
[-0.5, -0.5, 0.0],
])
.with_colors(vec![
[1.0, 0.0, 0.0, 1.0], // Haut-Gauche (Rouge)
[0.0, 1.0, 0.0, 1.0], // Haut-Droite (Vert)
[0.0, 0.0, 1.0, 1.0], // Bas-Droite (Bleu)
[1.0, 1.0, 0.0, 1.0], // Bas-Gauche (Jaune)
])
.with_indices(vec![0, 1, 2, 0, 2, 3]);
let mesh = Mesh::from_geometry(renderer.device(), Arc::new(geometry), None);
self.window = Some(window);
self.context = Some(context);