diff options
| author | Freya Murphy <freya@freyacat.org> | 2025-11-07 14:21:03 -0500 |
|---|---|---|
| committer | Freya Murphy <freya@freyacat.org> | 2025-11-07 14:21:03 -0500 |
| commit | 85fa878e5927fe23e8e54e924df688b39215b5bf (patch) | |
| tree | 46692a9f05f181a6c878f21d7c4b97a3430a4910 /graphics | |
| parent | graphics: new UI! (diff) | |
| download | DungeonCrawl-85fa878e5927fe23e8e54e924df688b39215b5bf.tar.gz DungeonCrawl-85fa878e5927fe23e8e54e924df688b39215b5bf.tar.bz2 DungeonCrawl-85fa878e5927fe23e8e54e924df688b39215b5bf.zip | |
graphics: refactor to get rid of casting hell, use u16 when possible
Diffstat (limited to 'graphics')
| -rw-r--r-- | graphics/src/render.rs | 318 |
1 files changed, 177 insertions, 141 deletions
diff --git a/graphics/src/render.rs b/graphics/src/render.rs index 87716de..1d79b13 100644 --- a/graphics/src/render.rs +++ b/graphics/src/render.rs @@ -1,8 +1,8 @@ use std::ops::Div; use dungeon::{ - Direction, Dungeon, Entity, EntityKind, FPos, Floor, Item, MAP_SIZE, - PLAYER_INVENTORY_SIZE, Player, Pos, Tile, + Direction, Dungeon, Entity, EntityKind, Floor, Item, MAP_SIZE, PLAYER_INVENTORY_SIZE, + Player, Pos, Tile, }; use raylib::{ RaylibHandle, RaylibThread, @@ -19,14 +19,60 @@ macro_rules! downcast { }; } +macro_rules! rect { + {$x:expr, $y:expr, $w:expr, $h:expr $(,)?} => { + ::raylib::math::Rectangle { + x: ($x) as f32, + y: ($y) as f32, + width: ($w) as f32, + height: ($h) as f32, + } + }; +} + +macro_rules! vec2 { + {$x:expr, $y:expr $(,)?} => { + ::raylib::math::Vector2 { + x: ($x) as f32, + y: ($y) as f32, + } + }; +} + /// The baseline size of all ingame sprites and tile textures -const BASE_TILE_SIZE: i32 = 32; +const BASE_TILE_SIZE: u16 = 32; /// The height of the wall (offset between tile layers) -const WALL_HEIGHT: i32 = 13; +const WALL_HEIGHT: u16 = 13; /// The (prefered) view distance of the game -const VIEW_DISTANCE: i32 = 5; +const VIEW_DISTANCE: u16 = 5; + +// Tile atlas.bmp textures +const ATLAS_WALL_SIDE: (u16, u16) = (0, 0); +const ATLAS_FLOOR_FULL: (u16, u16) = (1, 0); +const ATLAS_FLOOR_EMPTY: (u16, u16) = (2, 0); +const ATLAS_WALL_TOP: (u16, u16) = (3, 0); +const ATLAS_WALL_EDGE: (u16, u16) = (0, 1); + +// Entity atlas.bmp textures +const ATLAS_PLAYER: (u16, u16) = (0, 2); + +// UI atlas.bmp textures +const ATLAS_INV_CONTAINER: (u16, u16) = (1, 1); +const ATLAS_HEART_ICON: (u16, u16) = (2, 1); +const ATLAS_DAMAGE_ICON: (u16, u16) = (3, 1); + +// Misc atlas.bmp textures +const ATLAS_ERROR: (u16, u16) = (3, 3); + +/// Full source rec for any texture +const FULL_SOURCE_REC: Rectangle = rect! { + 0.0, + 0.0, + BASE_TILE_SIZE, + BASE_TILE_SIZE, +}; #[derive(Debug)] struct Textures { @@ -49,32 +95,6 @@ impl Textures { } } -// Tile atlas.bmp textures -const ATLAS_WALL_SIDE: (i32, i32) = (0, 0); -const ATLAS_FLOOR_FULL: (i32, i32) = (1, 0); -const ATLAS_FLOOR_EMPTY: (i32, i32) = (2, 0); -const ATLAS_WALL_TOP: (i32, i32) = (3, 0); -const ATLAS_WALL_EDGE: (i32, i32) = (0, 1); - -// Entity atlas.bmp textures -const ATLAS_PLAYER: (i32, i32) = (0, 2); - -// UI atlas.bmp textures -const ATLAS_INV_CONTAINER: (i32, i32) = (1, 1); -const ATLAS_HEART_ICON: (i32, i32) = (2, 1); -const ATLAS_DAMAGE_ICON: (i32, i32) = (3, 1); - -// Misc atlas.bmp textures -const ATLAS_ERROR: (i32, i32) = (3, 3); - -/// Full source rec for any texture -const FULL_SOURCE_REC: Rectangle = Rectangle { - x: 0.0, - y: 0.0, - width: BASE_TILE_SIZE as f32, - height: BASE_TILE_SIZE as f32, -}; - #[derive(Debug)] pub struct Renderer { /* Persistant Render Data */ @@ -88,20 +108,20 @@ pub struct Renderer { tiles_hash: Option<u64>, /* Per Frame Caculated Data */ /// Current tile size we are rendering - tile_size: i32, + tile_size: u16, /// Last known FPS fps: u32, /// Render width of the current frame - width: i32, + width: u16, /// Render height of the current frame - height: i32, + height: u16, } impl Renderer { pub fn new(handle: &mut RaylibHandle, thread: &RaylibThread) -> crate::Result<Self> { // Load resources let textures = Textures::new(handle, thread)?; // Load render textures - let tex_size = MAP_SIZE as u32 * BASE_TILE_SIZE as u32; + let tex_size = (MAP_SIZE * BASE_TILE_SIZE) as u32; let tilemap_fg = handle.load_render_texture(thread, tex_size, tex_size)?; let tilemap_bg = handle.load_render_texture(thread, tex_size, tex_size)?; @@ -137,14 +157,14 @@ impl Renderer { // Get last known fps self.fps = handle.get_fps(); // Get size of framebuffer - self.width = handle.get_render_width(); - self.height = handle.get_render_height(); + self.width = downcast!(handle.get_render_width(), u16); + self.height = downcast!(handle.get_render_height(), u16); // Get size (in pixels) to draw each tile self.tile_size = { let size = self.width.min(self.height); let dist = VIEW_DISTANCE * 2 + 1; let pixels = size.div(dist).max(BASE_TILE_SIZE); - 1 << (i32::BITS - pixels.leading_zeros()) + 1 << (u16::BITS - pixels.leading_zeros()) }; } @@ -153,16 +173,16 @@ impl Renderer { let cpos = dungeon.camera(); let width = self.width; let height = self.height; - let ui_height = self.get_ui_height() as f32; + let ui_height = self.get_ui_height(); Camera2D { target: Vector2::from(cpos.xy()) - .scale_by(self.tile_size as f32) - .max(Vector2::new(width as f32 / 2.0, height as f32 / 2.0)) - .min(Vector2::new( - (MAP_SIZE as i32 * self.tile_size) as f32 - (width as f32 / 2.0), - (MAP_SIZE as i32 * self.tile_size) as f32 - (height as f32 / 2.0), - )), - offset: Vector2::new(width as f32 / 2.0, height as f32 / 2.0 + ui_height), + .scale_by(self.tile_size.into()) + .max(vec2! {width/2, height/2}) + .min(vec2! { + (MAP_SIZE * self.tile_size) - (width/2), + (MAP_SIZE * self.tile_size) - (height/2), + }), + offset: vec2! {width/2, height/2 + ui_height}, rotation: 0.0, zoom: 1.0, } @@ -204,13 +224,12 @@ impl Renderer { where R: RaylibDraw + RaylibTextureModeExt, { - let size = BASE_TILE_SIZE as f32; + let size = BASE_TILE_SIZE; let mut rt = r.begin_texture_mode(t, &mut self.tilemap_fg); rt.clear_background(Color::BLANK); for pos in Pos::values() { - let (fx, fy) = FPos::from(pos).xy(); - let (xs, ys) = (fx * size, fy * size); + let (xs, ys) = (pos.x() * size, pos.y() * size); // fg layer only draws a top walls if floor.get(pos) != Tile::Wall { @@ -243,7 +262,7 @@ impl Renderer { where R: RaylibDraw + RaylibTextureModeExt, { - let size = BASE_TILE_SIZE as f32; + let size = BASE_TILE_SIZE; let mut rt = r.begin_texture_mode(t, &mut self.tilemap_bg); rt.clear_background(Color::BLACK); @@ -256,14 +275,7 @@ impl Renderer { Tile::Air if (x + y) % 2 == 1 => ATLAS_FLOOR_EMPTY, _ => ATLAS_ERROR, }; - rt.draw_atlas( - &self.textures.atlas, - idx, - x as f32 * size, - y as f32 * size, - size, - 0.0, - ); + rt.draw_atlas(&self.textures.atlas, idx, x * size, y * size, size, 0.0); } } @@ -272,9 +284,7 @@ impl Renderer { where R: RaylibDraw, { - let size = self.tile_size as f32; - let offset = WALL_HEIGHT as f32; - r.draw_tilemap(&self.tilemap_fg, size, offset); + r.draw_tilemap(&self.tilemap_fg, self.tile_size, WALL_HEIGHT); } /// Draw dungeon tiles (background layer) @@ -282,9 +292,7 @@ impl Renderer { where R: RaylibDraw, { - let size = self.tile_size as f32; - let offset = 0.0; - r.draw_tilemap(&self.tilemap_bg, size, offset); + r.draw_tilemap(&self.tilemap_bg, self.tile_size, 0); } /// Draws the entities on the map @@ -314,17 +322,17 @@ impl Renderer { } /// Returns the known UI height for this frame - fn get_ui_height(&self) -> i32 { + fn get_ui_height(&self) -> u16 { self.tile_size } /// Returns the padding used between ui elements - fn get_ui_padding(&self) -> i32 { + fn get_ui_padding(&self) -> u16 { self.get_ui_height() / 10 } /// Returns the font size for the UI - fn get_ui_font_size(&self) -> i32 { + fn get_ui_font_size(&self) -> u16 { self.get_ui_height() / 4 } @@ -334,7 +342,7 @@ impl Renderer { R: RaylibDraw, { // Draw UI base rect - r.draw_rectangle(0, 0, self.width, self.get_ui_height(), Color::BLACK); + r.draw_rectangle_ext(0, 0, self.width, self.get_ui_height(), Color::BLACK); // Draw core ui components self.draw_minimap(r, dungeon); @@ -361,19 +369,16 @@ impl Renderer { // Draw minimap in top left of UI bar let minimap_x = text_x + self.get_ui_font_size() + padding; let size = self.get_ui_height() - padding * 2; - r.draw_rectangle(minimap_x, y, size, size, Color::DARKGRAY); - - let size_u16 = downcast!(size, u16); - let group_size = (MAP_SIZE / size_u16).max(1); + let group_size = (MAP_SIZE / size).max(1); let groups = MAP_SIZE / group_size; - let dot_size = size_u16 / groups; + let dot_size = size / groups; let mut draw_dot = |x_idx: u16, y_idx: u16, color| { - r.draw_rectangle( - minimap_x + (x_idx * dot_size) as i32, - padding + (y_idx * dot_size) as i32, - dot_size as i32, - dot_size as i32, + r.draw_rectangle_ext( + minimap_x + x_idx * dot_size, + padding + y_idx * dot_size, + dot_size, + dot_size, color, ); }; @@ -409,7 +414,7 @@ impl Renderer { } /// Draws vertical text - fn draw_vertical_text<R>(&self, r: &mut R, x: i32, y: i32, text: &str, color: Color) + fn draw_vertical_text<R>(&self, r: &mut R, x: u16, y: u16, text: &str, color: Color) where R: RaylibDraw, { @@ -418,11 +423,11 @@ impl Renderer { let spacing = font_size + padding; let mut byte_off = 0; for (idx_usize, char) in text.chars().enumerate() { - let idx = downcast!(idx_usize, i32); + let idx = downcast!(idx_usize, u16); let byte_len = char.len_utf8(); let str = &text[byte_off..byte_off + byte_len]; let char_y = y + idx * spacing; - r.draw_text(str, x, char_y, font_size, color); + r.draw_text_ext(str, x, char_y, font_size, color); byte_off += byte_len; } } @@ -433,7 +438,7 @@ impl Renderer { where R: RaylibDraw, { - let slots = downcast!(PLAYER_INVENTORY_SIZE, i32); + let slots = downcast!(PLAYER_INVENTORY_SIZE, u16); let padding = self.get_ui_padding(); let font_size = self.get_ui_font_size(); let ui_height = self.get_ui_height(); @@ -458,27 +463,27 @@ impl Renderer { break; } - let slot_x = slots_x + slot_len * downcast!(idx, i32); - let size = (ui_height - padding * 2) as f32; + let slot_x = slots_x + slot_len * downcast!(idx, u16); + let size = ui_height - padding * 2; // Draw slot container r.draw_inv_atlas( &self.textures.atlas, ATLAS_INV_CONTAINER, - slot_x as f32, - padding as f32, + slot_x, + padding, size, 0.0, ); if let Some(item) = player.inventory.get(idx) { let tex = self.textures.item_texture(item); - let item_padding = padding as f32 * 3.0; - let dest_rec = Rectangle { - x: slot_x as f32 + item_padding / 2.0, - y: padding as f32 + item_padding / 2.0, - width: size - item_padding, - height: size - item_padding, + let item_padding = padding * 3; + let dest_rec = rect! { + slot_x + item_padding / 2, + padding+ item_padding / 2, + size - item_padding, + size - item_padding, }; r.draw_texture_pro( tex, @@ -514,12 +519,12 @@ impl Renderer { r.draw_inv_atlas( &self.textures.atlas, ATLAS_HEART_ICON, - icon_x as f32, - heart_y as f32, - icon_width as f32, + icon_x, + heart_y, + icon_width, 0.0, ); - r.draw_text( + r.draw_text_ext( &format!("x{health:02}"), text_x, heart_y + padding, @@ -532,12 +537,12 @@ impl Renderer { r.draw_inv_atlas( &self.textures.atlas, ATLAS_DAMAGE_ICON, - icon_x as f32, - damage_y as f32, - icon_width as f32, + icon_x, + damage_y, + icon_width, 0.0, ); - r.draw_text( + r.draw_text_ext( &format!("x{damage:02}"), text_x, damage_y + padding, @@ -563,7 +568,7 @@ impl Renderer { R: RaylibDraw, { let fps_str = format!("{}", self.fps); - r.draw_text(&fps_str, 10, 10, 30, Color::YELLOW); + r.draw_text_ext(&fps_str, 10, 10, 30, Color::YELLOW); } } @@ -633,70 +638,101 @@ where fn draw_atlas( &mut self, tex: &Texture2D, - (ax, ay): (i32, i32), - x: f32, - y: f32, - size: f32, - rotation: f32, + (ax, ay): (u16, u16), + x: impl Into<f32>, + y: impl Into<f32>, + size: impl Into<f32>, + rotation: impl Into<f32>, ) { - let source_rec = Rectangle { - x: (ax * BASE_TILE_SIZE) as f32, - y: (ay * BASE_TILE_SIZE) as f32, - width: BASE_TILE_SIZE as f32, - height: BASE_TILE_SIZE as f32, + let size_into = size.into(); + let source_rec = rect! { + ax * BASE_TILE_SIZE, + ay * BASE_TILE_SIZE, + BASE_TILE_SIZE, + BASE_TILE_SIZE, }; - let dest_rec = Rectangle { - x, - y, - width: size, - height: size, + let dest_rec = rect! { + x.into(), + y.into(), + size_into, + size_into, }; - let origin = Vector2 { - x: dest_rec.width / 2.0, - y: dest_rec.height / 2.0, + let origin = vec2! { + dest_rec.width / 2.0, + dest_rec.height / 2.0, }; - self.draw_texture_pro(tex, source_rec, dest_rec, origin, rotation, Color::WHITE); + self.draw_texture_pro( + tex, + source_rec, + dest_rec, + origin, + rotation.into(), + Color::WHITE, + ); } /// Draw in INV element from an atlas fn draw_inv_atlas( &mut self, tex: &Texture2D, - (ax, ay): (i32, i32), - x: f32, - y: f32, - size: f32, - rotation: f32, + (ax, ay): (u16, u16), + x: impl Into<f32>, + y: impl Into<f32>, + size: impl Into<f32>, + rotation: impl Into<f32>, ) { + let size_into = size.into(); self.draw_atlas( tex, (ax, ay), - x + size / 2.0, - y + size / 2.0, - size, + x.into() + size_into / 2.0, + y.into() + size_into / 2.0, + size_into, rotation, ); } /// Draw dungeon tiles helper function - fn draw_tilemap(&mut self, tex: &RenderTexture2D, size: f32, offset: f32) { - let scale = size / BASE_TILE_SIZE as f32; - let width = tex.width() as f32; - let height = tex.height() as f32; - let source_rec = Rectangle { - x: 0.0, - y: 0.0, + fn draw_tilemap(&mut self, tex: &RenderTexture2D, size: u16, offset: u16) { + let scale = size / BASE_TILE_SIZE; + let width = downcast!(tex.width(), u16); + let height = downcast!(tex.height(), u16); + let source_rec = rect! { + 0, + 0, width, - height: -height, + -height.cast_signed(), }; - let dest_rec = Rectangle { - x: 0.0, - y: -(offset * scale), - width: width * scale, - height: height * scale, + let dest_rec = rect! { + 0, + -(offset * scale).cast_signed(), + width * scale, + height * scale, }; let origin = Vector2::zero(); self.draw_texture_pro(tex, source_rec, dest_rec, origin, 0.0, Color::WHITE); } + + fn draw_text_ext( + &mut self, + text: &str, + x: impl Into<i32>, + y: impl Into<i32>, + font_size: impl Into<i32>, + color: Color, + ) { + self.draw_text(text, x.into(), y.into(), font_size.into(), color); + } + + fn draw_rectangle_ext( + &mut self, + x: impl Into<i32>, + y: impl Into<i32>, + width: impl Into<i32>, + height: impl Into<i32>, + color: Color, + ) { + self.draw_rectangle(x.into(), y.into(), width.into(), height.into(), color); + } } impl<T> RaylibDrawExt for T where T: RaylibDraw {} |