From 99976f29341fef274c8fa69dd8e0c56fe74597d6 Mon Sep 17 00:00:00 2001 From: Warren Lo Date: Thu, 19 Mar 2026 01:08:21 +0800 Subject: [PATCH] Add SDL2 renderer module --- src/player/renderer.rs | 115 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 115 insertions(+) create mode 100644 src/player/renderer.rs diff --git a/src/player/renderer.rs b/src/player/renderer.rs new file mode 100644 index 0000000..c53e400 --- /dev/null +++ b/src/player/renderer.rs @@ -0,0 +1,115 @@ +//! SDL2 renderer module + +use anyhow::Result; +use sdl2::pixels::PixelFormatEnum; +use sdl2::rect::Rect; +use std::sync::{Arc, Mutex}; + +pub struct Renderer { + sdl: sdl2::Sdl, + video_subsystem: sdl2::VideoSubsystem, + window: sdl2::video::Window, + canvas: sdl2::render::Canvas, + texture_creator: sdl2::render::TextureCreator, + texture: Option, + width: u32, + height: u32, +} + +impl Renderer { + pub fn new(title: &str, width: u32, height: u32) -> Result { + let sdl = sdl2::init()?; + let video_subsystem = sdl.video()?; + + let window = video_subsystem + .window(title, width, height) + .position_centered() + .build()?; + + let canvas = window.into_canvas().build()?; + let texture_creator = canvas.texture_creator(); + + Ok(Self { + sdl, + video_subsystem, + window, + canvas, + texture_creator, + texture: None, + width, + height, + }) + } + + pub fn create_texture(&mut self, width: u32, height: u32) -> Result<()> { + self.texture = Some( + self.texture_creator + .create_texture_streaming(PixelFormatEnum::RGB24, width, height)? + ); + self.width = width; + self.height = height; + Ok(()) + } + + pub fn update_texture(&mut self, data: &[u8]) -> Result<()> { + if let Some(ref mut texture) = self.texture { + texture.update(None, data, self.width as usize * 3)?; + } + Ok(()) + } + + pub fn clear(&mut self) { + self.canvas.set_draw_color(sdl2::pixels::Color::BLACK); + self.canvas.clear(); + } + + pub fn draw_bbox(&mut self, x: i32, y: i32, w: u32, h: u32, label: &str) { + // Draw rectangle border + self.canvas.set_draw_color(sdl2::pixels::Color::RGB(0, 255, 0)); + let _ = self.canvas.draw_rect(Rect::new(x, y, w, h)); + + // Draw label background + let label_rect = Rect::new(x, y - 20, 100, 20); + self.canvas.set_draw_color(sdl2::pixels::Color::RGBA(0, 0, 0, 180)); + let _ = self.canvas.fill_rect(label_rect); + } + + pub fn present(&mut self) { + // Draw texture if available + if let Some(ref texture) = self.texture { + self.canvas.copy(texture, None, None).ok(); + } + self.canvas.present(); + } + + pub fn set_fullscreen(&mut self, fullscreen: bool) -> Result<()> { + if fullscreen { + self.window.set_fullscreen(sdl2::video::FullscreenType::Desktop)?; + } else { + self.window.set_fullscreen(sdl2::video::FullscreenType::Off)?; + } + Ok(()) + } + + pub fn resize(&mut self, width: u32, height: u32) -> Result<()> { + self.window.set_size(width, height)?; + Ok(()) + } + + pub fn poll_events(&mut self) -> Vec { + let mut events = Vec::new(); + let pump = self.sdl.event_pump(); + if let Ok(pump) = pump { + for event in pump.poll_iter() { + events.push(event); + } + } + events + } +} + +impl Drop for Renderer { + fn drop(&mut self) { + // Cleanup handled automatically + } +}