1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
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,
},
);
}
}
}
|