//! Icons are map elements that have a specific size and cannot be stretched. They are usually used //! as markers for specific places in the world. use super::icon_renderer::IconRenderer; use crate::colours::DEFAULT_COLOURS; use crate::map::Mappable; use crate::math::{Rect, Vec2}; use crate::transform::Transform; use raylib::core::drawing::{RaylibDraw, RaylibDrawHandle}; use serde::{Deserialize, Serialize}; use std::ops::{Deref, DerefMut}; use std::rc::Rc; /// The icon data necessary to create an Icon again. #[derive(Clone, Serialize, Deserialize)] pub struct IconData { /// The id of the icon is the icons position in the currently loaded icon_data vector. pub id: usize, /// The position of the icon on the map, given by the vector in meters. pub position: Vec2, /// Rotation of the icon texture in degrees. pub rotation: f64, } /// Describes an icon in the world and can be drawn. #[derive(Clone)] pub struct Icon { data: IconData, selected: bool, renderer: Rc, } impl Icon { /// Create a new icon. Requires the icon renderer that is used to render this icon, as well as all /// the information necessary to describe the icon itself. pub fn new(id: usize, position: Vec2, rotation: f64, renderer: Rc) -> Self { Self::from_data( IconData { id, position, rotation, }, renderer, ) } /// Like `new()`, but with the icon data bundled into the icon data type. pub fn from_data(data: IconData, renderer: Rc) -> Self { Self { data, selected: false, renderer, } } } impl Mappable for Icon { fn draw(&self, rld: &mut RaylibDrawHandle, transform: &Transform) { let (texture, info) = self.renderer.get(self.id); // Round the position to whole pixels to fix rotation problems. let mut position_px = transform.point_m_to_px(&(self.position - (info.anchor / info.pixels_per_m))); position_px.x = position_px.x.floor(); position_px.y = position_px.y.floor(); rld.draw_texture_ex( texture, position_px, self.rotation as f32, (transform.pixels_per_m() / info.pixels_per_m) as f32, if self.selected() { DEFAULT_COLOURS.icon_selected } else { DEFAULT_COLOURS.icon_normal }, ); } fn set_selected(&mut self, selected: bool) { self.selected = selected; } fn selected(&self) -> bool { self.selected } fn bounding_rect(&self) -> Rect { Rect::new(self.data.position.x, self.data.position.y, 0., 0.) } } impl Deref for Icon { type Target = IconData; fn deref(&self) -> &Self::Target { &self.data } } impl DerefMut for Icon { fn deref_mut(&mut self) -> &mut Self::Target { &mut self.data } }