centralized state

This commit is contained in:
2026-06-13 13:44:02 +02:00
parent 0a8861a5b1
commit 48c499e356
11 changed files with 693 additions and 206 deletions
+29 -46
View File
@@ -1,9 +1,8 @@
//! wgpu-Zustand: Surface, Device und der zweistufige Render-Pfad
//! aus dem Renderer-Plan:
//!
//! Pass 1 (intern): 320×240 RGBA8 + Depth — hier entsteht das Bild.
//! Aktuell nur ein Testmuster-Shader; Schritt 3
//! ersetzt ihn durch die Szenen-Pipeline.
//! Pass 1 (intern): 320×240 RGBA8 + Depth — hier entsteht das Bild
//! ([`ScenePass`], PS1-Shader).
//! Pass 2 (Fenster): Nearest-Upscale des internen Targets mit
//! 4:3-Letterbox (via Viewport) auf die Surface.
@@ -11,8 +10,11 @@ use std::sync::Arc;
use winit::window::Window;
pub const INTERNAL_W: u32 = 320;
pub const INTERNAL_H: u32 = 240;
use crate::render::math::Mat4;
use crate::render::scene::ScenePass;
pub const INTERNAL_W: u32 = 480;
pub const INTERNAL_H: u32 = 360;
/// D16 reicht für PS1-Geometrieskalen und ist das älteste, überall
/// (auch GL-Fallback) unterstützte Depth-Format.
@@ -28,9 +30,9 @@ pub struct Gpu {
internal_view: wgpu::TextureView,
depth_view: wgpu::TextureView,
pattern_pipeline: wgpu::RenderPipeline,
blit_pipeline: wgpu::RenderPipeline,
blit_bind: wgpu::BindGroup,
scene: ScenePass,
blit_pipeline: wgpu::RenderPipeline,
blit_bind: wgpu::BindGroup,
}
impl Gpu {
@@ -84,40 +86,8 @@ impl Gpu {
let (internal_view, depth_view) = make_internal_targets(&device);
// Pass 1: Testmuster auf das interne Target.
let pattern_shader = device.create_shader_module(wgpu::ShaderModuleDescriptor {
label: Some("pattern"),
source: wgpu::ShaderSource::Wgsl(include_str!("pattern.wgsl").into()),
});
let pattern_pipeline = device.create_render_pipeline(&wgpu::RenderPipelineDescriptor {
label: Some("pattern"),
layout: None,
vertex: wgpu::VertexState {
module: &pattern_shader,
entry_point: Some("vs_main"),
compilation_options: Default::default(),
buffers: &[],
},
fragment: Some(wgpu::FragmentState {
module: &pattern_shader,
entry_point: Some("fs_main"),
compilation_options: Default::default(),
targets: &[Some(INTERNAL_FORMAT.into())],
}),
primitive: wgpu::PrimitiveState::default(),
// Depth hängt am Pass (Schritt 3 braucht es); das Muster
// selbst schreibt/testet nicht.
depth_stencil: Some(wgpu::DepthStencilState {
format: DEPTH_FORMAT,
depth_write_enabled: Some(false),
depth_compare: Some(wgpu::CompareFunction::Always),
stencil: wgpu::StencilState::default(),
bias: wgpu::DepthBiasState::default(),
}),
multisample: wgpu::MultisampleState::default(),
multiview_mask: None,
cache: None,
});
// Pass 1: die Szene.
let scene = ScenePass::new(&device, INTERNAL_FORMAT, DEPTH_FORMAT);
// Pass 2: internes Target nearest-gesampelt auf die Surface.
let blit_shader = device.create_shader_module(wgpu::ShaderModuleDescriptor {
@@ -169,7 +139,7 @@ impl Gpu {
Self {
surface, device, queue, config,
internal_view, depth_view,
pattern_pipeline, blit_pipeline, blit_bind,
scene, blit_pipeline, blit_bind,
}
}
@@ -179,7 +149,21 @@ impl Gpu {
self.surface.configure(&self.device, &self.config);
}
pub fn frame(&mut self) {
/// Einen Frame rendern. `t` = Sekunden seit Start (treibt vorerst
/// die Orbit-Kamera; ab Schritt 4 kommt die Kamera vom Aufrufer).
pub fn frame(&mut self, t: f32) {
// Hartkodierte Orbit-Kamera um den Testwürfel — macht Vertex-Snap
// und Dither in Bewegung sichtbar. Die Flycam ersetzt sie.
let yaw = t * 0.4;
let eye = [2.2 * yaw.sin(), 1.3, 2.2 * yaw.cos()];
let view = Mat4::view(eye, yaw, -0.5);
let proj = Mat4::perspective(
60f32.to_radians(),
INTERNAL_W as f32 / INTERNAL_H as f32,
0.1, 100.0,
);
self.scene.prepare(&self.queue, &proj.mul(&view));
use wgpu::CurrentSurfaceTexture as Cst;
let frame = match self.surface.get_current_texture() {
Cst::Success(f) | Cst::Suboptimal(f) => f,
@@ -221,8 +205,7 @@ impl Gpu {
occlusion_query_set: None,
multiview_mask: None,
});
pass.set_pipeline(&self.pattern_pipeline);
pass.draw(0..3, 0..1);
self.scene.draw(&mut pass);
}
// Pass 2: Letterbox-Blit aufs Fenster.