aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/editor.rs10
-rw-r--r--src/grid.rs10
-rw-r--r--src/main.rs3
-rw-r--r--src/map_data.rs10
-rw-r--r--src/tool/icon_tool.rs142
-rw-r--r--src/tool/mod.rs3
-rw-r--r--src/tool/room_tool.rs14
-rw-r--r--src/tool/wall_tool.rs14
8 files changed, 181 insertions, 25 deletions
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))
}
}