# pbio: simple pixel buffer and I/O system — 16-Bit-Truecolor-Variante Pixelbuffer-basiertes Fenster mit RGB565-Truecolor-Renderer (winit + wgpu) und Maus/Tastatureingaben. pbio nimmt ein `u16`-Array, interpretiert jeden Wert als RGB565-Pixel (Bits `RRRRRGGGGGGBBBBB`) und rendert ihn auf ein Fenster. Optional mit Letterbox für ein festes Seitenverhältnis. Dies ist der Branch `truecolor16`. Auf `master` liegt die 8-Bit-Variante mit Palette-Lookup — beide sind unabhängig voneinander nutzbar. ## Integration pbio ist nicht auf crates.io veröffentlicht. Das Crate kann direkt aus dem Git-Repository eingebunden werden: ```toml [dependencies] pbio = { git = "https://codeberg.org/irrlicht/rust-pbio.git", branch = "truecolor16" } ``` pbio braucht keine System-Libraries zum Bauen — winit lädt X11/Wayland zur Laufzeit per dlopen. Zur Laufzeit reichen aktuelle Grafiktreiber mit Vulkan-, Metal- oder DX12-Unterstützung für wgpu. ## Verwendung ```rust use pbio::{Event, Key, Platform, PlatformConfig}; fn main() { let mut p = Platform::new(PlatformConfig { title: "Demo".into(), window_size: (1024, 768), framebuffer_size: (320, 240), ..Default::default() }); while !p.should_close() { p.poll_events(None); while let Some(ev) = p.poll_event() { if let Event::Key { key: Key::Escape, pressed: true, .. } = ev { p.request_close(); } } let (w, _h) = p.framebuffer_size(); let fb = p.framebuffer_mut(); for (i, px) in fb.iter_mut().enumerate() { let v = ((i as u32 % w) ^ (i as u32 / w)) as u8; *px = pbio::rgb565(v, v, v); } p.present(); } } ``` ## API-Überblick - `PlatformConfig` – Titel, Fenster-/Framebuffer-Größe, optionales `aspect_ratio` (Letterbox), VSync, `mouse_visible`, `mouse_capture`. Default = 800×600 Fenster, 320×240 Framebuffer, 4:3. - `Platform::new(cfg)` – Fenster + GPU-Pipeline aufsetzen. - `poll_events(timeout)` – winit-Events einlesen (`None` = blockierend). - `poll_event() -> Option` – ein Event aus der Queue holen. Gibt `&mut self` nach jedem Call frei, sodass im Loop direkt auf die Platform reagiert werden kann (`request_close`, `set_mouse_capture` …). Empfohlen für die normale Event-Schleife. - `drain_events()` – Iterator über `Event` (`Key`, `Char`, `MouseMove`, `MouseBtn`, `Resize`, `CloseRequested`). Borrowt `&mut self` bis der Iterator fertig ist — Reaktionen auf die Platform müssen dann nach dem Loop angewandt werden. Nützlich für reines Loggen/Filtern. - `framebuffer_mut()` – `&mut [u16]` der Länge `w*h`, je Pixel ein RGB565-Wert. - `rgb565(r, g, b) -> u16` – packt 8-Bit-RGB in einen RGB565-Pixelwert (const fn). - `present()` – Frame auf das Fenster bringen. - `should_close()` / `request_close()`. - `set_mouse_visible(bool)` – Cursor anzeigen oder verstecken (freie Bewegung). - `set_mouse_capture(bool)` – Cursor einsperren + verstecken (winit `CursorGrabMode::Locked`, Fallback `Confined`), liefert unbegrenzte Bewegungsdeltas via `mouse_delta()`. Impliziert `mouse_visible = false`. Im Capture-Mode ist `Event::MouseMove` nicht sinnvoll (eingefrorene oder am Fensterrand klemmende Werte) — stattdessen `mouse_delta()` benutzen. - `mouse_delta() -> (f32, f32)` – akkumulierte Mausbewegung seit dem letzten Aufruf in Framebuffer-Pixeln (gleiche Skala wie `MouseMove`), danach genullt. Nützlich für FPS-Kamerasteuerung. ### Cursor-Modi | `mouse_visible` | `mouse_capture` | winit-Modus | Einsatz | |---|---|---|---| | `true` | `false` | sichtbar, frei | Standard-UI | | `false` | `false` | versteckt, frei | Eigener Cursor im Framebuffer | | `*` | `true` | `Locked` / `Confined`, versteckt | FPS-Kamera, unbegrenzte Deltas | ```rust // FPS-Kamera p.set_mouse_capture(true); let (dx, dy) = p.mouse_delta(); yaw += dx * sensitivity; pitch += dy * sensitivity; ``` ## Pixelformat RGB565: 5 Bit Rot, 6 Bit Grün, 5 Bit Blau in einem `u16` (Bits `RRRRRGGGGGGBBBBB`). Der Shader dekodiert die Bitfelder direkt — es gibt keine Palette. Zum Packen von 8-Bit-Kanälen dient `pbio::rgb565`: ```rust let orange = pbio::rgb565(255, 160, 0); p.framebuffer_mut()[0] = orange; ```