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
|
//! 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};
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)]
pub(super) struct IconFileInfo {
/// 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).
pub anchor: Vec2<f64>,
/// The scale of the icon as expressed in image pixels per real meter.
pub pixels_per_m: f64,
}
/// Manager for all icon texture or rendering data.
pub struct IconTextureManager {
texture_data: Vec<(Texture2D, IconFileInfo)>,
}
impl IconTextureManager {
/// Create a new icon manager. This loads all textures and information for icons that is needed
/// to draw them to the screen. Usually, there should be only one IconTextureManager, or at least one
/// manager 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
* 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 texture_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: IconFileInfo =
from_reader(ron).expect("Could not parse icon info from reader.");
texture_data.push((texture, icon_info));
}
Self { texture_data }
}
/// Get the textures 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 texture manager.
pub fn num_icons(&self) -> usize {
self.texture_data.len()
}
}
|