aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/button.rs7
-rw-r--r--src/colours.rs26
-rw-r--r--src/config.rs28
-rw-r--r--src/editor.rs19
-rw-r--r--src/grid.rs27
-rw-r--r--src/gui/dimension_indicator.rs6
-rw-r--r--src/gui/mod.rs9
-rw-r--r--src/gui/tool_sidebar.rs11
-rw-r--r--src/main.rs19
-rw-r--r--src/map/data.rs6
-rw-r--r--src/map/icon.rs8
-rw-r--r--src/map/icon_renderer.rs14
-rw-r--r--src/map/mappable.rs6
-rw-r--r--src/map/mod.rs29
-rw-r--r--src/map/polygon_room.rs10
-rw-r--r--src/map/rect_room.rs5
-rw-r--r--src/map/wall.rs21
-rw-r--r--src/math/line_segment.rs51
-rw-r--r--src/math/mod.rs2
-rw-r--r--src/math/polygon/mod.rs2
-rw-r--r--src/math/polygon/polygon_graph.rs7
-rw-r--r--src/math/rect.rs4
-rw-r--r--src/math/surface.rs2
-rw-r--r--src/math/triangle.rs2
-rw-r--r--src/math/vec2.rs14
-rw-r--r--src/svg/mod.rs11
-rw-r--r--src/svg/style.rs8
-rw-r--r--src/tool/deletion_tool.rs11
-rw-r--r--src/tool/icon_tool.rs9
-rw-r--r--src/tool/mod.rs23
-rw-r--r--src/tool/polygon_room_tool.rs5
-rw-r--r--src/tool/rect_room_tool.rs8
-rw-r--r--src/tool/selection_tool.rs11
-rw-r--r--src/tool/wall_tool.rs6
-rw-r--r--src/transform.rs8
-rw-r--r--src/transformable.rs9
36 files changed, 410 insertions, 34 deletions
diff --git a/src/button.rs b/src/button.rs
index 89ce9a5..846377e 100644
--- a/src/button.rs
+++ b/src/button.rs
@@ -11,10 +11,13 @@ use std::mem;
/// user has free reign over what key they use for what purpose.
#[derive(Serialize, Deserialize, Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub enum Button {
+ /// Button on the mouse with internal mouse button representation of raylib.
Mouse(MouseButton),
+ /// Keyboard button with internal keyboard key representation of raylib.
Keyboard(KeyboardKey),
}
+#[allow(missing_docs)]
#[repr(u32)]
#[derive(Serialize, Deserialize, Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub enum MouseButton {
@@ -23,6 +26,7 @@ pub enum MouseButton {
Middle = 2,
}
+#[allow(missing_docs)]
#[repr(u32)]
#[derive(Serialize, Deserialize, Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub enum KeyboardKey {
@@ -134,6 +138,9 @@ pub enum KeyboardKey {
}
impl Button {
+ /// Check if this button is pressed. If `mouse_blocked` is true, mouse buttons are ignored which
+ /// is useful when an element has captured the mouse, but other elements are still queried in the
+ /// background.
pub fn is_pressed(self, rl: &RaylibHandle, mouse_blocked: bool) -> bool {
match self {
Self::Mouse(button) => !mouse_blocked && rl.is_mouse_button_pressed(button.into()),
diff --git a/src/colours.rs b/src/colours.rs
index bafb53c..4a3b799 100644
--- a/src/colours.rs
+++ b/src/colours.rs
@@ -1,20 +1,40 @@
+//! The colour definitions used for items drawn in graf karto.
+
use raylib::ffi::Color;
+/// Contains the default colours used throughout, if nothing else is set.
pub const DEFAULT_COLOURS: Colours = Colours::default();
+/// All the different colours that may be used for different elements of the program. Contains one
+/// entry for each colourable component.
pub struct Colours {
+ /// Colour the rectangle used for the deletion tool is filled with.
pub deletion_rect: Color,
+ /// The colour of the outline of the deletion tool rectangle.
pub deletion_rect_outline: Color,
+ /// The colour that is used for filling the selection tool's rectangle.
pub selection_rect: Color,
+ /// Colour of the selection tool rectangle outline.
pub selection_rect_outline: Color,
+ /// Colour of the rooms that are currently not selected.
pub room_normal: Color,
+ /// The Colour the rooms should be tinted in when they have been selected.
pub room_selected: Color,
+ /// Colour of the walls when they are not selected.
pub wall_normal: Color,
+ /// Colour of the walls when they have been selected.
pub wall_selected: Color,
+ /// Colour of the icons when they are not selected.
pub icon_normal: Color,
+ /// Colour of the icons when they are selected.
pub icon_selected: Color,
+ /// Colour used to draw the rulers (the ruling lines) of the dimension indicator.
pub dimension_indicators: Color,
+ /// Colour of the text used to display the size of the dimension indicators dimensions.
pub dimension_text: Color,
+ /// The colour used for drawing the lines of the grid which divides the map into chunks of evenly
+ /// spaced cells.
+ pub grid_lines: Color,
}
impl Colours {
@@ -95,6 +115,12 @@ impl Colours {
b: 200,
a: 255,
},
+ grid_lines: Color {
+ r: 255,
+ g: 255,
+ b: 255,
+ a: 75,
+ },
}
}
}
diff --git a/src/config.rs b/src/config.rs
index 2a1e5ed..b5abb1e 100644
--- a/src/config.rs
+++ b/src/config.rs
@@ -1,3 +1,5 @@
+//! Home of the user configuratable content of graf karto, like keybindings and (TODO) colours etc.
+
use crate::button::*;
use ron::de::from_reader;
use ron::ser::{to_string_pretty, PrettyConfig};
@@ -6,6 +8,8 @@ use std::fs::File;
use std::io::{self, Write};
use std::path::Path;
+/// All configuration parameters the user can set are contained in this struct.
+#[allow(missing_docs)]
#[derive(Deserialize, Serialize)]
pub struct Config {
pub tool_activation_keys: ToolActivationKeys,
@@ -13,7 +17,10 @@ pub struct Config {
pub icon_keys: IconToolKeys,
}
+#[allow(missing_docs)]
#[derive(Deserialize, Serialize)]
+/// The keys used to activate the individual tools. These keystrokes will not be sent to the tools,
+/// but instead will be handled by the editor where the tools are registered.
pub struct ToolActivationKeys {
pub deletion: Button,
pub icon: Button,
@@ -24,21 +31,38 @@ pub struct ToolActivationKeys {
}
#[derive(Deserialize, Serialize)]
+/// Keys that are useful to most tools. These are packaged so that not every tool has the same n keys
+/// and then some more.
pub struct ToolGeneralKeys {
+ /// Keybinding to, where applicable, place a single node (usually a vertex) for the tool in
+ /// question.
pub place_single: Button,
+ /// Finish up whatever one is doing with the current tool, without removing information.
pub finish: Button,
+ /// Abort whatever one is doing with the current tool which means the last atomic action will not
+ /// be pushed into the map items.
pub abort: Button,
}
#[derive(Clone, Serialize, Deserialize)]
+/// Key bindings that are individually interesting to the icon tool.
pub struct IconToolKeys {
+ /// Key to change to the next icon of the icon list.
pub next: Button,
+ /// Key to change to the previous icon of the icon list.
pub previous: Button,
+ /// Rotate the working icon clockwise by a certain amount (currently 45 degrees)
pub rotate_clockwise: Button,
+ /// Rotate the working icon counterclockwise by a certain amount (currently 45 degrees)
pub rotate_counterclockwise: Button,
}
impl Config {
+ /// Try to parse a configuration from the file located at path.
+ ///
+ /// # Errors
+ /// If the file is not found or can not be read or parsed for a different reason, an IO-Error is
+ /// returned.
pub fn from_file<P: AsRef<Path>>(path: P) -> io::Result<Config> {
let file = File::open(&path)?;
match from_reader(file) {
@@ -47,6 +71,10 @@ impl Config {
}
}
+ /// Try to write the configuration to the file at path. If the file exists, it will be overwritten.
+ ///
+ /// # Errors
+ /// If the file can not be written, for example for lack of permissions, an IO-Error is returned.
pub fn write_file<P: AsRef<Path>>(&self, path: P) -> io::Result<()> {
let mut file = File::create(&path)?;
diff --git a/src/editor.rs b/src/editor.rs
index 87a8db4..d541fb6 100644
--- a/src/editor.rs
+++ b/src/editor.rs
@@ -1,3 +1,10 @@
+//! Element creation base
+//!
+//! The actual editor environment sits here. This especially means all tools that require low-level
+//! access to the data of items currently being created. While this may be subject to change, there is
+//! currently a difference between things that are being created (inside the editor) and things that
+//! are part of the environment (the map).
+
use crate::button::{Button, MouseButton};
use crate::config::Config;
use crate::grid::{snap_to_grid, SNAP_SIZE};
@@ -8,6 +15,7 @@ use raylib::core::drawing::RaylibDrawHandle;
use raylib::{RaylibHandle, RaylibThread};
use std::collections::HashMap;
+/// The editor containing all tools and currently the map of the stuff that has been created.
pub struct Editor {
map: Map,
/// HashMap that matches the ToolType with its proper activation key and of course the tool
@@ -18,6 +26,8 @@ pub struct Editor {
}
impl Editor {
+ /// Create a new editor with all tools necessary. There should be only one editor per program
+ /// instance.
pub fn new(rl: &mut RaylibHandle, rlt: &RaylibThread, config: Config) -> Self {
let map = Map::new(rl, rlt);
@@ -74,7 +84,8 @@ impl Editor {
}
}
- /// Get the currently active tool.
+ /// Get the currently active tool. Since the every tool exists only once, it is entirely indexable
+ /// by its type, which is what is actually returned.
pub fn active(&self) -> ToolType {
self.active
}
@@ -93,6 +104,8 @@ impl Editor {
}
}
+ /// Update the internal editor data where necessary and handle selecting different tools, aswell
+ /// as updating the currently active tool. Should be called once every frame.
pub fn update(&mut self, rl: &mut RaylibHandle, transform: &Transform, mouse_blocked: bool) {
// Handle keybindings for tool change
for (&tool_type, (_, activation_key)) in self.tools.iter() {
@@ -175,15 +188,19 @@ impl Editor {
}
}
+ /// Draw all tools and in case of the active tool also what is currently being edited by it, if
+ /// that exists.
pub fn draw_tools(&self, rld: &mut RaylibDrawHandle, transform: &Transform) {
for (tool, _) in self.tools.values() {
tool.draw(rld, transform);
}
}
+ /// Get the world containing all finished elements.
pub fn map(&self) -> &Map {
&self.map
}
+ /// Get the world containing all finished elements mutably.
pub fn map_mut(&mut self) -> &mut Map {
&mut self.map
}
diff --git a/src/grid.rs b/src/grid.rs
index ec27fa7..d1c4b15 100644
--- a/src/grid.rs
+++ b/src/grid.rs
@@ -1,18 +1,13 @@
+//! The grid used to divide the map into evenly sized chunks.
+
+use crate::colours::DEFAULT_COLOURS;
use crate::math::{self, Vec2};
use crate::transform::Transform;
use raylib::drawing::RaylibDraw;
-use raylib::ffi::Color;
/// The internal grid length which will be used to snap things to it.
pub const SNAP_SIZE: f64 = 0.5;
-pub const LINE_COLOUR: Color = Color {
- r: 255,
- g: 255,
- b: 255,
- 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<f64>, snap_fraction: f64) -> Vec2<f64> {
@@ -38,7 +33,13 @@ where
let mut draw_y = transform.point_m_to_px(&cell).y;
loop {
draw_y = math::round(draw_y, 1.);
- rld.draw_line(0, draw_y as i32, screen_width, draw_y as i32, LINE_COLOUR);
+ rld.draw_line(
+ 0,
+ draw_y as i32,
+ screen_width,
+ draw_y as i32,
+ DEFAULT_COLOURS.grid_lines,
+ );
cell.y += 1.;
draw_y = transform.point_m_to_px(&cell).y;
@@ -50,7 +51,13 @@ where
let mut draw_x = transform.point_m_to_px(&cell).x;
loop {
draw_x = math::round(draw_x, 1.);
- rld.draw_line(draw_x as i32, 0, draw_x as i32, screen_height, LINE_COLOUR);
+ rld.draw_line(
+ draw_x as i32,
+ 0,
+ draw_x as i32,
+ screen_height,
+ DEFAULT_COLOURS.grid_lines,
+ );
cell.x += 1.;
draw_x = transform.point_m_to_px(&cell).x;
diff --git a/src/gui/dimension_indicator.rs b/src/gui/dimension_indicator.rs
index aa00f67..e8848fe 100644
--- a/src/gui/dimension_indicator.rs
+++ b/src/gui/dimension_indicator.rs
@@ -1,10 +1,13 @@
+//! An interface element that shows the size of the selected map items and provides a means to
+//! manually change the size of them in a precise manner should need be.
+
use crate::colours::DEFAULT_COLOURS;
use crate::map::Map;
use crate::math::{self, Rect, Vec2};
use crate::transform::Transform;
use nalgebra::{Matrix3, Vector2};
use raylib::drawing::RaylibDraw;
-use raylib::ffi::{Color, KeyboardKey};
+use raylib::ffi::KeyboardKey;
use raylib::RaylibHandle;
/// A state the [DimensionIndicator] is currently in. This determines the behaviour of it and what
@@ -218,6 +221,7 @@ impl DimensionIndicator {
self.bounds = bounds;
}
+ /// Draw the dimensions detected on the current selection.
pub fn draw(&self, rld: &mut impl RaylibDraw, transform: &Transform) {
/* Ignore a selection that has no non-null dimensions, since this usually
* indicates that there is nothing to be scaled.
diff --git a/src/gui/mod.rs b/src/gui/mod.rs
index 032d430..a94122e 100644
--- a/src/gui/mod.rs
+++ b/src/gui/mod.rs
@@ -1,3 +1,12 @@
+//! General graphical user interfaces
+//!
+//! This mod does not contain all graphical content on screen, but all user interfaces that is drawn
+//! that is not contained in a different category. This means all interface elements where it does not
+//! make sense to bind it to any other part of the program, for instance a tool or type of element.
+//! It also does *not* contain anything that does anything that is not triggered by the user, which
+//! means everything is called top-down from this module. A function in this module should not be
+//! called from any point in the program except the main loop, where the user input is polled.
+
pub mod dimension_indicator;
pub mod tool_sidebar;
diff --git a/src/gui/tool_sidebar.rs b/src/gui/tool_sidebar.rs
index 7674c47..e6b8867 100644
--- a/src/gui/tool_sidebar.rs
+++ b/src/gui/tool_sidebar.rs
@@ -1,3 +1,8 @@
+//! The sidebar showing all tools available to the user. This toolbar handles changing the active tool
+//! based on the mouse input and (TODO!) keyboard inputs.
+// TODO: Currently, the keyboard shortcuts for tools are handled by the editor, but a lot speaks for
+// them being handled by the ToolSidebar instead.
+
use crate::math::{Rect, Surface, Vec2};
use crate::tool::ToolType;
use crate::Editor;
@@ -6,13 +11,16 @@ use raylib::rgui::RaylibDrawGui;
use raylib::{RaylibHandle, RaylibThread};
use std::mem;
+/// The file containing textures for all buttons describing the tools.
pub const BUTTON_FILE: &str = "assets/button/tool_buttons.png";
+/// Sidebar that renders and handles input for the tool activation buttons.
pub struct ToolSidebar {
button_texture: Texture2D,
}
impl ToolSidebar {
+ /// Create a new tool sidebar. There should be only one sidebar per program instance.
pub fn new(rl: &mut RaylibHandle, rlt: &RaylibThread) -> Self {
let button_texture = rl
.load_texture(rlt, BUTTON_FILE)
@@ -31,6 +39,9 @@ impl ToolSidebar {
Self::panel_rect(screen_height).contains_point(&mouse_pos)
}
+ /// Draw the tool buttons and encasing panel. Because of the way raylib works, this also handles
+ /// clicking on tool buttons, which may be changed in the future, should a different gui be
+ /// chosen.
pub fn draw(&self, screen_height: u16, rld: &mut impl RaylibDrawGui, editor: &mut Editor) {
rld.gui_panel(Self::panel_rect(screen_height));
diff --git a/src/main.rs b/src/main.rs
index 6e54c59..8c1d63e 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -1,3 +1,20 @@
+//! # Graf Karto cartographer
+//!
+//! ### What is it exactly
+//! Graf Karto is a table top role playing game (TTRPG) map creation tool that is optimised for real
+//! time map interaction.
+//!
+//! ### Motivation
+//! While there are certainly many TTRPG map creation tools for single user and multi user available
+//! online and on the market, we felt that most of them lack features or are to unwieldy to seriously
+//! consider for real time dungeon drawing, say for instance when drawing a map for an old school
+//! revival style game. This is why Graf Karto is optimised for speed above pretty graphical features.
+//! The aim is for the user not to have to think much about how they are going to achieve what they are
+//! doing and how they are going to make it pretty, but should just be able to *do* it, to have time to
+//! worry about other things. This does not mean that all maps created should visually be equivalent to
+//! a steaming pile of hot garbage, but if the visuals should try to get in the way, usability and speed
+//! takes precedence.
+
#![allow(dead_code)]
#![warn(missing_docs)]
@@ -25,7 +42,9 @@ use std::ffi::CString;
use std::io;
use transform::Transform;
+/// Location of the file containing the style used for the raylib user interface.
pub const GUI_STYLE: &str = "assets/style/cyber.rgs";
+/// Location of the graf karto configuration options file.
pub const CONFIG_FILE: &str = "config.ron";
fn main() {
diff --git a/src/map/data.rs b/src/map/data.rs
index f978081..1031d3c 100644
--- a/src/map/data.rs
+++ b/src/map/data.rs
@@ -1,3 +1,5 @@
+//! Module containing the raw map data version of the map.
+
use super::{IconData, PolygonRoomData, RectRoomData, WallData};
use ron::de::from_reader;
use ron::ser::{to_string_pretty, PrettyConfig};
@@ -18,6 +20,7 @@ pub struct MapData {
}
impl MapData {
+ /// Create a serialisable map data type from the data elements contained in a map.
pub fn new(
rect_rooms: Vec<RectRoomData>,
polygon_rooms: Vec<PolygonRoomData>,
@@ -32,6 +35,7 @@ impl MapData {
}
}
+ /// Load the map data from a file. Fails if the file does not exist or cannot be correctly parsed.
pub fn load_from_file<P: AsRef<Path>>(&mut self, path: P) -> io::Result<Self> {
let file = File::open(&path)?;
let data: Self = match from_reader(file) {
@@ -44,6 +48,8 @@ impl MapData {
Ok(data)
}
+ /// Write the map data to the file located at `path`. If the file already exists, it will be
+ /// overwritten. If the write fails, an IO-Error is returned.
pub fn write_to_file<P: AsRef<Path>>(&self, path: P) -> io::Result<()> {
let mut file = File::create(&path)?;
diff --git a/src/map/icon.rs b/src/map/icon.rs
index f623c98..2e45486 100644
--- a/src/map/icon.rs
+++ b/src/map/icon.rs
@@ -1,3 +1,6 @@
+//! 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;
@@ -8,6 +11,7 @@ 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.
@@ -18,6 +22,7 @@ pub struct IconData {
pub rotation: f64,
}
+/// Describes an icon in the world and can be drawn.
#[derive(Clone)]
pub struct Icon {
data: IconData,
@@ -26,6 +31,8 @@ pub struct Icon {
}
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<f64>, rotation: f64, renderer: Rc<IconRenderer>) -> Self {
Self::from_data(
IconData {
@@ -37,6 +44,7 @@ impl Icon {
)
}
+ /// Like `new()`, but with the icon data bundled into the icon data type.
pub fn from_data(data: IconData, renderer: Rc<IconRenderer>) -> Self {
Self {
data,
diff --git a/src/map/icon_renderer.rs b/src/map/icon_renderer.rs
index fb81e24..eef053d 100644
--- a/src/map/icon_renderer.rs
+++ b/src/map/icon_renderer.rs
@@ -1,3 +1,6 @@
+//! Since the same icon may be used very often on a map, it becomes impracticalto let every icon have
+//! it's own texture data saved, which is why a texture manager type of struct is used for it instead.
+
use crate::math::Vec2;
use raylib::core::texture::Texture2D;
use raylib::{RaylibHandle, RaylibThread};
@@ -5,6 +8,7 @@ use ron::de::from_reader;
use serde::Deserialize;
use std::fs::{self, File};
+/// The directory containing all files related to icons.
pub const ICON_DIR: &str = "assets/icons";
#[derive(Deserialize)]
@@ -16,11 +20,15 @@ pub(super) struct IconFileInfo {
pub pixels_per_m: f64,
}
+/// Manager for all icon texture or rendering data.
pub struct IconRenderer {
texture_data: Vec<(Texture2D, IconFileInfo)>,
}
impl IconRenderer {
+ /// Create a new icon renderer. This loads all textures and information for icons that is needed
+ /// to draw them to the screen. Usually, there should be only one IconRenderer, or at least one
+ /// renderer per directory and program instance.
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
@@ -67,10 +75,16 @@ impl IconRenderer {
Self { texture_data }
}
+ /// Get the data needed to render an icon of type `icon_id`.
+ ///
+ /// # Panics
+ /// If the `icon_id` does not describe a valid icon (is out of bounds), there is no data to be
+ /// accessed and the function panics.
pub(super) fn get(&self, icon_id: usize) -> &(Texture2D, IconFileInfo) {
&self.texture_data[icon_id]
}
+ /// The number of icons registered in this icon-renderer.
pub fn num_icons(&self) -> usize {
self.texture_data.len()
}
diff --git a/src/map/mappable.rs b/src/map/mappable.rs
index 323361a..7978f50 100644
--- a/src/map/mappable.rs
+++ b/src/map/mappable.rs
@@ -1,11 +1,12 @@
//! Something that's mappable can be placed on the map and drawn at a specific position. It has a
-//! dimension on the map and may be scaleable
+//! dimension on the map and may be transformable in various ways.
use crate::math::Rect;
use crate::transform::Transform;
use crate::transformable::NonRigidTransformable;
use raylib::drawing::RaylibDrawHandle;
+/// Anything that can be added to the map or world must implement this trait.
pub trait Mappable {
/// Draw this to `rld` with the transform. An item that cannot be drawn is not mappable, so
/// this must always be implemented.
@@ -21,10 +22,13 @@ pub trait Mappable {
/// Get the rectangle that contains the mappable object in its entirety without excess.
fn bounding_rect(&self) -> Rect<f64>;
+ /// If this mappable item can be transformed in a non-rigid way, a dynamic reference is returned,
+ /// otherwise none.
fn as_non_rigid(&self) -> Option<&dyn NonRigidTransformable> {
None
}
+ /// The same as `as_non_rigid`, but mutably.
fn as_non_rigid_mut(&mut self) -> Option<&mut dyn NonRigidTransformable> {
None
}
diff --git a/src/map/mod.rs b/src/map/mod.rs
index ff03474..88a7e6c 100644
--- a/src/map/mod.rs
+++ b/src/map/mod.rs
@@ -1,3 +1,16 @@
+//! The map contains all the items that make up the world.
+//!
+//! There are two main structs to look out for, the first being [Map]. This is the interaction point
+//! for most parts of the program. It contains the actual elements that are drawn on the screen. and
+//! can be changed by the user.
+//! The second is [MapData] and it contains the data that can be saved/loaded and distributed. Every
+//! map item has an internal item that it can be dereferenced to and can be used to construct this
+//! exact item in the same world elsewhere or at a different time. This is often different from the
+//! item that is being drawn. An example would be the [PolygonRoom], which contains a triangulated
+//! version of itself, so it can be drawn without always having to compute the triangles every frame.
+//! It's data type however [PolygonRoomData] contains only the raw polygon data, not the triangulated
+//! version, since that is enough to create the same [PolygonRoom] again.
+
pub mod data;
pub mod icon;
pub mod icon_renderer;
@@ -19,6 +32,7 @@ use raylib::drawing::RaylibDrawHandle;
use raylib::{RaylibHandle, RaylibThread};
use std::rc::Rc;
+/// The map containing all map elements that are seen on the screen.
pub struct Map {
rect_rooms: Vec<RectRoom>,
polygon_rooms: Vec<PolygonRoom>,
@@ -28,6 +42,7 @@ pub struct Map {
}
impl Map {
+ /// Create a new, empty map/world.
pub fn new(rl: &mut RaylibHandle, rlt: &RaylibThread) -> Self {
Self {
rect_rooms: Vec::new(),
@@ -38,14 +53,20 @@ impl Map {
}
}
+ /// Add a rectangularly shaped room to the world. Since the polygon room tool was added, and
+ /// afaik rects are polygon rooms, this will be phased out in favour of only having polygon
+ /// rooms, which will then become just normal rooms.
pub fn push_rect_room(&mut self, room_data: RectRoomData) {
self.rect_rooms.push(RectRoom::from_data(room_data));
}
+ /// Add a room to the map. Currently, holes are not supported in the polygon, but this might
+ /// change later.
pub fn push_polygon_room(&mut self, room_data: PolygonRoomData) {
self.polygon_rooms.push(PolygonRoom::from_data(room_data));
}
+ /// Add a wall to the world.
pub fn push_wall(&mut self, wall_data: WallData) {
/* Check for intersections with any wall that was arleady created so the wall ends can be
* rendered properly.
@@ -70,21 +91,25 @@ impl Map {
.push(Wall::from_data(wall_data, start_intersects, end_intersects));
}
+ /// Add an icon to the world.
pub fn push_icon(&mut self, icon: Icon) {
self.icons.push(icon);
}
+ /// Draw all elements of the map to the screen. This should be called after the background of the
+ /// map has already been drawn.
pub fn draw(&self, rld: &mut RaylibDrawHandle, transform: &Transform) {
for element in self.elements() {
element.draw(rld, transform);
}
}
+ /// Get the icon-renderer that is currently used to render the icons.
pub fn icon_renderer(&self) -> Rc<IconRenderer> {
self.icon_renderer.clone()
}
- /// Retain all map elements that fulfill the given predicate.
+ /// Retain all map elements that fulfill the given predicate, removing everything else.
pub fn retain<F>(&mut self, mut f: F)
where
F: FnMut(&dyn Mappable) -> bool,
@@ -107,6 +132,8 @@ impl Map {
.chain(self.icons.iter().map(|i| i as &dyn Mappable))
}
+ /// Iterator over all elements, but the individual elements can be mutated. It is however
+ /// impossible to add or remove elements in this way. For that, use the dedicated functions.
pub fn elements_mut(&mut self) -> impl Iterator<Item = &mut dyn Mappable> {
self.rect_rooms
.iter_mut()
diff --git a/src/map/polygon_room.rs b/src/map/polygon_room.rs
index 65eeaab..fd4122e 100644
--- a/src/map/polygon_room.rs
+++ b/src/map/polygon_room.rs
@@ -1,13 +1,18 @@
+//! Polygon rooms are the standard rooms in graf karto. They can take the form of anything that a
+//! [Polygon](crate::math::Polygon) can have.
+
use super::Mappable;
use crate::colours::DEFAULT_COLOURS;
use crate::math::{self, Polygon, Rect, Triangle};
use crate::transform::Transform;
use crate::transformable::NonRigidTransformable;
-use raylib::drawing::{RaylibDraw, RaylibDrawHandle};
use nalgebra::{Matrix3, Point2};
+use raylib::drawing::{RaylibDraw, RaylibDrawHandle};
+/// Data type for the Polygon room.
pub type PolygonRoomData = Polygon<f64>;
+/// A polygon room, which can be placed and modified in the world.
pub struct PolygonRoom {
data: PolygonRoomData,
// The polygon shape, but in triangles, so the polygon does not have to be triangulated every frame.
@@ -16,6 +21,7 @@ pub struct PolygonRoom {
}
impl PolygonRoom {
+ /// Create a room from the given polygon data.
pub fn from_data(data: PolygonRoomData) -> Self {
Self {
data: data.clone(),
@@ -24,6 +30,8 @@ impl PolygonRoom {
}
}
+ // When the internal polygon changes, it must be retriangulated to be drawn on the screen
+ // properly, so this function must be called any time that happens.
fn retriangulate(&mut self) {
self.triangulated = math::triangulate(self.data.clone());
}
diff --git a/src/map/rect_room.rs b/src/map/rect_room.rs
index ee184fb..6ed3ed6 100644
--- a/src/map/rect_room.rs
+++ b/src/map/rect_room.rs
@@ -1,3 +1,5 @@
+//! Deprecated simple rectangular room type.
+
use crate::colours::DEFAULT_COLOURS;
use crate::map::Mappable;
use crate::math::Rect;
@@ -6,8 +8,10 @@ use raylib::drawing::{RaylibDraw, RaylibDrawHandle};
use serde::Serialize;
use std::ops::{Deref, DerefMut};
+#[allow(missing_docs)]
pub type RectRoomData = Rect<f64>;
+#[allow(missing_docs)]
#[derive(Serialize)]
pub struct RectRoom {
data: RectRoomData,
@@ -15,6 +19,7 @@ pub struct RectRoom {
}
impl RectRoom {
+ #[allow(missing_docs)]
pub fn from_data(data: RectRoomData) -> Self {
RectRoom {
data,
diff --git a/src/map/wall.rs b/src/map/wall.rs
index d18096b..f1748bb 100644
--- a/src/map/wall.rs
+++ b/src/map/wall.rs
@@ -1,14 +1,23 @@
+//! Walls, solid barriers that are generally unscaleable.
+//!
+//! This interpretation is generally up to the GM to decide, but generally speaking, a wall cannot be
+//! crossed by a player. If special conditions apply (for instance, when the player wants to scale the
+//! wall), a check is necessary. If a check is not necessary, then maybe you were not thinking about
+//! a wall.
+
use super::Mappable;
use crate::colours::DEFAULT_COLOURS;
use crate::math::{LineSegment, Rect, Vec2};
use crate::transform::Transform;
use crate::transformable::NonRigidTransformable;
+use nalgebra::Matrix3;
use raylib::drawing::{RaylibDraw, RaylibDrawHandle};
use std::ops::{Deref, DerefMut};
-use nalgebra::{Matrix3, Point2};
+/// The data which defines a wall segment completely for serialisation.
pub type WallData = LineSegment<f64>;
+/// A solid wall a player cannot go through, except if special conditions apply.
pub struct Wall {
data: WallData,
selected: bool,
@@ -17,6 +26,7 @@ pub struct Wall {
}
impl Wall {
+ /// Create a new wall from the deserialised data and information known from internal sources.
pub fn from_data(data: WallData, round_start: bool, round_end: bool) -> Self {
Self {
data,
@@ -26,6 +36,7 @@ impl Wall {
}
}
+ /// Get the internal data for serialisation
pub fn data(&self) -> &WallData {
&self.data
}
@@ -94,12 +105,8 @@ impl Mappable for Wall {
impl NonRigidTransformable for Wall {
fn apply_matrix(&mut self, matrix: &Matrix3<f64>) {
- self.data.start = matrix
- .transform_point(&self.data.start.into())
- .into();
- self.data.end = matrix
- .transform_point(&self.data.end.into())
- .into();
+ self.data.start = matrix.transform_point(&self.data.start.into()).into();
+ self.data.end = matrix.transform_point(&self.data.end.into()).into();
}
}
diff --git a/src/math/line_segment.rs b/src/math/line_segment.rs
index b496787..204cf0c 100644
--- a/src/math/line_segment.rs
+++ b/src/math/line_segment.rs
@@ -1,3 +1,6 @@
+//! A line segment is like a line, but with a start and an end, with the line only being between
+//! those two.
+
use super::{Rect, Surface, TripletOrientation, Vec2};
use alga::general::{ClosedDiv, ClosedMul, ClosedSub};
use nalgebra::{RealField, Scalar};
@@ -5,6 +8,7 @@ use num_traits::Zero;
use serde::{Deserialize, Serialize};
use std::cmp::Ordering;
+#[allow(missing_docs)]
#[derive(Debug, Clone, Deserialize, Serialize)]
pub struct LineSegment<T: Scalar + Copy> {
pub start: Vec2<T>,
@@ -12,6 +16,7 @@ pub struct LineSegment<T: Scalar + Copy> {
}
impl<T: Scalar + Copy> LineSegment<T> {
+ /// Create a new line segment from `start` to `end`
pub fn new(start: Vec2<T>, end: Vec2<T>) -> Self {
Self { start, end }
}
@@ -92,6 +97,9 @@ impl<T: Scalar + Copy> LineSegment<T> {
false
}
+ /// Try to find the the point where the two line segments intersect. If they do not intersect,
+ /// `None` is returned. If the lines are parallel and intersect (at least part of a line is on
+ /// a part of the other line), inside that region is returned.
pub fn intersection(line_a: &LineSegment<T>, line_b: &LineSegment<T>) -> Option<Vec2<T>>
where
T: ClosedSub + ClosedMul + ClosedDiv + Zero + RealField,
@@ -104,10 +112,26 @@ impl<T: Scalar + Copy> LineSegment<T> {
let dby = line_b.start.y - line_b.end.y;
// Calculate determinant to see, if the lines are parallel or not
- // TODO: Collinearity check?
let d = (dax * dby) - (day * dbx);
if d == T::zero() {
- None
+ // The two line segments are parallel, check if one may be on the other.
+ if super::triplet_orientation(line_a.start, line_a.end, line_b.start) == TripletOrientation::Collinear
+ && super::triplet_orientation(line_a.start, line_a.end, line_b.end) == TripletOrientation::Collinear
+ {
+ if line_a.contains_collinear(line_b.start) {
+ Some(line_b.start)
+ } else if line_a.contains_collinear(line_b.end) {
+ Some(line_b.end)
+ } else if line_b.contains_collinear(line_a.start) {
+ Some(line_a.start)
+ } else if line_b.contains_collinear(line_a.end) {
+ Some(line_a.end)
+ } else {
+ None
+ }
+ } else {
+ None
+ }
} else {
let ad = (line_a.start.x * line_a.end.y) - (line_a.start.y * line_a.end.x);
let bd = (line_b.start.x * line_b.end.y) - (line_b.start.y * line_b.end.x);
@@ -190,4 +214,27 @@ mod test {
assert!(!segment.contains_collinear(Vec2::new(3., 3.)));
assert!(!segment.contains_collinear(Vec2::new(-1., 0.)));
}
+
+ #[test]
+ fn line_intersection() {
+ let segment_a = LineSegment::new(Vec2::new(-1., -1.), Vec2::new(1., 1.));
+ let segment_b = LineSegment::new(Vec2::new(1., -1.), Vec2::new(-1., 1.));
+ let segment_c = LineSegment::new(Vec2::new(1., -1.), Vec2::new(2., 2.));
+
+ assert!(LineSegment::intersect(&segment_a, &segment_b));
+ assert!(LineSegment::intersect(&segment_b, &segment_c));
+ assert!(!LineSegment::intersect(&segment_a, &segment_c));
+ assert!(LineSegment::intersect(&segment_a, &segment_a));
+
+ assert_eq!(
+ LineSegment::intersection(&segment_a, &segment_b),
+ Some(Vec2::new(0., 0.))
+ );
+ assert_eq!(
+ LineSegment::intersection(&segment_b, &segment_c),
+ Some(Vec2::new(1., -1.))
+ );
+ assert_eq!(LineSegment::intersection(&segment_a, &segment_c), None);
+ assert!(LineSegment::intersection(&segment_a, &segment_a).is_some());
+ }
}
diff --git a/src/math/mod.rs b/src/math/mod.rs
index 829a3c5..c9c1c6e 100644
--- a/src/math/mod.rs
+++ b/src/math/mod.rs
@@ -1,3 +1,5 @@
+//! Useful mathematical operations in graphical contexts.
+
pub mod line_segment;
pub mod polygon;
pub mod rect;
diff --git a/src/math/polygon/mod.rs b/src/math/polygon/mod.rs
index 98b1570..1577f63 100644
--- a/src/math/polygon/mod.rs
+++ b/src/math/polygon/mod.rs
@@ -15,6 +15,7 @@ use std::ops::Neg;
use thiserror::Error;
/// Describes errors that can happen when handling polygons, especially on creation.
+#[allow(missing_docs)]
#[derive(Debug, Error)]
pub enum PolygonError<T: Scalar + Copy> {
/// Since the polygon is not allowed to be complex, self intersection is an error.
@@ -28,6 +29,7 @@ pub enum PolygonError<T: Scalar + Copy> {
EdgeNotFound(LineSegment<T>),
}
+/// Describes a non-complex (non-self-intersecting) polygon, currently without holes.
#[derive(Clone, Debug, Deserialize, Serialize)]
// TODO: Support polygons with holes
pub struct Polygon<T: Scalar + Copy> {
diff --git a/src/math/polygon/polygon_graph.rs b/src/math/polygon/polygon_graph.rs
index 5a730b0..fd373dd 100644
--- a/src/math/polygon/polygon_graph.rs
+++ b/src/math/polygon/polygon_graph.rs
@@ -1,3 +1,8 @@
+//! Polygon graphs are used for a more general approach than polygons.
+//!
+//! They are not polygons, but often describe a polygon and make some algorithms on polygons faster
+//! or possible, which may not be practical on the polygon data alone.
+
use super::Polygon;
use crate::math::{self, LineSegment, Vec2};
use nalgebra::{RealField, Scalar};
@@ -16,7 +21,7 @@ struct EdgeIterator<'a, T: Scalar + Copy> {
/// An undirected graph, that is optimised for polygon edge operations. Since edges of a polygon
/// are an undirected graph, this structure also holds both directions. This makes it rather space
-/// inefficient, but makes edge operations rather swift. ß
+/// inefficient, but makes edge operations rather swift.
#[derive(Debug)]
pub struct PolygonGraph<T: Scalar + Copy + PartialOrd> {
/// The nodes of the graph, together with their adjacency list.
diff --git a/src/math/rect.rs b/src/math/rect.rs
index b571644..6f993d1 100644
--- a/src/math/rect.rs
+++ b/src/math/rect.rs
@@ -1,3 +1,5 @@
+//! Rectangles where the sides are parallel to the x and y-axes.
+
use super::{LineSegment, Polygon, Surface, Vec2};
//use alga::general::{Additive, Identity};
use nalgebra::{ClosedAdd, ClosedSub, RealField, Scalar};
@@ -20,6 +22,8 @@ pub struct Rect<T: Scalar + Copy> {
}
impl<T: Scalar + Copy> Rect<T> {
+ /// Create a new Rectangle from the internal values, where it might be nicer to use a function
+ /// instead of setting the values directly.
pub fn new(x: T, y: T, w: T, h: T) -> Self {
Self { x, y, w, h }
}
diff --git a/src/math/surface.rs b/src/math/surface.rs
index da265d8..ab1c703 100644
--- a/src/math/surface.rs
+++ b/src/math/surface.rs
@@ -1,3 +1,5 @@
+//! Surfaces, which are areas at a certain position in a vector space.
+
use super::{LineSegment, Polygon, Rect, Vec2};
use nalgebra::Scalar;
diff --git a/src/math/triangle.rs b/src/math/triangle.rs
index 35bdcec..b5c1bda 100644
--- a/src/math/triangle.rs
+++ b/src/math/triangle.rs
@@ -1,3 +1,5 @@
+//! Triangles. Nothing more, nothing less.
+
use super::{LineSegment, Vec2};
use alga::general::{ClosedMul, ClosedSub};
use nalgebra::{RealField, Scalar};
diff --git a/src/math/vec2.rs b/src/math/vec2.rs
index b9e3215..b5706a0 100644
--- a/src/math/vec2.rs
+++ b/src/math/vec2.rs
@@ -1,5 +1,8 @@
+//! Two-dimensional vectors and useful operations on them.
+
use crate::math::Rect;
use alga::general::{ClosedAdd, ClosedSub};
+use nalgebra::Point2;
use nalgebra::{RealField, Scalar};
use num_traits::{NumCast, One, ToPrimitive};
use serde::{Deserialize, Serialize};
@@ -7,8 +10,9 @@ use std::cmp::Ordering;
use std::convert::{From, Into};
use std::ops::{Add, AddAssign, Div, Mul, MulAssign, Neg, Sub, SubAssign};
use std::{fmt, mem};
-use nalgebra::Point2;
+/// Describes a vector, which may be a point or a directed length, depending on the interpretation.
+#[allow(missing_docs)]
#[derive(Clone, Copy, Debug, Default, PartialEq, Serialize, Deserialize, Eq, Hash)]
pub struct Vec2<T: Scalar + Copy> {
pub x: T,
@@ -16,10 +20,12 @@ pub struct Vec2<T: Scalar + Copy> {
}
impl<T: Scalar + Copy> Vec2<T> {
+ /// Create a new vector from its internal values.
pub fn new(x: T, y: T) -> Self {
Self { x, y }
}
+ /// Finds the euclidian length and returns it.
pub fn length(&self) -> T
where
T: RealField,
@@ -27,6 +33,9 @@ impl<T: Scalar + Copy> Vec2<T> {
(self.x * self.x + self.y * self.y).sqrt()
}
+ /// Consumes the vector and returns a vector that is rotated by Pi/2 in clockwise direction.
+ /// This is a special case of rotation and the function is faster than using the nonspecific
+ /// rotation function.
pub fn rotated_90_clockwise(mut self) -> Vec2<T>
where
T: One + Neg<Output = T> + MulAssign,
@@ -36,6 +45,9 @@ impl<T: Scalar + Copy> Vec2<T> {
self
}
+ /// Consumes the vector and returns a vector that is rotated by Pi/2 in counterclockwise direction.
+ /// This is a special case of rotation and the function is faster than using the nonspecific
+ /// rotation function.
pub fn rotated_90_counterclockwise(mut self) -> Vec2<T>
where
T: One + Neg<Output = T> + MulAssign,
diff --git a/src/svg/mod.rs b/src/svg/mod.rs
index fffc00b..af066f1 100644
--- a/src/svg/mod.rs
+++ b/src/svg/mod.rs
@@ -13,10 +13,10 @@ use style::Style;
use svgtypes::{Path as SVGPath, PathSegment};
use xmltree::{Element, XMLNode};
-// Find the first XML-Node with the given name. With depth, the maximum depth the
-// algorithm will search to can be set. If it is set to `None`, the algorithm will search the
-// entire sub-tree. Returns `None` if no such child can be found. Returns itself, in case the root
-// node is already of the name given.
+/// Find the first XML-Node with the given name. With depth, the maximum depth the
+/// algorithm will search to can be set. If it is set to `None`, the algorithm will search the
+/// entire sub-tree. Returns `None` if no such child can be found. Returns itself, in case the root
+/// node is already of the name given.
pub fn find_first_node(root: Element, name: &str, depth: Option<usize>) -> Option<Element> {
// The abort condition of this recursive function. If the element itself is of the required
// name, return it.
@@ -68,7 +68,10 @@ pub fn read_svg_file<P: AsRef<Path>>(file: P) -> io::Result<Element> {
}
}
+/// Trait that indicates a struct is capable of drawing SVG-elements.
pub trait DrawSVG {
+ /// Draw the elements given by `svg_data` and all its children to the implementor, with the
+ /// specified scale and translated by `position_px`.
fn draw_svg(&mut self, svg_data: &Element, pixels_per_m: f32, position_px: Vec2<f32>);
}
diff --git a/src/svg/style.rs b/src/svg/style.rs
index 78b800d..7a0110e 100644
--- a/src/svg/style.rs
+++ b/src/svg/style.rs
@@ -1,3 +1,8 @@
+//! Style options for SVG components.
+//!
+//! For information on SVG styles, pleas see the SVG documentation.
+// TODO: There should be a lib available that can be integrated into the program
+
use raylib::ffi::Color;
use std::str::FromStr;
@@ -32,6 +37,7 @@ pub fn colour_from_html(html: &str) -> Option<Color> {
/// The style of the end of the stroke.
/// See [stroke-line-cap property](https://www.w3.org/TR/SVG11/painting.html#StrokeLinecapProperty)
/// in the SVG Documentation.
+#[allow(missing_docs)]
pub enum StrokeLineCap {
Butt,
Round,
@@ -41,6 +47,7 @@ pub enum StrokeLineCap {
/// The style of the joining corners of the stroke.
/// See [stroke-line-join property](https://www.w3.org/TR/SVG11/painting.html#StrokeLinejoinProperty)
/// in the SVG Documentation
+#[allow(missing_docs)]
pub enum StrokeLineJoin {
Miter,
Round,
@@ -48,6 +55,7 @@ pub enum StrokeLineJoin {
}
/// The style of a path drawing instruction.
+#[allow(missing_docs)]
pub struct Style {
pub fill: Option<Color>,
pub stroke: Color,
diff --git a/src/tool/deletion_tool.rs b/src/tool/deletion_tool.rs
index cd38f6c..afd916a 100644
--- a/src/tool/deletion_tool.rs
+++ b/src/tool/deletion_tool.rs
@@ -1,3 +1,11 @@
+//! A meta tool for selecting parts of a map and removing them in a single operation.
+//!
+//! The user can draw a rectangle, which currently must have it's side parallel to the x and y-axes
+//! of the world. With the first node placement, the mode is started, while the second placement would
+//! finish the process and delete all elements that are *completely* contained in the rectangle
+//! (partially contained items are not deleted) or abort it, in which case the selection is removed
+//! and nothing is deleted.
+
use super::Tool;
use crate::colours::DEFAULT_COLOURS;
use crate::map::Map;
@@ -5,11 +13,14 @@ use crate::math::{Rect, Surface, Vec2};
use crate::transform::Transform;
use raylib::core::drawing::{RaylibDraw, RaylibDrawHandle};
+/// The deletion tool itself.
pub struct DeletionTool {
deletion_rect: Option<(Vec2<f64>, Vec2<f64>)>,
}
impl DeletionTool {
+ /// Create a new deletion tool, there should only be one deletion tool and it should be created
+ /// by the editor.
pub fn new() -> Self {
Self {
deletion_rect: None,
diff --git a/src/tool/icon_tool.rs b/src/tool/icon_tool.rs
index 09b0ac1..c9e671e 100644
--- a/src/tool/icon_tool.rs
+++ b/src/tool/icon_tool.rs
@@ -1,3 +1,6 @@
+//! Tool for creating icons. For explanation of icons, please see
+//! [the icon module](crate::map::icon).
+
use crate::button::Button;
use crate::config::IconToolKeys;
use crate::map::icon_renderer::IconRenderer;
@@ -8,10 +11,8 @@ use crate::transform::Transform;
use raylib::core::drawing::RaylibDrawHandle;
use std::rc::Rc;
-pub const ICON_DIR: &str = "assets/icons";
-
+/// The icon tool itself.
pub struct IconTool {
- // TODO: support svg
keybindings: IconToolKeys,
/// Saves whether the IconTool is the currently active tool or not.
active: bool,
@@ -22,6 +23,8 @@ pub struct IconTool {
}
impl IconTool {
+ /// Create a new icon tool that renders icons with the provided icon renderer. There should only
+ /// be one instance of the tool for the program, which should be created in the editor.
pub fn new(keybindings: IconToolKeys, renderer: Rc<IconRenderer>) -> Self {
Self {
keybindings,
diff --git a/src/tool/mod.rs b/src/tool/mod.rs
index aeabf19..70534ac 100644
--- a/src/tool/mod.rs
+++ b/src/tool/mod.rs
@@ -1,3 +1,11 @@
+//! Tools, which are user interfaces that must be specifically selected in order to do something.
+//!
+//! As stated, a tool is not simply everything that helps a user do something, think of it more as a
+//! mode which must be elected by the user to perform a task on a specific object type or a class of
+//! objects. If instead the operation is defined by the state of the program, it is not a tool, since
+//! the user didn't explicitly ask for this function to be performed, but it is rather an option
+//! that's inherent to the situation the user finds themselves in.
+
pub mod deletion_tool;
pub mod icon_tool;
pub mod polygon_room_tool;
@@ -20,16 +28,31 @@ use raylib::core::drawing::RaylibDrawHandle;
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
#[repr(u8)]
+/// The types of tools available in graf karto. For information about the tool itself, please see the
+/// referenced Tool's documentation.
pub enum ToolType {
+ /// See [super::RectRoomTool] for information on this tool.
RectRoomTool,
+ /// See [super::PolygonRoomTool] for information on this tool.
PolygonRoomTool,
+ /// See [super::WallTool] for information on this tool.
WallTool,
+ /// See [super::IconTool] for information on this tool.
IconTool,
+ /// See [super::DeletionTool] for information on this tool.
DeletionTool,
+ /// See [super::SelectionTool] for information on this tool.
SelectionTool,
+ /// Not a real tool but used to know how many tools are available. New tools must be added
+ /// above this variant.
+ // TODO: Since we now use a hash map in the editor, check if this is still necessary at all.
NumTools,
}
+/// Base trait for tools. A tool is something that performs a specific action on one or more types of
+/// elements. It must be selected in order to be active. For this reason, the selection tool is a
+/// tool (it must be selected from the toolbox), but the dimension indicator for instance is not,
+/// since it is automatically updated when applicable.
pub trait Tool {
/// Code that needs to be called when this Tool is activated or reactivated goes here.
fn activate(&mut self) {}
diff --git a/src/tool/polygon_room_tool.rs b/src/tool/polygon_room_tool.rs
index de6714d..33daaf5 100644
--- a/src/tool/polygon_room_tool.rs
+++ b/src/tool/polygon_room_tool.rs
@@ -1,3 +1,5 @@
+//! Tool to create rooms in the shape of generic polygons.
+
use super::Tool;
use crate::colours::DEFAULT_COLOURS;
use crate::map::Map;
@@ -10,6 +12,7 @@ struct UnfinishedPolygon {
pub working_corner: Vec2<f64>,
}
+/// The tool itself.
pub struct PolygonRoomTool {
unfinished_polygon: Option<UnfinishedPolygon>,
}
@@ -76,6 +79,8 @@ impl UnfinishedPolygon {
}
impl PolygonRoomTool {
+ /// Create a new polygon room tool. There should be only one instance and it should be created
+ /// in the editor.
pub fn new() -> Self {
Self {
unfinished_polygon: None,
diff --git a/src/tool/rect_room_tool.rs b/src/tool/rect_room_tool.rs
index 29173cd..7cb85bb 100644
--- a/src/tool/rect_room_tool.rs
+++ b/src/tool/rect_room_tool.rs
@@ -1,3 +1,7 @@
+//! The rectangle room tool is a specialised tool to create rooms of rectangular shape and with the
+//! sides of the room parallel to the x and y-axes. This is often useful, when a quick room creation
+//! is necessary and the shape of the room does not have to be very special.
+
use super::Tool;
use crate::colours::DEFAULT_COLOURS;
use crate::map::Map;
@@ -5,6 +9,7 @@ use crate::math::{Rect, Vec2};
use crate::transform::Transform;
use raylib::core::drawing::{RaylibDraw, RaylibDrawHandle};
+/// The tool to create simple, rectangular rooms.
pub struct RectRoomTool {
/// The rectangle that is currently being drawn by the user. Once it is finished, it will be
/// pushed into the room_rects.
@@ -12,7 +17,8 @@ pub struct RectRoomTool {
}
impl RectRoomTool {
- /// Create a new room tool where no rooms have been drawn yet.
+ /// Create a new room tool where no rooms have been drawn yet. Should be created only once per
+ /// program instance and by the editor.
pub fn new() -> Self {
Self {
unfinished_rect: None,
diff --git a/src/tool/selection_tool.rs b/src/tool/selection_tool.rs
index 30f91bf..c790734 100644
--- a/src/tool/selection_tool.rs
+++ b/src/tool/selection_tool.rs
@@ -1,3 +1,11 @@
+//! Selection of items on the map.
+//!
+//! When selecting items on the map, the editor goes into a different mode than when editing a
+//! specific kind of item. Actions that are available for specific types of items become
+//! unavailable, while other actions that make use of the properties to a wide range of items
+//! become available instead.
+//! For this reason, the selection tool can be thought of as a kind of meta tool over tools.
+
use super::Tool;
use crate::colours::DEFAULT_COLOURS;
use crate::map::Map;
@@ -5,11 +13,14 @@ use crate::math::{Rect, Surface, Vec2};
use crate::transform::Transform;
use raylib::core::drawing::{RaylibDraw, RaylibDrawHandle};
+/// The selection tool makes it possible to select any item on the map when activated.
pub struct SelectionTool {
selection_rect: Option<(Vec2<f64>, Vec2<f64>)>,
}
impl SelectionTool {
+ /// Create a new selection tool. There should be only one such tool per program instance and it
+ /// should be created in the editor.
pub fn new() -> Self {
Self {
selection_rect: None,
diff --git a/src/tool/wall_tool.rs b/src/tool/wall_tool.rs
index b958799..123171c 100644
--- a/src/tool/wall_tool.rs
+++ b/src/tool/wall_tool.rs
@@ -1,3 +1,6 @@
+//! Tool to create walls. For information about walls, see also
+//! [the wall module](crate::map::wall).
+
use super::Tool;
use crate::map::Map;
use crate::math::{LineSegment, Vec2};
@@ -5,11 +8,14 @@ use crate::transform::Transform;
use raylib::core::drawing::{RaylibDraw, RaylibDrawHandle};
use raylib::ffi::{Color, Vector2};
+/// The wall tool to create solid barriers a player usually cannot cross.
pub struct WallTool {
unfinished_wall: Option<LineSegment<f64>>,
}
impl WallTool {
+ /// Create a new wall tool. There should only be one wall tool per program instance, which should
+ /// be created inside of the editor.
pub fn new() -> Self {
Self {
unfinished_wall: None,
diff --git a/src/transform.rs b/src/transform.rs
index 7c1adbf..147956c 100644
--- a/src/transform.rs
+++ b/src/transform.rs
@@ -9,6 +9,8 @@ const STANDARD_PIXELS_PER_M: f64 = 64.;
const MIN_PIXELS_PER_M: f64 = 5.;
const MAX_PIXELS_PER_M: f64 = 10_000.;
+/// A rigid 2D transformation. Since the translation must often be accessed directly and so far there
+/// was no huge need for fancy transformation, this currently does not use any matrix transformations.
pub struct Transform {
/// The (not necessarily natural) number of pixels per m, i.e. the current scale of the map
pixels_per_m: f64,
@@ -119,9 +121,15 @@ impl Transform {
self.translation_px += *by;
}
+ /// Get the current scale with the number of pixels (as a real number) that makes up a meter of
+ /// actual map space.
pub fn pixels_per_m(&self) -> f64 {
self.pixels_per_m
}
+ /// Get the current translation of the map on the screen. This is purely in pixels, rather than
+ /// meters, since a translation in meters does not make sense, because all map items have an
+ /// absolute position and the translation is merely used to see where on the screen anything
+ /// should be drawn.
pub fn translation_px(&self) -> &Vec2<f64> {
&self.translation_px
}
diff --git a/src/transformable.rs b/src/transformable.rs
index c181bd6..b8212f9 100644
--- a/src/transformable.rs
+++ b/src/transformable.rs
@@ -1,3 +1,12 @@
+//! Traits for items that can be modified using a variety of matrix transformations.
+//!
+//! Items in the world may be resizable or rotateable etc. in a variety of different ways. This
+//! module contains the traits that are used to interact with such objects in a way, that ensures the
+//! item is not transformed illegaly. For example, an item may be scaleable by a factor, but that does
+//! not necessarily mean that it can be scaled by different factors in x and y direction (stretched).
+//! If need be, this module contains the different types of transformations and transformation
+//! restrictions to make these features available and restricting them reliably.
+
use nalgebra::Matrix3;
/// Trait for things that can be stretched and rotated etc. as one pleases without