idk shitload of stuff

This commit is contained in:
2026-06-13 18:18:17 +02:00
parent 48c499e356
commit 6bb9b009c4
24 changed files with 3221 additions and 119 deletions
+42 -16
View File
@@ -10,11 +10,14 @@ use std::sync::Arc;
use winit::window::Window;
use crate::engine::tga::Image;
use crate::render::math::Mat4;
use crate::render::scene::ScenePass;
use crate::render::scene::{Mesh, ScenePass};
use crate::render::sprite::SpritePass;
use crate::render::ui::Ui;
pub const INTERNAL_W: u32 = 480;
pub const INTERNAL_H: u32 = 360;
pub const INTERNAL_W: u32 = 320;
pub const INTERNAL_H: u32 = 240;
/// D16 reicht für PS1-Geometrieskalen und ist das älteste, überall
/// (auch GL-Fallback) unterstützte Depth-Format.
@@ -31,12 +34,19 @@ pub struct Gpu {
depth_view: wgpu::TextureView,
scene: ScenePass,
sprite: SpritePass,
blit_pipeline: wgpu::RenderPipeline,
blit_bind: wgpu::BindGroup,
}
impl Gpu {
pub fn new(window: Arc<Window>, display: winit::event_loop::OwnedDisplayHandle) -> Self {
pub fn new(
window: Arc<Window>,
display: winit::event_loop::OwnedDisplayHandle,
mesh: &Mesh,
images: &[Image],
ui_textures: &[Image],
) -> Self {
let size = window.inner_size();
// Display-Handle mitgeben: für den GL-Fallback (v.a. Wayland)
// Pflicht; Vulkan ignoriert es. `with_env` erlaubt Overrides wie
@@ -86,8 +96,15 @@ impl Gpu {
let (internal_view, depth_view) = make_internal_targets(&device);
// Pass 1: die Szene.
let scene = ScenePass::new(&device, INTERNAL_FORMAT, DEPTH_FORMAT);
// Pass 1: die Szene. Geometrie + Bilder kommen fertig vom Aufrufer
// (Decode in render::run); hier wird nur hochgeladen.
let scene = ScenePass::new(&device, &queue, INTERNAL_FORMAT, DEPTH_FORMAT, mesh, images);
// Overlay-Pass: zeichnet nach der Szene ins selbe interne Target.
let sprite = SpritePass::new(
&device, &queue, INTERNAL_FORMAT, DEPTH_FORMAT,
[INTERNAL_W as f32, INTERNAL_H as f32], ui_textures,
);
// Pass 2: internes Target nearest-gesampelt auf die Surface.
let blit_shader = device.create_shader_module(wgpu::ShaderModuleDescriptor {
@@ -139,7 +156,7 @@ impl Gpu {
Self {
surface, device, queue, config,
internal_view, depth_view,
scene, blit_pipeline, blit_bind,
scene, sprite, blit_pipeline, blit_bind,
}
}
@@ -149,20 +166,27 @@ impl Gpu {
self.surface.configure(&self.device, &self.config);
}
/// 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);
/// Fenster-Pixel (physisch) → interne Pixel, über dieselbe Letterbox wie
/// der Blit. Außerhalb des Bildbereichs auf die Ränder geklemmt.
pub fn map_cursor(&self, win: [f32; 2]) -> [f32; 2] {
let (vx, vy, vw, vh) = letterbox(self.config.width, self.config.height);
let ix = (win[0] - vx) / vw * INTERNAL_W as f32;
let iy = (win[1] - vy) / vh * INTERNAL_H as f32;
[ix.clamp(0.0, INTERNAL_W as f32), iy.clamp(0.0, INTERNAL_H as f32)]
}
/// Einen Frame rendern. Die View-Matrix kommt vom Aufrufer (Flycam);
/// die Projektion gehört hierher, weil sie an der internen Auflösung
/// hängt.
pub fn frame(&mut self, view: &Mat4, ui: &Ui) {
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));
let half_res = [INTERNAL_W as f32 * 0.5, INTERNAL_H as f32 * 0.5];
self.scene.prepare(&self.queue, &proj.mul(view), half_res);
self.sprite.prepare(&self.queue, &ui.verts);
use wgpu::CurrentSurfaceTexture as Cst;
let frame = match self.surface.get_current_texture() {
@@ -206,6 +230,8 @@ impl Gpu {
multiview_mask: None,
});
self.scene.draw(&mut pass);
// Overlay obenauf, im selben Pass (kein Tiefentest).
self.sprite.draw(&mut pass, &ui.batches);
}
// Pass 2: Letterbox-Blit aufs Fenster.