Framebuffer ist jetzt &mut [u16], jeder Wert ein RGB565-Pixel. Der Shader dekodiert die Bitfelder direkt aus einer R16Uint-Textur; die Palette (Textur, API, Presets, Tooling) entfaellt. Neu: pbio::rgb565() zum Packen von 8-Bit-Kanaelen. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
4.3 KiB
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:
[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
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, optionalesaspect_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<Event>– ein Event aus der Queue holen. Gibt&mut selfnach 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 überEvent(Key,Char,MouseMove,MouseBtn,Resize,CloseRequested). Borrowt&mut selfbis 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ängew*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 (winitCursorGrabMode::Locked, FallbackConfined), liefert unbegrenzte Bewegungsdeltas viamouse_delta(). Impliziertmouse_visible = false. Im Capture-Mode istEvent::MouseMovenicht sinnvoll (eingefrorene oder am Fensterrand klemmende Werte) — stattdessenmouse_delta()benutzen.mouse_delta() -> (f32, f32)– akkumulierte Mausbewegung seit dem letzten Aufruf in Framebuffer-Pixeln (gleiche Skala wieMouseMove), 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 |
// 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:
let orange = pbio::rgb565(255, 160, 0);
p.framebuffer_mut()[0] = orange;