diff options
| author | Arne Dußin | 2020-11-06 00:53:46 +0100 |
|---|---|---|
| committer | Arne Dußin | 2020-11-06 00:53:46 +0100 |
| commit | 625d00bb0e9a374e7ecf4b91fde599307199f3b6 (patch) | |
| tree | 3dfdcc544c5b29f1f49d09a374d129bd825ade56 | |
| parent | 6d5db404416b93d22438efd45c7df7be2cc67d11 (diff) | |
| download | graf_karto-625d00bb0e9a374e7ecf4b91fde599307199f3b6.tar.gz graf_karto-625d00bb0e9a374e7ecf4b91fde599307199f3b6.zip | |
Add icon tool
| -rw-r--r-- | assets/icons/triangle.png | bin | 0 -> 1672 bytes | |||
| -rw-r--r-- | assets/icons/triangle.ron | 7 | ||||
| -rw-r--r-- | src/editor.rs | 10 | ||||
| -rw-r--r-- | src/grid.rs | 10 | ||||
| -rw-r--r-- | src/main.rs | 3 | ||||
| -rw-r--r-- | src/map_data.rs | 10 | ||||
| -rw-r--r-- | src/tool/icon_tool.rs | 142 | ||||
| -rw-r--r-- | src/tool/mod.rs | 3 | ||||
| -rw-r--r-- | src/tool/room_tool.rs | 14 | ||||
| -rw-r--r-- | src/tool/wall_tool.rs | 14 |
10 files changed, 188 insertions, 25 deletions
diff --git a/assets/icons/triangle.png b/assets/icons/triangle.png Binary files differnew file mode 100644 index 0000000..daf0fd1 --- /dev/null +++ b/assets/icons/triangle.png diff --git a/assets/icons/triangle.ron b/assets/icons/triangle.ron new file mode 100644 index 0000000..11e9f6a --- /dev/null +++ b/assets/icons/triangle.ron @@ -0,0 +1,7 @@ +IconInfo ( + anchor: ( + x: 10, + y: 10 + ), + pixels_per_m: 256 +) diff --git a/src/editor.rs b/src/editor.rs index a68bb25..01bd268 100644 --- a/src/editor.rs +++ b/src/editor.rs @@ -3,7 +3,7 @@ use crate::tool::*; use crate::transform::Transform; use raylib::core::drawing::RaylibDrawHandle; use raylib::ffi::KeyboardKey; -use raylib::RaylibHandle; +use raylib::{RaylibHandle, RaylibThread}; pub struct Editor { map_data: MapData, @@ -12,13 +12,15 @@ pub struct Editor { } impl Editor { - pub fn new() -> Self { + pub fn new(rl: &mut RaylibHandle, rlt: &RaylibThread) -> Self { let mut tools: Vec<Box<dyn Tool>> = Vec::with_capacity(ToolType::NumTools as usize); assert_eq!(ToolType::RoomTool as u8, 0); tools.push(Box::new(RoomTool::new())); assert_eq!(ToolType::WallTool as u8, 1); tools.push(Box::new(WallTool::new())); - assert_eq!(ToolType::DeletionTool as u8, 2); + assert_eq!(ToolType::IconTool as u8, 2); + tools.push(Box::new(IconTool::new(rl, rlt))); + assert_eq!(ToolType::DeletionTool as u8, 3); tools.push(Box::new(DeletionTool::new())); assert_eq!(ToolType::NumTools as usize, tools.len()); @@ -36,6 +38,8 @@ impl Editor { ToolType::RoomTool as usize } else if rl.is_key_pressed(KeyboardKey::KEY_W) { ToolType::WallTool as usize + } else if rl.is_key_pressed(KeyboardKey::KEY_I) { + ToolType::IconTool as usize } else if rl.is_key_pressed(KeyboardKey::KEY_D) { ToolType::DeletionTool as usize } else { diff --git a/src/grid.rs b/src/grid.rs index d5fac6d..ecc59c3 100644 --- a/src/grid.rs +++ b/src/grid.rs @@ -1,3 +1,4 @@ +use crate::math::{self, Vec2}; use crate::transform::Transform; use raylib::drawing::RaylibDraw; use raylib::ffi::Color; @@ -9,6 +10,15 @@ pub const LINE_COLOUR: Color = Color { a: 75, }; +/// Snap a vector to the grid with the factor being the sub-grid accuracy. For instance, 0.5 will +/// snap to half a grid cell, while 2.0 would snap to every second grid cell +pub fn snap_to_grid(mut vec: Vec2<f32>, snap_fraction: f32) -> Vec2<f32> { + vec.x = math::round(vec.x, snap_fraction); + vec.y = math::round(vec.y, snap_fraction); + + vec +} + /// Draw an infinite grid that can be moved around on the screen and zoomed in and out of. pub fn draw_grid<D>(rld: &mut D, screen_width: i32, screen_height: i32, transform: &Transform) where diff --git a/src/main.rs b/src/main.rs index a598ebe..a72b172 100644 --- a/src/main.rs +++ b/src/main.rs @@ -8,14 +8,13 @@ pub mod transform; use editor::Editor; use raylib::prelude::*; -use svg::DrawSVG; use transform::Transform; fn main() { let (mut rl, thread) = raylib::init().resizable().title("Hello there!").build(); rl.set_target_fps(120); - let mut editor = Editor::new(); + let mut editor = Editor::new(&mut rl, &thread); let mut transform = Transform::new(); let mut last_mouse_pos = rl.get_mouse_position(); diff --git a/src/map_data.rs b/src/map_data.rs index 852d236..fa3a389 100644 --- a/src/map_data.rs +++ b/src/map_data.rs @@ -13,6 +13,7 @@ use std::path::Path; pub struct MapData { rooms: Vec<Rect<f32>>, walls: Vec<(Vec2<f32>, Vec2<f32>)>, + icons: Vec<(usize, Vec2<f32>)>, } impl MapData { @@ -20,6 +21,7 @@ impl MapData { Self { rooms: Vec::new(), walls: Vec::new(), + icons: Vec::new(), } } @@ -37,6 +39,7 @@ impl MapData { */ self.rooms.append(&mut data.rooms); self.walls.append(&mut data.walls); + self.icons.append(&mut data.icons); Ok(()) } @@ -72,4 +75,11 @@ impl MapData { pub fn walls_mut(&mut self) -> &mut Vec<(Vec2<f32>, Vec2<f32>)> { &mut self.walls } + + pub fn icons(&self) -> &Vec<(usize, Vec2<f32>)> { + &self.icons + } + pub fn icons_mut(&mut self) -> &mut Vec<(usize, Vec2<f32>)> { + &mut self.icons + } } diff --git a/src/tool/icon_tool.rs b/src/tool/icon_tool.rs new file mode 100644 index 0000000..0ff1dc2 --- /dev/null +++ b/src/tool/icon_tool.rs @@ -0,0 +1,142 @@ +use crate::grid::snap_to_grid; +use crate::map_data::MapData; +use crate::math::Vec2; +use crate::tool::Tool; +use crate::transform::Transform; +use raylib::core::drawing::{RaylibDraw, RaylibDrawHandle}; +use raylib::core::texture::Texture2D; +use raylib::ffi::{Color, KeyboardKey, MouseButton}; +use raylib::{RaylibHandle, RaylibThread}; +use ron::de::from_reader; +use serde::Deserialize; +use std::fs::{self, File}; + +pub const ICON_DIR: &'static str = "assets/icons"; + +#[derive(Deserialize)] +struct IconInfo { + /// The position the icon should be anchored in pixels. This is the Vector it will be moved by + /// relative to the mouse pointer (to the left and up). + anchor: Vec2<f32>, + /// The scale of the icon as expressed in image pixels per real meter. + pixels_per_m: f32, +} + +pub struct IconTool { + // TODO: support svg + /// The icon data, containing the image texture and the info for that image texture like the + /// scale the image actually has. + icon_data: Vec<(Texture2D, IconInfo)>, + /// The currently active icon, defined by its position in the Vec. + active_icon: usize, + current_icon_pos: Option<Vec2<f32>>, +} + +impl IconTool { + pub fn new(rl: &mut RaylibHandle, rlt: &RaylibThread) -> Self { + /* Read all available icons from the icon directory. SVGs do not need any special scale + * file, but pixel-based file formats require a RON-file declaring what the scale of the + * picture is right beside them. + */ + let mut image_files = Vec::new(); + for entry in fs::read_dir(ICON_DIR).expect("Could not open icon directory") { + let entry = entry.expect("Failed to read file from icon directory"); + + // Ignore the RON-files for now and put the image files into the vec + if entry + .path() + .extension() + .expect("Entry does not have a file extension") + != "ron" + { + image_files.push(entry); + } + } + + // Read the RON-files where it is necessary. + let mut icon_data = Vec::with_capacity(image_files.len()); + for file in image_files { + // TODO: Handle svg + + let texture = rl + .load_texture( + rlt, + file.path() + .to_str() + .expect("Unable to convert path to string."), + ) + .expect("Could not read image file"); + + let mut file = file.path(); + file.set_extension("ron"); + let ron = File::open(file).expect("Could not read ron file for icon information."); + let icon_info: IconInfo = + from_reader(ron).expect("Could not parse icon info from reader."); + + icon_data.push((texture, icon_info)); + } + + Self { + icon_data, + active_icon: 0, + current_icon_pos: None, + } + } +} + +impl Tool for IconTool { + fn active_update(&mut self, map: &mut MapData, rl: &RaylibHandle, transform: &Transform) { + // Put the currently active icon to where it would be placed. + self.current_icon_pos = Some(snap_to_grid( + transform.point_px_to_m(rl.get_mouse_position().into()), + 0.5, + )); + + // Activate the next icon when pressing the icon tool key. + if rl.is_key_pressed(KeyboardKey::KEY_I) { + self.active_icon = (self.active_icon + 1) % self.icon_data.len(); + } + + // Handle placing the icon on the map + if rl.is_mouse_button_pressed(MouseButton::MOUSE_LEFT_BUTTON) { + map.icons_mut() + .push((self.active_icon, self.current_icon_pos.unwrap())); + } + } + + fn draw(&self, map: &MapData, rld: &mut RaylibDrawHandle, transform: &Transform) { + // Draw all icons that have been placed on the map. + for (icon, pos) in map.icons() { + let (texture, info) = &self.icon_data[*icon]; + rld.draw_texture_ex( + texture, + transform.point_m_to_px(*pos - (info.anchor / info.pixels_per_m)), + 0., + transform.pixels_per_m() / info.pixels_per_m, + Color { + r: 255, + g: 255, + b: 255, + a: 255, + }, + ); + } + + // Draw the icon that would be placed + if let Some(current_icon_pos) = self.current_icon_pos { + let (texture, info) = &self.icon_data[self.active_icon]; + rld.draw_texture_ex( + texture, + transform.point_m_to_px(current_icon_pos - (info.anchor / info.pixels_per_m)), + 0., + transform.pixels_per_m() / info.pixels_per_m, + Color { + r: 120, + g: 200, + b: 120, + a: 255, + }, + ); + } + } +} diff --git a/src/tool/mod.rs b/src/tool/mod.rs index 73654d9..a3d5964 100644 --- a/src/tool/mod.rs +++ b/src/tool/mod.rs @@ -1,8 +1,10 @@ pub mod deletion_tool; +pub mod icon_tool; pub mod room_tool; pub mod wall_tool; pub use deletion_tool::DeletionTool; +pub use icon_tool::IconTool; pub use room_tool::RoomTool; pub use wall_tool::WallTool; @@ -16,6 +18,7 @@ use raylib::RaylibHandle; pub enum ToolType { RoomTool, WallTool, + IconTool, DeletionTool, NumTools, } diff --git a/src/tool/room_tool.rs b/src/tool/room_tool.rs index 0321ff3..09126c9 100644 --- a/src/tool/room_tool.rs +++ b/src/tool/room_tool.rs @@ -1,6 +1,7 @@ use super::Tool; +use crate::grid::snap_to_grid; use crate::map_data::MapData; -use crate::math::{self, Rect, Vec2}; +use crate::math::{Rect, Vec2}; use crate::transform::Transform; use raylib::core::drawing::{RaylibDraw, RaylibDrawHandle}; use raylib::ffi::{Color, MouseButton}; @@ -26,11 +27,7 @@ impl Tool for RoomTool { let mouse_pos_m = transform.point_px_to_m(rl.get_mouse_position().into()); // Update the currently drawn rectangle, if it exists if let Some((_, ref mut pos2)) = &mut self.unfinished_rect { - let snapped_mouse_pos = Vec2::new( - math::round(mouse_pos_m.x, 0.5), - math::round(mouse_pos_m.y, 0.5), - ); - *pos2 = snapped_mouse_pos; + *pos2 = snap_to_grid(mouse_pos_m, 0.5); } // Start or finish drawing the currently unfinished rectangle @@ -39,10 +36,7 @@ impl Tool for RoomTool { map_data.rooms_mut().push(Rect::bounding_rect(pos1, pos2)); self.unfinished_rect = None; } else { - let snapped_mouse_pos = Vec2::new( - math::round(mouse_pos_m.x, 0.5), - math::round(mouse_pos_m.y, 0.5), - ); + let snapped_mouse_pos = snap_to_grid(mouse_pos_m, 0.5); self.unfinished_rect = Some((snapped_mouse_pos, snapped_mouse_pos)) } } diff --git a/src/tool/wall_tool.rs b/src/tool/wall_tool.rs index d5760e6..5eda8e0 100644 --- a/src/tool/wall_tool.rs +++ b/src/tool/wall_tool.rs @@ -1,6 +1,7 @@ use super::Tool; +use crate::grid::snap_to_grid; use crate::map_data::MapData; -use crate::math::{self, Vec2}; +use crate::math::Vec2; use crate::transform::Transform; use raylib::core::drawing::{RaylibDraw, RaylibDrawHandle}; use raylib::ffi::{Color, MouseButton, Vector2}; @@ -22,11 +23,7 @@ impl Tool for WallTool { fn active_update(&mut self, map_data: &mut MapData, rl: &RaylibHandle, transform: &Transform) { let mouse_pos_m = transform.point_px_to_m(rl.get_mouse_position().into()); if let Some((_, ref mut pos2)) = &mut self.unfinished_wall { - let snapped_mouse_pos = Vec2::new( - math::round(mouse_pos_m.x, 0.5), - math::round(mouse_pos_m.y, 0.5), - ); - *pos2 = snapped_mouse_pos; + *pos2 = snap_to_grid(mouse_pos_m, 0.5); } if rl.is_mouse_button_pressed(MouseButton::MOUSE_LEFT_BUTTON) { @@ -34,10 +31,7 @@ impl Tool for WallTool { map_data.walls_mut().push((pos1, pos2)); self.unfinished_wall = Some((pos2, pos2)); } else { - let snapped_mouse_pos = Vec2::new( - math::round(mouse_pos_m.x, 0.5), - math::round(mouse_pos_m.y, 0.5), - ); + let snapped_mouse_pos = snap_to_grid(mouse_pos_m, 0.5); self.unfinished_wall = Some((snapped_mouse_pos, snapped_mouse_pos)) } } |
