diff options
| author | Freya Murphy <freya@freyacat.org> | 2025-10-18 13:21:40 -0400 |
|---|---|---|
| committer | Freya Murphy <freya@freyacat.org> | 2025-10-18 13:21:40 -0400 |
| commit | 8e7268c661e8df25224c907ba68eeb5a9cc5ff11 (patch) | |
| tree | 27db2f024ae85d95ca5ba7ead9e637ac3c9c9ee7 /graphics | |
| parent | graphics: remove anyhow (it was not being used) (diff) | |
| download | DungeonCrawl-8e7268c661e8df25224c907ba68eeb5a9cc5ff11.tar.gz DungeonCrawl-8e7268c661e8df25224c907ba68eeb5a9cc5ff11.tar.bz2 DungeonCrawl-8e7268c661e8df25224c907ba68eeb5a9cc5ff11.zip | |
graphics: add audio/texture subsytem
Diffstat (limited to 'graphics')
| -rw-r--r-- | graphics/src/assets.rs | 70 | ||||
| -rw-r--r-- | graphics/src/lib.rs | 32 | ||||
| -rw-r--r-- | graphics/src/render.rs | 28 |
3 files changed, 110 insertions, 20 deletions
diff --git a/graphics/src/assets.rs b/graphics/src/assets.rs new file mode 100644 index 0000000..3f2354a --- /dev/null +++ b/graphics/src/assets.rs @@ -0,0 +1,70 @@ +//! The `assets` crate stores all audio and image assets that need to be +//! loaded during runtime + +use std::error::Error; + +use raylib::{RaylibHandle, RaylibThread, audio::RaylibAudio}; + +#[expect(dead_code)] +type Sound = raylib::audio::Sound<'static>; + +/// The `AudioData` container initalizes the audio subsystem +/// for raylib, leaks it (to gurentee audio is statically loaded), +/// then loads all needed audio samples +#[derive(Debug)] +pub struct AudioData {} +impl AudioData { + pub(crate) fn load() -> Result<Self, Box<dyn Error>> { + // Phantom handle to the raylib audio subsystem + // Raylib doesnt use a handle, but the rust bindings + // have one to ensure memory safety. + // + // We must leak this handle after allocating it, + // if we dont then all audio will be unloaded :( + // + // NOTE: would this cause issues if `AudioData::load` was + // called multiple times? + let _handle = Box::leak(Box::new(RaylibAudio::init_audio_device()?)); + + // TODO: load audio samples + + //let example = handle.new_sound("example.ogg")?; + + Ok(Self {}) + } +} + +/// The `ImageData` container loads all game sprites, and other images into memory. +#[derive(Debug)] +pub(crate) struct ImageData {} +impl ImageData { + pub(crate) fn load( + _handle: &mut RaylibHandle, + _thread: &RaylibThread, + ) -> Result<Self, Box<dyn Error>> { + // TODO: load image data + + //let example = handle.load_texture(&thread, "example.png"); + + Ok(Self {}) + } +} + +#[derive(Debug)] +pub(crate) struct Assets { + /// Audio needs to be accessible outside of the renderer + pub(crate) audio: AudioData, + /// Images are only needed by the renderer + pub(crate) image: ImageData, +} +impl Assets { + pub(crate) fn load( + handle: &mut RaylibHandle, + thread: &RaylibThread, + ) -> Result<Self, Box<dyn Error>> { + let audio = AudioData::load()?; + let image = ImageData::load(handle, thread)?; + + Ok(Self { audio, image }) + } +} diff --git a/graphics/src/lib.rs b/graphics/src/lib.rs index 6e5eb91..1ca03b3 100644 --- a/graphics/src/lib.rs +++ b/graphics/src/lib.rs @@ -2,12 +2,15 @@ //! rendering using the `raylib` library. use std::cell::RefCell; +use std::error::Error; use raylib::prelude::*; +use crate::assets::{Assets, AudioData}; use crate::render::{FrameInfo, Renderer}; -pub mod render; +mod assets; +mod render; /// The `KeyCode` type represents different keys being pressed on the users keyboard pub use raylib::consts::KeyboardKey as KeyCode; @@ -15,8 +18,11 @@ pub use raylib::consts::KeyboardKey as KeyCode; /// The `Window` type represents the game window #[derive(Debug)] pub struct Window { + // core raylib handles handle: RefCell<RaylibHandle>, thread: RaylibThread, + // static assets + assets: Assets, } impl Window { @@ -27,20 +33,25 @@ impl Window { /// ```no_run /// use graphics::Window; /// - /// let window = Window::new(800, 600, "Dungeon Crawl"); + /// let window = Window::new(800, 600, "Dungeon Crawl").unwrap(); /// ``` - pub fn new(width: i32, height: i32, title: &str) -> Self { - let (handle, thread) = raylib::init() + pub fn new(width: i32, height: i32, title: &str) -> Result<Self, Box<dyn Error>> { + let (mut handle, thread) = raylib::init() .size(width, height) .title(title) .resizable() .log_level(TraceLogLevel::LOG_WARNING) .vsync() .build(); - Self { + + // we will now initalize all assets + let assets = Assets::load(&mut handle, &thread)?; + + Ok(Self { handle: RefCell::new(handle), thread, - } + assets, + }) } /// Returns if the window should be closed. @@ -55,11 +66,11 @@ impl Window { /// ```no_run /// use graphics::Window; /// - /// let mut window = Window::new(800, 600, "Dungeon Crawl"); + /// let mut window = Window::new(800, 600, "Dungeon Crawl").unwrap(); /// let mut renderer = window.renderer(); /// ``` pub fn renderer(&mut self) -> Renderer<'_> { - let info = FrameInfo::new(self.handle.get_mut()); + let info = FrameInfo::new(self.handle.get_mut(), &self.assets.image); let handle = self.handle.get_mut().begin_drawing(&self.thread); Renderer::new(handle, info) } @@ -88,4 +99,9 @@ impl Window { pub fn get_key_pressed(&self) -> Option<KeyCode> { self.handle.borrow_mut().get_key_pressed() } + + /// Get audio data for the window + pub fn audio(&self) -> &AudioData { + &self.assets.audio + } } diff --git a/graphics/src/render.rs b/graphics/src/render.rs index 8bde77d..d9b0473 100644 --- a/graphics/src/render.rs +++ b/graphics/src/render.rs @@ -8,21 +8,28 @@ use raylib::{ prelude::{RaylibDraw, RaylibDrawHandle, RaylibHandle}, }; +use crate::assets::ImageData; + /// The `FrameInfo` struct contains information about /// the current frame being rendered. -pub struct FrameInfo { +pub struct FrameInfo<'a> { /// Time in seconds since last frame drawn pub delta: f32, /// FPS for last frame drawn pub fps: u32, + /// Loaded texture data + /// NOTE: remove `expect` once we start using image data!! + #[expect(dead_code)] + pub(crate) image: &'a ImageData, } -impl FrameInfo { +impl<'a> FrameInfo<'a> { /// Creates a new `FrameInfo` from the provided /// `RaylibHandle`. - pub fn new(handle: &RaylibHandle) -> Self { + pub(crate) fn new(handle: &RaylibHandle, image: &'a ImageData) -> Self { Self { delta: handle.get_frame_time(), fps: handle.get_fps(), + image, } } } @@ -31,16 +38,16 @@ impl FrameInfo { /// frame of the game. It is created per frame. pub struct Renderer<'a> { handle: RaylibDrawHandle<'a>, - info: FrameInfo, + info: FrameInfo<'a>, } impl<'a> Renderer<'a> { /// Creates the renderer for the current frame - pub(crate) fn new(handle: RaylibDrawHandle<'a>, info: FrameInfo) -> Self { + pub(crate) fn new(handle: RaylibDrawHandle<'a>, info: FrameInfo<'a>) -> Self { Self { handle, info } } /// Returns the info struct for the current frame - pub fn info(&self) -> &FrameInfo { + pub fn info(&self) -> &FrameInfo<'a> { &self.info } @@ -70,7 +77,7 @@ impl<'a> Renderer<'a> { /// ```no_run /// use dungeon::Dungeon; /// use graphics::Window; - /// let mut window = Window::new(800, 600, "Dungeon Crawl"); + /// let mut window = Window::new(800, 600, "Dungeon Crawl").unwrap(); /// let mut renderer = window.renderer(); /// let dungeon = Dungeon::new(); /// renderer.draw_frame(&dungeon); @@ -94,22 +101,19 @@ impl<'a> Renderer<'a> { self.draw_fps(); } - /// Draw game over screen - pub fn draw_game_over(&mut self) { - // TODO: - } - /// Draw the player sprite pub fn draw_player(&mut self, player: &Player) { self.draw_entity(&player.entity); } /// Draws an entity + #[expect(clippy::unused_self)] pub fn draw_entity(&mut self, _entity: &Entity) { // TODO: } /// Draw dungeon tiles + #[expect(clippy::unused_self)] pub fn draw_tiles(&mut self, _dungeon: &Dungeon) { // TODO: } |